import { describe, it, expect } from 'vitest'; import { parseCommand, parseCommandSchema, validateCommand } from '../../src/utils/command'; describe('parseCommandSchema', () => { it('should parse empty schema', () => { const schema = parseCommandSchema(''); expect(schema).toEqual({ name: '', params: [], options: [], flags: [], }); }); it('should parse command name only', () => { const schema = parseCommandSchema('move'); expect(schema).toEqual({ name: 'move', params: [], options: [], flags: [], }); }); it('should parse required params', () => { const schema = parseCommandSchema('move '); expect(schema.params).toEqual([ { name: 'from', required: true, variadic: false }, { name: 'to', required: true, variadic: false }, ]); }); it('should parse optional params', () => { const schema = parseCommandSchema('move [to]'); expect(schema.params).toEqual([ { name: 'from', required: true, variadic: false }, { name: 'to', required: false, variadic: false }, ]); }); it('should parse variadic params', () => { const schema = parseCommandSchema('move [targets...]'); expect(schema.params).toEqual([ { name: 'from', required: true, variadic: false }, { name: 'targets', required: false, variadic: true }, ]); }); it('should parse required variadic params', () => { const schema = parseCommandSchema('move '); expect(schema.params).toEqual([ { name: 'targets', required: true, variadic: true }, ]); }); it('should parse long flags', () => { const schema = parseCommandSchema('move [--force] [--quiet]'); expect(schema.flags).toEqual([ { name: 'force' }, { name: 'quiet' }, ]); }); it('should parse short flags', () => { const schema = parseCommandSchema('move [-f] [-q]'); expect(schema.flags).toEqual([ { name: 'f', short: 'f' }, { name: 'q', short: 'q' }, ]); }); it('should parse long options', () => { const schema = parseCommandSchema('move --x [--y value]'); expect(schema.options).toEqual([ { name: 'x', required: true }, { name: 'y', required: false }, ]); }); it('should parse short options', () => { const schema = parseCommandSchema('move -x [-y value]'); expect(schema.options).toEqual([ { name: 'x', short: 'x', required: true }, { name: 'y', short: 'y', required: false }, ]); }); it('should parse mixed schema', () => { const schema = parseCommandSchema('move [--force] [-f] [--speed ] [-s val]'); expect(schema).toEqual({ name: 'move', params: [ { name: 'from', required: true, variadic: false }, { name: 'to', required: true, variadic: false }, ], flags: [ { name: 'force' }, { name: 'f', short: 'f' }, ], options: [ { name: 'speed', required: false }, { name: 's', short: 's', required: false }, ], }); }); it('should handle complex schema', () => { const schema = parseCommandSchema('place [x...] [--rotate ] [--force] [-f]'); expect(schema.name).toBe('place'); expect(schema.params).toHaveLength(3); expect(schema.flags).toHaveLength(2); expect(schema.options).toHaveLength(1); }); }); describe('validateCommand', () => { it('should validate correct command', () => { const schema = parseCommandSchema('move '); const command = parseCommand('move meeple1 region1'); const result = validateCommand(command, schema); expect(result).toEqual({ valid: true }); }); it('should reject wrong command name', () => { const schema = parseCommandSchema('move '); const command = parseCommand('place meeple1'); const result = validateCommand(command, schema); expect(result).toEqual({ valid: false, errors: expect.arrayContaining([ expect.stringContaining('命令名称不匹配'), ]), }); }); it('should reject missing required params', () => { const schema = parseCommandSchema('move '); const command = parseCommand('move meeple1'); const result = validateCommand(command, schema); expect(result).toEqual({ valid: false, errors: expect.arrayContaining([ expect.stringContaining('参数不足'), ]), }); }); it('should accept optional params missing', () => { const schema = parseCommandSchema('move [to]'); const command = parseCommand('move meeple1'); const result = validateCommand(command, schema); expect(result).toEqual({ valid: true }); }); it('should reject extra params without variadic', () => { const schema = parseCommandSchema('move '); const command = parseCommand('move meeple1 region1 extra'); const result = validateCommand(command, schema); expect(result).toEqual({ valid: false, errors: expect.arrayContaining([ expect.stringContaining('参数过多'), ]), }); }); it('should accept extra params with variadic', () => { const schema = parseCommandSchema('move [targets...]'); const command = parseCommand('move meeple1 region1 region2 region3'); const result = validateCommand(command, schema); expect(result).toEqual({ valid: true }); }); it('should reject missing required option', () => { const schema = parseCommandSchema('move --speed '); const command = parseCommand('move meeple1'); const result = validateCommand(command, schema); expect(result).toEqual({ valid: false, errors: expect.arrayContaining([ expect.stringContaining('缺少必需选项'), ]), }); }); it('should accept present required option', () => { const schema = parseCommandSchema('move --speed '); const command = parseCommand('move meeple1 --speed 10'); const result = validateCommand(command, schema); expect(result).toEqual({ valid: true }); }); it('should accept optional option missing', () => { const schema = parseCommandSchema('move [--speed [val]]'); const command = parseCommand('move meeple1'); const result = validateCommand(command, schema); expect(result).toEqual({ valid: true }); }); it('should accept flags present or not', () => { const schema = parseCommandSchema('move [--force]'); const cmd1 = parseCommand('move meeple1'); const cmd2 = parseCommand('move meeple1 --force'); expect(validateCommand(cmd1, schema)).toEqual({ valid: true }); expect(validateCommand(cmd2, schema)).toEqual({ valid: true }); }); it('should validate short form option', () => { const schema = parseCommandSchema('move -s '); const command = parseCommand('move meeple1 -s 10'); const result = validateCommand(command, schema); expect(result).toEqual({ valid: true }); }); it('should provide detailed error messages', () => { const schema = parseCommandSchema('place --rotate '); const command = parseCommand('place meeple1'); const result = validateCommand(command, schema); expect(result.valid).toBe(false); if (!result.valid) { expect(result.errors.length).toBeGreaterThanOrEqual(1); } }); }); describe('integration', () => { it('should work together parse and validate', () => { const schemaStr = 'place [--x ] [--y [val]] [--force] [-f]'; const schema = parseCommandSchema(schemaStr); const validCmd = parseCommand('place meeple1 board --x 5 --force'); expect(validateCommand(validCmd, schema)).toEqual({ valid: true }); const invalidCmd = parseCommand('place meeple1'); const result = validateCommand(invalidCmd, schema); expect(result.valid).toBe(false); }); });