import { describe, it, expect } from 'vitest'; import { flip, flipTo, roll, findPartById, isCellOccupied, getPartAtPosition, isCellOccupiedByRegion, getPartAtPositionInRegion, Part } from '@/core/part'; import { createRegion } from '@/core/region'; import { createRNG } from '@/utils/rng'; function createTestPart(overrides: Partial> & TMeta): Part { return { id: 'test-part', regionId: 'test-region', position: [0, 0], ...overrides, } as Part; } describe('flip', () => { it('should cycle to next side when sides is defined', () => { const part = createTestPart({ sides: 2, side: 0 }); flip(part); expect(part.side).toBe(1); flip(part); expect(part.side).toBe(0); }); it('should wrap around when side reaches sides count', () => { const part = createTestPart({ sides: 6, side: 5 }); flip(part); expect(part.side).toBe(0); }); it('should do nothing when sides is undefined', () => { const part = createTestPart({ side: 3 }); flip(part); expect(part.side).toBe(3); }); it('should initialize side to 0 when side is undefined', () => { const part = createTestPart({ sides: 4 }); flip(part); expect(part.side).toBe(1); }); }); describe('flipTo', () => { it('should set side to specified value', () => { const part = createTestPart({ sides: 6, side: 0 }); flipTo(part, 3); expect(part.side).toBe(3); }); it('should do nothing when sides is undefined', () => { const part = createTestPart({ side: 2 }); flipTo(part, 5); expect(part.side).toBe(2); }); it('should do nothing when side exceeds sides count', () => { const part = createTestPart({ sides: 6, side: 0 }); flipTo(part, 6); expect(part.side).toBe(0); }); it('should allow side equal to sides - 1', () => { const part = createTestPart({ sides: 6, side: 0 }); flipTo(part, 5); expect(part.side).toBe(5); }); }); describe('roll', () => { it('should randomize side when sides is defined', () => { const part = createTestPart({ sides: 6 }); const rng = createRNG(12345); roll(part, rng); expect(part.side).toBeGreaterThanOrEqual(0); expect(part.side).toBeLessThan(6); }); it('should do nothing when sides is undefined', () => { const part = createTestPart({ side: 3 }); const rng = createRNG(12345); roll(part, rng); expect(part.side).toBe(3); }); it('should produce deterministic results with same seed', () => { const part1 = createTestPart({ sides: 6 }); const part2 = createTestPart({ sides: 6 }); const rng1 = createRNG(42); const rng2 = createRNG(42); roll(part1, rng1); roll(part2, rng2); expect(part1.side).toBe(part2.side); }); }); describe('findPartById', () => { it('should find part by id', () => { const parts: Record = { 'part-1': createTestPart({ id: 'part-1' }), 'part-2': createTestPart({ id: 'part-2' }), }; const result = findPartById(parts, 'part-1'); expect(result).toBeDefined(); expect(result!.id).toBe('part-1'); }); it('should return undefined for non-existent id', () => { const parts: Record = { 'part-1': createTestPart({ id: 'part-1' }), }; const result = findPartById(parts, 'part-99'); expect(result).toBeUndefined(); }); it('should work with empty record', () => { const parts: Record = {}; const result = findPartById(parts, 'any'); expect(result).toBeUndefined(); }); }); describe('isCellOccupied', () => { it('should return true for occupied cell', () => { const parts: Record = { 'p1': createTestPart({ id: 'p1', regionId: 'board', position: [1, 2] }), }; expect(isCellOccupied(parts, 'board', [1, 2])).toBe(true); }); it('should return false for empty cell', () => { const parts: Record = { 'p1': createTestPart({ id: 'p1', regionId: 'board', position: [1, 2] }), }; expect(isCellOccupied(parts, 'board', [3, 4])).toBe(false); }); it('should return false for different region', () => { const parts: Record = { 'p1': createTestPart({ id: 'p1', regionId: 'board', position: [1, 2] }), }; expect(isCellOccupied(parts, 'hand', [1, 2])).toBe(false); }); it('should work with empty record', () => { const parts: Record = {}; expect(isCellOccupied(parts, 'board', [0, 0])).toBe(false); }); it('should handle multi-dimensional positions', () => { const parts: Record = { 'p1': createTestPart({ id: 'p1', regionId: 'board', position: [1, 2, 3] }), }; expect(isCellOccupied(parts, 'board', [1, 2, 3])).toBe(true); expect(isCellOccupied(parts, 'board', [1, 2])).toBe(false); }); }); describe('getPartAtPosition', () => { it('should return part at specified position', () => { const part1 = createTestPart({ id: 'p1', regionId: 'board', position: [1, 2] }); const parts: Record = { 'p1': part1 }; const result = getPartAtPosition(parts, 'board', [1, 2]); expect(result).toBe(part1); }); it('should return undefined for empty cell', () => { const parts: Record = { 'p1': createTestPart({ id: 'p1', regionId: 'board', position: [1, 2] }), }; const result = getPartAtPosition(parts, 'board', [3, 4]); expect(result).toBeUndefined(); }); it('should return undefined for different region', () => { const parts: Record = { 'p1': createTestPart({ id: 'p1', regionId: 'board', position: [1, 2] }), }; const result = getPartAtPosition(parts, 'hand', [1, 2]); expect(result).toBeUndefined(); }); it('should work with empty record', () => { const parts: Record = {}; const result = getPartAtPosition(parts, 'board', [0, 0]); expect(result).toBeUndefined(); }); }); describe('isCellOccupiedByRegion', () => { it('should return true for occupied cell', () => { const region = createRegion('board', [ { name: 'x', min: 0, max: 2 }, { name: 'y', min: 0, max: 2 }, ]); const part = createTestPart({ id: 'p1', regionId: 'board', position: [1, 2] }); region.childIds.push(part.id); region.partMap['1,2'] = part.id; expect(isCellOccupiedByRegion(region, [1, 2])).toBe(true); }); it('should return false for empty cell', () => { const region = createRegion('board', [ { name: 'x', min: 0, max: 2 }, { name: 'y', min: 0, max: 2 }, ]); const part = createTestPart({ id: 'p1', regionId: 'board', position: [1, 2] }); region.childIds.push(part.id); region.partMap['1,2'] = part.id; expect(isCellOccupiedByRegion(region, [0, 0])).toBe(false); }); it('should work with empty region', () => { const region = createRegion('board', []); expect(isCellOccupiedByRegion(region, [0, 0])).toBe(false); }); }); describe('getPartAtPositionInRegion', () => { it('should return part at specified position', () => { const region = createRegion('board', []); const part1 = createTestPart({ id: 'p1', regionId: 'board', position: [1, 2] }); const parts: Record = { 'p1': part1 }; region.childIds.push(part1.id); region.partMap['1,2'] = part1.id; const result = getPartAtPositionInRegion(region, parts, [1, 2]); expect(result).toBe(part1); }); it('should return undefined for empty cell', () => { const region = createRegion('board', []); const part1 = createTestPart({ id: 'p1', regionId: 'board', position: [1, 2] }); const parts: Record = { 'p1': part1 }; region.childIds.push(part1.id); region.partMap['1,2'] = part1.id; const result = getPartAtPositionInRegion(region, parts, [0, 0]); expect(result).toBeUndefined(); }); it('should work with empty region', () => { const region = createRegion('board', []); const parts: Record = {}; const result = getPartAtPositionInRegion(region, parts, [0, 0]); expect(result).toBeUndefined(); }); });