MessageTests.swift 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. //
  2. // MessageTests.swift
  3. // OmniKitTests
  4. //
  5. // Created by Pete Schwamb on 10/14/17.
  6. // Copyright © 2017 Pete Schwamb. All rights reserved.
  7. //
  8. import XCTest
  9. @testable import OmniKit
  10. class MessageTests: XCTestCase {
  11. func testMessageData() {
  12. // 2016-06-26T20:33:28.412197 ID1:1f01482a PTYPE:PDM SEQ:13 ID2:1f01482a B9:10 BLEN:3 BODY:0e0100802c CRC:88
  13. let msg = Message(address: 0x1f01482a, messageBlocks: [GetStatusCommand()], sequenceNum: 4)
  14. XCTAssertEqual("1f01482a10030e0100802c", msg.encoded().hexadecimalString)
  15. }
  16. func testMessageDecoding() {
  17. do {
  18. let msg = try Message(encodedData: Data(hexadecimalString: "1f00ee84300a1d18003f1800004297ff8128")!)
  19. XCTAssertEqual(0x1f00ee84, msg.address)
  20. XCTAssertEqual(12, msg.sequenceNum)
  21. let messageBlocks = msg.messageBlocks
  22. XCTAssertEqual(1, messageBlocks.count)
  23. let statusResponse = messageBlocks[0] as! StatusResponse
  24. XCTAssertEqual(nil, statusResponse.reservoirLevel)
  25. XCTAssertEqual(TimeInterval(minutes: 4261), statusResponse.timeActive)
  26. XCTAssertEqual(.scheduledBasal, statusResponse.deliveryStatus)
  27. XCTAssertEqual(.aboveFiftyUnits, statusResponse.podProgressStatus)
  28. XCTAssertEqual(6.3, statusResponse.insulin, accuracy: 0.01)
  29. XCTAssertEqual(0, statusResponse.bolusNotDelivered)
  30. XCTAssertEqual(3, statusResponse.lastProgrammingMessageSeqNum)
  31. XCTAssert(statusResponse.alerts.isEmpty)
  32. XCTAssertEqual("1f00ee84300a1d18003f1800004297ff8128", msg.encoded().hexadecimalString)
  33. } catch (let error) {
  34. XCTFail("message decoding threw error: \(error)")
  35. }
  36. }
  37. func testAssemblingMultiPacketMessage() {
  38. do {
  39. let packet1 = try Packet(encodedData: Data(hexadecimalString: "ffffffffe4ffffffff041d011b13881008340a5002070002070002030000a62b0004479420")!)
  40. XCTAssertEqual(packet1.data.hexadecimalString, "ffffffff041d011b13881008340a5002070002070002030000a62b00044794")
  41. XCTAssertEqual(packet1.packetType, .pod)
  42. XCTAssertThrowsError(try Message(encodedData: packet1.data)) { error in
  43. XCTAssertEqual(String(describing: error), "notEnoughData")
  44. }
  45. let packet2 = try Packet(encodedData: Data(hexadecimalString: "ffffffff861f00ee878352ff")!)
  46. XCTAssertEqual(packet2.address, 0xffffffff)
  47. XCTAssertEqual(packet2.data.hexadecimalString, "1f00ee878352")
  48. XCTAssertEqual(packet2.packetType, .con)
  49. let messageBody = packet1.data + packet2.data
  50. XCTAssertEqual(messageBody.hexadecimalString, "ffffffff041d011b13881008340a5002070002070002030000a62b000447941f00ee878352")
  51. let message = try Message(encodedData: messageBody)
  52. XCTAssertEqual(message.messageBlocks.count, 1)
  53. } catch (let error) {
  54. XCTFail("message decoding threw error: \(error)")
  55. }
  56. }
  57. func testParsingVersionResponse() {
  58. do {
  59. let config = try VersionResponse(encodedData: Data(hexadecimalString: "011502070002070002020000a64000097c279c1f08ced2")!)
  60. XCTAssertEqual(23, config.data.count)
  61. XCTAssertEqual("2.7.0", String(describing: config.piVersion))
  62. XCTAssertEqual("2.7.0", String(describing: config.pmVersion))
  63. XCTAssertEqual(0x1f08ced2, config.address)
  64. XCTAssertEqual(42560, config.lot)
  65. XCTAssertEqual(621607, config.tid)
  66. XCTAssertEqual(2, config.productID)
  67. XCTAssertEqual(.reminderInitialized, config.podProgressStatus)
  68. XCTAssertEqual(2, config.gain)
  69. XCTAssertEqual(0x1c, config.rssi)
  70. XCTAssertNil(config.pulseSize)
  71. XCTAssertNil(config.secondsPerBolusPulse)
  72. XCTAssertNil(config.secondsPerPrimePulse)
  73. XCTAssertNil(config.primeUnits)
  74. XCTAssertNil(config.cannulaInsertionUnits)
  75. XCTAssertNil(config.serviceDuration)
  76. } catch (let error) {
  77. XCTFail("message decoding threw error: \(error)")
  78. }
  79. }
  80. func testParsingLongVersionResponse() {
  81. do {
  82. let message = try Message(encodedData: Data(hexadecimalString: "ffffffff041d011b13881008340a5002070002070002030000a62b000447941f00ee878352")!)
  83. let config = message.messageBlocks[0] as! VersionResponse
  84. XCTAssertEqual(29, config.data.count)
  85. XCTAssertEqual("2.7.0", String(describing: config.piVersion))
  86. XCTAssertEqual("2.7.0", String(describing: config.pmVersion))
  87. XCTAssertEqual(42539, config.lot)
  88. XCTAssertEqual(280468, config.tid)
  89. XCTAssertEqual(0x1f00ee87, config.address)
  90. XCTAssertEqual(2, config.productID)
  91. XCTAssertEqual(.pairingCompleted, config.podProgressStatus)
  92. XCTAssertNil(config.rssi)
  93. XCTAssertNil(config.gain)
  94. XCTAssertEqual(Pod.pulseSize, config.pulseSize)
  95. XCTAssertEqual(Pod.secondsPerBolusPulse, config.secondsPerBolusPulse)
  96. XCTAssertEqual(Pod.secondsPerPrimePulse, config.secondsPerPrimePulse)
  97. XCTAssertEqual(Pod.primeUnits, config.primeUnits)
  98. XCTAssertEqual(Pod.cannulaInsertionUnits, config.cannulaInsertionUnits)
  99. XCTAssertEqual(Pod.serviceDuration, config.serviceDuration)
  100. } catch (let error) {
  101. XCTFail("message decoding threw error: \(error)")
  102. }
  103. }
  104. func testParsingConfigWithPairingExpired() {
  105. do {
  106. let message = try Message(encodedData: Data(hexadecimalString: "ffffffff04170115020700020700020e0000a5ad00053030971f08686301fd")!)
  107. let config = message.messageBlocks[0] as! VersionResponse
  108. XCTAssertEqual("2.7.0", String(describing: config.piVersion))
  109. XCTAssertEqual("2.7.0", String(describing: config.pmVersion))
  110. XCTAssertEqual(0x0000a5ad, config.lot)
  111. XCTAssertEqual(0x00053030, config.tid)
  112. XCTAssertEqual(0x1f086863, config.address)
  113. XCTAssertEqual(2, config.productID)
  114. XCTAssertEqual(.activationTimeExceeded, config.podProgressStatus)
  115. XCTAssertEqual(2, config.gain)
  116. XCTAssertEqual(0x17, config.rssi)
  117. XCTAssertNil(config.pulseSize)
  118. XCTAssertNil(config.secondsPerBolusPulse)
  119. XCTAssertNil(config.secondsPerPrimePulse)
  120. XCTAssertNil(config.primeUnits)
  121. XCTAssertNil(config.cannulaInsertionUnits)
  122. XCTAssertNil(config.serviceDuration)
  123. } catch (let error) {
  124. XCTFail("message decoding threw error: \(error)")
  125. }
  126. }
  127. func testAssignAddressCommand() {
  128. do {
  129. // Encode
  130. let encoded = AssignAddressCommand(address: 0x1f01482a)
  131. XCTAssertEqual("07041f01482a", encoded.data.hexadecimalString)
  132. // Decode
  133. let decoded = try AssignAddressCommand(encodedData: Data(hexadecimalString: "07041f01482a")!)
  134. XCTAssertEqual(0x1f01482a, decoded.address)
  135. } catch (let error) {
  136. XCTFail("message decoding threw error: \(error)")
  137. }
  138. }
  139. func testSetupPodCommand() {
  140. do {
  141. var components = DateComponents()
  142. components.day = 12
  143. components.month = 6
  144. components.year = 2016
  145. components.hour = 13
  146. components.minute = 47
  147. // Decode
  148. let decoded = try SetupPodCommand(encodedData: Data(hexadecimalString: "03131f0218c31404060c100d2f0000a4be0004e4a1")!)
  149. XCTAssertEqual(0x1f0218c3, decoded.address)
  150. XCTAssertEqual(components, decoded.dateComponents)
  151. XCTAssertEqual(0x0000a4be, decoded.lot)
  152. XCTAssertEqual(0x0004e4a1, decoded.tid)
  153. // Encode
  154. let encoded = SetupPodCommand(address: 0x1f0218c3, dateComponents: components, lot: 0x0000a4be, tid: 0x0004e4a1)
  155. XCTAssertEqual("03131f0218c31404060c100d2f0000a4be0004e4a1", encoded.data.hexadecimalString)
  156. } catch (let error) {
  157. XCTFail("message decoding threw error: \(error)")
  158. }
  159. }
  160. func testInsertCannula() {
  161. // 2018-04-03T19:23:14.3d ID1:1f00ee85 PTYPE:PDM SEQ:17 ID2:1f00ee85 B9:38 BLEN:31 BODY:1a0e7e30bf16020065010050000a000a170d000064000186a0 CRC:33
  162. // 2018-04-03T19:23:14.3d ID1:1f00ee85 PTYPE:ACK SEQ:18 ID2:1f00ee85 CRC:89
  163. // 2018-04-03T19:23:14.3d ID1:1f00ee85 PTYPE:CON SEQ:19 CON:000000000000808c CRC:6f
  164. // 2018-04-03T19:23:14.3d ID1:1f00ee85 PTYPE:POD SEQ:20 ID2:1f00ee85 B9:3c BLEN:10 BODY:1d570016f00a00000bff8099 CRC:86
  165. // 2018-04-03T19:23:14.3d ID1:1f00ee85 PTYPE:ACK SEQ:21 ID2:1f00ee85 CRC:a0
  166. do {
  167. // Decode
  168. let cmd = try SetInsulinScheduleCommand(encodedData: Data(hexadecimalString: "1a0ebed2e16b02010a0101a000340034")!)
  169. XCTAssertEqual(0xbed2e16b, cmd.nonce)
  170. if case SetInsulinScheduleCommand.DeliverySchedule.bolus(let units, let timeBetweenPulses) = cmd.deliverySchedule {
  171. XCTAssertEqual(2.6, units)
  172. XCTAssertEqual(.seconds(1), timeBetweenPulses)
  173. } else {
  174. XCTFail("Expected ScheduleEntry.bolus type")
  175. }
  176. } catch (let error) {
  177. XCTFail("message decoding threw error: \(error)")
  178. }
  179. }
  180. func testStatusResponseAlarmsParsing() {
  181. // 1d 28 0082 00 0044 46eb ff
  182. do {
  183. // Decode
  184. let status = try StatusResponse(encodedData: Data(hexadecimalString: "1d28008200004446ebff")!)
  185. XCTAssert(status.alerts.contains(.slot3))
  186. XCTAssert(status.alerts.contains(.slot7))
  187. } catch (let error) {
  188. XCTFail("message decoding threw error: \(error)")
  189. }
  190. }
  191. func testConfigureAlertsCommand() {
  192. // 79a4 10df 0502
  193. // Pod expires 1 minute short of 3 days
  194. let podSoftExpirationTime = TimeInterval(hours:72) - TimeInterval(minutes:1)
  195. let alertConfig1 = AlertConfiguration(alertType: .slot7, active: true, autoOffModifier: false, duration: .hours(7), trigger: .timeUntilAlert(podSoftExpirationTime), beepRepeat: .every60Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep)
  196. XCTAssertEqual("79a410df0502", alertConfig1.data.hexadecimalString)
  197. // 2800 1283 0602
  198. let podHardExpirationTime = TimeInterval(hours:79) - TimeInterval(minutes:1)
  199. let alertConfig2 = AlertConfiguration(alertType: .slot2, active: true, autoOffModifier: false, duration: .minutes(0), trigger: .timeUntilAlert(podHardExpirationTime), beepRepeat: .every15Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep)
  200. XCTAssertEqual("280012830602", alertConfig2.data.hexadecimalString)
  201. // 020f 0000 0202
  202. let alertConfig3 = AlertConfiguration(alertType: .slot0, active: false, autoOffModifier: true, duration: .minutes(15), trigger: .timeUntilAlert(0), beepRepeat: .every1MinuteFor15Minutes, beepType: .bipBeepBipBeepBipBeepBipBeep)
  203. XCTAssertEqual("020f00000202", alertConfig3.data.hexadecimalString)
  204. let configureAlerts = ConfigureAlertsCommand(nonce: 0xfeb6268b, configurations:[alertConfig1, alertConfig2, alertConfig3])
  205. XCTAssertEqual("1916feb6268b79a410df0502280012830602020f00000202", configureAlerts.data.hexadecimalString)
  206. do {
  207. let decoded = try ConfigureAlertsCommand(encodedData: Data(hexadecimalString: "1916feb6268b79a410df0502280012830602020f00000202")!)
  208. XCTAssertEqual(3, decoded.configurations.count)
  209. let config1 = decoded.configurations[0]
  210. XCTAssertEqual(.slot7, config1.slot)
  211. XCTAssertEqual(true, config1.active)
  212. XCTAssertEqual(false, config1.autoOffModifier)
  213. XCTAssertEqual(.hours(7), config1.duration)
  214. if case AlertTrigger.timeUntilAlert(let duration) = config1.trigger {
  215. XCTAssertEqual(podSoftExpirationTime, duration)
  216. }
  217. XCTAssertEqual(.every60Minutes, config1.beepRepeat)
  218. XCTAssertEqual(.bipBeepBipBeepBipBeepBipBeep, config1.beepType)
  219. let cfg = try AlertConfiguration(encodedData: Data(hexadecimalString: "4c0000640102")!)
  220. XCTAssertEqual(.slot4, cfg.slot)
  221. XCTAssertEqual(true, cfg.active)
  222. XCTAssertEqual(false, cfg.autoOffModifier)
  223. XCTAssertEqual(0, cfg.duration)
  224. if case AlertTrigger.unitsRemaining(let volume) = cfg.trigger {
  225. XCTAssertEqual(10, volume)
  226. }
  227. XCTAssertEqual(.every1MinuteFor3MinutesAndRepeatEvery60Minutes, cfg.beepRepeat)
  228. XCTAssertEqual(.bipBeepBipBeepBipBeepBipBeep, cfg.beepType)
  229. } catch (let error) {
  230. XCTFail("message decoding threw error: \(error)")
  231. }
  232. }
  233. }