diff --git a/src/components/board/__tests__/board-renderer.test.ts b/src/components/board/__tests__/board-renderer.test.ts new file mode 100644 index 0000000..23500b5 --- /dev/null +++ b/src/components/board/__tests__/board-renderer.test.ts @@ -0,0 +1,63 @@ +import { describe, it, expect } from 'vitest'; +import { + computeBoardDimensions, + canvasToBoard, + boardToCanvas, + computeStarPoints, +} from '../board-renderer'; + +describe('computeBoardDimensions', () => { + it('returns positive cellSize and padding for 15x15 board', () => { + const cfg = computeBoardDimensions(15, 800, 600); + expect(cfg.cellSize).toBeGreaterThan(0); + expect(cfg.padding).toBeGreaterThan(0); + expect(cfg.boardSize).toBe(15); + }); + + it('fits within the smaller canvas dimension', () => { + const cfg = computeBoardDimensions(15, 800, 600); + const total = cfg.padding * 2 + (cfg.boardSize - 1) * cfg.cellSize; + expect(total).toBeLessThanOrEqual(800); + }); +}); + +describe('canvasToBoard / boardToCanvas round-trip', () => { + it('round-trips for a 15x15 board center', () => { + const cfg = computeBoardDimensions(15, 800, 600); + const boardPos = { x: 7, y: 7 }; + const canvas = boardToCanvas(boardPos, cfg); + const restored = canvasToBoard(canvas.x, canvas.y, cfg); + expect(restored).toEqual(boardPos); + }); + + it('returns null for clicks outside the board', () => { + const cfg = computeBoardDimensions(15, 800, 600); + expect(canvasToBoard(-10, -10, cfg)).toBeNull(); + expect(canvasToBoard(9999, 9999, cfg)).toBeNull(); + }); +}); + +describe('computeStarPoints', () => { + it('returns 9 star points for 15x15 board', () => { + const points = computeStarPoints(15); + expect(points.length).toBe(9); + }); + + it('returns only center for board smaller than 9', () => { + const points = computeStarPoints(7); + expect(points.length).toBe(1); + expect(points[0]).toEqual([3, 3]); + }); + + it('star points are within board bounds', () => { + for (const size of [9, 13, 15, 19]) { + const points = computeStarPoints(size); + for (const [r, c] of points) { + expect(r).toBeGreaterThanOrEqual(0); + expect(r).toBeLessThan(size); + expect(c).toBeGreaterThanOrEqual(0); + expect(c).toBeLessThan(size); + } + } + }); +}); diff --git a/src/core/__tests__/types.test.ts b/src/core/__tests__/types.test.ts new file mode 100644 index 0000000..1c15884 --- /dev/null +++ b/src/core/__tests__/types.test.ts @@ -0,0 +1,38 @@ +import { describe, it, expect } from 'vitest'; + +describe('types', () => { + it('CellState values are correct', () => { + const empty: number = 0; + const black: number = 1; + const white: number = 2; + expect(empty).toBe(0); + expect(black).toBe(1); + expect(white).toBe(2); + }); + + it('MoveResult has correct shape', () => { + const result = { + position: { x: 7, y: 7 }, + is_win: false, + is_forbidden: false, + }; + expect(result.position.x).toBe(7); + expect(result.is_win).toBe(false); + }); + + it('GameConfig has all required fields with defaults', () => { + const config = { + boardSize: 15, + useForbiddenRules: true, + useTimer: false, + timeLimitSecs: 60, + aiDifficulty: 3, + playerColor: 'Black' as const, + isServer: false, + remoteAddress: '', + }; + expect(config.boardSize).toBeGreaterThanOrEqual(9); + expect(config.boardSize).toBeLessThanOrEqual(19); + expect(['Black', 'White']).toContain(config.playerColor); + }); +});