Files
KisaniCal/KisaniCalTests/AnalyticsAdapterTests.swift
kutesir f3213c080e analytics(integration): adapter + reconcile coordinator + deep links (KC-51 ph3)
Phase 3 core (verifiable): WorkoutAnalyticsAdapter (app data → DaySample),
AnalyticsCoordinator (idempotent backfill of missing weekly/monthly reports +
retention prune, injectable providers), AnalyticsDeepLink (wenza://analytics
report routing).

Fixed a reconcile bug caught by tests: a retention-boundary week was generated
then immediately pruned, regenerating every run — aligned completedWeekStartKeys
to the prune cutoff → idempotent.

Tests: AnalyticsAdapterTests + AnalyticsCoordinatorTests. Verified standalone via
swiftc (~90 analytics assertions total across engine/store/adapter/coordinator).
Remaining (app wiring, notifications, UI) requires an Xcode build — logged in
ISSUES.md as device-only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 22:57:13 +00:00

62 lines
2.8 KiB
Swift

import XCTest
@testable import KisaniCal
/// Adapter tests: exercise reduction (identity + volume), inclusive day-key
/// ranges, and app-data DaySample mapping (rest/missing/scheduled handling).
final class AnalyticsAdapterTests: XCTestCase {
private func cal() -> Calendar {
var c = Calendar(identifier: .gregorian)
c.timeZone = TimeZone(identifier: "UTC")!
c.locale = Locale(identifier: "en_US_POSIX")
return c
}
func testExerciseSampleReduction() {
let es = WorkoutAnalyticsAdapter.exerciseSample(name: " Bench Press ",
completedSets: [(60, 10), (60, 8), (70, 6)])
XCTAssertEqual(es.identity, "bench press")
XCTAssertEqual(es.sets, 3)
XCTAssertEqual(es.reps, 24)
XCTAssertEqual(es.volume, 1500) // 600 + 480 + 420
}
func testInclusiveDayKeys() {
let c = cal()
let start = Date(timeIntervalSince1970: 1_783_500_000) // 2026-07-08
let keys = WorkoutAnalyticsAdapter.dayKeys(from: start, to: c.date(byAdding: .day, value: 6, to: start)!, calendar: c)
XCTAssertEqual(keys.count, 7)
XCTAssertEqual(keys, keys.sorted())
}
func testDaySampleMapping() {
let c = cal()
let start = Date(timeIntervalSince1970: 1_783_500_000)
let keys = WorkoutAnalyticsAdapter.dayKeys(from: start, to: c.date(byAdding: .day, value: 6, to: start)!, calendar: c)
let es = WorkoutAnalyticsAdapter.exerciseSample(name: "Squat", completedSets: [(100, 5), (100, 5)])
let raw = RawWorkoutDay(dateKey: keys[0], didWorkout: true, sessions: 1, durationMinutes: 45, exercises: [es])
let samples = WorkoutAnalyticsAdapter.daySamples(
dayKeys: keys,
workouts: [keys[0]: raw],
scheduledKeys: [keys[0], keys[2]],
health: [keys[0]: RawHealthDay(steps: 8000, activeCalories: 500, restingHeartRate: 55)])
XCTAssertEqual(samples.count, 7)
XCTAssertTrue(samples[0].didWorkout)
XCTAssertEqual(samples[0].volume, 1000)
XCTAssertTrue(samples[0].scheduled)
XCTAssertEqual(samples[0].steps, 8000)
XCTAssertFalse(samples[1].didWorkout) // rest / missing
XCTAssertEqual(samples[1].volume, 0)
XCTAssertNil(samples[1].steps) // honest: no fabricated data
XCTAssertTrue(samples[2].scheduled && !samples[2].didWorkout) // scheduled but missed
}
func testWeekAndMonthDayKeys() {
let c = cal()
let d = Date(timeIntervalSince1970: 1_783_500_000)
XCTAssertEqual(WorkoutAnalyticsAdapter.weekDayKeys(containing: d, calendar: c).count, 7)
XCTAssertEqual(WorkoutAnalyticsAdapter.monthDayKeys(containing: d, calendar: c).count, 31) // July
}
}