CachedInsulinDeliveryObjectTests.swift 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. //
  2. // CachedInsulinDeliveryObjectTests.swift
  3. // LoopKitTests
  4. //
  5. // Copyright © 2018 LoopKit Authors. All rights reserved.
  6. //
  7. import XCTest
  8. import HealthKit
  9. @testable import LoopKit
  10. class CachedInsulinDeliveryObjectTests: PersistenceControllerTestCase {
  11. func testReasonGet() {
  12. cacheStore.managedObjectContext.performAndWait {
  13. let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  14. object.primitiveReason = NSNumber(integerLiteral: 2)
  15. XCTAssertEqual(object.reason, .bolus)
  16. }
  17. }
  18. func testReasonSet() {
  19. cacheStore.managedObjectContext.performAndWait {
  20. let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  21. object.reason = .basal
  22. XCTAssertEqual(object.primitiveReason, NSNumber(integerLiteral: 1))
  23. }
  24. }
  25. func testScheduledBasalRateGet() {
  26. cacheStore.managedObjectContext.performAndWait {
  27. let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  28. object.primitiveScheduledBasalRate = NSNumber(floatLiteral: 1.23)
  29. XCTAssertEqual(object.scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.23))
  30. }
  31. }
  32. func testScheduledBasalRateGetNil() {
  33. cacheStore.managedObjectContext.performAndWait {
  34. let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  35. object.primitiveScheduledBasalRate = nil
  36. XCTAssertNil(object.scheduledBasalRate)
  37. }
  38. }
  39. func testScheduledBasalRateSet() {
  40. cacheStore.managedObjectContext.performAndWait {
  41. let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  42. object.scheduledBasalRate = HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 2.34)
  43. XCTAssertEqual(object.primitiveScheduledBasalRate, NSNumber(floatLiteral: 2.34))
  44. }
  45. }
  46. func testScheduledBasalRateSetNil() {
  47. cacheStore.managedObjectContext.performAndWait {
  48. let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  49. object.scheduledBasalRate = nil
  50. XCTAssertNil(object.primitiveScheduledBasalRate)
  51. }
  52. }
  53. func testPrimitiveProgrammedTempBasalRateGet() {
  54. cacheStore.managedObjectContext.performAndWait {
  55. let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  56. object.primitiveProgrammedTempBasalRate = NSNumber(floatLiteral: 1.23)
  57. XCTAssertEqual(object.programmedTempBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.23))
  58. }
  59. }
  60. func testPrimitiveProgrammedTempBasalRateGetNil() {
  61. cacheStore.managedObjectContext.performAndWait {
  62. let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  63. object.primitiveProgrammedTempBasalRate = nil
  64. XCTAssertNil(object.programmedTempBasalRate)
  65. }
  66. }
  67. func testPrimitiveProgrammedTempBasalRateSet() {
  68. cacheStore.managedObjectContext.performAndWait {
  69. let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  70. object.programmedTempBasalRate = HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 2.34)
  71. XCTAssertEqual(object.primitiveProgrammedTempBasalRate, NSNumber(floatLiteral: 2.34))
  72. }
  73. }
  74. func testPrimitiveProgrammedTempBasalRateSetNil() {
  75. cacheStore.managedObjectContext.performAndWait {
  76. let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  77. object.programmedTempBasalRate = nil
  78. XCTAssertNil(object.primitiveProgrammedTempBasalRate)
  79. }
  80. }
  81. }
  82. class CachedInsulinDeliveryObjectDoseTests: PersistenceControllerTestCase {
  83. func testDoseBasal() {
  84. cacheStore.managedObjectContext.performAndWait {
  85. let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  86. object.provenanceIdentifier = Bundle.main.bundleIdentifier!
  87. object.hasLoopKitOrigin = true
  88. object.startDate = dateFormatter.date(from: "2020-01-02T03:04:05Z")!
  89. object.endDate = dateFormatter.date(from: "2020-01-02T04:04:05Z")!
  90. object.syncIdentifier = "876DDBF9-CC47-45ED-B0D7-AD77B77913C4"
  91. object.value = 0.5
  92. object.scheduledBasalRate = nil
  93. object.programmedTempBasalRate = nil
  94. object.reason = .basal
  95. object.createdAt = dateFormatter.date(from: "2020-01-02T04:04:06Z")!
  96. let dose = object.dose
  97. XCTAssertNotNil(dose)
  98. XCTAssertEqual(dose!.type, .basal)
  99. XCTAssertEqual(dose!.startDate, dateFormatter.date(from: "2020-01-02T03:04:05Z")!)
  100. XCTAssertEqual(dose!.endDate, dateFormatter.date(from: "2020-01-02T04:04:05Z")!)
  101. XCTAssertEqual(dose!.value, 0.5)
  102. XCTAssertEqual(dose!.unit, .units)
  103. XCTAssertEqual(dose!.deliveredUnits, nil)
  104. XCTAssertEqual(dose!.description, nil)
  105. XCTAssertEqual(dose!.syncIdentifier, "876DDBF9-CC47-45ED-B0D7-AD77B77913C4")
  106. XCTAssertEqual(dose!.scheduledBasalRate, nil)
  107. }
  108. }
  109. func testDoseTempBasal() {
  110. cacheStore.managedObjectContext.performAndWait {
  111. let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  112. object.provenanceIdentifier = Bundle.main.bundleIdentifier!
  113. object.hasLoopKitOrigin = false
  114. object.startDate = dateFormatter.date(from: "2020-01-02T03:04:06Z")!
  115. object.endDate = dateFormatter.date(from: "2020-01-02T03:34:06Z")!
  116. object.syncIdentifier = nil
  117. object.value = 0.75
  118. object.scheduledBasalRate = HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.0)
  119. object.programmedTempBasalRate = HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.5)
  120. object.reason = .basal
  121. object.createdAt = dateFormatter.date(from: "2020-01-02T04:04:07Z")!
  122. let dose = object.dose
  123. XCTAssertNotNil(dose)
  124. XCTAssertEqual(dose!.type, .tempBasal)
  125. XCTAssertEqual(dose!.startDate, dateFormatter.date(from: "2020-01-02T03:04:06Z")!)
  126. XCTAssertEqual(dose!.endDate, dateFormatter.date(from: "2020-01-02T03:34:06Z")!)
  127. XCTAssertEqual(dose!.value, 1.5)
  128. XCTAssertEqual(dose!.unit, .unitsPerHour)
  129. XCTAssertEqual(dose!.deliveredUnits, 0.75)
  130. XCTAssertEqual(dose!.description, nil)
  131. XCTAssertEqual(dose!.syncIdentifier, nil)
  132. XCTAssertEqual(dose!.scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.0))
  133. }
  134. }
  135. func testDoseBolus() {
  136. cacheStore.managedObjectContext.performAndWait {
  137. let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  138. object.provenanceIdentifier = Bundle.main.bundleIdentifier!
  139. object.hasLoopKitOrigin = true
  140. object.startDate = dateFormatter.date(from: "2020-01-02T05:04:05Z")!
  141. object.endDate = dateFormatter.date(from: "2020-01-02T05:05:05Z")!
  142. object.syncIdentifier = "9AA61454-EED5-476F-8E57-4BA63D0267C1"
  143. object.value = 2.25
  144. object.scheduledBasalRate = nil
  145. object.programmedTempBasalRate = nil
  146. object.reason = .bolus
  147. object.createdAt = dateFormatter.date(from: "2020-01-02T05:05:06Z")!
  148. let dose = object.dose
  149. XCTAssertNotNil(dose)
  150. XCTAssertEqual(dose!.type, .bolus)
  151. XCTAssertEqual(dose!.startDate, dateFormatter.date(from: "2020-01-02T05:04:05Z")!)
  152. XCTAssertEqual(dose!.endDate, dateFormatter.date(from: "2020-01-02T05:05:05Z")!)
  153. XCTAssertEqual(dose!.value, 2.25)
  154. XCTAssertEqual(dose!.unit, .units)
  155. XCTAssertEqual(dose!.deliveredUnits, nil)
  156. XCTAssertEqual(dose!.description, nil)
  157. XCTAssertEqual(dose!.syncIdentifier, "9AA61454-EED5-476F-8E57-4BA63D0267C1")
  158. XCTAssertEqual(dose!.scheduledBasalRate, nil)
  159. }
  160. }
  161. private let dateFormatter = ISO8601DateFormatter()
  162. }
  163. class CachedInsulinDeliveryObjectOperationsTests: PersistenceControllerTestCase {
  164. func testCreateWithoutUUID() {
  165. let metadata: [String: Any] = [
  166. HKMetadataKeySyncIdentifier: "AF41499D-973E-4974-AE03-D57083F5353C",
  167. HKMetadataKeySyncVersion: 2,
  168. HKMetadataKeyInsulinDeliveryReason: HKInsulinDeliveryReason.basal.rawValue,
  169. MetadataKeyHasLoopKitOrigin: true,
  170. MetadataKeyScheduledBasalRate: HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.0),
  171. MetadataKeyProgrammedTempBasalRate: HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.5),
  172. MetadataKeyProvenanceIdentifier: Bundle.main.bundleIdentifier!
  173. ]
  174. let sample = HKQuantitySample(type: HKQuantityType.quantityType(forIdentifier: .insulinDelivery)!,
  175. quantity: HKQuantity(unit: .internationalUnit(), doubleValue: 0.75),
  176. start: dateFormatter.date(from: "2020-01-02T03:04:05Z")!,
  177. end: dateFormatter.date(from: "2020-01-02T03:34:05Z")!,
  178. metadata: metadata)
  179. cacheStore.managedObjectContext.performAndWait {
  180. let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  181. object.create(fromNew: sample, on: dateFormatter.date(from: "2020-01-02T03:34:06Z")!)
  182. XCTAssertNil(object.uuid)
  183. XCTAssertEqual(object.provenanceIdentifier, Bundle.main.bundleIdentifier!)
  184. XCTAssertEqual(object.hasLoopKitOrigin, true)
  185. XCTAssertEqual(object.startDate, dateFormatter.date(from: "2020-01-02T03:04:05Z")!)
  186. XCTAssertEqual(object.endDate, dateFormatter.date(from: "2020-01-02T03:34:05Z")!)
  187. XCTAssertEqual(object.syncIdentifier, "AF41499D-973E-4974-AE03-D57083F5353C")
  188. XCTAssertEqual(object.value, 0.75)
  189. XCTAssertEqual(object.scheduledBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.0))
  190. XCTAssertEqual(object.programmedTempBasalRate, HKQuantity(unit: .internationalUnitsPerHour, doubleValue: 1.5))
  191. XCTAssertEqual(object.reason, .basal)
  192. XCTAssertEqual(object.createdAt, dateFormatter.date(from: "2020-01-02T03:34:06Z")!)
  193. }
  194. }
  195. func testCreateWithUUIDAndWithoutOptional() {
  196. let metadata: [String: Any] = [
  197. HKMetadataKeyInsulinDeliveryReason: HKInsulinDeliveryReason.bolus.rawValue,
  198. ]
  199. let sample = HKQuantitySample(type: HKQuantityType.quantityType(forIdentifier: .insulinDelivery)!,
  200. quantity: HKQuantity(unit: .internationalUnit(), doubleValue: 2.25),
  201. start: dateFormatter.date(from: "2020-02-03T04:05:06Z")!,
  202. end: dateFormatter.date(from: "2020-02-03T04:05:36Z")!,
  203. metadata: metadata)
  204. cacheStore.managedObjectContext.performAndWait {
  205. let object = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  206. object.create(fromExisting: sample, on: dateFormatter.date(from: "2020-02-03T04:05:37Z")!)
  207. XCTAssertEqual(object.uuid, sample.uuid)
  208. XCTAssertEqual(object.provenanceIdentifier, "") // Not yet persisted so HealthKit reports as empty string
  209. XCTAssertEqual(object.hasLoopKitOrigin, false)
  210. XCTAssertEqual(object.startDate, dateFormatter.date(from: "2020-02-03T04:05:06Z")!)
  211. XCTAssertEqual(object.endDate, dateFormatter.date(from: "2020-02-03T04:05:36Z")!)
  212. XCTAssertEqual(object.syncIdentifier, sample.uuid.uuidString)
  213. XCTAssertEqual(object.value, 2.25)
  214. XCTAssertNil(object.scheduledBasalRate)
  215. XCTAssertNil(object.programmedTempBasalRate)
  216. XCTAssertEqual(object.reason, .bolus)
  217. XCTAssertEqual(object.createdAt, dateFormatter.date(from: "2020-02-03T04:05:37Z")!)
  218. }
  219. }
  220. private let dateFormatter = ISO8601DateFormatter()
  221. }
  222. class CachedInsulinDeliveryObjectConstraintTests: PersistenceControllerTestCase {
  223. func testUUIDUniqueConstraintPreSave() {
  224. cacheStore.managedObjectContext.performAndWait {
  225. let uuid = UUID()
  226. let object1 = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  227. object1.setDefaultValues()
  228. object1.uuid = uuid
  229. object1.syncIdentifier = "object1"
  230. let object2 = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  231. object2.setDefaultValues()
  232. object2.uuid = uuid
  233. object2.syncIdentifier = "object2"
  234. try! cacheStore.managedObjectContext.save()
  235. let objects: [CachedInsulinDeliveryObject] = cacheStore.managedObjectContext.all()
  236. XCTAssertEqual(1, objects.count)
  237. }
  238. }
  239. func testUUIDUniqueConstraintPostSave() {
  240. cacheStore.managedObjectContext.performAndWait {
  241. let uuid = UUID()
  242. let object1 = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  243. object1.setDefaultValues()
  244. object1.uuid = uuid
  245. try! cacheStore.managedObjectContext.save()
  246. let object2 = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  247. object2.setDefaultValues()
  248. object2.uuid = uuid
  249. try! cacheStore.managedObjectContext.save()
  250. let objects: [CachedInsulinDeliveryObject] = cacheStore.managedObjectContext.all()
  251. XCTAssertEqual(1, objects.count)
  252. }
  253. }
  254. func testSyncIdentifierUniqueConstraint() {
  255. cacheStore.managedObjectContext.performAndWait {
  256. let uuid = UUID()
  257. let object1 = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  258. object1.setDefaultValues()
  259. object1.syncIdentifier = uuid.uuidString
  260. try! cacheStore.managedObjectContext.save()
  261. let object2 = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  262. object2.setDefaultValues()
  263. object2.syncIdentifier = uuid.uuidString
  264. try! cacheStore.managedObjectContext.save()
  265. let objects: [CachedInsulinDeliveryObject] = cacheStore.managedObjectContext.all()
  266. XCTAssertEqual(1, objects.count)
  267. }
  268. }
  269. func testSaveWithDefaultValues() {
  270. cacheStore.managedObjectContext.performAndWait {
  271. let object1 = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  272. object1.setDefaultValues()
  273. try! cacheStore.managedObjectContext.save()
  274. let object2 = CachedInsulinDeliveryObject(context: cacheStore.managedObjectContext)
  275. object2.setDefaultValues()
  276. try! cacheStore.managedObjectContext.save()
  277. let objects: [CachedInsulinDeliveryObject] = cacheStore.managedObjectContext.all()
  278. XCTAssertEqual(2, objects.count)
  279. }
  280. }
  281. }
  282. extension CachedInsulinDeliveryObject {
  283. fileprivate func setDefaultValues() {
  284. self.uuid = UUID()
  285. self.provenanceIdentifier = "CachedInsulinDeliveryObjectTests"
  286. self.hasLoopKitOrigin = true
  287. self.startDate = Date()
  288. self.endDate = Date()
  289. self.syncIdentifier = UUID().uuidString
  290. self.value = 3.5
  291. self.scheduledBasalRate = nil
  292. self.programmedTempBasalRate = nil
  293. self.reason = .basal
  294. self.createdAt = Date()
  295. }
  296. }