Files

134 lines
4.5 KiB
Go
Raw Permalink Normal View History

2026-07-03 23:29:08 +00:00
package spells
import (
"reflect"
"strings"
"testing"
2026-07-05 14:49:17 +00:00
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
2026-07-03 23:29:08 +00:00
"gitea.maximumdirect.net/eric/notarius/internal/framework/pipeline"
2026-07-17 06:50:08 +00:00
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd"
2026-07-03 23:29:08 +00:00
)
2026-07-17 06:50:08 +00:00
func TestNewRequiresLLMClientAndReturnsExtractor(t *testing.T) {
if _, err := New(nil, Options{}); err == nil || !strings.Contains(err.Error(), "LLM client") {
t.Fatalf("New(nil) error = %v, want LLM client error", err)
2026-07-03 23:29:08 +00:00
}
2026-07-17 06:50:08 +00:00
extractor := newExtractor(t, &fakeSpellsLLMClient{})
2026-07-03 23:29:08 +00:00
if extractor.Key() != Key {
t.Fatalf("extractor.Key() = %q, want %q", extractor.Key(), Key)
}
}
func TestModuleSpec(t *testing.T) {
got := ModuleSpec()
want := pipeline.ModuleSpec{
Key: Key,
Stage: pipeline.StageExtract,
ExecutionClass: contracts.ExecutionClassLLMBacked,
CorrectionProtocol: contracts.CorrectionProtocolSingleResponseV1,
2026-07-03 23:29:08 +00:00
Requires: []string{
"chunks",
"source.transcript",
},
Provides: []string{
"dnd.spell_casts",
},
2026-07-17 06:50:08 +00:00
ArtifactKind: dnd.SpellListKind,
2026-07-05 14:49:17 +00:00
ReferenceSlots: []contracts.ReferenceSlot{
{
Name: "glossary",
Description: "Optional campaign glossary reference material used only for disambiguation.",
AcceptedMediaTypes: []string{"application/json", "application/x-yaml", "application/yaml", "text/markdown", "text/plain"},
2026-07-05 14:49:17 +00:00
},
{
Name: NPCRegistryReferenceSlot,
Description: "Optional normalized NPC registry used for canonical caster-name grounding.",
AcceptedMediaTypes: []string{"application/json"},
2026-08-05 18:25:04 +00:00
AcceptedArtifactKinds: []contracts.ArtifactKind{dnd.NPCRegistryKind},
MaxBytes: NPCRegistryMaxBytes,
},
{
Name: "party",
Description: "Optional party roster reference material used only for disambiguation.",
AcceptedMediaTypes: []string{"application/json", "application/x-yaml", "application/yaml", "text/markdown", "text/plain"},
},
{
Name: "players",
Description: "Optional player list reference material used only for disambiguation.",
AcceptedMediaTypes: []string{"application/json", "application/x-yaml", "application/yaml", "text/markdown", "text/plain"},
},
2026-07-05 14:49:17 +00:00
{
Name: "roster",
Description: "Deprecated alias for party roster reference material used only for disambiguation.",
AcceptedMediaTypes: []string{"application/json", "application/x-yaml", "application/yaml", "text/markdown", "text/plain"},
2026-07-05 14:49:17 +00:00
},
{
Name: "spell_catalog",
Description: "Optional canonical spell-name catalog used for extraction grounding.",
AcceptedMediaTypes: []string{"application/json"},
MaxBytes: 1048576,
},
2026-07-05 14:49:17 +00:00
},
2026-07-03 23:29:08 +00:00
}
if !reflect.DeepEqual(got, want) {
t.Fatalf("ModuleSpec() = %#v, want %#v", got, want)
}
got.Requires[0] = "changed"
got.Provides[0] = "changed"
2026-07-05 14:49:17 +00:00
got.ReferenceSlots[0].AcceptedMediaTypes[0] = "changed"
2026-07-03 23:29:08 +00:00
again := ModuleSpec()
if !reflect.DeepEqual(again, want) {
t.Fatalf("ModuleSpec() after caller mutation = %#v, want %#v", again, want)
}
}
func TestRegisterMakesExtractorBuildable(t *testing.T) {
registry := pipeline.NewExtractorRegistry()
if err := Register(registry); err != nil {
t.Fatalf("Register() error = %v, want nil", err)
}
2026-07-17 06:50:08 +00:00
if _, err := DecodeOptions(map[string]any{"unexpected": true}); err == nil || !strings.Contains(err.Error(), "unknown option") {
t.Fatalf("DecodeOptions() error = %v, want unknown option error", err)
2026-07-03 23:29:08 +00:00
}
}
func TestRegisterStoresModuleSpec(t *testing.T) {
registry := pipeline.NewExtractorRegistry()
if err := Register(registry); err != nil {
t.Fatalf("Register() error = %v, want nil", err)
}
got, ok := registry.Spec(Key)
if !ok {
t.Fatal("Spec() ok = false, want true")
}
want := ModuleSpec()
if !reflect.DeepEqual(got, want) {
t.Fatalf("Spec() = %#v, want %#v", got, want)
}
}
func TestRuntimeReferenceSlotsMatchModuleSpec(t *testing.T) {
2026-07-17 06:50:08 +00:00
extractor := newExtractor(t, &fakeSpellsLLMClient{})
spec := ModuleSpec()
if !reflect.DeepEqual(extractor.ReferenceSlots(), spec.ReferenceSlots) {
t.Fatalf("ReferenceSlots() = %#v, want spec slots %#v", extractor.ReferenceSlots(), spec.ReferenceSlots)
}
}
2026-07-03 23:29:08 +00:00
func TestRegisterNilRegistryReturnsError(t *testing.T) {
err := Register(nil)
if err == nil {
t.Fatal("Register(nil) error = nil, want error")
}
if !strings.Contains(err.Error(), "extractor registry") {
t.Fatalf("Register(nil) error = %q, want registry context", err.Error())
}
}