package reconcile_test import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "git.d-ma.be/mathias/tapir/internal/domain" "git.d-ma.be/mathias/tapir/internal/reconcile" ) // Every judged spot is stored with a few words of left context, and the saved segments // carry the merged words while keeping the base's timing (ADR-035 decisions 6 and 7). func TestReconcileSpots_AKeptSpotAndAChangedSpotAreBothStoredWithTheirVerdict(t *testing.T) { adj := &scripted{fn: func(i int, _ reconcile.Request) (reconcile.Verdict, error) { if i == 0 { return reconcile.VerdictBase, nil } return reconcile.VerdictAlt, nil }} out := merge(t, tr(progBase), tr(progAlt), adj) require.Len(t, out.Reconciliation.Contested, 2) assert.Equal(t, "base", out.Reconciliation.Contested[0].Used) assert.Equal(t, "1015", out.Reconciliation.Contested[0].Base) assert.Equal(t, "alt", out.Reconciliation.Contested[1].Used) assert.Equal(t, 1, out.Reconciliation.Changed, "the exact counts are unchanged by storing more") } func TestReconcileSpots_AutoResolvedDisputesAreNotStored(t *testing.T) { out := merge(t, tr("i takrenns delen ska vi ju betala"), tr("i takrennsdelen ska vi betala"), always(reconcile.VerdictAlt)) assert.Empty(t, out.Reconciliation.Contested, "compounds and fillers were never judged; they are counted, not listed") } func TestReconcileSpots_ASpotCarriesTheWordsJustBeforeIt(t *testing.T) { out := merge(t, tr("vi skickar in ett vanligt meddelande till kassasystemet"), tr("vi skickar in ett KORT meddelande till kassasystemet"), always(reconcile.VerdictAlt)) require.Len(t, out.Reconciliation.Contested, 1) assert.Equal(t, "vi skickar in ett", out.Reconciliation.Contested[0].Before) } func TestReconcileSpots_TheContextIsAFewWordsNotTheWholeMeeting(t *testing.T) { long := "ett två tre fyra fem sex sju åtta nio tio elva tolv" out := merge(t, tr(long+" X slut"), tr(long+" Y slut"), always(reconcile.VerdictAlt)) require.Len(t, out.Reconciliation.Contested, 1) assert.Equal(t, "fem sex sju åtta nio tio elva tolv", out.Reconciliation.Contested[0].Before, "eight words: enough to find the place, small enough to stay out of the way") } func segmented(text string, segs ...domain.Segment) domain.Transcription { t := tr(text) t.Segments = segs return t } func TestReconcileSegments_AChangedWordReplacesTheBaseWordInItsOwnSegmentOnly(t *testing.T) { base := segmented("ett två tre. fyra fem sex. sju åtta nio.", domain.Segment{Start: 0, End: 10, Text: "ett två tre."}, domain.Segment{Start: 10, End: 20, Text: "fyra fem sex."}, domain.Segment{Start: 20, End: 30, Text: "sju åtta nio."}) out := merge(t, base, tr("ett två tre. fyra femm sex. sju åtta nio."), always(reconcile.VerdictAlt)) require.Len(t, out.Segments, 3) assert.Equal(t, "ett två tre.", out.Segments[0].Text, "an untouched segment keeps its exact text") assert.Equal(t, "fyra femm sex.", out.Segments[1].Text) assert.Equal(t, "sju åtta nio.", out.Segments[2].Text) assert.InDelta(t, 10.0, out.Segments[1].Start, 1e-9, "timing stays the base's") assert.InDelta(t, 20.0, out.Segments[1].End, 1e-9) } func TestReconcileSegments_AWordOnlyTheAlternativeHeardLandsInTheSegmentItBelongsTo(t *testing.T) { base := segmented("a b c. d e f.", domain.Segment{Start: 0, End: 5, Text: "a b c."}, domain.Segment{Start: 5, End: 10, Text: "d e f."}) out := merge(t, base, tr("a b c. d NY e f."), always(reconcile.VerdictAlt)) assert.Equal(t, "a b c.", out.Segments[0].Text) assert.Equal(t, "d NY e f.", out.Segments[1].Text) } func TestReconcileSegments_AWordOnlyTheBaseHeardIsRemovedFromItsSegment(t *testing.T) { base := segmented("a b c. d X e f.", domain.Segment{Start: 0, End: 5, Text: "a b c."}, domain.Segment{Start: 5, End: 10, Text: "d X e f."}) out := merge(t, base, tr("a b c. d e f."), always(reconcile.VerdictAlt)) assert.Equal(t, "d e f.", out.Segments[1].Text) } func TestReconcileSegments_AKeptBaseLeavesEverySegmentAsItWas(t *testing.T) { base := segmented("a x b", domain.Segment{Start: 0, End: 4, Text: "a x b"}) out := merge(t, base, tr("a y b"), always(reconcile.VerdictBase)) assert.Equal(t, base.Segments, out.Segments) } func TestReconcileSegments_TheCallersSegmentsAreNeverChangedInPlace(t *testing.T) { segs := []domain.Segment{{Start: 0, End: 4, Text: "a x b"}} base := segmented("a x b", segs...) _ = merge(t, base, tr("a y b"), always(reconcile.VerdictAlt)) assert.Equal(t, "a x b", segs[0].Text, "Reconcile builds new segments; it does not edit the base transcription's") } func TestReconcileSegments_SegmentsThatDoNotLineUpWithTheTextAreLeftAsTheBases(t *testing.T) { // A word wrapped across a segment edge makes the segments' word count differ from // the joined text's. Guessing would put words in the wrong place, so leave them. base := segmented("a x b c", domain.Segment{Start: 0, End: 4, Text: "a x"}, domain.Segment{Start: 4, End: 8, Text: "b c d"}) out := merge(t, base, tr("a y b c"), always(reconcile.VerdictAlt)) assert.Equal(t, base.Segments, out.Segments) assert.Equal(t, "a y b c", out.Text, "the merged text is unaffected") } func TestReconcileSegments_ASpanThatCrossesASegmentEdgeIsRemovedFromBothSegments(t *testing.T) { base := segmented("a b c d", domain.Segment{Start: 0, End: 5, Text: "a b"}, domain.Segment{Start: 5, End: 10, Text: "c d"}) out := merge(t, base, tr("a X d"), always(reconcile.VerdictAlt)) require.Equal(t, "a X d", out.Text) assert.Equal(t, "a X", out.Segments[0].Text) assert.Equal(t, "d", out.Segments[1].Text, "'c' was replaced too: it must not linger in the second segment") }