Quellcode durchsuchen

Allow subarray matching for our forecasts

Sam King vor 10 Monaten
Ursprung
Commit
249f749203

+ 32 - 6
Trio/Sources/APS/OpenAPSSwift/Logging/JSONCompare.swift

@@ -249,18 +249,27 @@ enum JSONCompare {
     private static func compareDict(
         function: OrefFunction,
         swiftDict: [String: Any],
-        jsDict: [String: Any]
+        jsDict: [String: Any],
+        path: String = ""
     ) -> [String: ValueDifference] {
         var differences: [String: ValueDifference] = [:]
         let approximateKeys = function.approximateMatchingNumbers()
+        let flexibleArrayKeys = function.flexibleArrayKeys()
 
         // Check all keys present in either dictionary
         Set(jsDict.keys).union(swiftDict.keys).forEach { key in
+            let currentPath = path.isEmpty ? key : "\(path).\(key)"
             let jsValue = jsDict[key].map(convertToJSONValue) ?? .null
             let swiftValue = swiftDict[key].map(convertToJSONValue) ?? .null
 
-            if !valuesAreEqual(jsValue, swiftValue, approximately: approximateKeys[key], approximateKeys: approximateKeys) {
-                differences[key] = ValueDifference(
+            if !valuesAreEqual(
+                jsValue, swiftValue,
+                approximately: approximateKeys[key],
+                approximateKeys: approximateKeys,
+                flexibleArrayKeys: flexibleArrayKeys,
+                currentPath: currentPath
+            ) {
+                differences[currentPath] = ValueDifference(
                     js: jsValue,
                     swift: swiftValue,
                     jsKeyMissing: !jsDict.keys.contains(key),
@@ -302,7 +311,9 @@ enum JSONCompare {
         _ value1: JSONValue,
         _ value2: JSONValue,
         approximately: Double?,
-        approximateKeys: [String: Double]
+        approximateKeys: [String: Double],
+        flexibleArrayKeys: [String],
+        currentPath: String
     ) -> Bool {
         switch (value1, value2) {
         case (.null, .null):
@@ -321,13 +332,28 @@ enum JSONCompare {
         case let (.boolean(b1), .boolean(b2)):
             return b1 == b2
         case let (.array(a1), .array(a2)):
+            if flexibleArrayKeys.contains(currentPath), !a1.isEmpty, !a2.isEmpty {
+                let shortestCount = min(a1.count, a2.count)
+                return zip(a1.prefix(shortestCount), a2.prefix(shortestCount)).allSatisfy { v1, v2 in
+                    valuesAreEqual(
+                        v1, v2, approximately: approximately, approximateKeys: approximateKeys,
+                        flexibleArrayKeys: flexibleArrayKeys, currentPath: currentPath
+                    )
+                }
+            }
             return a1.count == a2.count && zip(a1, a2).allSatisfy { v1, v2 in
-                valuesAreEqual(v1, v2, approximately: approximately, approximateKeys: approximateKeys)
+                valuesAreEqual(
+                    v1, v2, approximately: approximately, approximateKeys: approximateKeys,
+                    flexibleArrayKeys: flexibleArrayKeys, currentPath: currentPath
+                )
             }
         case let (.object(o1), .object(o2)):
             return o1.keys == o2.keys && o1.keys.allSatisfy { key in
                 guard let v1 = o1[key], let v2 = o2[key] else { return false }
-                return valuesAreEqual(v1, v2, approximately: approximateKeys[key], approximateKeys: approximateKeys)
+                return valuesAreEqual(
+                    v1, v2, approximately: approximateKeys[key], approximateKeys: approximateKeys,
+                    flexibleArrayKeys: flexibleArrayKeys, currentPath: "\(currentPath).\(key)"
+                )
             }
         default:
             return false

+ 9 - 0
Trio/Sources/APS/OpenAPSSwift/Logging/OrefFunction.swift

@@ -137,4 +137,13 @@ enum OrefFunction: String, Codable {
             return .dictionary
         }
     }
+
+    func flexibleArrayKeys() -> [String] {
+        switch self {
+        case .determineBasal:
+            return ["predBGs.UAM", "predBGs.COB", "predBGs.ZT", "predBGs.IOB"]
+        default:
+            return []
+        }
+    }
 }

+ 2 - 2
TrioTests/OpenAPSSwiftTests/DetermineBasalJsonTests.swift

@@ -97,13 +97,13 @@ import Testing
         #expect(comparison.resultType == .matching)
     }
 
-    @Test("Format determineBasal inputs for running in JS", .enabled(if: false)) func formatInputs() async throws {
+    @Test("Format determineBasal inputs for running in JS", .enabled(if: true)) 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 algorithmComparison = try await HttpFiles.downloadFile(at: "/files/896b7e15-0b16-4653-9b60-0adf6f6cf0eb.2.json")
         let determineBasalInput = algorithmComparison.determineBasalInput!
 
         let encoder = JSONCoding.encoder