Skip to main content
Glama
bsim0927
by bsim0927
solver-test.js7.46 kB
#!/usr/bin/env node /** * Integration tests for TexasSolver MCP Server */ import dotenv from 'dotenv'; import { SolverValidator } from '../../src/solver/validator.js'; import { CommandBuilder, buildSolverCommand } from '../../src/solver/command-builder.js'; import { SolverExecutor } from '../../src/solver/executor.js'; import { StorageManager } from '../../src/storage/manager.js'; import { RangeLoader } from '../../src/ranges/loader.js'; import { RangeParser } from '../../src/ranges/parser.js'; // Load environment dotenv.config(); const TESTS_PASSED = []; const TESTS_FAILED = []; /** * Test helper function */ async function test(name, fn) { try { await fn(); TESTS_PASSED.push(name); console.log(`✓ ${name}`); } catch (error) { TESTS_FAILED.push({ name, error: error.message }); console.log(`✗ ${name}`); console.log(` Error: ${error.message}`); } } /** * Run all tests */ async function runTests() { console.log('Starting TexasSolver MCP Server Integration Tests\n'); // Test 1: Validator tests console.log('--- Validator Tests ---'); await test('Validate pot (positive)', () => { SolverValidator.validatePot(10); }); await test('Validate pot (should fail on negative)', () => { try { SolverValidator.validatePot(-5); throw new Error('Should have failed'); } catch (error) { if (!error.message.includes('positive')) throw error; } }); await test('Validate stack', () => { SolverValidator.validateStack(100); }); await test('Validate board format', () => { SolverValidator.validateBoard('As,Kh,Qd'); }); await test('Validate empty board (preflop)', () => { SolverValidator.validateBoard(''); }); await test('Validate range format', () => { SolverValidator.validateRange('AA-22,AK-AJ'); }); // Test 2: Command Builder tests console.log('\n--- Command Builder Tests ---'); await test('Build basic command', () => { const builder = new CommandBuilder(); const cmd = builder .setPot(10) .setEffectiveStack(100) .setBoard('As,Kh,Qd') .setRange('ip', 'AA-22') .setRange('oop', 'AA-TT') .buildTree() .setSolverConfig({ thread_num: 4 }) .startSolve() .setDumpRounds(2) .dumpResult('/tmp/output.json') .build(); if (!cmd.includes('set_pot 10')) throw new Error('Missing pot'); if (!cmd.includes('set_board As,Kh,Qd')) throw new Error('Missing board'); if (!cmd.includes('set_range_ip AA-22')) throw new Error('Missing IP range'); if (!cmd.includes('build_tree')) throw new Error('Missing build_tree'); if (!cmd.includes('start_solve')) throw new Error('Missing start_solve'); if (!cmd.includes('dump_result /tmp/output.json')) throw new Error('Missing dump_result'); }); await test('Build command with bet sizes', () => { const builder = new CommandBuilder(); const cmd = builder .setPot(4) .setEffectiveStack(100) .setRange('ip', 'AA') .setRange('oop', 'AA') .setBetSizes('ip', 'flop', 'bet', [50]) .setBetSizes('ip', 'flop', 'raise', 'allin') .buildTree() .build(); if (!cmd.includes('set_bet_sizes ip,flop,bet,50')) throw new Error('Missing bet'); if (!cmd.includes('set_bet_sizes ip,flop,raise')) throw new Error('Missing allin'); }); // Test 3: Range Parser tests console.log('\n--- Range Parser Tests ---'); await test('Parse simple range', () => { const hands = RangeParser.parseRange('AA,KK,QQ'); if (hands.length !== 3) throw new Error(`Expected 3 hands, got ${hands.length}`); if (hands[0].hand !== 'AA') throw new Error('First hand should be AA'); }); await test('Parse range with weights', () => { const hands = RangeParser.parseRange('AA:1.0,KK:0.5,QQ'); if (hands[0].weight !== 1.0) throw new Error('AA should have weight 1.0'); if (hands[1].weight !== 0.5) throw new Error('KK should have weight 0.5'); if (hands[2].weight !== 1.0) throw new Error('QQ should have default weight 1.0'); }); await test('Calculate combinations', () => { const hands = RangeParser.parseRange('AA,KK'); const combos = RangeParser.calculateCombinations(hands); if (combos !== 12) throw new Error(`Expected 12 combos (6+6), got ${combos}`); }); await test('Validate hand notation', () => { if (!RangeParser.isValidHand('AA')) throw new Error('AA should be valid'); if (!RangeParser.isValidHand('AKs')) throw new Error('AKs should be valid'); if (RangeParser.isValidHand('XX')) throw new Error('XX should be invalid'); }); // Test 4: Storage Manager tests console.log('\n--- Storage Manager Tests ---'); await test('Initialize storage', async () => { const storage = new StorageManager('./test-data'); await storage.initialize(); }); await test('Generate unique filenames', () => { const storage = new StorageManager('./test-data'); const file1 = storage.generateFilename('test', 'txt'); const file2 = storage.generateFilename('test', 'txt'); if (file1 === file2) throw new Error('Generated filenames should be unique'); if (!file1.startsWith('test_')) throw new Error('Filename should start with prefix'); if (!file1.endsWith('.txt')) throw new Error('Filename should end with extension'); }); await test('Get command path', () => { const storage = new StorageManager('./test-data'); const path = storage.getCommandPath(); if (!path.includes('commands')) throw new Error('Path should include commands directory'); }); // Test 5: Solver Executor tests console.log('\n--- Solver Executor Tests ---'); const solverPath = process.env.TEXAS_SOLVER_PATH; if (solverPath) { await test('Validate solver exists', async () => { const isValid = await SolverExecutor.validateSolver(solverPath); if (!isValid) throw new Error('Solver should be valid'); }); await test('Get solver info', async () => { const executor = new SolverExecutor(solverPath); const info = await executor.getSolverInfo(); if (!info.exists) throw new Error('Solver should exist'); if (!info.is_executable) throw new Error('Solver should be executable'); }); } else { console.log('⊘ Skipping solver tests (TEXAS_SOLVER_PATH not set)'); } // Test 6: Range Loader tests console.log('\n--- Range Loader Tests ---'); if (solverPath) { await test('Instantiate RangeLoader', () => { const loader = new RangeLoader(solverPath); if (!loader.rangesDir) throw new Error('Should set rangesDir'); }); await test('List range files', async () => { const loader = new RangeLoader(solverPath); const ranges = await loader.listRangeFiles(); if (!Array.isArray(ranges)) throw new Error('Should return array'); }); } else { console.log('⊘ Skipping range loader tests (TEXAS_SOLVER_PATH not set)'); } // Summary console.log('\n--- Test Summary ---'); console.log(`Passed: ${TESTS_PASSED.length}`); console.log(`Failed: ${TESTS_FAILED.length}`); if (TESTS_FAILED.length > 0) { console.log('\nFailed tests:'); TESTS_FAILED.forEach(({ name, error }) => { console.log(` - ${name}: ${error}`); }); process.exit(1); } else { console.log('\n✓ All tests passed!'); process.exit(0); } } // Run tests runTests().catch(error => { console.error('Test runner error:', error); process.exit(1); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bsim0927/texas-solver-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server