boardgame-core/tests/commands/command.parser.test.ts

161 lines
5.5 KiB
TypeScript

import { describe, it, expect, beforeEach } from 'vitest';
import { CommandParser, createCommandParser } from '../../src/commands/CommandParser';
import { CommandParseError } from '../../src/commands/CommandParser';
describe('CommandParser', () => {
let parser: CommandParser;
beforeEach(() => {
parser = createCommandParser();
});
describe('parse', () => {
it('should parse simple command without args', () => {
const result = parser.parse('shuffle');
expect(result.commandName).toBe('shuffle');
expect(result.args.positional).toEqual([]);
expect(result.args.flags).toEqual({});
});
it('should parse command with positional args', () => {
const result = parser.parse('move card-1 discard');
expect(result.commandName).toBe('move');
expect(result.args.positional).toEqual(['card-1', 'discard']);
expect(result.args.flags).toEqual({});
});
it('should parse command with multiple positional args', () => {
const result = parser.parse('position p1 3 5');
expect(result.commandName).toBe('position');
expect(result.args.positional).toEqual(['p1', '3', '5']);
});
it('should parse command with flag', () => {
const result = parser.parse('shuffle discard --seed=2026');
expect(result.commandName).toBe('shuffle');
expect(result.args.positional).toEqual(['discard']);
expect(result.args.flags).toEqual({ seed: '2026' });
});
it('should parse command with multiple flags', () => {
const result = parser.parse('create meeple m1 --color=red --name=Player1');
expect(result.commandName).toBe('create');
expect(result.args.positional).toEqual(['meeple', 'm1']);
expect(result.args.flags).toEqual({ color: 'red', name: 'Player1' });
});
it('should parse command with boolean flag', () => {
const result = parser.parse('flip p1 --faceup');
expect(result.commandName).toBe('flip');
expect(result.args.positional).toEqual(['p1']);
expect(result.args.flags).toEqual({ faceup: true });
});
it('should parse command with short flag', () => {
const result = parser.parse('shuffle d1 -s');
expect(result.commandName).toBe('shuffle');
expect(result.args.positional).toEqual(['d1']);
expect(result.args.flags).toEqual({ s: true });
});
it('should parse command with short flag and value', () => {
const result = parser.parse('shuffle d1 --seed=2026');
expect(result.commandName).toBe('shuffle');
expect(result.args.positional).toEqual(['d1']);
expect(result.args.flags).toEqual({ seed: '2026' });
});
it('should parse command with string number value', () => {
const result = parser.parse('rotate p1 90');
expect(result.commandName).toBe('rotate');
expect(result.args.positional).toEqual(['p1', '90']);
});
it('should parse command with negative number', () => {
const result = parser.parse('rotate p1 -45');
expect(result.commandName).toBe('rotate');
expect(result.args.positional).toEqual(['p1', '-45']);
});
it('should parse command with float number', () => {
const result = parser.parse('rotate p1 45.5');
expect(result.commandName).toBe('rotate');
expect(result.args.positional).toEqual(['p1', '45.5']);
});
it('should parse command with quoted string', () => {
const result = parser.parse('create meeple m1 --name="Red Player"');
expect(result.commandName).toBe('create');
expect(result.args.positional).toEqual(['meeple', 'm1']);
expect(result.args.flags).toEqual({ name: 'Red Player' });
});
it('should parse command with single quoted string', () => {
const result = parser.parse("create meeple m1 --name='Blue Player'");
expect(result.commandName).toBe('create');
expect(result.args.positional).toEqual(['meeple', 'm1']);
expect(result.args.flags).toEqual({ name: 'Blue Player' });
});
it('should handle extra whitespace', () => {
const result = parser.parse(' move card-1 discard ');
expect(result.commandName).toBe('move');
expect(result.args.positional).toEqual(['card-1', 'discard']);
});
it('should throw on empty command', () => {
expect(() => parser.parse('')).toThrow(CommandParseError);
expect(() => parser.parse(' ')).toThrow(CommandParseError);
});
it('should throw on unclosed quote', () => {
expect(() => parser.parse('create meeple m1 --name="Red')).toThrow(CommandParseError);
});
});
describe('formatCommand', () => {
it('should format simple command', () => {
const formatted = CommandParser.formatCommand('shuffle');
expect(formatted).toBe('shuffle');
});
it('should format command with positional args', () => {
const formatted = CommandParser.formatCommand('move', {
positional: ['card-1', 'discard'],
flags: {},
});
expect(formatted).toBe('move card-1 discard');
});
it('should format command with flags', () => {
const formatted = CommandParser.formatCommand('shuffle', {
positional: ['discard'],
flags: { seed: 2026 },
});
expect(formatted).toBe('shuffle discard --seed=2026');
});
it('should format command with boolean flag', () => {
const formatted = CommandParser.formatCommand('flip', {
positional: ['p1'],
flags: { faceup: true },
});
expect(formatted).toBe('flip p1 --faceup');
});
});
});