feat: implement Haptika PPG and Watch V1
This commit is contained in:
+52
@@ -0,0 +1,52 @@
|
||||
import XCTest
|
||||
@testable import HaptikaSignal
|
||||
|
||||
final class PPGCoherencePolicyTests: XCTestCase {
|
||||
func testSessionDurationLimitsRemainPurposeSpecific() {
|
||||
XCTAssertEqual(PPGCoherencePolicy.maximumDurationSeconds(isCoherence: false), 120)
|
||||
XCTAssertEqual(PPGCoherencePolicy.maximumDurationSeconds(isCoherence: true), 300)
|
||||
XCTAssertEqual(PPGCoherencePolicy.coherenceBufferDurationSeconds, 75)
|
||||
}
|
||||
|
||||
func testLiveTrackerPublishesEveryNewBeatOnlyOnce() {
|
||||
var tracker = PPGLiveBeatTracker()
|
||||
let first = tracker.ingest([
|
||||
interval(end: 1, duration: 800), interval(end: 1.8, duration: 800),
|
||||
])
|
||||
XCTAssertEqual(first.map(\.sequence), [1, 2])
|
||||
let overlapping = tracker.ingest([
|
||||
interval(end: 1.82, duration: 800), interval(end: 2.6, duration: 780),
|
||||
])
|
||||
XCTAssertEqual(overlapping.map(\.sequence), [3])
|
||||
XCTAssertEqual(overlapping.first?.timestampSeconds, 2.6)
|
||||
}
|
||||
|
||||
func testTrackerDoesNotMoveBackwardAndResetsCleanly() {
|
||||
var tracker = PPGLiveBeatTracker()
|
||||
_ = tracker.ingest([interval(end: 10, duration: 700)])
|
||||
XCTAssertTrue(tracker.ingest([interval(end: 9.9, duration: 700)]).isEmpty)
|
||||
tracker.reset()
|
||||
XCTAssertEqual(tracker.ingest([interval(end: 1, duration: 700)]).first?.sequence, 1)
|
||||
}
|
||||
|
||||
func testTrackerRejectsInvalidAndRejectedIntervals() {
|
||||
var tracker = PPGLiveBeatTracker()
|
||||
let rejected = PulseInterval(
|
||||
sourceIndex: 0, startSeconds: 0, endSeconds: 1,
|
||||
durationMilliseconds: 800, rejectionReason: .localOutlier, qualityScore: 1
|
||||
)
|
||||
XCTAssertTrue(tracker.ingest([
|
||||
rejected, interval(end: .nan, duration: 800), interval(end: 2, duration: 2_500),
|
||||
]).isEmpty)
|
||||
}
|
||||
|
||||
private func interval(end: Double, duration: Double) -> PulseInterval {
|
||||
PulseInterval(
|
||||
sourceIndex: 0,
|
||||
startSeconds: end - duration / 1_000,
|
||||
endSeconds: end,
|
||||
durationMilliseconds: duration,
|
||||
qualityScore: 0.9
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user