Files
audita/internal/framework/proposals/apply_test.go

294 lines
9.7 KiB
Go

package proposals
import (
"reflect"
"testing"
"gitea.maximumdirect.net/eric/audita/internal/core/schema"
)
func TestApplyProposalsApplyingOneProposal(t *testing.T) {
transcript := &schema.Transcript{Segments: []schema.Segment{{ID: 1, Text: "gestures"}}}
proposals := []EnrichedCorrectionProposal{
{
CorrectionProposal: CorrectionProposal{
TargetSegmentID: 1,
OriginalText: "gestures",
CorrectedText: "Jesters",
Confidence: 0.95,
},
ProposalMetadata: ProposalMetadata{ProposalIndex: 0, ModuleKey: "glossary", ModuleInstance: "glossary_1"},
},
}
result := ApplyProposals(transcript, proposals, ReplacementPolicyRequireUnique)
if got := result.Transcript.Segments[0].Text; got != "Jesters" {
t.Fatalf("expected corrected text Jesters, got %q", got)
}
if len(result.Applied) != 1 {
t.Fatalf("expected 1 applied change, got %d", len(result.Applied))
}
if len(result.Skipped) != 0 {
t.Fatalf("expected 0 skipped changes, got %d", len(result.Skipped))
}
}
func TestApplyProposalsApplyingMultipleProposalsInStableOrder(t *testing.T) {
transcript := &schema.Transcript{Segments: []schema.Segment{{ID: 1, Text: "rank rank"}}}
proposals := []EnrichedCorrectionProposal{
{
CorrectionProposal: CorrectionProposal{
TargetSegmentID: 1,
OriginalText: "Hrank",
CorrectedText: "X",
Confidence: 0.9,
},
ProposalMetadata: ProposalMetadata{ProposalIndex: 2, ModuleKey: "grammar", ModuleInstance: "grammar_1"},
},
{
CorrectionProposal: CorrectionProposal{
TargetSegmentID: 1,
OriginalText: "rank",
CorrectedText: "Hrank",
Confidence: 0.9,
},
ProposalMetadata: ProposalMetadata{ProposalIndex: 1, ModuleKey: "homophones", ModuleInstance: "homophones"},
},
}
result := ApplyProposals(transcript, proposals, ReplacementPolicyReplaceAll)
if got := result.Transcript.Segments[0].Text; got != "X X" {
t.Fatalf("expected final text X X, got %q", got)
}
if len(result.Applied) != 2 {
t.Fatalf("expected 2 applied changes, got %d", len(result.Applied))
}
if result.Applied[0].ProposalIndex != 1 || result.Applied[1].ProposalIndex != 2 {
t.Fatalf("expected applied order [1,2], got [%d,%d]", result.Applied[0].ProposalIndex, result.Applied[1].ProposalIndex)
}
}
func TestApplyProposalsStaleProposalSkippedAfterEarlierChange(t *testing.T) {
transcript := &schema.Transcript{Segments: []schema.Segment{{ID: 1, Text: "foo bar"}}}
proposals := []EnrichedCorrectionProposal{
{
CorrectionProposal: CorrectionProposal{
TargetSegmentID: 1,
OriginalText: "foo bar",
CorrectedText: "foo-bar",
Confidence: 0.9,
},
ProposalMetadata: ProposalMetadata{ProposalIndex: 0, ModuleKey: "grammar", ModuleInstance: "grammar_1"},
},
{
CorrectionProposal: CorrectionProposal{
TargetSegmentID: 1,
OriginalText: "foo bar",
CorrectedText: "foobar",
Confidence: 0.9,
},
ProposalMetadata: ProposalMetadata{ProposalIndex: 1, ModuleKey: "grammar", ModuleInstance: "grammar_1"},
},
}
result := ApplyProposals(transcript, proposals, ReplacementPolicyRequireUnique)
if got := result.Transcript.Segments[0].Text; got != "foo-bar" {
t.Fatalf("expected final text foo-bar, got %q", got)
}
if len(result.Applied) != 1 {
t.Fatalf("expected 1 applied change, got %d", len(result.Applied))
}
if len(result.Skipped) != 1 {
t.Fatalf("expected 1 skipped change, got %d", len(result.Skipped))
}
if result.Skipped[0].SkipReason != SkipReasonMissingOriginalText {
t.Fatalf("expected stale skip reason %q, got %q", SkipReasonMissingOriginalText, result.Skipped[0].SkipReason)
}
}
func TestApplyProposalsMissingSegmentSkip(t *testing.T) {
transcript := &schema.Transcript{Segments: []schema.Segment{{ID: 1, Text: "hello"}}}
proposals := []EnrichedCorrectionProposal{
{
CorrectionProposal: CorrectionProposal{
TargetSegmentID: 999,
OriginalText: "hello",
CorrectedText: "hi",
Confidence: 0.9,
},
ProposalMetadata: ProposalMetadata{ProposalIndex: 0, ModuleKey: "grammar", ModuleInstance: "grammar_1"},
},
}
result := ApplyProposals(transcript, proposals, ReplacementPolicyRequireUnique)
if len(result.Skipped) != 1 {
t.Fatalf("expected 1 skipped change, got %d", len(result.Skipped))
}
if result.Skipped[0].SkipReason != SkipReasonMissingSegment {
t.Fatalf("expected skip reason %q, got %q", SkipReasonMissingSegment, result.Skipped[0].SkipReason)
}
}
func TestApplyProposalsRequireUniqueAmbiguousSkip(t *testing.T) {
transcript := &schema.Transcript{Segments: []schema.Segment{{ID: 1, Text: "uh uh"}}}
proposals := []EnrichedCorrectionProposal{
{
CorrectionProposal: CorrectionProposal{
TargetSegmentID: 1,
OriginalText: "uh",
CorrectedText: "um",
Confidence: 0.9,
},
ProposalMetadata: ProposalMetadata{ProposalIndex: 0, ModuleKey: "spoken_word", ModuleInstance: "spoken_word"},
},
}
result := ApplyProposals(transcript, proposals, ReplacementPolicyRequireUnique)
if len(result.Skipped) != 1 {
t.Fatalf("expected 1 skipped change, got %d", len(result.Skipped))
}
if result.Skipped[0].SkipReason != SkipReasonAmbiguousOriginal {
t.Fatalf("expected skip reason %q, got %q", SkipReasonAmbiguousOriginal, result.Skipped[0].SkipReason)
}
}
func TestApplyProposalsReplaceAllMultipleReplacements(t *testing.T) {
transcript := &schema.Transcript{Segments: []schema.Segment{{ID: 1, Text: "uh uh uh"}}}
proposals := []EnrichedCorrectionProposal{
{
CorrectionProposal: CorrectionProposal{
TargetSegmentID: 1,
OriginalText: "uh",
CorrectedText: "um",
Confidence: 0.9,
},
ProposalMetadata: ProposalMetadata{ProposalIndex: 0, ModuleKey: "spoken_word", ModuleInstance: "spoken_word"},
},
}
result := ApplyProposals(transcript, proposals, ReplacementPolicyReplaceAll)
if len(result.Applied) != 1 {
t.Fatalf("expected 1 applied change, got %d", len(result.Applied))
}
if got := result.Transcript.Segments[0].Text; got != "um um um" {
t.Fatalf("expected final text um um um, got %q", got)
}
if result.Applied[0].ReplacementCount != 3 {
t.Fatalf("expected replacement count 3, got %d", result.Applied[0].ReplacementCount)
}
}
func TestApplyProposalsNoMutationOfInputTranscript(t *testing.T) {
transcript := &schema.Transcript{Segments: []schema.Segment{{ID: 1, Text: "hello"}}}
before := cloneTranscript(transcript)
proposals := []EnrichedCorrectionProposal{
{
CorrectionProposal: CorrectionProposal{
TargetSegmentID: 1,
OriginalText: "hello",
CorrectedText: "hi",
Confidence: 0.9,
},
ProposalMetadata: ProposalMetadata{ProposalIndex: 0, ModuleKey: "grammar", ModuleInstance: "grammar_1"},
},
}
_ = ApplyProposals(transcript, proposals, ReplacementPolicyRequireUnique)
if !reflect.DeepEqual(transcript, before) {
t.Fatalf("input transcript mutated: before=%+v after=%+v", before, transcript)
}
}
func TestApplyProposalsSegmentMetadataPreservation(t *testing.T) {
transcript := &schema.Transcript{Segments: []schema.Segment{{
ID: 1,
Speaker: "A",
Start: 12.5,
End: 15.0,
Text: "rank",
Categories: []string{"combat", "term"},
}}}
proposals := []EnrichedCorrectionProposal{
{
CorrectionProposal: CorrectionProposal{
TargetSegmentID: 1,
OriginalText: "rank",
CorrectedText: "Hrank",
Confidence: 0.9,
},
ProposalMetadata: ProposalMetadata{ProposalIndex: 0, ModuleKey: "glossary", ModuleInstance: "glossary_1"},
},
}
result := ApplyProposals(transcript, proposals, ReplacementPolicyRequireUnique)
seg := result.Transcript.Segments[0]
if seg.Speaker != "A" || seg.Start != 12.5 || seg.End != 15.0 {
t.Fatalf("segment metadata changed: %+v", seg)
}
if !reflect.DeepEqual(seg.Categories, []string{"combat", "term"}) {
t.Fatalf("segment categories changed: %v", seg.Categories)
}
}
func TestApplyProposalsAppliedAndSkippedRecords(t *testing.T) {
transcript := &schema.Transcript{Segments: []schema.Segment{{ID: 1, Text: "hello"}}}
proposals := []EnrichedCorrectionProposal{
{
CorrectionProposal: CorrectionProposal{
TargetSegmentID: 1,
OriginalText: "hello",
CorrectedText: "hi",
Confidence: 0.9,
},
ProposalMetadata: ProposalMetadata{ProposalIndex: 0, ModuleKey: "grammar", ModuleInstance: "grammar_1"},
},
{
CorrectionProposal: CorrectionProposal{
TargetSegmentID: 999,
OriginalText: "x",
CorrectedText: "y",
Confidence: 0.9,
},
ProposalMetadata: ProposalMetadata{ProposalIndex: 1, ModuleKey: "grammar", ModuleInstance: "grammar_1"},
},
}
result := ApplyProposals(transcript, proposals, ReplacementPolicyRequireUnique)
if len(result.Applied) != 1 || len(result.Skipped) != 1 {
t.Fatalf("expected 1 applied and 1 skipped, got applied=%d skipped=%d", len(result.Applied), len(result.Skipped))
}
applied := result.Applied[0]
if applied.ProposalIndex != 0 || applied.ModuleKey != "grammar" || applied.ModuleInstance != "grammar_1" {
t.Fatalf("unexpected applied record metadata: %+v", applied)
}
if applied.TargetSegmentID != 1 || applied.OriginalText != "hello" || applied.CorrectedText != "hi" || applied.ReplacementCount != 1 {
t.Fatalf("unexpected applied record contents: %+v", applied)
}
skipped := result.Skipped[0]
if skipped.ProposalIndex != 1 || skipped.ModuleKey != "grammar" || skipped.ModuleInstance != "grammar_1" {
t.Fatalf("unexpected skipped record metadata: %+v", skipped)
}
if skipped.TargetSegmentID != 999 || skipped.OriginalText != "x" || skipped.CorrectedText != "y" {
t.Fatalf("unexpected skipped record contents: %+v", skipped)
}
if skipped.SkipReason != SkipReasonMissingSegment {
t.Fatalf("unexpected skipped reason: %q", skipped.SkipReason)
}
if skipped.Message == "" {
t.Fatal("expected non-empty skipped message")
}
}