Parcourir la source

Implement DetermineBasal replay

This commit includes the test cases for replaying determine basal. It
also includes:

- Rebased testing JS to include the most recent changes to trio-oref
- A few small bug fixes for expectedDelta
Sam King il y a 10 mois
Parent
commit
1ffcb9bfdf

+ 8 - 0
Trio.xcodeproj/project.pbxproj

@@ -217,6 +217,7 @@
 		3B1C5C452D68E269004E9273 /* IobTotalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B1C5C382D68E269004E9273 /* IobTotalTests.swift */; };
 		3B1C5C472D68E269004E9273 /* IobCalculateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B1C5C352D68E269004E9273 /* IobCalculateTests.swift */; };
 		3B1C5C482D68E269004E9273 /* IobHistoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B1C5C362D68E269004E9273 /* IobHistoryTests.swift */; };
+		3B214EEA2E29632900046304 /* determine-basal-prepare.js in Resources */ = {isa = PBXBuildFile; fileRef = 3B214EE92E29631F00046304 /* determine-basal-prepare.js */; };
 		3B2CE68B2E24ADF7005EF782 /* IobGenerateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B2CE68A2E24ADF3005EF782 /* IobGenerateTests.swift */; };
 		3B2F77862D7E52ED005ED9FA /* TDD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B2F77852D7E52ED005ED9FA /* TDD.swift */; };
 		3B2F77882D7E5387005ED9FA /* CurrentTDDSetup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B2F77872D7E5387005ED9FA /* CurrentTDDSetup.swift */; };
@@ -316,6 +317,7 @@
 		3BD9687F2D8DDD8800899469 /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 3BD9687E2D8DDD8800899469 /* CryptoSwift */; };
 		3BE2F1E82E030E2F009E2900 /* MealCobTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BE2F1E72E030E2F009E2900 /* MealCobTests.swift */; };
 		3BE2F1EA2E031951009E2900 /* MealCobBucketingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BE2F1E92E031951009E2900 /* MealCobBucketingTests.swift */; };
+		3BE9F0BB2E28C99B001B14EB /* DetermineBasalJsonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BE9F0BA2E28C993001B14EB /* DetermineBasalJsonTests.swift */; };
 		3BEA3AE02D58F79700A67A1D /* OrefFunction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BEA3ADE2D58F79700A67A1D /* OrefFunction.swift */; };
 		3BEA3AE12D58F79700A67A1D /* AlgorithmComparison.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BEA3ADB2D58F79700A67A1D /* AlgorithmComparison.swift */; };
 		3BEA3AE22D58F79700A67A1D /* JsSwiftOrefComparisonLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BEA3ADD2D58F79700A67A1D /* JsSwiftOrefComparisonLogger.swift */; };
@@ -1157,6 +1159,7 @@
 		3B1C5C382D68E269004E9273 /* IobTotalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IobTotalTests.swift; sourceTree = "<group>"; };
 		3B1C5C3D2D68E269004E9273 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
 		3B1C5C3E2D68E269004E9273 /* IobJsonTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IobJsonTypes.swift; sourceTree = "<group>"; };
+		3B214EE92E29631F00046304 /* determine-basal-prepare.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "determine-basal-prepare.js"; sourceTree = "<group>"; };
 		3B2CE68A2E24ADF3005EF782 /* IobGenerateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IobGenerateTests.swift; sourceTree = "<group>"; };
 		3B2F77852D7E52ED005ED9FA /* TDD.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TDD.swift; sourceTree = "<group>"; };
 		3B2F77872D7E5387005ED9FA /* CurrentTDDSetup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentTDDSetup.swift; sourceTree = "<group>"; };
@@ -1233,6 +1236,7 @@
 		3BDEA2DC60EDE0A3CA54DC73 /* TargetsEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TargetsEditorProvider.swift; sourceTree = "<group>"; };
 		3BE2F1E72E030E2F009E2900 /* MealCobTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealCobTests.swift; sourceTree = "<group>"; };
 		3BE2F1E92E031951009E2900 /* MealCobBucketingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealCobBucketingTests.swift; sourceTree = "<group>"; };
+		3BE9F0BA2E28C993001B14EB /* DetermineBasalJsonTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetermineBasalJsonTests.swift; sourceTree = "<group>"; };
 		3BEA3ADB2D58F79700A67A1D /* AlgorithmComparison.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlgorithmComparison.swift; sourceTree = "<group>"; };
 		3BEA3ADC2D58F79700A67A1D /* JSONCompare.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONCompare.swift; sourceTree = "<group>"; };
 		3BEA3ADD2D58F79700A67A1D /* JsSwiftOrefComparisonLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JsSwiftOrefComparisonLogger.swift; sourceTree = "<group>"; };
@@ -2920,6 +2924,7 @@
 				3B8B5D3B2DF523B800365ED3 /* AutosensJsonTests.swift */,
 				3BBC22622DF5B93900169236 /* AutosensTests.swift */,
 				DD30B9FF2E0745C400DA677C /* DetermineBasalDeltaCalculationTests.swift */,
+				3BE9F0BA2E28C993001B14EB /* DetermineBasalJsonTests.swift */,
 				DD30B9FD2E0742E200DA677C /* DetermineBasalSMBEnablementTests.swift */,
 				3B1C5C352D68E269004E9273 /* IobCalculateTests.swift */,
 				3B2CE68A2E24ADF3005EF782 /* IobGenerateTests.swift */,
@@ -2985,6 +2990,7 @@
 		3BF92F2B2D86DEE9006B545A /* bundle */ = {
 			isa = PBXGroup;
 			children = (
+				3B214EE92E29631F00046304 /* determine-basal-prepare.js */,
 				3B16C39B2DF75BCB00C5C801 /* autosens-prepare.js */,
 				3BC0AA402DA8B8F7000DF7B7 /* iob-history-prepare.js */,
 				3BF92F212D86DEE9006B545A /* autosens.js */,
@@ -4416,6 +4422,7 @@
 				3BF92F352D86DEE9006B545A /* basal-set-temp.js in Resources */,
 				3BF92F362D86DEE9006B545A /* autotune-core.js in Resources */,
 				3BC0AA3B2DA74C87000DF7B7 /* iob-total.js in Resources */,
+				3B214EEA2E29632900046304 /* determine-basal-prepare.js in Resources */,
 				3BC0AA3E2DA817EC000DF7B7 /* iob-calculate.js in Resources */,
 				3BC0AA3F2DA817EC000DF7B7 /* iob-history.js in Resources */,
 				3BC0AA412DA8B900000DF7B7 /* iob-history-prepare.js in Resources */,
@@ -5197,6 +5204,7 @@
 				BD8FC0622D6619E600B95AED /* OverrideStorageTests.swift in Sources */,
 				BD8FC0592D66189700B95AED /* TestAssembly.swift in Sources */,
 				DDC6CA6D2DD90A2A0060EE25 /* LocalizationTests.swift in Sources */,
+				3BE9F0BB2E28C99B001B14EB /* DetermineBasalJsonTests.swift in Sources */,
 				3B997DCF2DC00A3A006B6BB2 /* JSONImporterTests.swift in Sources */,
 				3B31D5742E0E26C00047D32D /* ReplayTests.swift in Sources */,
 				3B8B5D3C2DF523C000365ED3 /* AutosensJsonTests.swift in Sources */,

+ 2 - 2
Trio/Sources/APS/OpenAPSSwift/DetermineBasal/DetermineBasal+Helpers.swift

@@ -113,9 +113,9 @@ extension DeterminationGenerator {
         // to move eventual glucose to target over a 2 hr window
         // TODO: expects that glucose can only be available in 5min chunks. do we need to change this handling?
 
-        let fiveMinuteBlocks = (2 * 60) / 5
+        let fiveMinuteBlocks = Decimal((2 * 60) / 5)
         let delta = targetGlucose - eventualGlucose
-        return (glucoseImpact + Decimal(Int(delta) / fiveMinuteBlocks)).rounded(toPlaces: 1)
+        return (glucoseImpact + (delta / fiveMinuteBlocks)).rounded(toPlaces: 1)
     }
 
     /// Determines whether SMBs are enabled based on profile settings,

+ 1 - 1
Trio/Sources/APS/OpenAPSSwift/DetermineBasal/DetermineBasalGenerator.swift

@@ -177,7 +177,7 @@ enum DeterminationGenerator {
 
         // used for pre dosing decision sanity later on
         let expectedDelta = calculateExpectedDelta(
-            targetGlucose: profile.targetBg ?? 100,
+            targetGlucose: profile.minBg ?? 100,
             eventualGlucose: eventualGlucose,
             glucoseImpact: currentGlucoseImpact
         )

+ 3 - 1
Trio/Sources/APS/OpenAPSSwift/Logging/OrefFunction.swift

@@ -112,7 +112,9 @@ enum OrefFunction: String, Codable {
                 "newisf": 1.5
             ]
         case .determineBasal:
-            return [:]
+            return [
+                "sensitivityRatio": 0.011 // consistent with Autosens
+            ]
         }
     }
 

+ 21 - 21
TrioTests/OpenAPSSwiftTests/DetermineBasalDeltaCalculationTests.swift

@@ -10,8 +10,8 @@ import Testing
             eventualGlucose: Decimal(100),
             glucoseImpact: Decimal(2)
         )
-        // delta = 20; Int(20)/24 = 0 → result = 2 + 0 = 2.0
-        #expect(result == Decimal(2.0))
+        // delta = 20; 20 / 24 = 0.8333; result = 2 + 0.8333 = 2.8333 -> rounded to 2.8
+        #expect(result == 2.8)
     }
 
     /// When delta spans exactly one block, adds 1 to glucoseImpact.
@@ -21,8 +21,8 @@ import Testing
             eventualGlucose: Decimal(100),
             glucoseImpact: Decimal(1.5)
         )
-        // delta = 24; Int(24)/24 = 1 → result = 1.5 + 1 = 2.5
-        #expect(result == Decimal(2.5))
+        // delta = 24; 24 / 24 = 1 → result = 1.5 + 1 = 2.5
+        #expect(result == 2.5)
     }
 
     /// When delta spans multiple blocks, uses integer division.
@@ -32,8 +32,8 @@ import Testing
             eventualGlucose: Decimal(100),
             glucoseImpact: Decimal(0)
         )
-        // delta = 40; Int(40)/24 = 1 → result = 0 + 1 = 1.0
-        #expect(result == Decimal(1.0))
+        // delta = 40; 40 / 24 = 1.666... → result = 0 + 1.666... = 1.7
+        #expect(result == 1.7)
     }
 
     /// Negative delta yields negative adjustment when blocks exceed delta.
@@ -43,19 +43,19 @@ import Testing
             eventualGlucose: Decimal(100),
             glucoseImpact: Decimal(0)
         )
-        // delta = -20; Int(-20)/24 = 0 (trunc toward zero) → result = 0 + 0 = 0.0
-        #expect(result == Decimal(0.0))
+        // delta = -20; -20 / 24 = -0.8333... → result = 0 + (-0.8333...) = -0.8
+        #expect(result == -0.8)
     }
 
     /// Fractional delta is truncated before block division.
     @Test("fractional delta truncation") func fractionalDelta() {
         let result = DeterminationGenerator.calculateExpectedDelta(
-            targetGlucose: Decimal(string: "125.5")!,
+            targetGlucose: Decimal(125.5),
             eventualGlucose: Decimal(100),
             glucoseImpact: Decimal(0)
         )
-        // delta = 25.5; Int(25.5)=25; 25/24=1 → result = 1.0
-        #expect(result == Decimal(1.0))
+        // delta = 25.5; 25.5 / 24 = 1.0625 → result = 1.1
+        #expect(result == 1.1)
     }
 
     /// Rounding to one decimal place works when glucoseImpact has two decimals.
@@ -63,10 +63,10 @@ import Testing
         let result = DeterminationGenerator.calculateExpectedDelta(
             targetGlucose: Decimal(124),
             eventualGlucose: Decimal(100),
-            glucoseImpact: Decimal(string: "1.27")!
+            glucoseImpact: Decimal(1.27)
         )
-        // delta=24 → blocks=1; adjustment=1; 1.27+1=2.27 → rounded to 2.3
-        #expect(result == Decimal(string: "2.3")!)
+        // delta=24 → adjustment=1; 1.27+1=2.27 → rounded to 2.3
+        #expect(result == 2.3)
     }
 
     /// Extreme high eventual glucose produces a large negative expected delta.
@@ -76,8 +76,8 @@ import Testing
             eventualGlucose: Decimal(350),
             glucoseImpact: Decimal(0)
         )
-        // delta = 120 - 350 = -230; Int(-230)/24 = -9 → result = 0 + (-9) = -9.0
-        #expect(result == Decimal(string: "-9.0")!)
+        // delta = 120 - 350 = -230; -230 / 24 = -9.5833... → result = -9.6
+        #expect(result == -9.6)
     }
 
     /// Extreme low eventual glucose produces a positive expected delta.
@@ -87,8 +87,8 @@ import Testing
             eventualGlucose: Decimal(39),
             glucoseImpact: Decimal(0)
         )
-        // delta = 81; Int(81)/24 = 3 → result = 0 + 3 = 3.0
-        #expect(result == Decimal(string: "3.0")!)
+        // delta = 81; 81 / 24 = 3.375 → result = 3.4
+        #expect(result == 3.4)
     }
 
     /// Invalid low‐unit input (<39 mg/dL) falls back to only using glucoseImpact.
@@ -96,9 +96,9 @@ import Testing
         let result = DeterminationGenerator.calculateExpectedDelta(
             targetGlucose: Decimal(5), // e.g. mmol/L mistakenly passed
             eventualGlucose: Decimal(3),
-            glucoseImpact: Decimal(string: "1.7")!
+            glucoseImpact: Decimal(1.7)
         )
-        // delta = 2; Int(2)/24 = 0 → result = 1.7 + 0 = 1.7
-        #expect(result == Decimal(string: "1.7")!)
+        // delta = 2; 2 / 24 = 0.0833... → result = 1.7 + 0.0833... = 1.8
+        #expect(result == 1.8)
     }
 }

+ 188 - 0
TrioTests/OpenAPSSwiftTests/DetermineBasalJsonTests.swift

@@ -0,0 +1,188 @@
+import Foundation
+import Testing
+@testable import Trio
+
+@Suite("DetermineBasal testing using JSON inputs", .serialized) struct DetermineBasalJsonTests {
+    let timeZoneForTests = TimeZoneForTests()
+
+    @Test(
+        "DetermineBasal should produce same results for fixed JS",
+        .enabled(if: ReplayTests.enabled)
+    ) func replayErrorInputs() async throws {
+        // Note: This test case can only test one timezone per invocation
+        // so you need to manually change this to try out errors from
+        // different timezones
+        let testingTimezone = ReplayTests.timezone
+        let files = try await HttpFiles.listFiles()
+        for filePath in files {
+            let algorithmComparison = try await HttpFiles.downloadFile(at: filePath)
+            print("Checking \(filePath) @ \(algorithmComparison.createdAt)")
+            guard algorithmComparison.timezone == testingTimezone else {
+                continue
+            }
+            guard let determineBasalInput = algorithmComparison.determineBasalInput else {
+                print("Skipping, no determineBasalInput found")
+                if let str = algorithmComparison.comparisonError {
+                    print(str)
+                }
+                if let str = algorithmComparison.swiftException {
+                    print(str)
+                    #expect(Bool(false), "Swift exception on determine")
+                }
+                continue
+            }
+
+            timeZoneForTests.setTimezone(identifier: algorithmComparison.timezone)
+
+            try await checkFixedJsAgainstSwift(determineBasalInput: determineBasalInput)
+            print("Checked \(filePath) \(algorithmComparison.timezone)")
+            timeZoneForTests.resetTimezone()
+        }
+    }
+
+    func checkFixedJsAgainstSwift(determineBasalInput: DetermineBasalInputs) async throws {
+        let openAps = OpenAPSFixed()
+        let (determineBasalResultSwift, _) = OpenAPSSwift.determineBasal(
+            glucose: determineBasalInput.glucose,
+            currentTemp: determineBasalInput.currentTemp,
+            iob: try JSONBridge.to(determineBasalInput.iob),
+            profile: try JSONBridge.to(determineBasalInput.profile),
+            autosens: try JSONBridge.to(determineBasalInput.autosens),
+            meal: try JSONBridge.to(determineBasalInput.meal),
+            microBolusAllowed: determineBasalInput.microBolusAllowed,
+            reservoir: determineBasalInput.reservoir ?? 0,
+            pumpHistory: determineBasalInput.pumpHistory,
+            preferences: determineBasalInput.preferences,
+            basalProfile: determineBasalInput.basalProfile,
+            trioCustomOrefVariables: determineBasalInput.trioCustomOrefVariables,
+            clock: determineBasalInput.clock
+        )
+
+        let determineBasalResultJavascript = try await openAps.determineBasalJavascript(
+            glucose: determineBasalInput.glucose,
+            currentTemp: determineBasalInput.currentTemp,
+            iob: try JSONBridge.to(determineBasalInput.iob),
+            profile: try JSONBridge.to(determineBasalInput.profile),
+            autosens: try JSONBridge.to(determineBasalInput.autosens),
+            meal: try JSONBridge.to(determineBasalInput.meal),
+            microBolusAllowed: determineBasalInput.microBolusAllowed,
+            reservoir: determineBasalInput.reservoir ?? 0,
+            pumpHistory: determineBasalInput.pumpHistory,
+            preferences: determineBasalInput.preferences,
+            basalProfile: determineBasalInput.basalProfile,
+            trioCustomOrefVariables: determineBasalInput.trioCustomOrefVariables,
+            clock: determineBasalInput.clock
+        )
+
+        let comparison = JSONCompare.createComparison(
+            function: .determineBasal,
+            swift: determineBasalResultSwift,
+            swiftDuration: 0.1,
+            javascript: determineBasalResultJavascript,
+            javascriptDuration: 0.1,
+            iobInputs: nil,
+            mealInputs: nil,
+            autosensInputs: nil,
+            determineBasalInputs: nil
+        )
+
+        if comparison.resultType == .valueDifference {
+            print(comparison.differences!.prettyPrintedJSON!)
+        }
+
+        if comparison.resultType != .matching {
+            print("REPLAY ERROR: Fixed JS didn't match")
+        }
+
+        #expect(comparison.resultType == .matching)
+    }
+
+    @Test("Format determineBasal inputs for running in JS", .enabled(if: false)) func formatInputs() async throws {
+        let openAps = OpenAPSFixed()
+
+        // this test is meant for one-off analysis so it's ok to hard code
+        // a file, just make sure to _not_ check in updates to this to
+        // avoid polluting our change logs
+        let algorithmComparison = try await HttpFiles.downloadFile(at: "/files/f1d04efa-c39b-4f0a-9955-65ab663ff9fb.0.json")
+        let determineBasalInput = algorithmComparison.determineBasalInput!
+
+        let encoder = JSONCoding.encoder
+        let output = try encoder.encode(determineBasalInput)
+
+        let sharedDir = FileManager.default.temporaryDirectory
+        let outputURL = sharedDir.appendingPathComponent("determine_basal_error_inputs.json")
+        // Print the path so you can find it
+        print("Writing to: \(outputURL.path)")
+        try output.write(to: outputURL)
+
+        timeZoneForTests.setTimezone(identifier: algorithmComparison.timezone)
+
+        let (determineBasalResultSwift, _) = OpenAPSSwift.determineBasal(
+            glucose: determineBasalInput.glucose,
+            currentTemp: determineBasalInput.currentTemp,
+            iob: try JSONBridge.to(determineBasalInput.iob),
+            profile: try JSONBridge.to(determineBasalInput.profile),
+            autosens: try JSONBridge.to(determineBasalInput.autosens),
+            meal: try JSONBridge.to(determineBasalInput.meal),
+            microBolusAllowed: determineBasalInput.microBolusAllowed,
+            reservoir: determineBasalInput.reservoir ?? 0,
+            pumpHistory: determineBasalInput.pumpHistory,
+            preferences: determineBasalInput.preferences,
+            basalProfile: determineBasalInput.basalProfile,
+            trioCustomOrefVariables: determineBasalInput.trioCustomOrefVariables,
+            clock: determineBasalInput.clock
+        )
+
+        print("Swift result")
+        switch determineBasalResultSwift {
+        case let .success(rawJson):
+            print(rawJson)
+        case let .failure(error):
+            print(error.localizedDescription)
+        }
+
+        let determineBasalResultJavascript = try await openAps.determineBasalJavascript(
+            glucose: determineBasalInput.glucose,
+            currentTemp: determineBasalInput.currentTemp,
+            iob: try JSONBridge.to(determineBasalInput.iob),
+            profile: try JSONBridge.to(determineBasalInput.profile),
+            autosens: try JSONBridge.to(determineBasalInput.autosens),
+            meal: try JSONBridge.to(determineBasalInput.meal),
+            microBolusAllowed: determineBasalInput.microBolusAllowed,
+            reservoir: determineBasalInput.reservoir ?? 0,
+            pumpHistory: determineBasalInput.pumpHistory,
+            preferences: determineBasalInput.preferences,
+            basalProfile: determineBasalInput.basalProfile,
+            trioCustomOrefVariables: determineBasalInput.trioCustomOrefVariables,
+            clock: determineBasalInput.clock
+        )
+
+        print("Fixed JS result")
+        switch determineBasalResultJavascript {
+        case let .success(rawJson):
+            print(rawJson)
+        case let .failure(error):
+            print(error.localizedDescription)
+        }
+
+        let comparison = JSONCompare.createComparison(
+            function: .determineBasal,
+            swift: determineBasalResultSwift,
+            swiftDuration: 0.1,
+            javascript: determineBasalResultJavascript,
+            javascriptDuration: 0.1,
+            iobInputs: nil,
+            mealInputs: nil,
+            autosensInputs: nil,
+            determineBasalInputs: nil
+        )
+
+        if comparison.resultType == .valueDifference {
+            print(comparison.differences!.prettyPrintedJSON!)
+        }
+
+        #expect(comparison.resultType == .matching)
+
+        timeZoneForTests.resetTimezone()
+    }
+}

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
TrioTests/OpenAPSSwiftTests/javascript/bundle/autotune-core.js


+ 51 - 0
TrioTests/OpenAPSSwiftTests/javascript/bundle/determine-basal-prepare.js

@@ -0,0 +1,51 @@
+//для enact/smb-suggested.json параметры: monitor/iob.json monitor/temp_basal.json monitor/glucose.json settings/profile.json settings/autosens.json --meal monitor/meal.json --microbolus --reservoir monitor/reservoir.json
+
+function generate(iob, currenttemp, glucose, profile, autosens = null, meal = null, microbolusAllowed = false, reservoir = null, clock = new Date(), pump_history, preferences, basalProfile, trio_custom_oref_variables) {
+
+    // We pass in the clock when we're replaying
+    //var clock = new Date();
+    
+    var middleware_was_used = "";
+    try {
+        var middlewareReason = middleware(iob, currenttemp, glucose, profile, autosens, meal, reservoir, clock, pump_history, preferences, basalProfile, trio_custom_oref_variables);
+        middleware_was_used = (middlewareReason || "Nothing changed");
+        console.log("Middleware reason: " + middleware_was_used);
+    } catch (error) {
+        console.log("Invalid middleware: " + error);
+    };
+
+    var glucose_status = trio_glucoseGetLast(glucose);
+    var autosens_data = null;
+
+    if (autosens) {
+        autosens_data = autosens;
+    }
+    
+    var reservoir_data = null;
+    if (reservoir) {
+        reservoir_data = reservoir;
+    }
+
+    var meal_data = {};
+    if (meal) {
+        meal_data = meal;
+    }
+    
+    var pumphistory = {};
+    if (pump_history) {
+        pumphistory = pump_history;
+    }
+    
+    var basalprofile = {};
+    if (basalProfile) {
+        basalprofile = basalProfile;
+    }
+    
+    var trio_custom_oref_variables_temp = {};
+    if (trio_custom_oref_variables) {
+        trio_custom_oref_variables_temp = trio_custom_oref_variables;
+    }
+    
+    return trio_determineBasal(glucose_status, currenttemp, iob, profile, autosens_data, meal_data, trio_basalSetTemp, microbolusAllowed, reservoir_data, clock, pumphistory, preferences, basalprofile, trio_custom_oref_variables_temp, middleware_was_used);
+}
+

Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
TrioTests/OpenAPSSwiftTests/javascript/bundle/determine-basal.js


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
TrioTests/OpenAPSSwiftTests/javascript/bundle/glucose-get-last.js


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
TrioTests/OpenAPSSwiftTests/javascript/bundle/profile.js


+ 68 - 0
TrioTests/OpenAPSSwiftTests/utils/OpenAPSFixed.swift

@@ -13,6 +13,74 @@ final class OpenAPSFixed {
         return try JSONBridge.to(pumpHistorySwift.sorted(by: { $0.timestamp > $1.timestamp }))
     }
 
+    private func middlewareScript(name: String) -> Script? {
+        if let url = Foundation.Bundle.main.url(forResource: "javascript/\(name)", withExtension: "") {
+            do {
+                let body = try String(contentsOf: url)
+                return Script(name: name, body: body)
+            } catch {
+                debug(.openAPS, "Failed to load script \(name): \(error)")
+            }
+        }
+
+        return nil
+    }
+
+    func determineBasalJavascript(
+        glucose: JSON,
+        currentTemp: JSON,
+        iob: JSON,
+        profile: JSON,
+        autosens: JSON,
+        meal: JSON,
+        microBolusAllowed: Bool,
+        reservoir: JSON,
+        pumpHistory: JSON,
+        preferences: JSON,
+        basalProfile: JSON,
+        trioCustomOrefVariables: JSON,
+        clock: Date
+    ) async throws -> OrefFunctionResult {
+        do {
+            let worker = JavaScriptWorker(poolSize: 1)
+            let testBundle = Bundle(for: OpenAPSFixed.self)
+            let result = try await withCheckedThrowingContinuation { continuation in
+                worker.evaluateBatch(scripts: [
+                    Script(name: "prepare/log.js"),
+                    Script.fromTestingBundle(name: "determine-basal-prepare.js", bundle: testBundle),
+                    Script.fromTestingBundle(name: "basal-set-temp.js", bundle: testBundle),
+                    Script.fromTestingBundle(name: "glucose-get-last.js", bundle: testBundle),
+                    Script.fromTestingBundle(name: "determine-basal.js", bundle: testBundle)
+                ])
+
+                if let middleware = self.middlewareScript(name: OpenAPS.Middleware.determineBasal) {
+                    worker.evaluate(script: middleware)
+                }
+
+                let result = worker.call(function: "generate", with: [
+                    iob,
+                    currentTemp,
+                    glucose,
+                    profile,
+                    autosens,
+                    meal,
+                    microBolusAllowed,
+                    reservoir,
+                    clock,
+                    pumpHistory,
+                    preferences,
+                    basalProfile,
+                    trioCustomOrefVariables
+                ])
+
+                continuation.resume(returning: result)
+            }
+            return .success(result)
+        } catch {
+            return .failure(error)
+        }
+    }
+
     func iobHistory(pumphistory: JSON, profile: JSON, clock: JSON, autosens: JSON, zeroTempDuration: JSON) async throws -> JSON {
         let jsWorker = JavaScriptWorker(poolSize: 1)
         let testBundle = Bundle(for: OpenAPSFixed.self)