package engine import ( "math" "testing" ) func TestNewGrid(t *testing.T) { tests := []struct { name string iconSize float64 paddingRatio float64 wantPadding int wantCell int }{ { name: "standard 64px icon with 8% padding", iconSize: 64.0, paddingRatio: 0.08, wantPadding: 5, // 0.5 + 64 * 0.08 = 5.62, rounded to 5 wantCell: 13, // (64 - 5*2) / 4 = 54/4 = 13.5, truncated to 13 }, { name: "large 256px icon with 10% padding", iconSize: 256.0, paddingRatio: 0.10, wantPadding: 26, // 0.5 + 256 * 0.10 = 26.1, rounded to 26 wantCell: 51, // (256 - 26*2) / 4 = 204/4 = 51 }, { name: "small 32px icon with 5% padding", iconSize: 32.0, paddingRatio: 0.05, wantPadding: 2, // 0.5 + 32 * 0.05 = 2.1, rounded to 2 wantCell: 7, // (32 - 2*2) / 4 = 28/4 = 7 }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { grid := NewGrid(tt.iconSize, tt.paddingRatio) if grid.Padding != tt.wantPadding { t.Errorf("NewGrid() padding = %v, want %v", grid.Padding, tt.wantPadding) } if grid.Cell != tt.wantCell { t.Errorf("NewGrid() cell = %v, want %v", grid.Cell, tt.wantCell) } // Verify that the grid is centered expectedSize := tt.iconSize - float64(tt.wantPadding*2) if math.Abs(grid.Size-expectedSize) > 0.1 { t.Errorf("NewGrid() size = %v, want %v", grid.Size, expectedSize) } }) } } func TestGridCellToCoordinate(t *testing.T) { grid := NewGrid(64.0, 0.08) tests := []struct { name string cellX int cellY int wantX float64 wantY float64 }{ { name: "origin cell (0,0)", cellX: 0, cellY: 0, wantX: float64(grid.X), wantY: float64(grid.Y), }, { name: "center cell (1,1)", cellX: 1, cellY: 1, wantX: float64(grid.X + grid.Cell), wantY: float64(grid.Y + grid.Cell), }, { name: "corner cell (3,3)", cellX: 3, cellY: 3, wantX: float64(grid.X + 3*grid.Cell), wantY: float64(grid.Y + 3*grid.Cell), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { gotX, gotY := grid.CellToCoordinate(tt.cellX, tt.cellY) if gotX != tt.wantX { t.Errorf("CellToCoordinate() x = %v, want %v", gotX, tt.wantX) } if gotY != tt.wantY { t.Errorf("CellToCoordinate() y = %v, want %v", gotY, tt.wantY) } }) } } func TestLayoutEngineGetShapePositions(t *testing.T) { le := NewLayoutEngine(64.0, 0.08) tests := []struct { name string shapeType string wantLen int wantFirst Position wantLast Position }{ { name: "sides positions", shapeType: "sides", wantLen: 8, wantFirst: Position{1, 0}, wantLast: Position{0, 2}, }, { name: "corners positions", shapeType: "corners", wantLen: 4, wantFirst: Position{0, 0}, wantLast: Position{0, 3}, }, { name: "center positions", shapeType: "center", wantLen: 4, wantFirst: Position{1, 1}, wantLast: Position{1, 2}, }, { name: "invalid shape type", shapeType: "invalid", wantLen: 0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { positions := le.GetShapePositions(tt.shapeType) if len(positions) != tt.wantLen { t.Errorf("GetShapePositions() len = %v, want %v", len(positions), tt.wantLen) } if tt.wantLen > 0 { if positions[0] != tt.wantFirst { t.Errorf("GetShapePositions() first = %v, want %v", positions[0], tt.wantFirst) } if positions[len(positions)-1] != tt.wantLast { t.Errorf("GetShapePositions() last = %v, want %v", positions[len(positions)-1], tt.wantLast) } } }) } } func TestLayoutEngineGetTransformedPosition(t *testing.T) { le := NewLayoutEngine(64.0, 0.08) tests := []struct { name string cellX int cellY int rotation int wantX int // Expected cell X after rotation wantY int // Expected cell Y after rotation }{ { name: "no rotation", cellX: 1, cellY: 0, rotation: 0, wantX: 1, wantY: 0, }, { name: "90 degree rotation", cellX: 1, cellY: 0, rotation: 1, wantX: 0, wantY: 2, // 3-1 = 2 }, { name: "180 degree rotation", cellX: 1, cellY: 0, rotation: 2, wantX: 2, // 3-1 = 2 wantY: 3, // 3-0 = 3 }, { name: "270 degree rotation", cellX: 1, cellY: 0, rotation: 3, wantX: 3, // 3-0 = 3 wantY: 1, }, { name: "rotation overflow (4 = 0)", cellX: 1, cellY: 0, rotation: 4, wantX: 1, wantY: 0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { gotX, gotY, gotCellSize := le.GetTransformedPosition(tt.cellX, tt.cellY, tt.rotation) // Convert back to cell coordinates to verify rotation expectedX, expectedY := le.grid.CellToCoordinate(tt.wantX, tt.wantY) if gotX != expectedX { t.Errorf("GetTransformedPosition() x = %v, want %v", gotX, expectedX) } if gotY != expectedY { t.Errorf("GetTransformedPosition() y = %v, want %v", gotY, expectedY) } if gotCellSize != float64(le.grid.Cell) { t.Errorf("GetTransformedPosition() cellSize = %v, want %v", gotCellSize, float64(le.grid.Cell)) } }) } } func TestApplySymmetry(t *testing.T) { positions := []Position{{0, 0}, {1, 0}, {2, 0}, {3, 0}} tests := []struct { name string index int want int // expected length }{ { name: "valid index", index: 1, want: 4, }, { name: "index out of bounds", index: 10, want: 4, }, { name: "negative index", index: -1, want: 4, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := ApplySymmetry(positions, tt.index) if len(result) != tt.want { t.Errorf("ApplySymmetry() len = %v, want %v", len(result), tt.want) } // Verify that the positions are unchanged (current implementation) for i, pos := range result { if pos != positions[i] { t.Errorf("ApplySymmetry() changed position at index %d: got %v, want %v", i, pos, positions[i]) } } }) } } func TestGridValidateGrid(t *testing.T) { tests := []struct { name string grid *Grid want bool }{ { name: "valid grid", grid: &Grid{Size: 64, Cell: 16, Padding: 4}, want: true, }, { name: "zero cell size", grid: &Grid{Size: 64, Cell: 0, Padding: 4}, want: false, }, { name: "zero size", grid: &Grid{Size: 0, Cell: 16, Padding: 4}, want: false, }, { name: "negative padding", grid: &Grid{Size: 64, Cell: 16, Padding: -1}, want: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := tt.grid.ValidateGrid(); got != tt.want { t.Errorf("ValidateGrid() = %v, want %v", got, tt.want) } }) } } func TestGridGetIconBounds(t *testing.T) { grid := NewGrid(64.0, 0.08) x, y, width, height := grid.GetIconBounds() expectedX := float64(grid.X) expectedY := float64(grid.Y) expectedWidth := float64(grid.Cell * 4) expectedHeight := float64(grid.Cell * 4) if x != expectedX { t.Errorf("GetIconBounds() x = %v, want %v", x, expectedX) } if y != expectedY { t.Errorf("GetIconBounds() y = %v, want %v", y, expectedY) } if width != expectedWidth { t.Errorf("GetIconBounds() width = %v, want %v", width, expectedWidth) } if height != expectedHeight { t.Errorf("GetIconBounds() height = %v, want %v", height, expectedHeight) } } func TestGridGetCenterOffset(t *testing.T) { grid := NewGrid(64.0, 0.08) dx, dy := grid.GetCenterOffset() expected := float64(grid.Cell) / 2 if dx != expected { t.Errorf("GetCenterOffset() dx = %v, want %v", dx, expected) } if dy != expected { t.Errorf("GetCenterOffset() dy = %v, want %v", dy, expected) } } func TestNewLayoutEngine(t *testing.T) { le := NewLayoutEngine(64.0, 0.08) if le.grid == nil { t.Error("NewLayoutEngine() grid is nil") } if le.Grid() != le.grid { t.Error("NewLayoutEngine() Grid() does not return internal grid") } // Verify grid configuration if !le.grid.ValidateGrid() { t.Error("NewLayoutEngine() created invalid grid") } }