Files
kangkang/康康Tests/SeriesBucketTests.swift
link2026 1b01923c8e feat(capture): 统一报告捕获流程并集成视觉语言模型识别
- 替换 QuickCaptureFlow 和 ArchiveFlow 为 UnifiedCaptureFlow 统一流程
- 新增 VLSession 封装 Qwen2.5-VL 模型进行图像文本推理
- 实现 AIRuntime 中 VL 模型的准备和分析功能
- 添加 VLPrompts 定义体检化验单识别的 JSON 输出模板
- 创建 CaptureReviewForm 提供 VL 解析结果的可编辑表单界面
- 集成 VisionKit 文档扫描器支持真机多页文档扫描
- 为模拟器实现 PhotosPicker 回退方案选择已有照片
- 在 RootView 中统一使用 UnifiedCaptureFlow 处理快速和归档流程
- 添加 CustomMetricEditor 支持自定义监测指标的创建编辑删除
- 扩展 KangkangApp 模型配置以支持新数据类型
- 实现档案列表中症状结束功能通过时间线行点击触发
2026-05-26 11:18:00 +08:00

108 lines
4.2 KiB
Swift

import Testing
import Foundation
@testable import
struct SeriesBucketTests {
private func makeIndicator(
name: String = "测试",
value: String,
unit: String = "mmol/L",
range: String = "",
status: IndicatorStatus = .normal,
capturedAt: Date,
seriesKey: String?
) -> Indicator {
Indicator(name: name, value: value, unit: unit, range: range,
status: status, capturedAt: capturedAt,
seriesKey: seriesKey)
}
@Test func skipsIndicatorsWithoutSeriesKey() {
let now = Date()
let items = [
makeIndicator(value: "5.0", capturedAt: now, seriesKey: nil),
makeIndicator(value: "5.2", capturedAt: now, seriesKey: nil),
]
let buckets = SeriesBucket.build(from: items)
#expect(buckets.isEmpty)
}
@Test func filtersOutSeriesWithFewerThanMinPoints() {
let now = Date()
let items = [
makeIndicator(value: "5.0", capturedAt: now, seriesKey: "glucose.fasting"),
]
let buckets = SeriesBucket.build(from: items, minPoints: 2)
#expect(buckets.isEmpty)
}
@Test func singleSeriesBucketSortedAscending() {
let day = { (offset: Int) -> Date in
Calendar.current.date(byAdding: .day, value: offset, to: .now)!
}
let items = [
makeIndicator(value: "5.5", capturedAt: day(-3), seriesKey: "glucose.fasting"),
makeIndicator(value: "5.2", capturedAt: day(-1), seriesKey: "glucose.fasting"),
makeIndicator(value: "5.8", capturedAt: day(-2), seriesKey: "glucose.fasting"),
]
let buckets = SeriesBucket.build(from: items)
#expect(buckets.count == 1)
let line = try! #require(buckets.first?.lines.first)
// sorted ascending -3, -2, -1
let values = line.points.map(\.value)
#expect(values == [5.5, 5.8, 5.2])
}
@Test func bloodPressureMergesIntoSingleBucket() {
let now = Date()
let day = { (offset: Int) -> Date in
Calendar.current.date(byAdding: .day, value: offset, to: now)!
}
let items = [
makeIndicator(value: "125", capturedAt: day(-2), seriesKey: "bp.systolic"),
makeIndicator(value: "82", capturedAt: day(-2), seriesKey: "bp.diastolic"),
makeIndicator(value: "130", capturedAt: day(-1), seriesKey: "bp.systolic"),
makeIndicator(value: "85", capturedAt: day(-1), seriesKey: "bp.diastolic"),
]
let buckets = SeriesBucket.build(from: items)
let bp = try! #require(buckets.first { $0.id == "bp" })
#expect(bp.lines.count == 2)
#expect(bp.title == "血压")
#expect(bp.lines.contains { $0.seriesKey == "bp.systolic" })
#expect(bp.lines.contains { $0.seriesKey == "bp.diastolic" })
}
@Test func mixedSeriesProducesMultipleBucketsSortedByRecency() {
let cal = Calendar.current
let day = { (offset: Int) -> Date in
cal.date(byAdding: .day, value: offset, to: .now)!
}
let items = [
// weight
makeIndicator(value: "68", capturedAt: day(-10), seriesKey: "weight"),
makeIndicator(value: "67", capturedAt: day(-7), seriesKey: "weight"),
// glucose
makeIndicator(value: "5.1", capturedAt: day(-2), seriesKey: "glucose.fasting"),
makeIndicator(value: "5.3", capturedAt: day(-1), seriesKey: "glucose.fasting"),
]
let buckets = SeriesBucket.build(from: items)
#expect(buckets.count == 2)
// glucose
#expect(buckets.first?.id == "glucose.fasting")
#expect(buckets.last?.id == "weight")
}
@Test func nonNumericValueDropped() {
let now = Date()
let items = [
makeIndicator(value: "", capturedAt: now, seriesKey: "weight"),
makeIndicator(value: "68", capturedAt: now, seriesKey: "weight"),
makeIndicator(value: "67", capturedAt: now.addingTimeInterval(60), seriesKey: "weight"),
]
let buckets = SeriesBucket.build(from: items)
let line = try! #require(buckets.first?.lines.first)
#expect(line.points.count == 2) // ""
}
}