package model import ( "encoding/json" "testing" "time" ) func TestValidConsultationTransition(t *testing.T) { ok := [][2]string{ {"unassigned", "assigned"}, {"assigned", "accepted"}, {"assigned", "needs_info"}, {"accepted", "resolved"}, {"needs_info", "resolved"}, {"resolved", "archived"}, } for _, c := range ok { if !ValidConsultationTransition(c[0], c[1]) { t.Errorf("%s → %s 应合法", c[0], c[1]) } } bad := [][2]string{ {"unassigned", "archived"}, {"unassigned", "resolved"}, {"resolved", "resolved"}, {"archived", "pending"}, {"", "resolved"}, } for _, c := range bad { if ValidConsultationTransition(c[0], c[1]) { t.Errorf("%s → %s 不应合法", c[0], c[1]) } } } func TestConsultationRejectsArchiveBeforeResolution(t *testing.T) { if ValidConsultationTransition("accepted", "archived") { t.Fatal("accepted 不能直接归档") } if ValidConsultationTransition("unassigned", "archived") { t.Fatal("unassigned 不能直接归档") } } func TestConsultationSLAMarksOverdue(t *testing.T) { now := time.Now() deadline := now.Add(-time.Hour) task := Consultation{Status: "assigned", SLADeadline: &deadline} if state := ConsultationSLAState(task, now); state != "overdue" { t.Fatalf("SLA 状态 = %s, want overdue", state) } future := now.Add(time.Hour) task.SLADeadline = &future if state := ConsultationSLAState(task, now); state != "on_time" { t.Fatalf("SLA 状态 = %s, want on_time", state) } if state := ConsultationSLAState(Consultation{}, now); state != "unscheduled" { t.Fatalf("SLA 状态 = %s, want unscheduled", state) } } func TestConsultationSnapshotJSON(t *testing.T) { now := time.Now() s := ConsultationSnapshot{ RoomName: "蚕房1#", LampTest: &LampTest{ID: "lamp-1", Status: "resulted"}, Inspection: &InspectionRecord{ID: "insp-1", AIStatus: "done"}, Batch: &Batch{ID: "batch-1", Name: "批次A"}, WeatherAlerts: []WeatherAlert{{Disease: "白僵病", Level: "orange"}}, CreatedAt: now, } raw, err := json.Marshal(s) if err != nil { t.Fatalf("快照序列化失败: %v", err) } var m map[string]any if err := json.Unmarshal(raw, &m); err != nil { t.Fatalf("快照反序列化失败: %v", err) } for _, key := range []string{"roomName", "lampTest", "inspection", "batch", "weatherAlerts", "createdAt"} { if _, ok := m[key]; !ok { t.Errorf("快照缺少字段 %s", key) } } }