86211923db
Repository Interface Optimization: - Created IBaseRepository.ts and IPaginatedRepository.ts - Refactored all 7 repository interfaces to extend base interfaces - Eliminated ~200 lines of redundant code (70% reduction) - Improved type safety and maintainability Dependency Injection Improvements: - Added EmailService and GameTokenService to DIContainer - Updated CreateUserCommandHandler constructor for DI - Updated RequestPasswordResetCommandHandler constructor for DI - Enhanced testability and service consistency Environment Configuration: - Created comprehensive .env.example with 40+ variables - Organized into 12 logical sections (Database, Security, Email, etc.) - Added security guidelines and best practices - Documented all backend environment requirements Documentation: - Added comprehensive codebase review - Created refactoring summary report - Added frontend implementation guide Impact: Improved code quality, reduced maintenance overhead, enhanced developer experience
133 lines
5.5 KiB
TypeScript
133 lines
5.5 KiB
TypeScript
import { BoardGenerationService } from '../../../src/Application/Game/BoardGenerationService';
|
|
|
|
// Mock dependencies
|
|
jest.mock('../../../src/Application/Services/LoggingService');
|
|
|
|
describe('BoardGenerationService', () => {
|
|
let boardGenerationService: BoardGenerationService;
|
|
|
|
beforeEach(() => {
|
|
boardGenerationService = new BoardGenerationService();
|
|
});
|
|
|
|
describe('generateBoard', () => {
|
|
it('should generate a board with the correct number of special fields', async () => {
|
|
const positiveFields = 10;
|
|
const negativeFields = 8;
|
|
const luckFields = 5;
|
|
|
|
const result = await boardGenerationService.generateBoard(
|
|
positiveFields,
|
|
negativeFields,
|
|
luckFields
|
|
);
|
|
|
|
expect(result).toBeDefined();
|
|
expect(result.fields).toHaveLength(100);
|
|
|
|
// Count special fields
|
|
const actualPositive = result.fields.filter(f => f.type === 'positive').length;
|
|
const actualNegative = result.fields.filter(f => f.type === 'negative').length;
|
|
const actualLuck = result.fields.filter(f => f.type === 'luck').length;
|
|
|
|
expect(actualPositive).toBe(positiveFields);
|
|
expect(actualNegative).toBe(negativeFields);
|
|
expect(actualLuck).toBe(luckFields);
|
|
});
|
|
|
|
it('should ensure positive fields have positive step values', async () => {
|
|
const result = await boardGenerationService.generateBoard(5, 5, 2);
|
|
|
|
const positiveFields = result.fields.filter(f => f.type === 'positive');
|
|
positiveFields.forEach(field => {
|
|
expect(field.stepValue).toBeGreaterThan(0);
|
|
});
|
|
});
|
|
|
|
it('should ensure negative fields have negative step values', async () => {
|
|
const result = await boardGenerationService.generateBoard(5, 5, 2);
|
|
|
|
const negativeFields = result.fields.filter(f => f.type === 'negative');
|
|
negativeFields.forEach(field => {
|
|
expect(field.stepValue).toBeLessThan(0);
|
|
});
|
|
});
|
|
|
|
it('should ensure luck fields do not have step values', async () => {
|
|
const result = await boardGenerationService.generateBoard(5, 5, 2);
|
|
|
|
const luckFields = result.fields.filter(f => f.type === 'luck');
|
|
luckFields.forEach(field => {
|
|
expect(field.stepValue).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
it('should produce validation results without -1 values', async () => {
|
|
const result = await boardGenerationService.generateBoard(10, 8, 5);
|
|
|
|
// Check validation results for invalid moves (-1 values)
|
|
let invalidMoves = 0;
|
|
let totalMoves = 0;
|
|
|
|
Object.values(result.validationResults).forEach(diceOutcomes => {
|
|
diceOutcomes.forEach(outcome => {
|
|
totalMoves++;
|
|
if (outcome === -1) {
|
|
invalidMoves++;
|
|
}
|
|
});
|
|
});
|
|
|
|
const errorRate = totalMoves > 0 ? (invalidMoves / totalMoves) * 100 : 0;
|
|
|
|
// Log the results for analysis
|
|
console.log(`Error rate: ${errorRate}%`);
|
|
console.log(`Invalid moves: ${invalidMoves}/${totalMoves}`);
|
|
|
|
// The new algorithm should produce much fewer invalid moves
|
|
expect(errorRate).toBeLessThan(50); // Allow some errors but much better than before
|
|
});
|
|
|
|
it('should respect the 20-30 movement rule in validation', async () => {
|
|
const result = await boardGenerationService.generateBoard(10, 8, 5);
|
|
|
|
// Check each validation result to ensure it respects distance rules
|
|
Object.entries(result.validationResults).forEach(([fieldPosition, diceOutcomes]) => {
|
|
const currentPos = parseInt(fieldPosition);
|
|
|
|
diceOutcomes.forEach((outcome, diceIndex) => {
|
|
if (outcome !== -1) { // Only check valid moves
|
|
const distance = Math.abs(outcome - currentPos);
|
|
|
|
if (currentPos <= 85) {
|
|
// Fields 1-85: max 20 in any direction
|
|
expect(distance).toBeLessThanOrEqual(20);
|
|
} else {
|
|
// Fields 86-100: max 30 backward, max 20 forward
|
|
if (outcome > currentPos) {
|
|
expect(distance).toBeLessThanOrEqual(20); // forward
|
|
} else {
|
|
expect(distance).toBeLessThanOrEqual(30); // backward
|
|
}
|
|
}
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
it('should position special fields safely within the safe range', async () => {
|
|
const result = await boardGenerationService.generateBoard(10, 8, 5);
|
|
|
|
const specialFields = result.fields.filter(f => f.type !== 'regular');
|
|
|
|
// Most special fields should be in the safe range (11-90) for the new algorithm
|
|
const safeFields = specialFields.filter(f => f.position >= 11 && f.position <= 90);
|
|
const safePercentage = (safeFields.length / specialFields.length) * 100;
|
|
|
|
console.log(`Safe field percentage: ${safePercentage}%`);
|
|
|
|
// Expect most fields to be positioned safely
|
|
expect(safePercentage).toBeGreaterThan(70);
|
|
});
|
|
});
|
|
}); |