Files
notarius/internal/modules/dnd/validate/scenedescriptions/shape/validator_test.go

70 lines
3.4 KiB
Go

package shape
import (
"context"
"reflect"
"testing"
"gitea.maximumdirect.net/eric/notarius/internal/core/source"
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
)
func TestValidatorRequiresSceneShapeAndExactlyOneExtractionRecord(t *testing.T) {
valid := list(scene("one", dnd.SceneKindNarrative, "Arrival", "The party arrives.", 1, 1))
validator := New(Options{})
for _, test := range []struct {
name string
value dnd.SceneDescriptionList
stage string
approved bool
}{
{name: "valid normalization", value: valid, approved: true},
{name: "valid extraction", value: valid, stage: string(pipeline.StageExtract), approved: true},
{name: "multiple extraction records", value: list(valid.Scenes[0], scene("two", dnd.SceneKindMeta, "Rules", "The table checks rules.", 2, 2)), stage: string(pipeline.StageExtract)},
{name: "nil list", value: dnd.SceneDescriptionList{}},
{name: "empty list", value: dnd.SceneDescriptionList{Scenes: []dnd.SceneDescription{}}},
{name: "blank ID", value: list(scene(" ", dnd.SceneKindNarrative, "Arrival", "The party arrives.", 1, 1))},
{name: "unsupported kind", value: list(scene("one", "other", "Arrival", "The party arrives.", 1, 1))},
{name: "empty title", value: list(scene("one", dnd.SceneKindNarrative, "", "The party arrives.", 1, 1))},
{name: "whitespace-only title", value: list(scene("one", dnd.SceneKindNarrative, " ", "The party arrives.", 1, 1))},
{name: "empty summary", value: list(scene("one", dnd.SceneKindNarrative, "Arrival", "", 1, 1))},
{name: "whitespace-only summary", value: list(scene("one", dnd.SceneKindNarrative, "Arrival", " ", 1, 1))},
{name: "untrimmed prose", value: list(scene("one", dnd.SceneKindNarrative, " Arrival ", "The party arrives.", 1, 1))},
{name: "empty source reference", value: dnd.SceneDescriptionList{Scenes: []dnd.SceneDescription{{ID: "one", Kind: dnd.SceneKindNarrative, Title: "Arrival", Summary: "The party arrives."}}}},
} {
t.Run(test.name, func(t *testing.T) {
result, err := validator.Validate(context.Background(), contracts.TypedValidationRequest[dnd.SceneDescriptionList]{Stage: test.stage, Value: test.value})
if err != nil || result.Approved != test.approved {
t.Fatalf("Validate() = %#v, %v; want approved=%t", result, err, test.approved)
}
})
}
}
func TestValidatorContractAndRegistration(t *testing.T) {
registry := pipeline.NewValidatorRegistry()
if err := Register(registry); err != nil {
t.Fatalf("Register() error = %v", err)
}
if _, ok := registry.Spec(Key); !ok {
t.Fatalf("registry has no spec for %q", Key)
}
if _, err := DecodeOptions(map[string]any{"unexpected": true}); err == nil {
t.Fatal("DecodeOptions() accepted unknown options")
}
validator := New(Options{})
if got, want := validator.CheckpointFingerprints(), []pipeline.CheckpointFingerprint{{Name: "policy", Value: policy}}; !reflect.DeepEqual(got, want) {
t.Fatalf("fingerprints = %#v, want %#v", got, want)
}
}
func list(scenes ...dnd.SceneDescription) dnd.SceneDescriptionList {
return dnd.SceneDescriptionList{Scenes: scenes}
}
func scene(id string, kind dnd.SceneKind, title, summary string, start, end int) dnd.SceneDescription {
return dnd.SceneDescription{ID: id, Kind: kind, Title: title, Summary: summary, SourceRef: source.SourceRef{SourceID: "session", StartUnitID: start, EndUnitID: end}}
}