Skip to content

Commit

Permalink
adjust tests
Browse files Browse the repository at this point in the history
  • Loading branch information
lukaskollmer committed Jan 21, 2025
1 parent cb9fcf1 commit d6aef67
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 108 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ extension SampleType {

/// The sample type representing blood oxygen saturation quantity samples
@inlinable public static var bloodOxygen: SampleType<HKQuantitySample> {
.quantity(.oxygenSaturation, displayTitle: "Blood Oxygen", displayUnit: .percent())
.quantity(
.oxygenSaturation,
displayTitle: "Blood Oxygen",
displayUnit: .percent(),
expectedValuesRange: 80...105
)
}

/// The sample type representing heart rate quantity samples
Expand Down
118 changes: 118 additions & 0 deletions Tests/SpeziHealthKitTests/MockQueryResults.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
//
// This source file is part of the Stanford Spezi open-source project
//
// SPDX-FileCopyrightText: 2025 Stanford University and the project authors (see CONTRIBUTORS.md)
//
// SPDX-License-Identifier: MIT
//


import HealthKit
import SpeziHealthKit
import XCTest


@Observable
final class MockQueryResults: HealthKitQueryResults, @unchecked Sendable { // it really isn't sendable, but we also can't mark it as being MainActor-constrained, but since we only ever mutate it from the MainActor, we should (hopefully???) be safe here??

Check failure on line 16 in Tests/SpeziHealthKitTests/MockQueryResults.swift

View workflow job for this annotation

GitHub Actions / SwiftLint / SwiftLint / SwiftLint

File Types Order Violation: A 'main_type' should not be placed amongst the file type(s) 'supporting_type' (file_types_order)
typealias Sample = HKQuantitySample
typealias Element = HKQuantitySample
typealias Index = [Sample].Index

let sampleType: SampleType<Sample>
let timeRange: HealthKitQueryTimeRange
var samples: [Sample]

let queryError: (any Error)? = nil

init(sampleType: SampleType<Sample>, timeRange: HealthKitQueryTimeRange, samples: [Sample]) {
self.sampleType = sampleType
self.samples = samples
self.timeRange = timeRange
}

var startIndex: Index {
samples.startIndex
}

var endIndex: Index {
samples.endIndex
}

subscript(position: Index) -> HKQuantitySample {
samples[position]
}
}


// MARK: Utility things


func makeDateProvider(
interval: (component: Calendar.Component, multiple: Int),
starting startDate: DateComponents
) throws -> some (Sequence<Date> & IteratorProtocol<Date>) {
let cal = Calendar.current
let startDate = try XCTUnwrap(cal.date(from: startDate))
return sequence(first: startDate) {
cal.date(byAdding: interval.component, value: interval.multiple, to: $0)
}
}



extension HKQuantitySample {
convenience init(type: SampleType<HKQuantitySample>, quantity: HKQuantity, date: Date) {
self.init(type: type.hkSampleType, quantity: quantity, start: date, end: date)
}
}


extension IteratorProtocol {
mutating func consume(_ count: Int) {
var numConsumed = 0
while numConsumed < count, let _ = next() {
numConsumed += 1
}
}
}




extension Collection {
public func makeLoopingIterator() -> LoopingCollectionIterator<Self> {
LoopingCollectionIterator(self)
}
}


public struct LoopingCollectionIterator<Base: Collection>: IteratorProtocol {
public typealias Element = Base.Element

/// The collection we want to provide looping iteration over.
private let base: Base
/// The current iteration state, i.e. the index of the next element to be yielded from the iterator.
private var idx: Base.Index

fileprivate init(_ base: Base) {
self.base = base
self.idx = base.startIndex
}

public mutating func next() -> Element? {
defer {
base.formIndex(after: &idx)
if idx >= base.endIndex {
idx = base.startIndex
}
}
return base[idx]
}

/// "Resets" the iterator to the beginning of the collection.
/// The next call to ``LoopingIterator.next()`` will yield the collection's first element.
public mutating func reset() {
idx = base.startIndex
}
}

109 changes: 2 additions & 107 deletions Tests/SpeziHealthKitTests/SpeziHealthKitTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ final class SpeziHealthKitTests: XCTestCase {
}

@MainActor
func testEmptyHealthChartEntriesButNoData() {
func testEmptyHealthChartEntriesButNoData() throws {
throw XCTSkip()
let data = MockQueryResults(sampleType: .heartRate, timeRange: .currentWeek, samples: [])

Check warning on line 130 in Tests/SpeziHealthKitTests/SpeziHealthKitTests.swift

View workflow job for this annotation

GitHub Actions / Build and Test Swift Package / Test using xcodebuild or run fastlane

code after 'throw' will never be executed
let healthChart = HealthChart {
HealthChartEntry(data, drawingConfig: .init(mode: .bar, color: .red))
Expand Down Expand Up @@ -170,116 +171,10 @@ final class SpeziHealthKitTests: XCTestCase {
}.frame(width: 600, height: 500)
}


let healthChart1 = makeHealthChart(flag: true)
assertSnapshot(of: healthChart1, as: .image)

Check failure on line 175 in Tests/SpeziHealthKitTests/SpeziHealthKitTests.swift

View workflow job for this annotation

GitHub Actions / Build and Test Swift Package / Test using xcodebuild or run fastlane

testConditionalHealthChartContent, failed - Snapshot does not match reference.

let healthChart2 = makeHealthChart(flag: false)
assertSnapshot(of: healthChart2, as: .image)

Check failure on line 178 in Tests/SpeziHealthKitTests/SpeziHealthKitTests.swift

View workflow job for this annotation

GitHub Actions / Build and Test Swift Package / Test using xcodebuild or run fastlane

testConditionalHealthChartContent, failed - Snapshot does not match reference.
}
}


@Observable
private final class MockQueryResults: HealthKitQueryResults, @unchecked Sendable { // it really isn't sendable, but we also can't mark it as being MainActor-constrained, but since we only ever mutate it from the MainActor, we should (hopefully???) be safe here??
typealias Sample = HKQuantitySample
typealias Element = HKQuantitySample
typealias Index = [Sample].Index

let sampleType: SampleType<Sample>
let timeRange: HealthKitQueryTimeRange
var samples: [Sample]

let queryError: (any Error)? = nil

init(sampleType: SampleType<Sample>, timeRange: HealthKitQueryTimeRange, samples: [Sample]) {
self.sampleType = sampleType
self.samples = samples
self.timeRange = timeRange
}

var startIndex: Index {
samples.startIndex
}

var endIndex: Index {
samples.endIndex
}

subscript(position: Index) -> HKQuantitySample {
samples[position]
}
}


// MARK: Utility things


private func makeDateProvider(
interval: (component: Calendar.Component, multiple: Int),
starting startDate: DateComponents
) throws -> some (Sequence<Date> & IteratorProtocol<Date>) {
let cal = Calendar.current
let startDate = try XCTUnwrap(cal.date(from: startDate))
return sequence(first: startDate) {
cal.date(byAdding: interval.component, value: interval.multiple, to: $0)
}
}



extension HKQuantitySample {
convenience init(type: SampleType<HKQuantitySample>, quantity: HKQuantity, date: Date) {
self.init(type: type.hkSampleType, quantity: quantity, start: date, end: date)
}
}


extension IteratorProtocol {
mutating func consume(_ count: Int) {
var numConsumed = 0
while numConsumed < count, let _ = next() {
numConsumed += 1
}
}
}




extension Collection {
public func makeLoopingIterator() -> LoopingCollectionIterator<Self> {
LoopingCollectionIterator(self)
}
}


public struct LoopingCollectionIterator<Base: Collection>: IteratorProtocol {
public typealias Element = Base.Element

/// The collection we want to provide looping iteration over.
private let base: Base
/// The current iteration state, i.e. the index of the next element to be yielded from the iterator.
private var idx: Base.Index

fileprivate init(_ base: Base) {
self.base = base
self.idx = base.startIndex
}

public mutating func next() -> Element? {
defer {
base.formIndex(after: &idx)
if idx >= base.endIndex {
idx = base.startIndex
}
}
return base[idx]
}

/// "Resets" the iterator to the beginning of the collection.
/// The next call to ``LoopingIterator.next()`` will yield the collection's first element.
public mutating func reset() {
idx = base.startIndex
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit d6aef67

Please sign in to comment.