package app import ( "context" "io" "sync" "testing" "time" "tea.chunkbyte.com/kato/captioneer/src/config" "tea.chunkbyte.com/kato/captioneer/src/output" ) func TestControllerStartObserveAndStop(t *testing.T) { started := make(chan struct{}) runner := func(ctx context.Context, settings config.Settings, sink output.Sink, diagnostics io.Writer, observer RuntimeObserver) error { observe(observer, RuntimeEvent{Kind: RuntimeSource, Value: "monitor-source"}) observe(observer, RuntimeEvent{Kind: RuntimeListening}) observe(observer, RuntimeEvent{Kind: RuntimeSpeech, Active: true}) close(started) <-ctx.Done() observe(observer, RuntimeEvent{Kind: RuntimeStopped}) return nil } controller := newControllerWithRunner(nil, io.Discard, runner) settings := config.DefaultSettings() if err := controller.Start(settings); err != nil { t.Fatalf("Start() error = %v", err) } select { case <-started: case <-time.After(time.Second): t.Fatal("runner did not start") } status := controller.Status() if status.State != StateListening || status.Source != "monitor-source" || !status.SpeechActive { t.Fatalf("Status() = %#v", status) } ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() if err := controller.Stop(ctx); err != nil { t.Fatalf("Stop() error = %v", err) } status = controller.Status() if status.State != StateStopped || status.SpeechActive { t.Fatalf("Status() after stop = %#v", status) } } func TestControllerRestartUsesNewSettings(t *testing.T) { var mu sync.Mutex var modes []config.Mode started := make(chan struct{}, 2) runner := func(ctx context.Context, settings config.Settings, sink output.Sink, diagnostics io.Writer, observer RuntimeObserver) error { mu.Lock() modes = append(modes, settings.Mode) mu.Unlock() observe(observer, RuntimeEvent{Kind: RuntimeListening}) started <- struct{}{} <-ctx.Done() return nil } controller := newControllerWithRunner(nil, io.Discard, runner) settings := config.DefaultSettings() if err := controller.Start(settings); err != nil { t.Fatal(err) } <-started settings.Mode = config.ModeFixed ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() if err := controller.Restart(ctx, settings); err != nil { t.Fatalf("Restart() error = %v", err) } <-started mu.Lock() defer mu.Unlock() if len(modes) != 2 || modes[0] != config.ModeVAD || modes[1] != config.ModeFixed { t.Fatalf("runner modes = %v", modes) } }