Pārlūkot izejas kodu

remove unused profile properties and remove public qualifiers

Sam King 1 gadu atpakaļ
vecāks
revīzija
93163752bc

+ 4 - 0
FreeAPS.xcodeproj/project.pbxproj

@@ -254,6 +254,7 @@
 		3B5CD2CE2D4AECD500CE213C /* ProfileBasalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B5CD2C12D4AECD500CE213C /* ProfileBasalTests.swift */; };
 		3BCE75B32D4B38AE009E9453 /* InsulinSensitivities+Convert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BCE75B22D4B38A0009E9453 /* InsulinSensitivities+Convert.swift */; };
 		3BCE75B52D4B391F009E9453 /* Decimal+rounding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BCE75B42D4B3917009E9453 /* Decimal+rounding.swift */; };
+		3BF8D0C12D5175BE001B3F84 /* ProfileJsNativeCompareTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BF8D0C02D5175B3001B3F84 /* ProfileJsNativeCompareTests.swift */; };
 		45252C95D220E796FDB3B022 /* ConfigEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */; };
 		45717281F743594AA9D87191 /* ConfigEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 920DDB21E5D0EB813197500D /* ConfigEditorRootView.swift */; };
 		5075C1608E6249A51495C422 /* TargetsEditorProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BDEA2DC60EDE0A3CA54DC73 /* TargetsEditorProvider.swift */; };
@@ -980,6 +981,7 @@
 		3BCE75B42D4B3917009E9453 /* Decimal+rounding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Decimal+rounding.swift"; sourceTree = "<group>"; };
 		3BDEA2DC60EDE0A3CA54DC73 /* TargetsEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TargetsEditorProvider.swift; sourceTree = "<group>"; };
 		3BF768BD6264FF7D71D66767 /* NightscoutConfigProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NightscoutConfigProvider.swift; sourceTree = "<group>"; };
+		3BF8D0C02D5175B3001B3F84 /* ProfileJsNativeCompareTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileJsNativeCompareTests.swift; sourceTree = "<group>"; };
 		3F60E97100041040446F44E7 /* PumpConfigStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PumpConfigStateModel.swift; sourceTree = "<group>"; };
 		3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorDataFlow.swift; sourceTree = "<group>"; };
 		42369F66CF91F30624C0B3A6 /* BasalProfileEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BasalProfileEditorProvider.swift; sourceTree = "<group>"; };
@@ -2390,6 +2392,7 @@
 		3B5CD2C72D4AECD500CE213C /* OpenAPSSwiftTests */ = {
 			isa = PBXGroup;
 			children = (
+				3BF8D0C02D5175B3001B3F84 /* ProfileJsNativeCompareTests.swift */,
 				3B5CD2C12D4AECD500CE213C /* ProfileBasalTests.swift */,
 				3B5CD2C32D4AECD500CE213C /* ProfileCarbsTests.swift */,
 				3B5CD2C42D4AECD500CE213C /* ProfileIsfTests.swift */,
@@ -4072,6 +4075,7 @@
 				3B5CD2CD2D4AECD500CE213C /* ProfileIsfTests.swift in Sources */,
 				3B5CD2CE2D4AECD500CE213C /* ProfileBasalTests.swift in Sources */,
 				CEE9A65E2BBC9F6500EB5194 /* CalibrationsTests.swift in Sources */,
+				3BF8D0C12D5175BE001B3F84 /* ProfileJsNativeCompareTests.swift in Sources */,
 				CE1F6DD92BADF4620064EB8D /* PluginManagerTests.swift in Sources */,
 				38FCF3F925E902C20078B0D1 /* FileStorageTests.swift in Sources */,
 			);

+ 3 - 2
FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift

@@ -681,7 +681,8 @@ final class OpenAPS {
         }
     }
 
-    private func makeProfileJavascript(
+    // use `internal` protection to expose to unit tests
+    func makeProfileJavascript(
         preferences: JSON,
         pumpSettings: JSON,
         bgTargets: JSON,
@@ -766,7 +767,7 @@ final class OpenAPS {
         let nativeDuration = Date().timeIntervalSince(startNativeAt)
 
         JSONCompare.logDifferences(
-            label: "makeProfile",
+            function: .makeProfile,
             native: nativeJson,
             nativeRuntime: nativeDuration,
             javascript: jsJson,

+ 2 - 2
FreeAPS/Sources/APS/OpenAPSSwift/Extensions/Date+MinutesFromMidnight.swift

@@ -1,9 +1,9 @@
 import Foundation
 
-public enum MinutesFromMidnightError: LocalizedError, Equatable {
+enum MinutesFromMidnightError: LocalizedError, Equatable {
     case invalidCalendar
 
-    public var errorDescription: String? {
+    var errorDescription: String? {
         switch self {
         case .invalidCalendar:
             return "Unable to extract hours and minutes from the current calendar"

+ 3 - 3
FreeAPS/Sources/APS/OpenAPSSwift/Models/ComputedInsulinSensitivities.swift

@@ -21,7 +21,7 @@ struct ComputedInsulinSensitivityEntry: Codable {
     var endOffset: Int?
     let id: UUID // we use this to help with mutating inputs, we don't serialize it
 
-    public init(sensitivity: Decimal, offset: Int, start: String, endOffset: Int? = nil, id: UUID? = nil) {
+    init(sensitivity: Decimal, offset: Int, start: String, endOffset: Int? = nil, id: UUID? = nil) {
         self.sensitivity = sensitivity
         self.offset = offset
         self.start = start
@@ -36,7 +36,7 @@ struct ComputedInsulinSensitivityEntry: Codable {
         case endOffset
     }
 
-    public func encode(to encoder: Encoder) throws {
+    func encode(to encoder: Encoder) throws {
         var container = encoder.container(keyedBy: CodingKeys.self)
         try container.encode(sensitivity, forKey: .sensitivity)
         try container.encode(offset, forKey: .offset)
@@ -44,7 +44,7 @@ struct ComputedInsulinSensitivityEntry: Codable {
         try container.encodeIfPresent(endOffset, forKey: .endOffset)
     }
 
-    public init(from decoder: Decoder) throws {
+    init(from decoder: Decoder) throws {
         let container = try decoder.container(keyedBy: CodingKeys.self)
         sensitivity = try container.decode(Decimal.self, forKey: .sensitivity)
         offset = try container.decode(Int.self, forKey: .offset)

+ 0 - 7
FreeAPS/Sources/APS/OpenAPSSwift/Models/Profile.swift

@@ -20,7 +20,6 @@ struct Profile: Codable {
     var lowTemptargetLowersSensitivity: Bool = false // lower sensitivity for temptargets <= 99
     var sensitivityRaisesTarget: Bool = false // raise BG target when autosens detects sensitivity
     var resistanceLowersTarget: Bool = false // lower BG target when autosens detects resistance
-    var exerciseMode: Bool = false // when true, > 100 mg/dL high temp target adjusts sensitivityRatio
     var halfBasalExerciseTarget: Decimal = 160 // when temptarget is 160 mg/dL *and* exercise_mode=true, run 50% basal
     var maxCOB: Decimal = 120 // maximum carbs a typical body can absorb over 4 hours
     var skipNeutralTemps: Bool = false
@@ -54,10 +53,8 @@ struct Profile: Codable {
     var curve: InsulinCurve = .rapidActing
     var useCustomPeakTime: Bool = false
     var insulinPeakTime: Decimal = 75
-    var offlineHotspot: Bool = false
     var noisyCGMTargetMultiplier: Decimal = 1.3
     var suspendZerosIob: Bool = true
-    var enableEnliteBgproxy: Bool = false
     var calcGlucoseNoise: Bool = false
     var adjustmentFactor: Decimal = 0.8
     var adjustmentFactorSigmoid: Decimal = 0.5
@@ -91,7 +88,6 @@ struct Profile: Codable {
         case lowTemptargetLowersSensitivity = "low_temptarget_lowers_sensitivity"
         case sensitivityRaisesTarget = "sensitivity_raises_target"
         case resistanceLowersTarget = "resistance_lowers_target"
-        case exerciseMode = "exercise_mode"
         case halfBasalExerciseTarget = "half_basal_exercise_target"
         case maxCOB
         case skipNeutralTemps = "skip_neutral_temps"
@@ -123,11 +119,8 @@ struct Profile: Codable {
         case curve
         case useCustomPeakTime
         case insulinPeakTime
-        case offlineHotspot = "offline_hotspot"
         case noisyCGMTargetMultiplier
         case suspendZerosIob = "suspend_zeros_iob"
-        case enableEnliteBgproxy
-        case calcGlucoseNoise = "calc_glucose_noise"
         case adjustmentFactor
         case adjustmentFactorSigmoid
         case useNewFormula

+ 2 - 2
FreeAPS/Sources/APS/OpenAPSSwift/Profile/ProfileError.swift

@@ -1,6 +1,6 @@
 import Foundation
 
-public enum ProfileError: LocalizedError, Equatable {
+enum ProfileError: LocalizedError, Equatable {
     case invalidDIA(value: Decimal)
     case invalidCurrentBasal(value: Decimal?)
     case invalidMaxDailyBasal(value: Decimal?)
@@ -10,7 +10,7 @@ public enum ProfileError: LocalizedError, Equatable {
     case invalidBgTargets
     case invalidCalendar
 
-    public var errorDescription: String? {
+    var errorDescription: String? {
         switch self {
         case let .invalidDIA(value):
             return "DIA of \(String(describing: value)) is not supported (must be > 1)"

+ 0 - 1
FreeAPS/Sources/APS/OpenAPSSwift/Profile/ProfileGenerator.swift

@@ -39,7 +39,6 @@ extension Profile {
         lowTemptargetLowersSensitivity = preferences.lowTemptargetLowersSensitivity
         sensitivityRaisesTarget = preferences.sensitivityRaisesTarget
         resistanceLowersTarget = preferences.resistanceLowersTarget
-        exerciseMode = preferences.exerciseMode
         skipNeutralTemps = preferences.skipNeutralTemps
         enableUAM = preferences.enableUAM
         a52RiskEnable = preferences.a52RiskEnable

+ 26 - 11
FreeAPS/Sources/APS/OpenAPSSwift/Utils/JSONCompare.swift

@@ -8,7 +8,7 @@ enum JSONValue: Codable {
     case object([String: JSONValue])
     case null
 
-    public init(from decoder: Decoder) throws {
+    init(from decoder: Decoder) throws {
         let container = try decoder.singleValueContainer()
 
         if container.decodeNil() {
@@ -34,7 +34,7 @@ enum JSONValue: Codable {
         }
     }
 
-    public func encode(to encoder: Encoder) throws {
+    func encode(to encoder: Encoder) throws {
         var container = encoder.singleValueContainer()
         switch self {
         case let .string(value): try container.encode(value)
@@ -47,32 +47,46 @@ enum JSONValue: Codable {
     }
 }
 
-public struct ValueDifference: Codable {
+struct ValueDifference: Codable {
     let js: JSONValue
     let native: JSONValue
     let jsKeyMissing: Bool
     let nativeKeyMissing: Bool
 }
 
-public enum JSONCompare {
-    public static func logDifferences(
-        label: String,
+enum JSONCompare {
+    enum Function {
+        case makeProfile
+
+        // since we're removing some keys from our Profile that exist in Javascript
+        // we need to let the difference function know which keys to ignore when
+        // calculating differences
+        func keysToIgnore() -> Set<String> {
+            switch self {
+            case .makeProfile:
+                return Set(["calc_glucose_noise", "enableEnliteBgproxy", "exercise_mode", "offline_hotspot"])
+            }
+        }
+    }
+
+    static func logDifferences(
+        function: Function,
         native: String,
         nativeRuntime: TimeInterval,
         javascript: String,
         javascriptRuntime: TimeInterval
     ) {
-        guard let differences = try? differences(native: native, javascript: javascript) else {
+        guard let differences = try? differences(function: function, native: native, javascript: javascript) else {
             warning(.openAPS, "Exception calculating differences")
             return
         }
 
         // TODO: For now we'll just print this out to the console but we'll add proper logging next
-        debug(.openAPS, "\(label) -> n: \(nativeRuntime)s, js: \(javascriptRuntime)s")
+        debug(.openAPS, "\(function) -> n: \(nativeRuntime)s, js: \(javascriptRuntime)s")
         prettyPrint(differences)
     }
 
-    public static func prettyPrint(_ differences: [String: ValueDifference]) {
+    static func prettyPrint(_ differences: [String: ValueDifference]) {
         let encoder = JSONEncoder()
         encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
 
@@ -83,7 +97,7 @@ public enum JSONCompare {
         }
     }
 
-    public static func differences(native: String, javascript: String) throws -> [String: ValueDifference] {
+    static func differences(function: Function, native: String, javascript: String) throws -> [String: ValueDifference] {
         guard let jsData = javascript.data(using: .utf8),
               let nativeData = native.data(using: .utf8),
               let jsDict = try JSONSerialization.jsonObject(with: jsData) as? [String: Any],
@@ -109,7 +123,8 @@ public enum JSONCompare {
             }
         }
 
-        return differences
+        let keysToIgnore = function.keysToIgnore()
+        return differences.filter { !keysToIgnore.contains($0.key) }
     }
 
     private static func convertToJSONValue(_ value: Any) -> JSONValue {

+ 5 - 5
FreeAPS/Sources/APS/OpenAPSSwift/Utils/JavascriptOptional.swift

@@ -1,13 +1,13 @@
-@propertyWrapper public struct JavascriptOptional<T> {
-    public var wrappedValue: T?
+@propertyWrapper struct JavascriptOptional<T> {
+    var wrappedValue: T?
 
-    public init(wrappedValue: T?) {
+    init(wrappedValue: T?) {
         self.wrappedValue = wrappedValue
     }
 }
 
 extension JavascriptOptional: Codable where T: Codable {
-    public init(from decoder: Decoder) throws {
+    init(from decoder: Decoder) throws {
         let container = try decoder.singleValueContainer()
         if let value = try? container.decode(T.self) {
             wrappedValue = value
@@ -18,7 +18,7 @@ extension JavascriptOptional: Codable where T: Codable {
         }
     }
 
-    public func encode(to encoder: Encoder) throws {
+    func encode(to encoder: Encoder) throws {
         var container = encoder.singleValueContainer()
         if let value = wrappedValue {
             try container.encode(value)

+ 95 - 0
FreeAPSTests/OpenAPSSwiftTests/ProfileJsNativeCompareTests.swift

@@ -0,0 +1,95 @@
+import Foundation
+@testable import FreeAPS
+import Testing
+
+@Suite("Profile js vs native comparison") struct ProfileJsNativeCompareTests {
+    // Base test inputs that match the JavaScript test setup
+    private func createBaseInputs() -> (
+        Preferences,
+        PumpSettings,
+        BGTargets,
+        [BasalProfileEntry],
+        InsulinSensitivities,
+        CarbRatios,
+        [TempTarget],
+        String,
+        FreeAPSSettings
+    ) {
+        let pumpSettings = PumpSettings(
+            insulinActionCurve: 3,
+            maxBolus: 10,
+            maxBasal: 2
+        )
+
+        let bgTargets = BGTargets(
+            units: .mgdL,
+            userPreferredUnits: .mgdL,
+            targets: [
+                BGTargetEntry(low: 100, high: 120, start: "00:00", offset: 0)
+            ]
+        )
+
+        let basalProfile = [
+            BasalProfileEntry(start: "00:00", minutes: 0, rate: 1.0)
+        ]
+
+        let isf = InsulinSensitivities(
+            units: .mgdL,
+            userPreferredUnits: .mgdL,
+            sensitivities: [
+                InsulinSensitivityEntry(sensitivity: 100, offset: 0, start: "00:00")
+            ]
+        )
+
+        let preferences = Preferences()
+
+        let carbRatios = CarbRatios(
+            units: .grams,
+            schedule: [
+                CarbRatioEntry(start: "00:00", offset: 0, ratio: 20)
+            ]
+        )
+
+        let tempTargets: [TempTarget] = []
+        let model = "\"250\""
+        let freeaps = FreeAPSSettings()
+
+        return (preferences, pumpSettings, bgTargets, basalProfile, isf, carbRatios, tempTargets, model, freeaps)
+    }
+
+    @Test("should compare Profile for js and native with base inputs") func withBasicInputs() async throws {
+        let inputs = createBaseInputs()
+        let openAps = OpenAPS(storage: BaseFileStorage())
+        let profileJs = try! await openAps.makeProfileJavascript(
+            preferences: inputs.0,
+            pumpSettings: inputs.1,
+            bgTargets: inputs.2,
+            basalProfile: inputs.3,
+            isf: inputs.4,
+            carbRatio: inputs.5,
+            tempTargets: inputs.6,
+            model: inputs.7,
+            autotune: RawJSON.null,
+            freeaps: inputs.8
+        )
+
+        let profileNative = OpenAPSSwift.makeProfile(
+            preferences: inputs.0,
+            pumpSettings: inputs.1,
+            bgTargets: inputs.2,
+            basalProfile: inputs.3,
+            isf: inputs.4,
+            carbRatio: inputs.5,
+            tempTargets: inputs.6,
+            model: inputs.7,
+            freeaps: inputs.8
+        )
+
+        let differences = try! JSONCompare.differences(function: .makeProfile, native: profileNative, javascript: profileJs)
+
+        if !differences.isEmpty {
+            JSONCompare.prettyPrint(differences)
+        }
+        #expect(differences.isEmpty)
+    }
+}