package ai import ( "fmt" "sync" "testing" ) func TestWriteAndRead(t *testing.T) { buf := NewTerminalBuffer(100) buf.Write([]byte("line1\nline2\nline3\n")) all := buf.ReadAll() if len(all) != 3 { t.Fatalf("expected 3 lines, got %d", len(all)) } if all[0] != "line1" || all[1] != "line2" || all[2] != "line3" { t.Errorf("unexpected lines: %v", all) } } func TestRingBufferOverflow(t *testing.T) { buf := NewTerminalBuffer(200) // Write 300 lines for i := 0; i < 300; i++ { buf.Write([]byte(fmt.Sprintf("line %d\n", i))) } all := buf.ReadAll() if len(all) != 200 { t.Fatalf("expected 200 lines (ring buffer), got %d", len(all)) } // First line should be "line 100" (oldest retained) if all[0] != "line 100" { t.Errorf("expected first line 'line 100', got %q", all[0]) } // Last line should be "line 299" if all[199] != "line 299" { t.Errorf("expected last line 'line 299', got %q", all[199]) } } func TestReadLastSubset(t *testing.T) { buf := NewTerminalBuffer(100) buf.Write([]byte("a\nb\nc\nd\ne\n")) last3 := buf.ReadLast(3) if len(last3) != 3 { t.Fatalf("expected 3 lines, got %d", len(last3)) } if last3[0] != "c" || last3[1] != "d" || last3[2] != "e" { t.Errorf("unexpected lines: %v", last3) } // Request more than available last10 := buf.ReadLast(10) if len(last10) != 5 { t.Fatalf("expected 5 lines (all available), got %d", len(last10)) } } func TestConcurrentAccess(t *testing.T) { buf := NewTerminalBuffer(1000) var wg sync.WaitGroup // Spawn 10 writers for w := 0; w < 10; w++ { wg.Add(1) go func(id int) { defer wg.Done() for i := 0; i < 100; i++ { buf.Write([]byte(fmt.Sprintf("writer %d line %d\n", id, i))) } }(w) } // Spawn 5 readers for r := 0; r < 5; r++ { wg.Add(1) go func() { defer wg.Done() for i := 0; i < 100; i++ { _ = buf.ReadLast(10) _ = buf.Len() } }() } wg.Wait() total := buf.Len() if total != 1000 { t.Errorf("expected 1000 lines (10 writers * 100), got %d", total) } } func TestWritePartialLines(t *testing.T) { buf := NewTerminalBuffer(100) // Write data without trailing newline buf.Write([]byte("partial")) // Should have no complete lines yet if buf.Len() != 0 { t.Errorf("expected 0 lines for partial write, got %d", buf.Len()) } // Complete the line buf.Write([]byte(" line\n")) if buf.Len() != 1 { t.Fatalf("expected 1 line after completing partial, got %d", buf.Len()) } all := buf.ReadAll() if all[0] != "partial line" { t.Errorf("expected 'partial line', got %q", all[0]) } } func TestWriteMultiplePartials(t *testing.T) { buf := NewTerminalBuffer(100) buf.Write([]byte("hello ")) buf.Write([]byte("world")) buf.Write([]byte("!\nfoo\n")) all := buf.ReadAll() if len(all) != 2 { t.Fatalf("expected 2 lines, got %d: %v", len(all), all) } if all[0] != "hello world!" { t.Errorf("expected 'hello world!', got %q", all[0]) } if all[1] != "foo" { t.Errorf("expected 'foo', got %q", all[1]) } } func TestClear(t *testing.T) { buf := NewTerminalBuffer(100) buf.Write([]byte("line1\nline2\n")) buf.Clear() if buf.Len() != 0 { t.Errorf("expected 0 lines after clear, got %d", buf.Len()) } } func TestReadLastZero(t *testing.T) { buf := NewTerminalBuffer(100) buf.Write([]byte("line\n")) result := buf.ReadLast(0) if len(result) != 0 { t.Errorf("expected empty result for ReadLast(0), got %d lines", len(result)) } } func TestReadLastNegative(t *testing.T) { buf := NewTerminalBuffer(100) buf.Write([]byte("line\n")) result := buf.ReadLast(-1) if len(result) != 0 { t.Errorf("expected empty result for ReadLast(-1), got %d lines", len(result)) } }