import Testing import Foundation @testable import 康康 struct CaptureServiceJSONTests { @Test func parsesCleanJSON() throws { let raw = """ {"title":"春检","type":"checkup","report_date":"2026-04-12","institution":"协和","page_count":2,"summary":"血脂偏高","indicators":[{"name":"LDL-C","value":"3.84","unit":"mmol/L","range":"< 3.40","status":"high"}]} """ let parsed = try CaptureService.parseReportJSON(raw) #expect(parsed.title == "春检") #expect(parsed.typeRaw == ReportType.checkup.rawValue) #expect(parsed.institution == "协和") #expect(parsed.pageCount == 2) #expect(parsed.indicators.count == 1) #expect(parsed.indicators.first?.status == .high) } @Test func stripsMarkdownCodeFence() throws { let raw = """ ```json {"title":"x","type":"lab","report_date":"2026-05-01","institution":"","page_count":1,"summary":"","indicators":[]} ``` """ let parsed = try CaptureService.parseReportJSON(raw) #expect(parsed.title == "x") #expect(parsed.typeRaw == ReportType.lab.rawValue) #expect(parsed.indicators.isEmpty) } @Test func extractsObjectAfterLeadingText() throws { let raw = """ 好的,识别结果如下: {"title":"y","type":"lab","report_date":"2026-05-01","institution":"","page_count":1,"summary":"","indicators":[]} 以上。 """ let parsed = try CaptureService.parseReportJSON(raw) #expect(parsed.title == "y") } @Test func handlesNestedBraces() throws { let raw = """ {"title":"y","type":"lab","report_date":"2026-05-01","institution":"","page_count":1,"summary":"含嵌套{x}对象","indicators":[]} """ let parsed = try CaptureService.parseReportJSON(raw) #expect(parsed.summary == "含嵌套{x}对象") } @Test func handlesEscapedQuotesInStrings() throws { let raw = #"{"title":"y \"内嵌\" 引号","type":"lab","report_date":"2026-05-01","institution":"","page_count":1,"summary":"","indicators":[]}"# let parsed = try CaptureService.parseReportJSON(raw) #expect(parsed.title == #"y "内嵌" 引号"#) } @Test func fillsDefaultsForMissingFields() throws { // 缺 title / type / report_date / institution / summary / page_count let raw = """ {"indicators":[{"name":"X","value":"1","unit":"","range":"","status":"normal"}]} """ let parsed = try CaptureService.parseReportJSON(raw) #expect(parsed.title == "拍摄识别") // 默认值 #expect(parsed.typeRaw == ReportType.other.rawValue) #expect(parsed.indicators.count == 1) } @Test func skipsIndicatorsWithEmptyName() throws { let raw = """ {"title":"t","type":"lab","report_date":"2026-05-01","institution":"","page_count":1,"summary":"","indicators":[ {"name":"","value":"1","unit":"","range":"","status":"normal"}, {"name":" ","value":"1","unit":"","range":"","status":"normal"}, {"name":"OK","value":"1","unit":"","range":"","status":"normal"} ]} """ let parsed = try CaptureService.parseReportJSON(raw) #expect(parsed.indicators.count == 1) #expect(parsed.indicators.first?.name == "OK") } @Test func malformedJSONThrows() { let raw = "完全不是 JSON" #expect(throws: CaptureError.self) { _ = try CaptureService.parseReportJSON(raw) } } @Test func valueAsNumberStillParses() throws { let raw = """ {"title":"t","type":"lab","report_date":"2026-05-01","institution":"","page_count":1,"summary":"","indicators":[{"name":"X","value":3.84,"unit":"","range":"","status":"high"}]} """ let parsed = try CaptureService.parseReportJSON(raw) #expect(parsed.indicators.first?.value == "3.84") } @Test func unknownStatusFallsBackToNormal() throws { let raw = """ {"title":"t","type":"lab","report_date":"2026-05-01","institution":"","page_count":1,"summary":"","indicators":[{"name":"X","value":"1","unit":"","range":"","status":"abnormal"}]} """ let parsed = try CaptureService.parseReportJSON(raw) #expect(parsed.indicators.first?.status == .normal) } @Test func badReportDateFallsBackToNow() throws { let raw = """ {"title":"t","type":"lab","report_date":"昨天","institution":"","page_count":1,"summary":"","indicators":[]} """ let parsed = try CaptureService.parseReportJSON(raw) let now = Date() let diff = abs(parsed.reportDate.timeIntervalSince(now)) #expect(diff < 5) // 5 秒内算 .now } /// VL 多项时偶尔直接吐裸数组 [{...},{...}],旧实现(只认 {})会只截第一项静默丢其余。 @Test func parsesTopLevelArrayAsIndicators() throws { let raw = """ [{"name":"A","value":"1","unit":"","range":"","status":"high"}, {"name":"B","value":"2","unit":"","range":"","status":"low"}] """ let parsed = try CaptureService.parseReportJSON(raw) #expect(parsed.indicators.count == 2) #expect(parsed.indicators.first?.name == "A") #expect(parsed.indicators.last?.status == .low) } /// VL 不同来源会吐 yyyy/MM/dd 等格式,不应回退到「今天」导致归档年份错位。 @Test func parsesSlashAndCJKDateFormats() throws { for ds in ["2026/04/12", "2026.04.12", "2026年04月12日"] { let raw = """ {"title":"t","type":"lab","report_date":"\(ds)","institution":"","page_count":1,"summary":"","indicators":[]} """ let parsed = try CaptureService.parseReportJSON(raw) let c = Calendar(identifier: .gregorian).dateComponents([.year, .month, .day], from: parsed.reportDate) #expect(c.year == 2026 && c.month == 4 && c.day == 12, "格式 \(ds) 解析失败") } } }