DetermineBasalJsonTests.swift 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import Foundation
  2. import Testing
  3. @testable import Trio
  4. @Suite("DetermineBasal testing using JSON inputs", .serialized) struct DetermineBasalJsonTests {
  5. let timeZoneForTests = TimeZoneForTests()
  6. @Test(
  7. "DetermineBasal should produce same results for fixed JS",
  8. .enabled(if: ReplayTests.enabled)
  9. ) func replayErrorInputs() async throws {
  10. // Note: This test case can only test one timezone per invocation
  11. // so you need to manually change this to try out errors from
  12. // different timezones
  13. let testingTimezone = ReplayTests.timezone
  14. let files = try await HttpFiles.listFiles()
  15. for filePath in files {
  16. let algorithmComparison = try await HttpFiles.downloadFile(at: filePath)
  17. print("Checking \(filePath) @ \(algorithmComparison.createdAt)")
  18. guard algorithmComparison.timezone == testingTimezone else {
  19. continue
  20. }
  21. guard let determineBasalInput = algorithmComparison.determineBasalInput else {
  22. print("Skipping, no determineBasalInput found")
  23. if let str = algorithmComparison.comparisonError {
  24. print(str)
  25. }
  26. if let str = algorithmComparison.swiftException {
  27. print(str)
  28. #expect(Bool(false), "Swift exception on determine")
  29. }
  30. continue
  31. }
  32. timeZoneForTests.setTimezone(identifier: algorithmComparison.timezone)
  33. try await checkFixedJsAgainstSwift(determineBasalInput: determineBasalInput)
  34. print("Checked \(filePath) \(algorithmComparison.timezone)")
  35. timeZoneForTests.resetTimezone()
  36. }
  37. }
  38. func checkFixedJsAgainstSwift(determineBasalInput: DetermineBasalInputs) async throws {
  39. let openAps = OpenAPSFixed()
  40. let (determineBasalResultSwift, _) = OpenAPSSwift.determineBasal(
  41. glucose: determineBasalInput.glucose,
  42. currentTemp: determineBasalInput.currentTemp,
  43. iob: try JSONBridge.to(determineBasalInput.iob),
  44. profile: try JSONBridge.to(determineBasalInput.profile),
  45. autosens: try JSONBridge.to(determineBasalInput.autosens),
  46. meal: try JSONBridge.to(determineBasalInput.meal),
  47. microBolusAllowed: determineBasalInput.microBolusAllowed,
  48. reservoir: determineBasalInput.reservoir ?? 0,
  49. pumpHistory: determineBasalInput.pumpHistory,
  50. preferences: determineBasalInput.preferences,
  51. basalProfile: determineBasalInput.basalProfile,
  52. trioCustomOrefVariables: determineBasalInput.trioCustomOrefVariables,
  53. clock: determineBasalInput.clock
  54. )
  55. let determineBasalResultJavascript = try await openAps.determineBasalJavascript(
  56. glucose: determineBasalInput.glucose,
  57. currentTemp: determineBasalInput.currentTemp,
  58. iob: try JSONBridge.to(determineBasalInput.iob),
  59. profile: try JSONBridge.to(determineBasalInput.profile),
  60. autosens: try JSONBridge.to(determineBasalInput.autosens),
  61. meal: try JSONBridge.to(determineBasalInput.meal),
  62. microBolusAllowed: determineBasalInput.microBolusAllowed,
  63. reservoir: determineBasalInput.reservoir ?? 0,
  64. pumpHistory: determineBasalInput.pumpHistory,
  65. preferences: determineBasalInput.preferences,
  66. basalProfile: determineBasalInput.basalProfile,
  67. trioCustomOrefVariables: determineBasalInput.trioCustomOrefVariables,
  68. clock: determineBasalInput.clock
  69. )
  70. let comparison = JSONCompare.createComparison(
  71. function: .determineBasal,
  72. swift: determineBasalResultSwift,
  73. swiftDuration: 0.1,
  74. javascript: determineBasalResultJavascript,
  75. javascriptDuration: 0.1,
  76. iobInputs: nil,
  77. mealInputs: nil,
  78. autosensInputs: nil,
  79. determineBasalInputs: nil
  80. )
  81. if comparison.resultType == .valueDifference {
  82. print(comparison.differences!.prettyPrintedJSON!)
  83. }
  84. if comparison.resultType != .matching {
  85. print("REPLAY ERROR: Fixed JS didn't match")
  86. }
  87. #expect(comparison.resultType == .matching)
  88. }
  89. @Test("Format determineBasal inputs for running in JS", .enabled(if: false)) func formatInputs() async throws {
  90. let openAps = OpenAPSFixed()
  91. // this test is meant for one-off analysis so it's ok to hard code
  92. // a file, just make sure to _not_ check in updates to this to
  93. // avoid polluting our change logs
  94. let algorithmComparison = try await HttpFiles.downloadFile(at: "/files/f1d04efa-c39b-4f0a-9955-65ab663ff9fb.0.json")
  95. let determineBasalInput = algorithmComparison.determineBasalInput!
  96. let encoder = JSONCoding.encoder
  97. let output = try encoder.encode(determineBasalInput)
  98. let sharedDir = FileManager.default.temporaryDirectory
  99. let outputURL = sharedDir.appendingPathComponent("determine_basal_error_inputs.json")
  100. // Print the path so you can find it
  101. print("Writing to: \(outputURL.path)")
  102. try output.write(to: outputURL)
  103. timeZoneForTests.setTimezone(identifier: algorithmComparison.timezone)
  104. let (determineBasalResultSwift, _) = OpenAPSSwift.determineBasal(
  105. glucose: determineBasalInput.glucose,
  106. currentTemp: determineBasalInput.currentTemp,
  107. iob: try JSONBridge.to(determineBasalInput.iob),
  108. profile: try JSONBridge.to(determineBasalInput.profile),
  109. autosens: try JSONBridge.to(determineBasalInput.autosens),
  110. meal: try JSONBridge.to(determineBasalInput.meal),
  111. microBolusAllowed: determineBasalInput.microBolusAllowed,
  112. reservoir: determineBasalInput.reservoir ?? 0,
  113. pumpHistory: determineBasalInput.pumpHistory,
  114. preferences: determineBasalInput.preferences,
  115. basalProfile: determineBasalInput.basalProfile,
  116. trioCustomOrefVariables: determineBasalInput.trioCustomOrefVariables,
  117. clock: determineBasalInput.clock
  118. )
  119. print("Swift result")
  120. switch determineBasalResultSwift {
  121. case let .success(rawJson):
  122. print(rawJson)
  123. case let .failure(error):
  124. print(error.localizedDescription)
  125. }
  126. let determineBasalResultJavascript = try await openAps.determineBasalJavascript(
  127. glucose: determineBasalInput.glucose,
  128. currentTemp: determineBasalInput.currentTemp,
  129. iob: try JSONBridge.to(determineBasalInput.iob),
  130. profile: try JSONBridge.to(determineBasalInput.profile),
  131. autosens: try JSONBridge.to(determineBasalInput.autosens),
  132. meal: try JSONBridge.to(determineBasalInput.meal),
  133. microBolusAllowed: determineBasalInput.microBolusAllowed,
  134. reservoir: determineBasalInput.reservoir ?? 0,
  135. pumpHistory: determineBasalInput.pumpHistory,
  136. preferences: determineBasalInput.preferences,
  137. basalProfile: determineBasalInput.basalProfile,
  138. trioCustomOrefVariables: determineBasalInput.trioCustomOrefVariables,
  139. clock: determineBasalInput.clock
  140. )
  141. print("Fixed JS result")
  142. switch determineBasalResultJavascript {
  143. case let .success(rawJson):
  144. print(rawJson)
  145. case let .failure(error):
  146. print(error.localizedDescription)
  147. }
  148. let comparison = JSONCompare.createComparison(
  149. function: .determineBasal,
  150. swift: determineBasalResultSwift,
  151. swiftDuration: 0.1,
  152. javascript: determineBasalResultJavascript,
  153. javascriptDuration: 0.1,
  154. iobInputs: nil,
  155. mealInputs: nil,
  156. autosensInputs: nil,
  157. determineBasalInputs: nil
  158. )
  159. if comparison.resultType == .valueDifference {
  160. print(comparison.differences!.prettyPrintedJSON!)
  161. }
  162. #expect(comparison.resultType == .matching)
  163. timeZoneForTests.resetTimezone()
  164. }
  165. }