package dnd import ( "encoding/json" "strings" "testing" "gitea.maximumdirect.net/eric/notarius/internal/core/source" ) func TestUnitRefUnmarshalAcceptsIntegerAndString(t *testing.T) { var integerRef UnitRef if err := json.Unmarshal([]byte(`12`), &integerRef); err != nil { t.Fatalf("Unmarshal(integer) error = %v, want nil", err) } if got := integerRef.String(); got != "12" { t.Fatalf("integer ref = %q, want 12", got) } var stringRef UnitRef if err := json.Unmarshal([]byte(`"seg-001"`), &stringRef); err != nil { t.Fatalf("Unmarshal(string) error = %v, want nil", err) } if got := stringRef.String(); got != "seg-001" { t.Fatalf("string ref = %q, want seg-001", got) } } func TestUnitRefUnmarshalRejectsNonIntegerTypes(t *testing.T) { for _, raw := range []string{`true`, `null`, `1.5`, `{}`} { t.Run(raw, func(t *testing.T) { var ref UnitRef err := json.Unmarshal([]byte(raw), &ref) if err == nil { t.Fatal("Unmarshal() error = nil, want error") } if !strings.Contains(err.Error(), "string or integer") { t.Fatalf("Unmarshal() error = %q, want type context", err.Error()) } }) } } func TestResolveUnitIDPrefersExactSourceUnitID(t *testing.T) { doc := unitRefSourceDocument("2", "10") got, err := ResolveUnitID(doc, "start_unit_id", UnitRefFromInt(2)) if err != nil { t.Fatalf("ResolveUnitID() error = %v, want nil", err) } if got != "2" { t.Fatalf("ResolveUnitID() = %q, want exact source unit ID", got) } } func TestResolveUnitIDFallsBackToOneBasedUnitNumber(t *testing.T) { doc := unitRefSourceDocument("seg-001", "seg-002") got, err := ResolveUnitID(doc, "end_unit_id", UnitRefFromInt(2)) if err != nil { t.Fatalf("ResolveUnitID() error = %v, want nil", err) } if got != "seg-002" { t.Fatalf("ResolveUnitID() = %q, want second source unit ID", got) } } func TestResolveUnitIDRejectsMissingUnit(t *testing.T) { doc := unitRefSourceDocument("seg-001") _, err := ResolveUnitID(doc, "start_unit_id", UnitRefFromInt(9)) if err == nil { t.Fatal("ResolveUnitID() error = nil, want error") } if !strings.Contains(err.Error(), "start_unit_id 9") { t.Fatalf("ResolveUnitID() error = %q, want field and value context", err.Error()) } } func TestSourceRefCandidateCanonicalizesValidRefsAndPreservesInvalidRefs(t *testing.T) { doc := unitRefSourceDocument("seg-001", "seg-002") valid := SourceRefCandidate(doc, SourceRefResponse{ SourceID: " session-alpha ", StartUnitID: UnitRefFromInt(1), EndUnitID: UnitRefFromInt(2), }) if valid != (source.SourceRef{SourceID: "session-alpha", StartUnitID: "seg-001", EndUnitID: "seg-002"}) { t.Fatalf("valid candidate = %#v, want canonical source ref", valid) } invalid := SourceRefCandidate(doc, SourceRefResponse{ SourceID: "session-alpha", StartUnitID: UnitRefFromInt(9), EndUnitID: UnitRefFromString("missing"), }) if invalid != (source.SourceRef{SourceID: "session-alpha", StartUnitID: "9", EndUnitID: "missing"}) { t.Fatalf("invalid candidate = %#v, want unresolved values for validator", invalid) } } func unitRefSourceDocument(ids ...string) *source.SourceDocument { doc := &source.SourceDocument{ ID: "session-alpha", Kind: "transcript", Format: "application/json", Digest: "sha256:test", } for _, id := range ids { doc.Units = append(doc.Units, source.SourceUnit{ ID: id, Kind: "transcript_segment", Text: "text", }) } return doc }