test(04-02): add i3bar formatting with TDD

- I3BarBlock struct for i3bar protocol JSON
- formatI3BarBlocks: compact format D-06/D-07/D-08
- 10 tests covering mixed states, colors, labels, markers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Pierre Martin
2026-03-23 21:29:09 +01:00
parent 399e3e8f02
commit a28e8d6f1e
2 changed files with 181 additions and 0 deletions

129
i3bar_test.go Normal file
View File

@@ -0,0 +1,129 @@
package main
import (
"testing"
)
func TestFormatI3BarBlocks_MixedStates(t *testing.T) {
sessions := []SessionInfo{
{Cwd: "/home/pierre/Code/auth", State: "Needs Input"},
{Cwd: "/home/pierre/Code/portal", State: "Working"},
{Cwd: "/home/pierre/Code/neia", State: "Idle"},
}
blocks := formatI3BarBlocks(sessions)
if len(blocks) != 1 {
t.Fatalf("expected 1 block, got %d", len(blocks))
}
want := "vmux: auth[!] portal[W] neia[I]"
if blocks[0].FullText != want {
t.Errorf("full_text = %q, want %q", blocks[0].FullText, want)
}
if blocks[0].Color != "#ff0000" {
t.Errorf("color = %q, want #ff0000", blocks[0].Color)
}
}
func TestFormatI3BarBlocks_AllWorking(t *testing.T) {
sessions := []SessionInfo{
{Cwd: "/a/b/one", State: "Working"},
{Cwd: "/a/b/two", State: "Working"},
{Cwd: "/a/b/three", State: "Working"},
}
blocks := formatI3BarBlocks(sessions)
want := "vmux: all working (3)"
if blocks[0].FullText != want {
t.Errorf("full_text = %q, want %q", blocks[0].FullText, want)
}
if blocks[0].Color != "#00ff00" {
t.Errorf("color = %q, want #00ff00", blocks[0].Color)
}
}
func TestFormatI3BarBlocks_NoSessions(t *testing.T) {
blocks := formatI3BarBlocks(nil)
want := "vmux: no sessions"
if blocks[0].FullText != want {
t.Errorf("full_text = %q, want %q", blocks[0].FullText, want)
}
if blocks[0].Color != "#00ff00" {
t.Errorf("color = %q, want #00ff00", blocks[0].Color)
}
}
func TestFormatI3BarBlocks_ColorRed(t *testing.T) {
sessions := []SessionInfo{
{Cwd: "/a/b/x", State: "Working"},
{Cwd: "/a/b/y", State: "Needs Input"},
}
blocks := formatI3BarBlocks(sessions)
if blocks[0].Color != "#ff0000" {
t.Errorf("color = %q, want #ff0000", blocks[0].Color)
}
}
func TestFormatI3BarBlocks_ColorGreen(t *testing.T) {
sessions := []SessionInfo{
{Cwd: "/a/b/x", State: "Working"},
{Cwd: "/a/b/y", State: "Idle"},
}
blocks := formatI3BarBlocks(sessions)
if blocks[0].Color != "#00ff00" {
t.Errorf("color = %q, want #00ff00", blocks[0].Color)
}
}
func TestFormatI3BarBlocks_UsesLabel(t *testing.T) {
sessions := []SessionInfo{
{Cwd: "/home/pierre/Code/auth-service", Label: "auth", State: "Working"},
}
blocks := formatI3BarBlocks(sessions)
want := "vmux: all working (1)"
if blocks[0].FullText != want {
t.Errorf("full_text = %q, want %q", blocks[0].FullText, want)
}
}
func TestFormatI3BarBlocks_UsesLabelInMixed(t *testing.T) {
sessions := []SessionInfo{
{Cwd: "/home/pierre/Code/auth-service", Label: "auth", State: "Needs Input"},
}
blocks := formatI3BarBlocks(sessions)
want := "vmux: auth[!]"
if blocks[0].FullText != want {
t.Errorf("full_text = %q, want %q", blocks[0].FullText, want)
}
}
func TestFormatI3BarBlocks_UsesCwdBase(t *testing.T) {
sessions := []SessionInfo{
{Cwd: "/home/pierre/Code/vibe/vmux", State: "Needs Input"},
}
blocks := formatI3BarBlocks(sessions)
want := "vmux: vmux[!]"
if blocks[0].FullText != want {
t.Errorf("full_text = %q, want %q", blocks[0].FullText, want)
}
}
func TestFormatI3BarBlocks_NeedsInputMarker(t *testing.T) {
sessions := []SessionInfo{
{Cwd: "/a/proj", State: "Needs Input"},
}
blocks := formatI3BarBlocks(sessions)
want := "vmux: proj[!]"
if blocks[0].FullText != want {
t.Errorf("full_text = %q, want %q", blocks[0].FullText, want)
}
}
func TestFormatI3BarBlocks_IdleMarker(t *testing.T) {
sessions := []SessionInfo{
{Cwd: "/a/proj", State: "Idle"},
{Cwd: "/a/other", State: "Needs Input"},
}
blocks := formatI3BarBlocks(sessions)
want := "vmux: proj[I] other[!]"
if blocks[0].FullText != want {
t.Errorf("full_text = %q, want %q", blocks[0].FullText, want)
}
}