MealJsonTests.swift 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import Foundation
  2. import Testing
  3. @testable import Trio
  4. @Suite("Meal testing using JSON inputs", .serialized) struct MealJsonTests {
  5. let timeZoneForTests = TimeZoneForTests()
  6. @Test(
  7. "Meal 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 mealInputs = algorithmComparison.mealInput else {
  22. print("Skipping, no mealInputs 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 meal")
  29. }
  30. continue
  31. }
  32. timeZoneForTests.setTimezone(identifier: algorithmComparison.timezone)
  33. try await checkFixedJsAgainstSwift(mealInputs: mealInputs)
  34. print("Checked \(filePath) \(algorithmComparison.timezone)")
  35. timeZoneForTests.resetTimezone()
  36. }
  37. }
  38. func checkFixedJsAgainstSwift(mealInputs: MealInputs) async throws {
  39. let openAps = OpenAPSFixed()
  40. let (mealResultSwift, _) = OpenAPSSwift.meal(
  41. pumphistory: mealInputs.pumpHistory,
  42. profile: try JSONBridge.to(mealInputs.profile),
  43. basalProfile: mealInputs.basalProfile,
  44. clock: mealInputs.clock,
  45. carbs: mealInputs.carbs,
  46. glucose: mealInputs.glucose
  47. )
  48. let mealResultJavascript = await openAps.mealJavascript(
  49. pumphistory: mealInputs.pumpHistory,
  50. profile: try JSONBridge.to(mealInputs.profile),
  51. basalProfile: mealInputs.basalProfile,
  52. clock: mealInputs.clock,
  53. carbs: mealInputs.carbs,
  54. glucose: mealInputs.glucose
  55. )
  56. let comparison = JSONCompare.createComparison(
  57. function: .meal,
  58. swift: mealResultSwift,
  59. swiftDuration: 0.1,
  60. javascript: mealResultJavascript,
  61. javascriptDuration: 0.1,
  62. iobInputs: nil,
  63. mealInputs: nil,
  64. autosensInputs: nil,
  65. determineBasalInputs: nil
  66. )
  67. if comparison.resultType == .valueDifference {
  68. print(comparison.differences!.prettyPrintedJSON!)
  69. }
  70. if comparison.resultType != .matching {
  71. print("REPLAY ERROR: Fixed JS didn't match")
  72. }
  73. #expect(comparison.resultType == .matching)
  74. }
  75. @Test("Format meal inputs for running in JS", .enabled(if: false)) func formatInputs() async throws {
  76. let openAps = OpenAPSFixed()
  77. // this test is meant for one-off analysis so it's ok to hard code
  78. // a file, just make sure to _not_ check in updates to this to
  79. // avoid polluting our change logs
  80. let algorithmComparison = try await HttpFiles.downloadFile(at: "/files/7a8a377e-f483-46a5-adbb-290baa04801b.3.json")
  81. let mealInputs = algorithmComparison.mealInput!
  82. let encoder = JSONCoding.encoder
  83. let output = try encoder.encode(mealInputs)
  84. let sharedDir = FileManager.default.temporaryDirectory
  85. let outputURL = sharedDir.appendingPathComponent("meal_error_inputs.json")
  86. // Print the path so you can find it
  87. print("Writing to: \(outputURL.path)")
  88. try output.write(to: outputURL)
  89. timeZoneForTests.setTimezone(identifier: algorithmComparison.timezone)
  90. let (mealResultSwift, _) = OpenAPSSwift.meal(
  91. pumphistory: mealInputs.pumpHistory,
  92. profile: try JSONBridge.to(mealInputs.profile),
  93. basalProfile: mealInputs.basalProfile,
  94. clock: mealInputs.clock,
  95. carbs: mealInputs.carbs,
  96. glucose: mealInputs.glucose
  97. )
  98. print("Swift result")
  99. switch mealResultSwift {
  100. case let .success(rawJson):
  101. print(rawJson)
  102. case let .failure(error):
  103. print(error.localizedDescription)
  104. }
  105. let mealResultJavascript = await openAps.mealJavascript(
  106. pumphistory: mealInputs.pumpHistory,
  107. profile: try JSONBridge.to(mealInputs.profile),
  108. basalProfile: mealInputs.basalProfile,
  109. clock: mealInputs.clock,
  110. carbs: mealInputs.carbs,
  111. glucose: mealInputs.glucose
  112. )
  113. print("Fixed JS result")
  114. switch mealResultJavascript {
  115. case let .success(rawJson):
  116. print(rawJson)
  117. case let .failure(error):
  118. print(error.localizedDescription)
  119. }
  120. timeZoneForTests.resetTimezone()
  121. }
  122. }