package source import ( "strings" "testing" ) func TestValidateDocumentValid(t *testing.T) { doc := validDocument() if err := ValidateDocument(doc); err != nil { t.Fatalf("ValidateDocument() error = %v, want nil", err) } } func TestValidateDocumentNil(t *testing.T) { err := ValidateDocument(nil) if err == nil { t.Fatal("ValidateDocument() error = nil, want error") } if err.Error() != "source document must not be nil" { t.Fatalf("ValidateDocument() error = %q", err.Error()) } } func TestValidateDocumentMissingFields(t *testing.T) { tests := []struct { name string mutate func(*SourceDocument) wantErr string }{ { name: "id", mutate: func(doc *SourceDocument) { doc.ID = " \t" }, wantErr: "source document id must not be empty", }, { name: "id surrounding whitespace", mutate: func(doc *SourceDocument) { doc.ID = " source-1 " }, wantErr: "source document id \" source-1 \" must not contain leading or trailing whitespace", }, { name: "kind", mutate: func(doc *SourceDocument) { doc.Kind = "" }, wantErr: "source document kind must not be empty", }, { name: "format", mutate: func(doc *SourceDocument) { doc.Format = "\n" }, wantErr: "source document format must not be empty", }, { name: "digest", mutate: func(doc *SourceDocument) { doc.Digest = "" }, wantErr: "source document digest must not be empty", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { doc := validDocument() tt.mutate(doc) err := ValidateDocument(doc) if err == nil { t.Fatal("ValidateDocument() error = nil, want error") } if err.Error() != tt.wantErr { t.Fatalf("ValidateDocument() error = %q, want %q", err.Error(), tt.wantErr) } }) } } func TestValidateDocumentEmptyUnits(t *testing.T) { doc := validDocument() doc.Units = nil err := ValidateDocument(doc) if err == nil { t.Fatal("ValidateDocument() error = nil, want error") } if err.Error() != "source document units must not be empty" { t.Fatalf("ValidateDocument() error = %q", err.Error()) } } func TestValidateDocumentMissingUnitFields(t *testing.T) { tests := []struct { name string mutate func(*SourceDocument) wantErr string }{ { name: "id", mutate: func(doc *SourceDocument) { doc.Units[1].ID = "" }, wantErr: "source unit[1].id must not be empty", }, { name: "id surrounding whitespace", mutate: func(doc *SourceDocument) { doc.Units[1].ID = " u2 " }, wantErr: "source unit[1].id \" u2 \" must not contain leading or trailing whitespace", }, { name: "kind", mutate: func(doc *SourceDocument) { doc.Units[1].Kind = " " }, wantErr: "source unit[1].kind must not be empty", }, { name: "text", mutate: func(doc *SourceDocument) { doc.Units[1].Text = "\n\t" }, wantErr: "source unit[1].text must not be empty", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { doc := validDocument() tt.mutate(doc) err := ValidateDocument(doc) if err == nil { t.Fatal("ValidateDocument() error = nil, want error") } if err.Error() != tt.wantErr { t.Fatalf("ValidateDocument() error = %q, want %q", err.Error(), tt.wantErr) } }) } } func TestValidateDocumentDuplicateUnitIDs(t *testing.T) { doc := validDocument() doc.Units[1].ID = "u1" err := ValidateDocument(doc) if err == nil { t.Fatal("ValidateDocument() error = nil, want error") } if err.Error() != "source unit id \"u1\" is duplicated" { t.Fatalf("ValidateDocument() error = %q", err.Error()) } } func TestValidateRefValid(t *testing.T) { doc := validDocument() ref := SourceRef{ SourceID: "source-1", StartUnitID: "u1", EndUnitID: "u2", } if err := ValidateRef(doc, ref); err != nil { t.Fatalf("ValidateRef() error = %v, want nil", err) } } func TestValidateRefSourceIDMismatch(t *testing.T) { doc := validDocument() ref := SourceRef{ SourceID: "source-2", StartUnitID: "u1", EndUnitID: "u2", } err := ValidateRef(doc, ref) if err == nil { t.Fatal("ValidateRef() error = nil, want error") } if err.Error() != "source ref source_id \"source-2\" does not match document id \"source-1\"" { t.Fatalf("ValidateRef() error = %q", err.Error()) } } func TestValidateRefMissingUnitIDs(t *testing.T) { tests := []struct { name string ref SourceRef wantErr string }{ { name: "missing source id", ref: SourceRef{StartUnitID: "u1", EndUnitID: "u2"}, wantErr: "source ref source_id must not be empty", }, { name: "source id surrounding whitespace", ref: SourceRef{SourceID: " source-1 ", StartUnitID: "u1", EndUnitID: "u2"}, wantErr: "source ref source_id \" source-1 \" must not contain leading or trailing whitespace", }, { name: "missing start id", ref: SourceRef{SourceID: "source-1", EndUnitID: "u2"}, wantErr: "source ref start_unit_id must not be empty", }, { name: "start id surrounding whitespace", ref: SourceRef{SourceID: "source-1", StartUnitID: " u1 ", EndUnitID: "u2"}, wantErr: "source ref start_unit_id \" u1 \" must not contain leading or trailing whitespace", }, { name: "missing end id", ref: SourceRef{SourceID: "source-1", StartUnitID: "u1"}, wantErr: "source ref end_unit_id must not be empty", }, { name: "end id surrounding whitespace", ref: SourceRef{SourceID: "source-1", StartUnitID: "u1", EndUnitID: " u2 "}, wantErr: "source ref end_unit_id \" u2 \" must not contain leading or trailing whitespace", }, { name: "unknown start id", ref: SourceRef{SourceID: "source-1", StartUnitID: "u9", EndUnitID: "u2"}, wantErr: "source ref start_unit_id \"u9\" was not found", }, { name: "unknown end id", ref: SourceRef{SourceID: "source-1", StartUnitID: "u1", EndUnitID: "u9"}, wantErr: "source ref end_unit_id \"u9\" was not found", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := ValidateRef(validDocument(), tt.ref) if err == nil { t.Fatal("ValidateRef() error = nil, want error") } if err.Error() != tt.wantErr { t.Fatalf("ValidateRef() error = %q, want %q", err.Error(), tt.wantErr) } }) } } func TestValidateRefReversedUnitOrder(t *testing.T) { doc := validDocument() ref := SourceRef{ SourceID: "source-1", StartUnitID: "u2", EndUnitID: "u1", } err := ValidateRef(doc, ref) if err == nil { t.Fatal("ValidateRef() error = nil, want error") } if !strings.Contains(err.Error(), "appears after") { t.Fatalf("ValidateRef() error = %q, want reversed order error", err.Error()) } } func TestUnitIndex(t *testing.T) { doc := validDocument() index, ok := UnitIndex(doc, "u2") if !ok { t.Fatal("UnitIndex() ok = false, want true") } if index != 1 { t.Fatalf("UnitIndex() index = %d, want 1", index) } index, ok = UnitIndex(doc, "u9") if ok { t.Fatal("UnitIndex() ok = true, want false") } if index != 0 { t.Fatalf("UnitIndex() index = %d, want 0", index) } } func validDocument() *SourceDocument { return &SourceDocument{ ID: "source-1", Kind: "document", Format: "text/plain", Digest: "sha256:abc123", Units: []SourceUnit{ { ID: "u1", Kind: "paragraph", Text: "First unit.", }, { ID: "u2", Kind: "paragraph", Text: "Second unit.", }, }, } }