package main import ( "strings" "testing" "time" ) func TestLiveCaptionDisplayTextFitsOverlayBuffer(t *testing.T) { input := strings.Repeat("这是一句实时字幕", 12) got := liveCaptionDisplayText(input) if got == "" { t.Fatal("caption should not be empty") } if len([]byte(got)) > liveCaptionMaxBytes { t.Fatalf("caption bytes = %d, want <= %d", len([]byte(got)), liveCaptionMaxBytes) } if !strings.HasPrefix(got, "...") { t.Fatalf("caption = %q, want leading truncation marker", got) } } func TestReleaseTailCaptureDelayUsesEngineCapability(t *testing.T) { a := &App{} a.replaceEngine(tailCaptureTestEngine{delay: 300 * time.Millisecond}) if got := a.releaseTailCaptureDelay(); got != 300*time.Millisecond { t.Fatalf("releaseTailCaptureDelay() = %v, want 300ms", got) } } func TestReleaseTailCaptureDelayCanBeDisabledByEngineCapability(t *testing.T) { a := &App{} a.replaceEngine(tailCaptureTestEngine{delay: 0}) if got := a.releaseTailCaptureDelay(); got != 0 { t.Fatalf("releaseTailCaptureDelay() = %v, want 0", got) } } func TestReleaseTailCaptureDelayDefaultsToNoProtectionWindow(t *testing.T) { a := &App{} a.replaceEngine(plainTestEngine{}) if got := a.releaseTailCaptureDelay(); got != 0 { t.Fatalf("releaseTailCaptureDelay() = %v, want 0", got) } } func TestReleaseTailCaptureDelayDisabledWithoutEngine(t *testing.T) { a := &App{} a.replaceEngine(nil) if got := a.releaseTailCaptureDelay(); got != 0 { t.Fatalf("releaseTailCaptureDelay() = %v, want 0 without engine", got) } } func TestSlowRecognitionReason(t *testing.T) { tests := []struct { name string recognizeMS int64 totalMS int64 want string }{ {name: "fast", recognizeMS: 2000, totalMS: 2500, want: ""}, {name: "recognize", recognizeMS: 2001, totalMS: 2400, want: "recognize"}, {name: "total", recognizeMS: 1000, totalMS: 2501, want: "total"}, {name: "both", recognizeMS: 2001, totalMS: 2501, want: "recognize,total"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := slowRecognitionReason(tt.recognizeMS, tt.totalMS); got != tt.want { t.Fatalf("slowRecognitionReason(%d, %d) = %q, want %q", tt.recognizeMS, tt.totalMS, got, tt.want) } }) } } func TestHoldPreCaptureUsesEngineCapability(t *testing.T) { a := &App{} a.replaceEngine(holdPreCaptureTestEngine{enabled: true}) if !a.holdPreCaptureEnabled.Load() { t.Fatal("hold pre-capture should be enabled by engine capability") } } func TestHoldPreCaptureCanBeDisabledByEngineCapability(t *testing.T) { a := &App{} a.replaceEngine(holdPreCaptureTestEngine{enabled: false}) if a.holdPreCaptureEnabled.Load() { t.Fatal("hold pre-capture should respect engine capability false") } } func TestHoldPreCaptureDefaultsToTrueForReadyEngine(t *testing.T) { a := &App{} a.replaceEngine(plainTestEngine{}) if !a.holdPreCaptureEnabled.Load() { t.Fatal("hold pre-capture should default to true for ready engines") } } func TestHoldPreCaptureDisabledWithoutEngine(t *testing.T) { a := &App{} a.replaceEngine(nil) if a.holdPreCaptureEnabled.Load() { t.Fatal("hold pre-capture should be disabled without an engine") } } func TestShouldStartHoldPreCaptureLocked(t *testing.T) { a := &App{} a.holdPreCaptureEnabled.Store(true) if !a.shouldStartHoldPreCaptureLocked() { t.Fatal("expected hold pre-capture to start when enabled and idle") } a.isRecording = true if a.shouldStartHoldPreCaptureLocked() { t.Fatal("should not pre-capture while already recording") } a.isRecording = false a.isStoppingRecording = true if a.shouldStartHoldPreCaptureLocked() { t.Fatal("should not pre-capture while stopping") } a.isStoppingRecording = false a.isFreetalking = true if a.shouldStartHoldPreCaptureLocked() { t.Fatal("should not pre-capture while tap recording is active") } a.isFreetalking = false a.lastStopTime = time.Now() if a.shouldStartHoldPreCaptureLocked() { t.Fatal("should not pre-capture during post-stop debounce") } } func TestStartRecordingIgnoredWhileStoppingRecording(t *testing.T) { a := &App{isStoppingRecording: true} a.startRecordingLocked() if a.isRecording { t.Fatal("startRecordingLocked should not start while stop tail capture is pending") } } func TestStartTapRecordingIgnoredWhileStoppingRecording(t *testing.T) { a := &App{isStoppingRecording: true} a.startTapRecordingLocked() if a.isRecording || a.isFreetalking { t.Fatal("startTapRecordingLocked should not start while stop tail capture is pending") } } type plainTestEngine struct{} func (plainTestEngine) Recognize([]float32) (string, error) { return "", nil } func (plainTestEngine) HardwareInfo() string { return "test" } func (plainTestEngine) Close() {} type tailCaptureTestEngine struct { plainTestEngine delay time.Duration } func (e tailCaptureTestEngine) ReleaseTailCaptureDelay() time.Duration { return e.delay } type holdPreCaptureTestEngine struct { plainTestEngine enabled bool } func (e holdPreCaptureTestEngine) HoldPreCaptureEnabled() bool { return e.enabled }