172 lines
5.5 KiB
TypeScript
172 lines
5.5 KiB
TypeScript
|
|
import { describe, it, expect } from 'vitest';
|
||
|
|
import { createPart, createParts, createPartPool, mergePartPools, PartPool } from '@/core/part-factory';
|
||
|
|
|
||
|
|
describe('createPart', () => {
|
||
|
|
it('should create a part with given template and id', () => {
|
||
|
|
const part = createPart<{ player: string }>(
|
||
|
|
{ regionId: 'board', position: [1, 2], player: 'X' },
|
||
|
|
'piece-1'
|
||
|
|
);
|
||
|
|
expect(part.id).toBe('piece-1');
|
||
|
|
expect(part.regionId).toBe('board');
|
||
|
|
expect(part.position).toEqual([1, 2]);
|
||
|
|
expect(part.player).toBe('X');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should apply default values for regionId and position when not provided', () => {
|
||
|
|
const part = createPart({}, 'piece-1');
|
||
|
|
expect(part.regionId).toBe('');
|
||
|
|
expect(part.position).toEqual([]);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should allow overriding default values', () => {
|
||
|
|
const part = createPart({ regionId: 'custom', position: [0] }, 'piece-1');
|
||
|
|
expect(part.regionId).toBe('custom');
|
||
|
|
expect(part.position).toEqual([0]);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should preserve metadata fields', () => {
|
||
|
|
type TestMeta = { type: string; count: number };
|
||
|
|
const part = createPart<TestMeta>(
|
||
|
|
{ regionId: 'board', position: [0], type: 'kitten', count: 5 },
|
||
|
|
'piece-1'
|
||
|
|
);
|
||
|
|
expect(part.type).toBe('kitten');
|
||
|
|
expect(part.count).toBe(5);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('createParts', () => {
|
||
|
|
it('should create multiple parts with auto-generated IDs', () => {
|
||
|
|
const parts = createParts(
|
||
|
|
{ regionId: 'deck', position: [] },
|
||
|
|
3,
|
||
|
|
'card'
|
||
|
|
);
|
||
|
|
expect(parts.length).toBe(3);
|
||
|
|
expect(parts[0].id).toBe('card-1');
|
||
|
|
expect(parts[1].id).toBe('card-2');
|
||
|
|
expect(parts[2].id).toBe('card-3');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should create parts with identical properties', () => {
|
||
|
|
const parts = createParts(
|
||
|
|
{ regionId: 'deck', position: [], type: 'token' },
|
||
|
|
2,
|
||
|
|
'token'
|
||
|
|
);
|
||
|
|
expect(parts[0].regionId).toBe('deck');
|
||
|
|
expect(parts[1].regionId).toBe('deck');
|
||
|
|
expect(parts[0].type).toBe('token');
|
||
|
|
expect(parts[1].type).toBe('token');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should create zero parts when count is 0', () => {
|
||
|
|
const parts = createParts({}, 0, 'empty');
|
||
|
|
expect(parts.length).toBe(0);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('createPartPool', () => {
|
||
|
|
it('should create a pool with specified count', () => {
|
||
|
|
const pool = createPartPool(
|
||
|
|
{ regionId: 'supply', position: [] },
|
||
|
|
5,
|
||
|
|
'token'
|
||
|
|
);
|
||
|
|
expect(pool.remaining()).toBe(5);
|
||
|
|
expect(Object.keys(pool.parts).length).toBe(5);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should generate parts with correct IDs', () => {
|
||
|
|
const pool = createPartPool({}, 3, 'piece');
|
||
|
|
expect(pool.parts['piece-1']).toBeDefined();
|
||
|
|
expect(pool.parts['piece-2']).toBeDefined();
|
||
|
|
expect(pool.parts['piece-3']).toBeDefined();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should draw parts from the pool', () => {
|
||
|
|
const pool = createPartPool({}, 2, 'card');
|
||
|
|
const drawn = pool.draw();
|
||
|
|
expect(drawn).toBeDefined();
|
||
|
|
expect(drawn!.id).toBe('card-2');
|
||
|
|
expect(pool.remaining()).toBe(1);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should return undefined when pool is empty', () => {
|
||
|
|
const pool = createPartPool({}, 1, 'card');
|
||
|
|
pool.draw();
|
||
|
|
const drawn = pool.draw();
|
||
|
|
expect(drawn).toBeUndefined();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should return part to pool', () => {
|
||
|
|
const pool = createPartPool({ regionId: 'board', position: [0, 0] }, 1, 'card');
|
||
|
|
const drawn = pool.draw();
|
||
|
|
expect(pool.remaining()).toBe(0);
|
||
|
|
|
||
|
|
pool.return(drawn!);
|
||
|
|
expect(pool.remaining()).toBe(1);
|
||
|
|
expect(drawn!.regionId).toBe('');
|
||
|
|
expect(drawn!.position).toEqual([]);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should store parts as Record keyed by ID', () => {
|
||
|
|
const pool = createPartPool({}, 2, 'piece');
|
||
|
|
expect(typeof pool.parts).toBe('object');
|
||
|
|
expect(pool.parts['piece-1']).toBeDefined();
|
||
|
|
expect(pool.parts['piece-2']).toBeDefined();
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
describe('mergePartPools', () => {
|
||
|
|
it('should merge multiple pools', () => {
|
||
|
|
const pool1 = createPartPool({ regionId: 'deck1', position: [] }, 2, 'card1');
|
||
|
|
const pool2 = createPartPool({ regionId: 'deck2', position: [] }, 3, 'card2');
|
||
|
|
const merged = mergePartPools(pool1, pool2);
|
||
|
|
|
||
|
|
expect(Object.keys(merged.parts).length).toBe(5);
|
||
|
|
// Parts with regionId: '' are available; pool parts have regionId from template
|
||
|
|
// After merge, available = parts with regionId === ''
|
||
|
|
expect(merged.remaining()).toBe(0); // parts have regionId: 'deck1' or 'deck2'
|
||
|
|
expect(merged.parts['card1-1']).toBeDefined();
|
||
|
|
expect(merged.parts['card2-3']).toBeDefined();
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should use first pool template', () => {
|
||
|
|
const pool1 = createPartPool({ regionId: 'deck1', position: [] }, 1, 'card1');
|
||
|
|
const pool2 = createPartPool({ regionId: 'deck2', position: [] }, 1, 'card2');
|
||
|
|
const merged = mergePartPools(pool1, pool2);
|
||
|
|
|
||
|
|
expect(merged.template.regionId).toBe('deck1');
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should return empty pool when no pools provided', () => {
|
||
|
|
const merged = mergePartPools();
|
||
|
|
expect(Object.keys(merged.parts).length).toBe(0);
|
||
|
|
expect(merged.remaining()).toBe(0);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should only count available parts for remaining()', () => {
|
||
|
|
const pool1 = createPartPool({}, 2, 'card');
|
||
|
|
const pool2 = createPartPool({}, 2, 'token');
|
||
|
|
|
||
|
|
const drawn = pool1.draw();
|
||
|
|
drawn!.regionId = 'board';
|
||
|
|
drawn!.position = [0, 0];
|
||
|
|
|
||
|
|
const merged = mergePartPools(pool1, pool2);
|
||
|
|
expect(merged.remaining()).toBe(3);
|
||
|
|
});
|
||
|
|
|
||
|
|
it('should handle drawing from merged pool', () => {
|
||
|
|
const pool1 = createPartPool({}, 2, 'card');
|
||
|
|
const pool2 = createPartPool({}, 2, 'token');
|
||
|
|
const merged = mergePartPools(pool1, pool2);
|
||
|
|
|
||
|
|
const drawn = merged.draw();
|
||
|
|
expect(drawn).toBeDefined();
|
||
|
|
expect(merged.remaining()).toBe(3);
|
||
|
|
});
|
||
|
|
});
|