package flinger import ( "errors" "net" "testing" "time" ) // TestEnginePatternStartStop runs the engine with the synthetic pattern source // and verifies it produces frames on the wire and stops cleanly. func TestEnginePatternStartStop(t *testing.T) { cfg := DefaultConfig() cfg.Source = "pattern" cfg.Port = 19756 // fixed high port for the test eng, err := New(cfg) if err != nil { t.Fatalf("New: %v", err) } eng.Start() defer eng.Stop() // Connect a raw receiver and read until the engine reports frames sent. conn, err := net.Dial("tcp", "127.0.0.1:"+itoa(eng.sender.Port())) if err != nil { t.Fatalf("dial: %v", err) } defer func() { _ = conn.Close() }() // The video loop sends ~30fps; wait for the counter to advance. deadline := time.Now().Add(3 * time.Second) _ = conn.SetReadDeadline(deadline) // Drain whatever arrives while waiting for the frame counter to move. go func() { buf := make([]byte, 64*1024) for { if _, err := conn.Read(buf); err != nil { return } } }() for time.Now().Before(deadline) { if eng.Status().Frames > 0 { break } time.Sleep(20 * time.Millisecond) } if eng.Status().Frames == 0 { t.Error("expected frames to be counted") } } // TestEngineConfigDefaults verifies DefaultConfig is sane. func TestEngineConfigDefaults(t *testing.T) { c := DefaultConfig() if c.Port != 9756 { t.Errorf("default port = %d, want 9756", c.Port) } if c.Source != "screen" { t.Errorf("default source = %q, want screen", c.Source) } if c.Quality < 1 || c.Quality > 100 { t.Errorf("default quality %d out of range", c.Quality) } } // TestNewRejectsBadSource ensures invalid sources fail fast. func TestNewRejectsBadSource(t *testing.T) { cfg := DefaultConfig() cfg.Source = "bogus" if _, err := New(cfg); err == nil { t.Error("expected error for unknown source") } } // TestSetErrStatus verifies runtime errors are exposed via Status and can be // cleared. func TestSetErrStatus(t *testing.T) { cfg := DefaultConfig() cfg.Source = "pattern" cfg.Port = 19757 eng, err := New(cfg) if err != nil { t.Fatalf("New: %v", err) } if st := eng.Status(); st.Err != nil { t.Fatalf("expected no error initially, got %v", st.Err) } sentinel := errors.New("test capture failure") eng.setErr(sentinel) if st := eng.Status(); st.Err != sentinel { t.Errorf("expected sentinel error, got %v", st.Err) } eng.setErr(nil) if st := eng.Status(); st.Err != nil { t.Errorf("expected cleared error, got %v", st.Err) } } // TestValidate rejects out-of-range values. func TestValidate(t *testing.T) { bad := []func(*Config){ func(c *Config) { c.Port = 0 }, func(c *Config) { c.Port = 70000 }, func(c *Config) { c.Quality = 0 }, func(c *Config) { c.Quality = 101 }, func(c *Config) { c.FPS = 0 }, func(c *Config) { c.StreamIndex = -1 }, } for i, mutate := range bad { c := DefaultConfig() mutate(&c) if err := c.Validate(); err == nil { t.Errorf("case %d: expected validation error", i) } } if err := DefaultConfig().Validate(); err != nil { t.Errorf("default config should validate: %v", err) } } func itoa(v int) string { if v == 0 { return "0" } var buf [20]byte i := len(buf) for v > 0 { i-- buf[i] = byte('0' + v%10) v /= 10 } return string(buf[i:]) }