TherapySettingsTests.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. //
  2. // TherapySettingsTests.swift
  3. // LoopKitTests
  4. //
  5. // Created by Anna Quinlan on 7/27/20.
  6. // Copyright © 2020 LoopKit Authors. All rights reserved.
  7. //
  8. import XCTest
  9. import HealthKit
  10. import LoopKit
  11. class TherapySettingsCodableTests: XCTestCase {
  12. private let dateFormatter = ISO8601DateFormatter()
  13. private let encoder: JSONEncoder = {
  14. let encoder = JSONEncoder()
  15. encoder.outputFormatting = [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes]
  16. encoder.dateEncodingStrategy = .iso8601
  17. return encoder
  18. }()
  19. private let decoder: JSONDecoder = {
  20. let decoder = JSONDecoder()
  21. decoder.dateDecodingStrategy = .iso8601
  22. return decoder
  23. }()
  24. let encodedString = """
  25. {
  26. "basalRateSchedule" : {
  27. "items" : [
  28. {
  29. "startTime" : 0,
  30. "value" : 1
  31. },
  32. {
  33. "startTime" : 28800,
  34. "value" : 1.125
  35. },
  36. {
  37. "startTime" : 36000,
  38. "value" : 1.25
  39. },
  40. {
  41. "startTime" : 43200,
  42. "value" : 1.5
  43. },
  44. {
  45. "startTime" : 50400,
  46. "value" : 1.25
  47. },
  48. {
  49. "startTime" : 57600,
  50. "value" : 1.5
  51. },
  52. {
  53. "startTime" : 64800,
  54. "value" : 1.25
  55. },
  56. {
  57. "startTime" : 75600,
  58. "value" : 1
  59. }
  60. ],
  61. "referenceTimeInterval" : 0,
  62. "repeatInterval" : 86400,
  63. "timeZone" : {
  64. "identifier" : "GMT-0700"
  65. }
  66. },
  67. "carbRatioSchedule" : {
  68. "unit" : "g",
  69. "valueSchedule" : {
  70. "items" : [
  71. {
  72. "startTime" : 0,
  73. "value" : 10
  74. },
  75. {
  76. "startTime" : 28800,
  77. "value" : 12
  78. },
  79. {
  80. "startTime" : 36000,
  81. "value" : 9
  82. },
  83. {
  84. "startTime" : 43200,
  85. "value" : 10
  86. },
  87. {
  88. "startTime" : 50400,
  89. "value" : 11
  90. },
  91. {
  92. "startTime" : 57600,
  93. "value" : 12
  94. },
  95. {
  96. "startTime" : 64800,
  97. "value" : 8
  98. },
  99. {
  100. "startTime" : 75600,
  101. "value" : 10
  102. }
  103. ],
  104. "referenceTimeInterval" : 0,
  105. "repeatInterval" : 86400,
  106. "timeZone" : {
  107. "identifier" : "GMT-0700"
  108. }
  109. }
  110. },
  111. "correctionRangeOverrides" : {
  112. "preMealRange" : {
  113. "bloodGlucoseUnit" : "mg/dL",
  114. "range" : {
  115. "maxValue" : 90,
  116. "minValue" : 80
  117. }
  118. },
  119. "workoutRange" : {
  120. "bloodGlucoseUnit" : "mg/dL",
  121. "range" : {
  122. "maxValue" : 140,
  123. "minValue" : 130
  124. }
  125. }
  126. },
  127. "defaultRapidActingModel" : "rapidActingAdult",
  128. "glucoseTargetRangeSchedule" : {
  129. "rangeSchedule" : {
  130. "unit" : "mg/dL",
  131. "valueSchedule" : {
  132. "items" : [
  133. {
  134. "startTime" : 0,
  135. "value" : {
  136. "maxValue" : 110,
  137. "minValue" : 100
  138. }
  139. },
  140. {
  141. "startTime" : 28800,
  142. "value" : {
  143. "maxValue" : 105,
  144. "minValue" : 95
  145. }
  146. },
  147. {
  148. "startTime" : 50400,
  149. "value" : {
  150. "maxValue" : 105,
  151. "minValue" : 95
  152. }
  153. },
  154. {
  155. "startTime" : 57600,
  156. "value" : {
  157. "maxValue" : 110,
  158. "minValue" : 100
  159. }
  160. },
  161. {
  162. "startTime" : 64800,
  163. "value" : {
  164. "maxValue" : 100,
  165. "minValue" : 90
  166. }
  167. },
  168. {
  169. "startTime" : 75600,
  170. "value" : {
  171. "maxValue" : 120,
  172. "minValue" : 110
  173. }
  174. }
  175. ],
  176. "referenceTimeInterval" : 0,
  177. "repeatInterval" : 86400,
  178. "timeZone" : {
  179. "identifier" : "GMT-0700"
  180. }
  181. }
  182. }
  183. },
  184. "insulinSensitivitySchedule" : {
  185. "unit" : "mg/dL",
  186. "valueSchedule" : {
  187. "items" : [
  188. {
  189. "startTime" : 0,
  190. "value" : 45
  191. },
  192. {
  193. "startTime" : 28800,
  194. "value" : 40
  195. },
  196. {
  197. "startTime" : 36000,
  198. "value" : 35
  199. },
  200. {
  201. "startTime" : 43200,
  202. "value" : 30
  203. },
  204. {
  205. "startTime" : 50400,
  206. "value" : 35
  207. },
  208. {
  209. "startTime" : 57600,
  210. "value" : 40
  211. }
  212. ],
  213. "referenceTimeInterval" : 0,
  214. "repeatInterval" : 86400,
  215. "timeZone" : {
  216. "identifier" : "GMT-0700"
  217. }
  218. }
  219. },
  220. "maximumBasalRatePerHour" : 3,
  221. "maximumBolus" : 5,
  222. "suspendThreshold" : {
  223. "unit" : "mg/dL",
  224. "value" : 80
  225. }
  226. }
  227. """
  228. func testInsulinModelEncoding() throws {
  229. let adult = ExponentialInsulinModelPreset.rapidActingAdult
  230. let child = ExponentialInsulinModelPreset.rapidActingChild
  231. XCTAssertEqual("""
  232. "rapidActingAdult"
  233. """, String(data: try encoder.encode(adult), encoding: .utf8)!)
  234. XCTAssertEqual("""
  235. "rapidActingChild"
  236. """, String(data: try encoder.encode(child), encoding: .utf8)!)
  237. }
  238. func testTherapySettingEncoding() throws {
  239. let original = TherapySettings.test
  240. let data = try encoder.encode(original)
  241. XCTAssertEqual(encodedString, String(data: data, encoding: .utf8)!)
  242. }
  243. func testTherapySettingDecoding() throws {
  244. let data = encodedString.data(using: .utf8)!
  245. let decoded = try decoder.decode(TherapySettings.self, from: data)
  246. let expected = TherapySettings.test
  247. XCTAssertEqual(expected, decoded)
  248. XCTAssertEqual(decoded.basalRateSchedule, expected.basalRateSchedule)
  249. XCTAssertEqual(decoded.insulinSensitivitySchedule, expected.insulinSensitivitySchedule)
  250. XCTAssertEqual(decoded.correctionRangeOverrides, expected.correctionRangeOverrides)
  251. XCTAssertEqual(decoded.maximumBolus, expected.maximumBolus)
  252. XCTAssertEqual(decoded.maximumBasalRatePerHour, expected.maximumBasalRatePerHour)
  253. XCTAssertEqual(decoded.suspendThreshold, expected.suspendThreshold)
  254. XCTAssertEqual(decoded.carbRatioSchedule, expected.carbRatioSchedule)
  255. XCTAssertEqual(decoded.defaultRapidActingModel, expected.defaultRapidActingModel)
  256. XCTAssertEqual(decoded.glucoseTargetRangeSchedule, expected.glucoseTargetRangeSchedule)
  257. }
  258. }
  259. fileprivate extension TherapySettings {
  260. static var test: TherapySettings {
  261. let timeZone = TimeZone(secondsFromGMT: -25200)
  262. let glucoseTargetRangeSchedule = GlucoseRangeSchedule(
  263. rangeSchedule: DailyQuantitySchedule(unit: .milligramsPerDeciliter,
  264. dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: DoubleRange(minValue: 100.0, maxValue: 110.0)),
  265. RepeatingScheduleValue(startTime: .hours(8), value: DoubleRange(minValue: 95.0, maxValue: 105.0)),
  266. RepeatingScheduleValue(startTime: .hours(14), value: DoubleRange(minValue: 95.0, maxValue: 105.0)),
  267. RepeatingScheduleValue(startTime: .hours(16), value: DoubleRange(minValue: 100.0, maxValue: 110.0)),
  268. RepeatingScheduleValue(startTime: .hours(18), value: DoubleRange(minValue: 90.0, maxValue: 100.0)),
  269. RepeatingScheduleValue(startTime: .hours(21), value: DoubleRange(minValue: 110.0, maxValue: 120.0))],
  270. timeZone: timeZone)!)
  271. let basalRateSchedule = BasalRateSchedule(
  272. dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: 1.0),
  273. RepeatingScheduleValue(startTime: .hours(8), value: 1.125),
  274. RepeatingScheduleValue(startTime: .hours(10), value: 1.25),
  275. RepeatingScheduleValue(startTime: .hours(12), value: 1.5),
  276. RepeatingScheduleValue(startTime: .hours(14), value: 1.25),
  277. RepeatingScheduleValue(startTime: .hours(16), value: 1.5),
  278. RepeatingScheduleValue(startTime: .hours(18), value: 1.25),
  279. RepeatingScheduleValue(startTime: .hours(21), value: 1.0)],
  280. timeZone: timeZone)!
  281. let insulinSensitivitySchedule = InsulinSensitivitySchedule(
  282. unit: .milligramsPerDeciliter,
  283. dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: 45.0),
  284. RepeatingScheduleValue(startTime: .hours(8), value: 40.0),
  285. RepeatingScheduleValue(startTime: .hours(10), value: 35.0),
  286. RepeatingScheduleValue(startTime: .hours(12), value: 30.0),
  287. RepeatingScheduleValue(startTime: .hours(14), value: 35.0),
  288. RepeatingScheduleValue(startTime: .hours(16), value: 40.0)],
  289. timeZone: timeZone)!
  290. let carbRatioSchedule = CarbRatioSchedule(
  291. unit: .gram(),
  292. dailyItems: [RepeatingScheduleValue(startTime: .hours(0), value: 10.0),
  293. RepeatingScheduleValue(startTime: .hours(8), value: 12.0),
  294. RepeatingScheduleValue(startTime: .hours(10), value: 9.0),
  295. RepeatingScheduleValue(startTime: .hours(12), value: 10.0),
  296. RepeatingScheduleValue(startTime: .hours(14), value: 11.0),
  297. RepeatingScheduleValue(startTime: .hours(16), value: 12.0),
  298. RepeatingScheduleValue(startTime: .hours(18), value: 8.0),
  299. RepeatingScheduleValue(startTime: .hours(21), value: 10.0)],
  300. timeZone: timeZone)!
  301. let correctionRangeOverrides = CorrectionRangeOverrides(
  302. preMeal: DoubleRange(minValue: 80.0, maxValue: 90.0),
  303. workout: DoubleRange(minValue: 130.0, maxValue: 140.0),
  304. unit: .milligramsPerDeciliter)
  305. return TherapySettings(
  306. glucoseTargetRangeSchedule: glucoseTargetRangeSchedule,
  307. correctionRangeOverrides: correctionRangeOverrides,
  308. maximumBasalRatePerHour: 3,
  309. maximumBolus: 5,
  310. suspendThreshold: GlucoseThreshold(unit: .milligramsPerDeciliter, value: 80),
  311. insulinSensitivitySchedule: insulinSensitivitySchedule,
  312. carbRatioSchedule: carbRatioSchedule,
  313. basalRateSchedule: basalRateSchedule,
  314. defaultRapidActingModel: ExponentialInsulinModelPreset.rapidActingAdult
  315. )
  316. }
  317. }