package worker import "testing" func TestBuildFixedSegmentsUsesFiveToFifteenSeconds(t *testing.T) { for _, duration := range []float64{5, 15, 19, 31, 33, 39, 45, 46, 121.4} { segments := buildFixedSegments(duration) if len(segments) == 0 { t.Fatalf("duration %.1f returned no segments", duration) } for _, segment := range segments { length := segment.End - segment.Start if length < 5 || length > 15.0001 { t.Fatalf("duration %.1f produced %.3f second segment", duration, length) } } if difference := segments[len(segments)-1].End - duration; difference < -0.001 || difference > 0.001 { t.Fatalf("duration %.1f ends at %.3f", duration, segments[len(segments)-1].End) } } } func TestNormalizeAnalysisDurationUsesBoundaryTolerance(t *testing.T) { tests := []struct { input float64 want float64 }{ {input: 4.01, want: 5}, {input: 4.999, want: 5}, {input: 5, want: 5}, {input: 15, want: 15}, {input: 15.069002, want: 15}, {input: 15.999, want: 15}, {input: 16, want: 16}, } for _, test := range tests { if got := normalizeAnalysisDuration(test.input); got != test.want { t.Fatalf("normalizeAnalysisDuration(%f) = %f, want %f", test.input, got, test.want) } } segments := buildFixedSegments(normalizeAnalysisDuration(15.069002)) if len(segments) != 1 || segments[0].End != 15 { t.Fatalf("15.069002 seconds produced %#v, want one 15 second segment", segments) } } func TestBuildFixedSegmentsRedistributesShortTail(t *testing.T) { tests := []struct { duration float64 want []float64 }{ {duration: 33, want: []float64{15, 9, 9}}, {duration: 39, want: []float64{15, 15, 9}}, } for _, test := range tests { segments := buildFixedSegments(test.duration) if len(segments) != len(test.want) { t.Fatalf("duration %.1f produced %d segments, want %d", test.duration, len(segments), len(test.want)) } for index, segment := range segments { if got := segment.End - segment.Start; got != test.want[index] { t.Fatalf("duration %.1f segment %d = %.1f, want %.1f", test.duration, index+1, got, test.want[index]) } } } } func TestFrameTimestampsPreserveBoundariesAndLimit(t *testing.T) { segment := fixedSegment{Index: 1, Start: 10, End: 23} frames := frameTimestamps(segment) if len(frames) > 16 { t.Fatalf("returned %d frames, want at most 16", len(frames)) } if frames[0] > 10.1 || frames[len(frames)-1] < 22.9 { t.Fatalf("boundaries not preserved: first %.3f last %.3f", frames[0], frames[len(frames)-1]) } } func TestFrameRetryTimestampMovesBoundarySamplesIntoSegment(t *testing.T) { segment := fixedSegment{Index: 9, Start: 113.31, End: 121.62} if got, ok := frameRetryTimestamp(segment, 121.57); !ok || got != 121.07 { t.Fatalf("end retry = %.3f, %v; want 121.070, true", got, ok) } if got, ok := frameRetryTimestamp(segment, 113.36); !ok || got != 113.86 { t.Fatalf("start retry = %.3f, %v; want 113.860, true", got, ok) } } func TestMentionAssetsSkipsDialogue(t *testing.T) { tests := []struct { name string prompt string want string }{ { name: "Chinese quotes and all asset types", prompt: "Grace走进古堡大厅,把青铜钥匙放在桌上,说:“Ethan,去古堡大厅找青铜钥匙和神秘徽记。”神秘徽记微微发光。", want: "@Grace走进@古堡大厅,把@青铜钥匙放在桌上,说:“Ethan,去古堡大厅找青铜钥匙和神秘徽记。”@神秘徽记微微发光。", }, { name: "English quotes and existing mention", prompt: `@Grace says: "Ethan, take the Key marked \"Grace\"." Ethan nods beside Castle.`, want: `@Grace says: "Ethan, take the Key marked \"Grace\"." @Ethan nods beside @Castle.`, }, } names := []string{"Grace", "Ethan", "古堡大厅", "青铜钥匙", "神秘徽记", "Key", "Castle"} for _, test := range tests { t.Run(test.name, func(t *testing.T) { if got := mentionAssets(test.prompt, names); got != test.want { t.Fatalf("mentionAssets() = %q, want %q", got, test.want) } }) } } func TestMentionAssetsUsesKnownAssetsAndPrefersLongerNames(t *testing.T) { names := []string{"지우", "지우의 아버지", "도현", "婚礼殿堂"} prompt := "新娘지우走进婚礼殿堂,지우의 아버지看向도현,说:“지우和도현已经到了。”" want := "新娘@지우走进@婚礼殿堂,@지우의 아버지看向@도현,说:“지우和도현已经到了。”" got := mentionAssets(prompt, names) if got != want { t.Fatalf("mentionAssets() = %q, want %q", got, want) } mentioned := mentionedAssetNames(got, names) wantMentioned := []string{"지우", "婚礼殿堂", "지우의 아버지", "도현"} if len(mentioned) != len(wantMentioned) { t.Fatalf("mentionedAssetNames() = %#v, want %#v", mentioned, wantMentioned) } for index := range wantMentioned { if mentioned[index] != wantMentioned[index] { t.Fatalf("mentionedAssetNames() = %#v, want %#v", mentioned, wantMentioned) } } } func TestParseSubtitle(t *testing.T) { items := parseSubtitle("1\n00:00:01.000 --> 00:00:02.500\n第一句\n\n2\n00:00:03,000 --> 00:00:04,000\n2025年,第二句") if len(items) != 2 || items[0].Text != "第一句" || items[1].Text != "2025年,第二句" { t.Fatalf("unexpected subtitles: %#v", items) } }