From c75d8de4b462bb0acd56dc22118089591eb903df Mon Sep 17 00:00:00 2001 From: lamtruong28 Date: Wed, 29 Jul 2026 13:53:15 +0700 Subject: [PATCH] Write unit test --- .../utils/UartCommunicationTest.kt | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 composeApp/src/commonTest/kotlin/com/digitoolsolutions/app/torquevaultkmp/utils/UartCommunicationTest.kt diff --git a/composeApp/src/commonTest/kotlin/com/digitoolsolutions/app/torquevaultkmp/utils/UartCommunicationTest.kt b/composeApp/src/commonTest/kotlin/com/digitoolsolutions/app/torquevaultkmp/utils/UartCommunicationTest.kt new file mode 100644 index 0000000..19abd00 --- /dev/null +++ b/composeApp/src/commonTest/kotlin/com/digitoolsolutions/app/torquevaultkmp/utils/UartCommunicationTest.kt @@ -0,0 +1,159 @@ +package com.digitoolsolutions.app.torquevaultkmp.utils + +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNotNull + +class UartCommunicationTest { + + /** + * Tests the "Start Work Order" communication flow. + * 1. Device sends a request for work orders ($START_WO;wheel) + * 2. App responds with work order data or empty notification. + */ + @Test + fun testStartWorkOrderFlow() { + // --- STEP 1: App receives request from Device --- + // Format: $COMMAND;TYPE;[WOID;DATA...]\nSECURITYCRC#\n + val deviceRequest = $$"$START_WO;wheel\n00cr16#\n" + val decoded = Helper.decodeRxData(deviceRequest) + + assertNotNull(decoded) + assertEquals(Helper.Command.START_WO.name, decoded.command) + assertEquals("wheel", decoded.type) + assertEquals("0", decoded.woId) + assertEquals("", decoded.data) + assertEquals("00", decoded.securityCode) + assertEquals("cr16", decoded.crc16) + + // --- STEP 2: App prepares response (Empty Case) --- + val emptyCase = Helper.buildUartCommand(Helper.CMD_EMPTY_WO) + assertEquals($$"$START_WO;empty\n00cr16#\n", emptyCase) + + // --- STEP 3: App prepares response (Multiple WO Case) --- + // Format: WO_RES;id;action;make;license;torque;unit;wheelsMask + val wo1 = "WO_RES;1024;0;Mercedes-Benz;A-910;90.00;Nm;3076" + val wo2 = "WO_RES;1025;0;Audi;B-123;100.00;ft-lb;773" + val combined = "$wo1\n$wo2" + + val finalCommand = Helper.buildUartCommand(combined) + val expected = $$"$WO_RES;1024;0;Mercedes-Benz;A-910;90.00;Nm;3076\n" + + "WO_RES;1025;0;Audi;B-123;100.00;ft-lb;773\n" + + "00cr16#\n" + assertEquals(expected, finalCommand) + } + + /** + * Tests the "Confirm Work Order" communication flow. + * 1. Device sends a request to accept a specific work order ($ACCEPT_WO;wheel;1024) + * 2. App responds with OK or NG confirmation. + */ + @Test + fun testConfirmWorkOrder() { + // --- STEP 1: App receives confirmation from Device --- + val deviceRequest = $$"$ACCEPT_WO;wheel;1024\n00cr16#\n" + val decoded = Helper.decodeRxData(deviceRequest) + + assertNotNull(decoded) + assertEquals(Helper.Command.ACCEPT_WO.name, decoded.command) + assertEquals("wheel", decoded.type) + assertEquals("1024", decoded.woId) + assertEquals("00", decoded.securityCode) + assertEquals("cr16", decoded.crc16) + + // --- STEP 2: App prepares OK response --- + val okResponseStr = Helper.CMD_RES_OK(Helper.Command.ACCEPT_WO.name) + val finalOkCommand = Helper.buildUartCommand(okResponseStr) + + assertEquals($$"$ACCEPT_WO;OK\n00cr16#\n", finalOkCommand) + + // --- Exception: App prepares NG response --- + val ngResponseStr = Helper.CMD_RES_NG(Helper.Command.ACCEPT_WO.name) + val finalNgCommand = Helper.buildUartCommand(ngResponseStr) + + assertEquals($$"$ACCEPT_WO;NG\n00cr16#\n", finalNgCommand) + } + + /** + * Tests the "Finish Work Order" data parsing flow. + * Simulates receiving complex torque measurement data from the device. + */ + @Test + fun testFinishWorkOrderFlow() { + // Device sends finish data: $FINISH_WO;w_type;woId;action;unit;nuts;[wheelName;torqueValue...] + // Action: 0 (Torque), 1 (Re-torque), 2 (Cancel) + // In this example: Action=0, Unit=ft-lb, Nuts=7, Wheel=DF (70.70, 70.77, 69.69, 77.89, 71.69, 70.00, 70.00) + val rawData = $$"$FINISH_WO;wheel;1024;0;ft-lb;7;DF;70.70;70.77;69.69;77.89;71.69;70.00;70.00\n00cr16#\n" + val decoded = Helper.decodeRxData(rawData) + + assertNotNull(decoded) + assertEquals("FINISH_WO", decoded.command) + assertEquals("wheel", decoded.type) + assertEquals("1024", decoded.woId) + assertEquals("00", decoded.securityCode) + assertEquals("cr16", decoded.crc16) + assertEquals("0;ft-lb;7;DF;70.70;70.77;69.69;77.89;71.69;70.00;70.00", decoded.data) + + val bleData = decoded.data.split(";") + val action = bleData[0] + val nuts = bleData[2].toInt() + val torqueDataStrings = bleData.subList(3, bleData.size) + + assertEquals(Helper.TorqueAction.TORQUE, action) + assertEquals(7, nuts) + + // Final parsing into a map using Helper + val wheelTorqueData = Helper.parseWheelTorqueData(torqueDataStrings, nuts) + assertEquals(1, wheelTorqueData.size) + assertEquals(listOf(70.70, 70.77, 69.69, 77.89, 71.69, 70.00, 70.00), wheelTorqueData["DF"]) + + // --- App prepares OK response --- + val okResponseStr = Helper.CMD_RES_OK(Helper.Command.FINISH_WO.name) + val finalOkCommand = Helper.buildUartCommand(okResponseStr) + + assertEquals($$"$FINISH_WO;OK\n00cr16#\n", finalOkCommand) + + // --- Exception: App prepares NG response --- + val ngResponseStr = Helper.CMD_RES_NG(Helper.Command.FINISH_WO.name) + val finalNgCommand = Helper.buildUartCommand(ngResponseStr) + + assertEquals($$"$FINISH_WO;NG\n00cr16#\n", finalNgCommand) + } + + /** + * Tests the "Cancel Work Order" communication flow. + * 1. Device sends a request to cancel the current work order ($FINISH_WO;wheel;1024;2;...) + * 2. App responds with OK confirmation. + */ + @Test + fun testCancelWorkOrder() { + // --- STEP 1: App receives cancel request from Device --- + // Action "2" represents CANCEL in TorqueAction + val rawData = $$"$FINISH_WO;wheel;1024;2;ft-lb;7;DF;70.70;70.77;69.69;77.89;71.69;70.00;70.00\n00cr16#\n" + val decoded = Helper.decodeRxData(rawData) + + assertNotNull(decoded) + assertEquals("FINISH_WO", decoded.command) + + assertEquals("wheel", decoded.type) + assertEquals("1024", decoded.woId) + assertEquals("00", decoded.securityCode) + assertEquals("cr16", decoded.crc16) + assertEquals("2;ft-lb;7;DF;70.70;70.77;69.69;77.89;71.69;70.00;70.00", decoded.data) + val bleData = decoded.data.split(";") + val action = bleData[0] + assertEquals(Helper.TorqueAction.CANCEL, action) + + // --- App prepares OK response --- + val okResponseStr = Helper.CMD_RES_OK(Helper.Command.FINISH_WO.name) + val finalOkCommand = Helper.buildUartCommand(okResponseStr) + + assertEquals($$"$FINISH_WO;OK\n00cr16#\n", finalOkCommand) + + // --- Exception: App prepares NG response --- + val ngResponseStr = Helper.CMD_RES_NG(Helper.Command.FINISH_WO.name) + val finalNgCommand = Helper.buildUartCommand(ngResponseStr) + + assertEquals($$"$FINISH_WO;NG\n00cr16#\n", finalNgCommand) + } +}