From a88392de8288d4832eae8b75c6464cedd3faaab9 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Sun, 18 Feb 2024 13:44:10 -0600 Subject: [PATCH] Updates to tests for iOS 17 (#517) * Fix tests on xcode15 * Update circleci config * Switch resource class * Remove resource class spec * Build packages * use xcpretty on package building * Add test github action * Fix syntax error * Fix syntax * Fix checkout * Fix indentation * List xcode versions * Update action name * macos-14 not available yet * Try m1 resource class * Try updated xcode * Update sdk as well * Update github workflow to 17.2 * Fix typo * Fix sporadic failure of dosestore tests --- .circleci/config.yml | 11 ++++---- .github/workflows/test.yml | 21 ++++++++++++++++ LoopKitTests/AlertTests.swift | 25 +++++++++++-------- LoopKitTests/DoseStoreTests.swift | 10 +++++++- LoopKitTests/DosingDecisionStoreTests.swift | 21 ++++++++-------- .../CachedGlucoseObjectTests.swift | 24 ++++++++++-------- LoopKitTests/Persistence/PumpEventTests.swift | 14 +++++------ 7 files changed, 80 insertions(+), 46 deletions(-) create mode 100644 .github/workflows/test.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index e34cfae8f..7acd7f40a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,29 +7,29 @@ version: 2.1 jobs: test: macos: - xcode: 15.0.0 + xcode: 15.2.0 steps: - checkout - run: name: Test command: | - set -o pipefail && xcodebuild -project LoopKit.xcodeproj -scheme Shared build -destination 'name=iPhone 14,OS=16.4' test | xcpretty + set -o pipefail && xcodebuild -project LoopKit.xcodeproj -scheme Shared build -destination 'OS=17.2,name=iPhone 15' test | xcpretty - store_test_results: path: test_output package: macos: - xcode: 15.0.0 + xcode: 15.2.0 steps: - checkout - run: rm -rf LoopKit.xcodeproj - run: name: Build LoopKit Package command: | - set -o pipefail && xcodebuild build -scheme LoopKit -destination "name=iPhone 14,OS=16.4" | xcpretty + set -o pipefail && xcodebuild build -scheme LoopKit -sdk iphonesimulator17.2 -destination "OS=17.2,name=iPhone 15" | xcpretty - run: name: Build LoopKitUI Package command: | - set -o pipefail && xcodebuild build -scheme LoopKitUI -destination "name=iPhone 14,OS=16.4" | xcpretty + set -o pipefail && xcodebuild build -scheme LoopKitUI -sdk iphonesimulator17.2 -destination "OS=17.2,name=iPhone 15" | xcpretty # # Workflows # @@ -40,3 +40,4 @@ workflows: jobs: - test - package + diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000..9cbc4e839 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,21 @@ +name: Test LoopKit Build +on: + push: +jobs: + build-and-test: + runs-on: macos-13 + steps: + - name: Checkout target repo + uses: actions/checkout@v3 + - name: Show available xcode versions + run: "ls -al /Applications/Xcode*" + - name: Select Xcode + run: "sudo xcode-select --switch /Applications/Xcode_15.2.app/Contents/Developer" + - name: Run Tests + run: set -o pipefail && xcodebuild -project LoopKit.xcodeproj -scheme Shared build -destination 'OS=17.2,name=iPhone 15' test | xcpretty + - name: Remove xcode project + run: rm -rf LoopKit.xcodeproj + - name: Build LoopKit Swift Package + run: set -o pipefail && xcodebuild build -scheme LoopKit -sdk iphonesimulator17.2 -destination "OS=17.2,name=iPhone 15" | xcpretty + - name: Build LoopKitUI Swift Package + run: set -o pipefail && xcodebuild build -scheme LoopKitUI -sdk iphonesimulator17.2 -destination "OS=17.2,name=iPhone 15" | xcpretty diff --git a/LoopKitTests/AlertTests.swift b/LoopKitTests/AlertTests.swift index f0d03acd7..d2009aea4 100644 --- a/LoopKitTests/AlertTests.swift +++ b/LoopKitTests/AlertTests.swift @@ -20,32 +20,37 @@ class AlertTests: XCTestCase { func testAlertImmediateEncodable() { let alert = Alert(identifier: identifier, foregroundContent: foregroundContent, backgroundContent: backgroundContent, trigger: .immediate) - let str = try? alert.encodeToString() - XCTAssertEqual("{\"trigger\":\"immediate\",\"interruptionLevel\":\"timeSensitive\",\"identifier\":{\"managerIdentifier\":\"managerIdentifier1\",\"alertIdentifier\":\"alertIdentifier1\"},\"foregroundContent\":{\"title\":\"title1\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel1\",\"body\":\"body1\"},\"backgroundContent\":{\"title\":\"title2\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel2\",\"body\":\"body2\"}}", str) + let str = try! alert.encodeToString() + let decoded = try! Alert.decode(from: str) + XCTAssertEqual(alert, decoded) } func testAlertDelayedEncodable() { let alert = Alert(identifier: identifier, foregroundContent: foregroundContent, backgroundContent: backgroundContent, trigger: .delayed(interval: 1.0)) - let str = try? alert.encodeToString() - XCTAssertEqual("{\"trigger\":{\"delayed\":{\"delayInterval\":1}},\"interruptionLevel\":\"timeSensitive\",\"identifier\":{\"managerIdentifier\":\"managerIdentifier1\",\"alertIdentifier\":\"alertIdentifier1\"},\"foregroundContent\":{\"title\":\"title1\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel1\",\"body\":\"body1\"},\"backgroundContent\":{\"title\":\"title2\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel2\",\"body\":\"body2\"}}", str) + let str = try! alert.encodeToString() + let decoded = try! Alert.decode(from: str) + XCTAssertEqual(alert, decoded) } func testAlertRepeatingEncodable() { let alert = Alert(identifier: identifier, foregroundContent: foregroundContent, backgroundContent: backgroundContent, trigger: .repeating(repeatInterval: 2.0)) - let str = try? alert.encodeToString() - XCTAssertEqual("{\"trigger\":{\"repeating\":{\"repeatInterval\":2}},\"interruptionLevel\":\"timeSensitive\",\"identifier\":{\"managerIdentifier\":\"managerIdentifier1\",\"alertIdentifier\":\"alertIdentifier1\"},\"foregroundContent\":{\"title\":\"title1\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel1\",\"body\":\"body1\"},\"backgroundContent\":{\"title\":\"title2\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel2\",\"body\":\"body2\"}}", str) + let str = try! alert.encodeToString() + let decoded = try! Alert.decode(from: str) + XCTAssertEqual(alert, decoded) } func testAlertVibrateSoundEncodable() { let alert = Alert(identifier: identifier, foregroundContent: foregroundContent, backgroundContent: backgroundContent, trigger: .immediate, sound: .vibrate) - let str = try? alert.encodeToString() - XCTAssertEqual("{\"trigger\":\"immediate\",\"interruptionLevel\":\"timeSensitive\",\"sound\":\"vibrate\",\"identifier\":{\"managerIdentifier\":\"managerIdentifier1\",\"alertIdentifier\":\"alertIdentifier1\"},\"foregroundContent\":{\"title\":\"title1\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel1\",\"body\":\"body1\"},\"backgroundContent\":{\"title\":\"title2\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel2\",\"body\":\"body2\"}}", str) + let str = try! alert.encodeToString() + let decoded = try! Alert.decode(from: str) + XCTAssertEqual(alert, decoded) } func testAlertSoundEncodable() { let alert = Alert(identifier: identifier, foregroundContent: foregroundContent, backgroundContent: backgroundContent, trigger: .immediate, sound: .sound(name: "soundName")) - let str = try? alert.encodeToString() - XCTAssertEqual("{\"trigger\":\"immediate\",\"interruptionLevel\":\"timeSensitive\",\"sound\":{\"sound\":{\"name\":\"soundName\"}},\"identifier\":{\"managerIdentifier\":\"managerIdentifier1\",\"alertIdentifier\":\"alertIdentifier1\"},\"foregroundContent\":{\"title\":\"title1\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel1\",\"body\":\"body1\"},\"backgroundContent\":{\"title\":\"title2\",\"acknowledgeActionButtonLabel\":\"acknowledgeActionButtonLabel2\",\"body\":\"body2\"}}", str) + let str = try! alert.encodeToString() + let decoded = try! Alert.decode(from: str) + XCTAssertEqual(alert, decoded) } func testAlertImmediateDecodable() { diff --git a/LoopKitTests/DoseStoreTests.swift b/LoopKitTests/DoseStoreTests.swift index bbc848cb1..93777b093 100644 --- a/LoopKitTests/DoseStoreTests.swift +++ b/LoopKitTests/DoseStoreTests.swift @@ -1334,12 +1334,20 @@ class DoseStoreCriticalEventLogTests: PersistenceControllerTestCase { PersistedPumpEvent(date: dateFormatter.date(from: "2100-01-02T03:06:00Z")!, persistedDate: persistedDate, dose: nil, isUploaded: false, objectIDURL: url, raw: nil, title: nil, type: nil), PersistedPumpEvent(date: dateFormatter.date(from: "2100-01-02T03:02:00Z")!, persistedDate: persistedDate, dose: nil, isUploaded: false, objectIDURL: url, raw: nil, title: nil, type: nil)] + + + let semaphore = DispatchSemaphore(value: 0) doseStore = DoseStore(cacheStore: cacheStore, insulinModelProvider: StaticInsulinModelProvider(insulinModel), longestEffectDuration: insulinModel.effectDuration, basalProfile: basalProfile, insulinSensitivitySchedule: insulinSensitivitySchedule, - provenanceIdentifier: Bundle.main.bundleIdentifier!) + provenanceIdentifier: Bundle.main.bundleIdentifier!, + onReady: { (error) in + semaphore.signal() + }) + semaphore.wait() + XCTAssertNil(doseStore.addPumpEvents(events: events)) outputStream = MockOutputStream() diff --git a/LoopKitTests/DosingDecisionStoreTests.swift b/LoopKitTests/DosingDecisionStoreTests.swift index 38837b5b0..dc9846e92 100644 --- a/LoopKitTests/DosingDecisionStoreTests.swift +++ b/LoopKitTests/DosingDecisionStoreTests.swift @@ -103,7 +103,9 @@ class DosingDecisionStorePersistenceTests: PersistenceControllerTestCase, Dosing object.data = try PropertyListEncoder().encode(StoredDosingDecision.test) object.date = dateFormatter.date(from: "2100-01-02T03:03:00Z")! object.modificationCounter = 123 - try assertDosingDecisionObjectEncodable(object, encodesJSON: """ + + let data = try encoder.encode(object) + XCTAssertEqual(String(data: data, encoding: .utf8), """ { "data" : { "automaticDoseRecommendation" : { @@ -248,7 +250,7 @@ class DosingDecisionStorePersistenceTests: PersistenceControllerTestCase, Dosing "pendingInsulin" : 0.75 } }, - "manualBolusRequested" : 0.80000000000000004, + "manualBolusRequested" : 0.8, "manualGlucoseSample" : { "condition" : "aboveRange", "device" : { @@ -267,7 +269,7 @@ class DosingDecisionStorePersistenceTests: PersistenceControllerTestCase, Dosing "syncIdentifier" : "d3876f59-adb3-4a4f-8b29-315cda22062e", "syncVersion" : 1, "trend" : 7, - "trendRate" : -10.199999999999999, + "trendRate" : -10.2, "uuid" : "DA0CED44-E4F1-49C4-BAF8-6EFA6D75525F", "wasUserEntered" : true }, @@ -368,11 +370,6 @@ class DosingDecisionStorePersistenceTests: PersistenceControllerTestCase, Dosing } } - private func assertDosingDecisionObjectEncodable(_ original: DosingDecisionObject, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - } - private let dateFormatter = ISO8601DateFormatter() private let encoder: JSONEncoder = { @@ -714,7 +711,9 @@ class DosingDecisionStoreCriticalEventLogTests: PersistenceControllerTestCase { class StoredDosingDecisionCodableTests: XCTestCase { func testCodable() throws { - try assertStoredDosingDecisionCodable(StoredDosingDecision.test, encodesJSON: """ + + let data = try encoder.encode(StoredDosingDecision.test) + XCTAssertEqual(String(data: data, encoding: .utf8), """ { "automaticDoseRecommendation" : { "basalAdjustment" : { @@ -858,7 +857,7 @@ class StoredDosingDecisionCodableTests: XCTestCase { "pendingInsulin" : 0.75 } }, - "manualBolusRequested" : 0.80000000000000004, + "manualBolusRequested" : 0.8, "manualGlucoseSample" : { "condition" : "aboveRange", "device" : { @@ -877,7 +876,7 @@ class StoredDosingDecisionCodableTests: XCTestCase { "syncIdentifier" : "d3876f59-adb3-4a4f-8b29-315cda22062e", "syncVersion" : 1, "trend" : 7, - "trendRate" : -10.199999999999999, + "trendRate" : -10.2, "uuid" : "DA0CED44-E4F1-49C4-BAF8-6EFA6D75525F", "wasUserEntered" : true }, diff --git a/LoopKitTests/Persistence/CachedGlucoseObjectTests.swift b/LoopKitTests/Persistence/CachedGlucoseObjectTests.swift index d53c15969..bc2bf6dc8 100644 --- a/LoopKitTests/Persistence/CachedGlucoseObjectTests.swift +++ b/LoopKitTests/Persistence/CachedGlucoseObjectTests.swift @@ -215,7 +215,10 @@ class CachedGlucoseObjectEncodableTests: PersistenceControllerTestCase { cachedGlucoseObject.isDisplayOnly = false cachedGlucoseObject.wasUserEntered = true cachedGlucoseObject.modificationCounter = 123 - try! assertCachedGlucoseObjectEncodable(cachedGlucoseObject, encodesJSON: """ + + let data = try! encoder.encode(cachedGlucoseObject) + + let expected = """ { "isDisplayOnly" : false, "modificationCounter" : 123, @@ -225,11 +228,11 @@ class CachedGlucoseObjectEncodableTests: PersistenceControllerTestCase { "syncVersion" : 2, "unitString" : "mg/dL", "uuid" : "2A67A303-5203-4CB8-8263-79498265368E", - "value" : 98.700000000000003, + "value" : 98.7, "wasUserEntered" : true } """ - ) + XCTAssertEqual(String(data: data, encoding: .utf8), expected) } } @@ -243,24 +246,23 @@ class CachedGlucoseObjectEncodableTests: PersistenceControllerTestCase { cachedGlucoseObject.isDisplayOnly = true cachedGlucoseObject.wasUserEntered = false cachedGlucoseObject.modificationCounter = 234 - try! assertCachedGlucoseObjectEncodable(cachedGlucoseObject, encodesJSON: """ + + let data = try! encoder.encode(cachedGlucoseObject) + + let expected = """ { "isDisplayOnly" : true, "modificationCounter" : 234, "provenanceIdentifier" : "238E41EA-9576-4981-A1A4-51E10228584F", "startDate" : "2020-05-14T22:38:14Z", "unitString" : "mg/dL", - "value" : 87.599999999999994, + "value" : 87.6, "wasUserEntered" : false } """ - ) - } - } + XCTAssertEqual(String(data: data, encoding: .utf8), expected) - private func assertCachedGlucoseObjectEncodable(_ original: CachedGlucoseObject, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) + } } private let dateFormatter = ISO8601DateFormatter() diff --git a/LoopKitTests/Persistence/PumpEventTests.swift b/LoopKitTests/Persistence/PumpEventTests.swift index 5e965d504..fcfb8fec4 100644 --- a/LoopKitTests/Persistence/PumpEventTests.swift +++ b/LoopKitTests/Persistence/PumpEventTests.swift @@ -30,13 +30,14 @@ class PumpEventEncodableTests: PersistenceControllerTestCase { pumpEvent.alarmType = .other("An Alarm") pumpEvent.modificationCounter = 123 pumpEvent.wasProgrammedByPumpUI = true - try! assertPumpEventEncodable(pumpEvent, encodesJSON: """ + let data = try! encoder.encode(pumpEvent) + XCTAssertEqual(String(data: data, encoding: .utf8), """ { "alarmType" : "An Alarm", "automatic" : false, "createdAt" : "2020-05-14T22:33:48Z", "date" : "2020-05-14T22:38:14Z", - "deliveredUnits" : 0.56000000000000005, + "deliveredUnits" : 0.56, "doseType" : "tempBasal", "duration" : 1800, "insulinType" : 3, @@ -65,7 +66,9 @@ class PumpEventEncodableTests: PersistenceControllerTestCase { pumpEvent.mutable = false pumpEvent.modificationCounter = 234 pumpEvent.wasProgrammedByPumpUI = true - try! assertPumpEventEncodable(pumpEvent, encodesJSON: """ + + let data = try! encoder.encode(pumpEvent) + XCTAssertEqual(String(data: data, encoding: .utf8), """ { "createdAt" : "2020-05-13T22:33:48Z", "date" : "2020-05-13T22:38:14Z", @@ -81,11 +84,6 @@ class PumpEventEncodableTests: PersistenceControllerTestCase { } } - private func assertPumpEventEncodable(_ original: PumpEvent, encodesJSON string: String) throws { - let data = try encoder.encode(original) - XCTAssertEqual(String(data: data, encoding: .utf8), string) - } - private let dateFormatter = ISO8601DateFormatter() private let encoder: JSONEncoder = {