package handler import ( "testing" "silk-server-go/internal/model" ) func TestQRPayloadRoundTripAndTamper(t *testing.T) { payload := model.EncodeQRPayload("batch", "public-abc", model.QRVersion) entityType, publicID, version, err := model.ParseQRPayload(payload) if err != nil { t.Fatalf("parse failed: %v", err) } if entityType != "batch" || publicID != "public-abc" || version != model.QRVersion { t.Fatalf("payload = %s/%s/%d", entityType, publicID, version) } if _, _, _, err := model.ParseQRPayload("batch:public-abc:1"); err == nil { t.Fatal("tampered format should fail") } if _, _, _, err := model.ParseQRPayload(model.EncodeQRPayload("batch", "public-abc", 2)); err != nil { t.Fatal("different version should parse but must be rejected by resolver") } } func TestSeedSourceCycleRejected(t *testing.T) { chain := map[string]string{ "a": "b", "b": "c", "c": "a", } if err := model.SeedSourceCycleError(chain, "d", "a"); err == nil { t.Fatal("cycle should be rejected") } if err := model.SeedSourceCycleError(chain, "a", "a"); err == nil { t.Fatal("self reference should be rejected") } } func TestSeedSourceCycleAllowsAcyclic(t *testing.T) { chain := map[string]string{"a": "b", "b": "c"} if err := model.SeedSourceCycleError(chain, "d", "a"); err != nil { t.Fatalf("acyclic chain should pass: %v", err) } } func TestDisinfectionRequiredFields(t *testing.T) { record := model.DisinfectionRecord{Kind: "execution", Agent: "漂白粉", Concentration: "1%"} if err := model.ValidateDisinfectionRecord(record); err != nil { t.Fatalf("valid record should pass: %v", err) } record.Agent = "" if err := model.ValidateDisinfectionRecord(record); err == nil { t.Fatal("missing agent should fail") } record.Agent = "漂白粉" record.Concentration = "" if err := model.ValidateDisinfectionRecord(record); err == nil { t.Fatal("missing concentration should fail") } record.Concentration = "1%" record.Kind = "unknown" if err := model.ValidateDisinfectionRecord(record); err == nil { t.Fatal("invalid kind should fail") } }