package protected_terms import ( "context" "testing" "gitea.maximumdirect.net/eric/audita/internal/core/schema" "gitea.maximumdirect.net/eric/audita/internal/framework/contracts" "gitea.maximumdirect.net/eric/audita/internal/framework/proposals" frameworkvalidators "gitea.maximumdirect.net/eric/audita/internal/framework/validators" validatormetadata "gitea.maximumdirect.net/eric/audita/internal/validators/metadata" ) func proposal(index int, moduleKey, original, corrected string) proposals.EnrichedCorrectionProposal { return proposals.EnrichedCorrectionProposal{ CorrectionProposal: proposals.CorrectionProposal{ TargetSegmentID: 1, OriginalText: original, CorrectedText: corrected, Confidence: 0.95, }, ProposalMetadata: proposals.ProposalMetadata{ ProposalIndex: index, ModuleKey: moduleKey, ModuleInstance: moduleKey, }, } } func tinyGlossary() *schema.Glossary { return &schema.Glossary{ Entries: []schema.GlossaryEntry{ {Name: "Jesters", Category: "faction", Summary: "Faction"}, }, } } func TestNewReportsStableKeyAndDeterministicClass(t *testing.T) { v, err := New() if err != nil { t.Fatalf("New: %v", err) } if v.Name() != Key { t.Fatalf("expected key %q, got %q", Key, v.Name()) } if got := validatormetadata.ClassOf(v); got != validatormetadata.ExecutionClassDeterministic { t.Fatalf("expected deterministic class, got %q", got) } } func TestNewUsesGeneralBehaviorForGlossaryModule(t *testing.T) { v, err := New() if err != nil { t.Fatalf("New: %v", err) } req := contracts.ValidationRequest{ ModuleKey: "glossary", Glossary: tinyGlossary(), CandidateProposal: []proposals.EnrichedCorrectionProposal{ proposal(0, "glossary", "Jesters", "Gestures"), }, } result, err := v.Validate(context.Background(), req) if err != nil { t.Fatalf("Validate: %v", err) } if len(result.Decisions) != 1 { t.Fatalf("expected one decision, got %+v", result.Decisions) } if !result.Decisions[0].Approved { t.Fatalf("expected glossary-module approval in general variant, got %+v", result.Decisions[0]) } if result.Decisions[0].ReasonCode != frameworkvalidators.ReasonApproved { t.Fatalf("expected reason %q, got %+v", frameworkvalidators.ReasonApproved, result.Decisions[0]) } } func TestNewRejectsProtectedTermChangeOutsideGlossaryStage(t *testing.T) { v, err := New() if err != nil { t.Fatalf("New: %v", err) } req := contracts.ValidationRequest{ ModuleKey: "homophones", Glossary: tinyGlossary(), CandidateProposal: []proposals.EnrichedCorrectionProposal{ proposal(0, "homophones", "Jesters", "Gestures"), }, } result, err := v.Validate(context.Background(), req) if err != nil { t.Fatalf("Validate: %v", err) } if len(result.Decisions) != 1 { t.Fatalf("expected one decision, got %+v", result.Decisions) } if result.Decisions[0].Approved { t.Fatalf("expected protected_terms rejection, got %+v", result.Decisions[0]) } if result.Decisions[0].ReasonCode != frameworkvalidators.ReasonProtectedGlossaryTerm { t.Fatalf("expected reason %q, got %+v", frameworkvalidators.ReasonProtectedGlossaryTerm, result.Decisions[0]) } } func TestNewGlossaryStageRejectsProtectedTermChange(t *testing.T) { v, err := NewGlossaryStage() if err != nil { t.Fatalf("NewGlossaryStage: %v", err) } if v.Name() != Key { t.Fatalf("expected key %q, got %q", Key, v.Name()) } if got := validatormetadata.ClassOf(v); got != validatormetadata.ExecutionClassDeterministic { t.Fatalf("expected deterministic class, got %q", got) } req := contracts.ValidationRequest{ ModuleKey: "glossary", Glossary: tinyGlossary(), CandidateProposal: []proposals.EnrichedCorrectionProposal{ proposal(0, "glossary", "Jesters", "Gestures"), }, } result, err := v.Validate(context.Background(), req) if err != nil { t.Fatalf("Validate: %v", err) } if len(result.Decisions) != 1 { t.Fatalf("expected one decision, got %+v", result.Decisions) } if result.Decisions[0].Approved { t.Fatalf("expected glossary-stage protected_terms rejection, got %+v", result.Decisions[0]) } if result.Decisions[0].ReasonCode != frameworkvalidators.ReasonProtectedGlossaryTerm { t.Fatalf("expected reason %q, got %+v", frameworkvalidators.ReasonProtectedGlossaryTerm, result.Decisions[0]) } } func TestNewGlossaryStageAllowsProtectedTermInsertion(t *testing.T) { v, err := NewGlossaryStage() if err != nil { t.Fatalf("NewGlossaryStage: %v", err) } req := contracts.ValidationRequest{ ModuleKey: "glossary", Glossary: tinyGlossary(), CandidateProposal: []proposals.EnrichedCorrectionProposal{ proposal(0, "glossary", "gestures", "Jesters"), }, } result, err := v.Validate(context.Background(), req) if err != nil { t.Fatalf("Validate: %v", err) } if len(result.Decisions) != 1 { t.Fatalf("expected one decision, got %+v", result.Decisions) } if !result.Decisions[0].Approved { t.Fatalf("expected glossary-stage approval for protected-term insertion, got %+v", result.Decisions[0]) } }