package modules import ( "context" "errors" "testing" "gitea.maximumdirect.net/eric/audita/internal/framework/contracts" "gitea.maximumdirect.net/eric/audita/internal/framework/proposals" ) type noopModule struct { key string } func (m noopModule) Key() string { return m.key } func (m noopModule) ReplacementPolicy() proposals.ReplacementPolicy { return proposals.ReplacementPolicyRequireUnique } func (m noopModule) Validators() []contracts.Validator { return nil } func (m noopModule) Propose(ctx context.Context, req contracts.ProposalRequest) ([]proposals.CorrectionProposal, error) { _ = ctx _ = req return nil, nil } func TestKnownModuleKeyRecognition(t *testing.T) { for _, key := range []string{ModuleKeyGlossary, ModuleKeyHomophones, ModuleKeySpokenWord, ModuleKeyGrammar} { if !IsKnownModuleKey(key) { t.Fatalf("expected key %q to be recognized", key) } } } func TestUnknownModuleKeyNotRecognized(t *testing.T) { if IsKnownModuleKey("made_up") { t.Fatal("expected unknown key to be unrecognized") } } func TestRepeatedRunSpecNamingRemainsDeterministic(t *testing.T) { specs, err := contracts.ResolveModuleRunSpecs([]string{"glossary", "glossary", "grammar"}) if err != nil { t.Fatalf("ResolveModuleRunSpecs error: %v", err) } if specs[0].InstanceName != "glossary_1" || specs[1].InstanceName != "glossary_2" || specs[2].InstanceName != "grammar" { t.Fatalf("unexpected instance names: %+v", specs) } } func TestUnsupportedUnknownModuleKeyFailsCleanly(t *testing.T) { factory := NewFactory(Dependencies{}) _, err := factory.ModuleForSpec(contracts.ModuleRunSpec{ModuleKey: "unknown", InstanceName: "unknown"}) if err == nil { t.Fatal("expected unsupported-module error") } var unsupported *UnsupportedModuleError if !errors.As(err, &unsupported) { t.Fatalf("expected UnsupportedModuleError, got %T (%v)", err, err) } if unsupported.ReasonCode() != ReasonUnsupportedModule { t.Fatalf("unexpected reason code: %q", unsupported.ReasonCode()) } } func TestRecognizedButUnimplementedModuleKeyFailsCleanly(t *testing.T) { factory := NewFactory(Dependencies{}) for _, key := range []string{ModuleKeyGlossary, ModuleKeyHomophones, ModuleKeySpokenWord} { t.Run(key, func(t *testing.T) { _, err := factory.ModuleForSpec(contracts.ModuleRunSpec{ModuleKey: key, InstanceName: key}) if err == nil { t.Fatal("expected unimplemented-module error") } var unimplemented *UnimplementedModuleError if !errors.As(err, &unimplemented) { t.Fatalf("expected UnimplementedModuleError, got %T (%v)", err, err) } if unimplemented.ReasonCode() != ReasonUnimplementedModule { t.Fatalf("unexpected reason code: %q", unimplemented.ReasonCode()) } }) } } func TestGrammarIsRegisteredAndConstructibleByDefault(t *testing.T) { factory := NewFactory(Dependencies{}) module, err := factory.ModuleForSpec(contracts.ModuleRunSpec{ModuleKey: ModuleKeyGrammar, InstanceName: ModuleKeyGrammar}) if err != nil { t.Fatalf("ModuleForSpec error: %v", err) } if module.Key() != ModuleKeyGrammar { t.Fatalf("expected grammar module key, got %q", module.Key()) } } func TestRegisterConstructorAndConstruct(t *testing.T) { factory := NewFactory(Dependencies{}) if err := factory.RegisterConstructor(ModuleKeyGlossary, func(ctx context.Context, req ConstructRequest) (contracts.TranscriptModule, error) { _ = ctx if req.RunSpec.InstanceName != "glossary_1" { t.Fatalf("expected run spec instance name, got %q", req.RunSpec.InstanceName) } return noopModule{key: req.RunSpec.ModuleKey}, nil }); err != nil { t.Fatalf("RegisterConstructor error: %v", err) } module, err := factory.ModuleForSpec(contracts.ModuleRunSpec{ ModuleKey: ModuleKeyGlossary, InstanceName: "glossary_1", }) if err != nil { t.Fatalf("ModuleForSpec error: %v", err) } if module.Key() != ModuleKeyGlossary { t.Fatalf("unexpected module key %q", module.Key()) } } func TestRegisterConstructorRejectsUnknownModuleKey(t *testing.T) { factory := NewFactory(Dependencies{}) err := factory.RegisterConstructor("unknown", func(ctx context.Context, req ConstructRequest) (contracts.TranscriptModule, error) { _ = ctx _ = req return noopModule{key: "unknown"}, nil }) if err == nil { t.Fatal("expected register failure for unknown key") } var unsupported *UnsupportedModuleError if !errors.As(err, &unsupported) { t.Fatalf("expected UnsupportedModuleError, got %T (%v)", err, err) } }