import { TeamDrivingRatingCalculator, TeamDrivingRaceResult, TeamDrivingQualifyingResult, TeamDrivingOvertakeStats } from './TeamDrivingRatingCalculator'; describe('TeamDrivingRatingCalculator', () => { describe('calculateFromRaceFinish', () => { it('should create events from race finish data', () => { const result: TeamDrivingRaceResult = { teamId: 'team-123', position: 1, incidents: 0, status: 'finished', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', }; const events = TeamDrivingRatingCalculator.calculateFromRaceFinish(result); expect(events.length).toBeGreaterThan(0); expect(events[0].teamId).toBe('team-123'); expect(events[0].dimension.value).toBe('driving'); }); it('should create events for DNS status', () => { const result: TeamDrivingRaceResult = { teamId: 'team-123', position: 1, incidents: 0, status: 'dns', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', }; const events = TeamDrivingRatingCalculator.calculateFromRaceFinish(result); expect(events.length).toBeGreaterThan(0); const dnsEvent = events.find(e => e.reason.code === 'RACE_DNS'); expect(dnsEvent).toBeDefined(); expect(dnsEvent?.delta.value).toBeLessThan(0); }); it('should create events for DNF status', () => { const result: TeamDrivingRaceResult = { teamId: 'team-123', position: 5, incidents: 2, status: 'dnf', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', }; const events = TeamDrivingRatingCalculator.calculateFromRaceFinish(result); expect(events.length).toBeGreaterThan(0); const dnfEvent = events.find(e => e.reason.code === 'RACE_DNF'); expect(dnfEvent).toBeDefined(); expect(dnfEvent?.delta.value).toBe(-15); }); it('should create events for DSQ status', () => { const result: TeamDrivingRaceResult = { teamId: 'team-123', position: 5, incidents: 0, status: 'dsq', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', }; const events = TeamDrivingRatingCalculator.calculateFromRaceFinish(result); expect(events.length).toBeGreaterThan(0); const dsqEvent = events.find(e => e.reason.code === 'RACE_DSQ'); expect(dsqEvent).toBeDefined(); expect(dsqEvent?.delta.value).toBe(-25); }); it('should create events for AFK status', () => { const result: TeamDrivingRaceResult = { teamId: 'team-123', position: 5, incidents: 0, status: 'afk', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', }; const events = TeamDrivingRatingCalculator.calculateFromRaceFinish(result); expect(events.length).toBeGreaterThan(0); const afkEvent = events.find(e => e.reason.code === 'RACE_AFK'); expect(afkEvent).toBeDefined(); expect(afkEvent?.delta.value).toBe(-20); }); it('should apply incident penalties', () => { const result: TeamDrivingRaceResult = { teamId: 'team-123', position: 3, incidents: 5, status: 'finished', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', }; const events = TeamDrivingRatingCalculator.calculateFromRaceFinish(result); const incidentEvent = events.find(e => e.reason.code === 'RACE_INCIDENTS'); expect(incidentEvent).toBeDefined(); expect(incidentEvent?.delta.value).toBeLessThan(0); }); it('should apply gain bonus for beating higher-rated teams', () => { const result: TeamDrivingRaceResult = { teamId: 'team-123', position: 1, incidents: 0, status: 'finished', fieldSize: 10, strengthOfField: 65, // High strength raceId: 'race-456', }; const events = TeamDrivingRatingCalculator.calculateFromRaceFinish(result); const gainEvent = events.find(e => e.reason.code === 'RACE_GAIN_BONUS'); expect(gainEvent).toBeDefined(); expect(gainEvent?.delta.value).toBeGreaterThan(0); expect(gainEvent?.weight).toBe(0.5); }); it('should create pace events when pace is provided', () => { const result: TeamDrivingRaceResult = { teamId: 'team-123', position: 3, incidents: 0, status: 'finished', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', pace: 80, }; const events = TeamDrivingRatingCalculator.calculateFromRaceFinish(result); const paceEvent = events.find(e => e.reason.code === 'RACE_PACE'); expect(paceEvent).toBeDefined(); expect(paceEvent?.delta.value).toBeGreaterThan(0); expect(paceEvent?.weight).toBe(0.3); }); it('should create consistency events when consistency is provided', () => { const result: TeamDrivingRaceResult = { teamId: 'team-123', position: 3, incidents: 0, status: 'finished', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', consistency: 85, }; const events = TeamDrivingRatingCalculator.calculateFromRaceFinish(result); const consistencyEvent = events.find(e => e.reason.code === 'RACE_CONSISTENCY'); expect(consistencyEvent).toBeDefined(); expect(consistencyEvent?.delta.value).toBeGreaterThan(0); expect(consistencyEvent?.weight).toBe(0.3); }); it('should create teamwork events when teamwork is provided', () => { const result: TeamDrivingRaceResult = { teamId: 'team-123', position: 3, incidents: 0, status: 'finished', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', teamwork: 90, }; const events = TeamDrivingRatingCalculator.calculateFromRaceFinish(result); const teamworkEvent = events.find(e => e.reason.code === 'RACE_TEAMWORK'); expect(teamworkEvent).toBeDefined(); expect(teamworkEvent?.delta.value).toBeGreaterThan(0); expect(teamworkEvent?.weight).toBe(0.4); }); it('should create sportsmanship events when sportsmanship is provided', () => { const result: TeamDrivingRaceResult = { teamId: 'team-123', position: 3, incidents: 0, status: 'finished', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', sportsmanship: 95, }; const events = TeamDrivingRatingCalculator.calculateFromRaceFinish(result); const sportsmanshipEvent = events.find(e => e.reason.code === 'RACE_SPORTSMANSHIP'); expect(sportsmanshipEvent).toBeDefined(); expect(sportsmanshipEvent?.delta.value).toBeGreaterThan(0); expect(sportsmanshipEvent?.weight).toBe(0.3); }); it('should handle all optional ratings together', () => { const result: TeamDrivingRaceResult = { teamId: 'team-123', position: 1, incidents: 1, status: 'finished', fieldSize: 10, strengthOfField: 65, // High enough for gain bonus raceId: 'race-456', pace: 75, consistency: 80, teamwork: 85, sportsmanship: 90, }; const events = TeamDrivingRatingCalculator.calculateFromRaceFinish(result); // Should have multiple events expect(events.length).toBeGreaterThan(5); // Check for specific events expect(events.find(e => e.reason.code === 'RACE_PERFORMANCE')).toBeDefined(); expect(events.find(e => e.reason.code === 'RACE_GAIN_BONUS')).toBeDefined(); expect(events.find(e => e.reason.code === 'RACE_INCIDENTS')).toBeDefined(); expect(events.find(e => e.reason.code === 'RACE_PACE')).toBeDefined(); expect(events.find(e => e.reason.code === 'RACE_CONSISTENCY')).toBeDefined(); expect(events.find(e => e.reason.code === 'RACE_TEAMWORK')).toBeDefined(); expect(events.find(e => e.reason.code === 'RACE_SPORTSMANSHIP')).toBeDefined(); }); }); describe('calculateFromQualifying', () => { it('should create qualifying events', () => { const result: TeamDrivingQualifyingResult = { teamId: 'team-123', qualifyingPosition: 3, fieldSize: 10, raceId: 'race-456', }; const events = TeamDrivingRatingCalculator.calculateFromQualifying(result); expect(events.length).toBeGreaterThan(0); expect(events[0].teamId).toBe('team-123'); expect(events[0].dimension.value).toBe('driving'); expect(events[0].reason.code).toBe('RACE_QUALIFYING'); expect(events[0].weight).toBe(0.25); }); it('should create positive delta for good qualifying position', () => { const result: TeamDrivingQualifyingResult = { teamId: 'team-123', qualifyingPosition: 1, fieldSize: 10, raceId: 'race-456', }; const events = TeamDrivingRatingCalculator.calculateFromQualifying(result); expect(events[0].delta.value).toBeGreaterThan(0); }); it('should create negative delta for poor qualifying position', () => { const result: TeamDrivingQualifyingResult = { teamId: 'team-123', qualifyingPosition: 10, fieldSize: 10, raceId: 'race-456', }; const events = TeamDrivingRatingCalculator.calculateFromQualifying(result); expect(events[0].delta.value).toBeLessThan(0); }); }); describe('calculateFromOvertakeStats', () => { it('should create overtake events', () => { const stats: TeamDrivingOvertakeStats = { teamId: 'team-123', overtakes: 5, successfulDefenses: 3, raceId: 'race-456', }; const events = TeamDrivingRatingCalculator.calculateFromOvertakeStats(stats); expect(events.length).toBeGreaterThan(0); const overtakeEvent = events.find(e => e.reason.code === 'RACE_OVERTAKE'); expect(overtakeEvent).toBeDefined(); expect(overtakeEvent?.delta.value).toBeGreaterThan(0); expect(overtakeEvent?.weight).toBe(0.5); }); it('should create defense events', () => { const stats: TeamDrivingOvertakeStats = { teamId: 'team-123', overtakes: 0, successfulDefenses: 4, raceId: 'race-456', }; const events = TeamDrivingRatingCalculator.calculateFromOvertakeStats(stats); const defenseEvent = events.find(e => e.reason.code === 'RACE_DEFENSE'); expect(defenseEvent).toBeDefined(); expect(defenseEvent?.delta.value).toBeGreaterThan(0); expect(defenseEvent?.weight).toBe(0.4); }); it('should create both overtake and defense events', () => { const stats: TeamDrivingOvertakeStats = { teamId: 'team-123', overtakes: 3, successfulDefenses: 2, raceId: 'race-456', }; const events = TeamDrivingRatingCalculator.calculateFromOvertakeStats(stats); expect(events.length).toBe(2); expect(events.find(e => e.reason.code === 'RACE_OVERTAKE')).toBeDefined(); expect(events.find(e => e.reason.code === 'RACE_DEFENSE')).toBeDefined(); }); it('should return empty array for zero stats', () => { const stats: TeamDrivingOvertakeStats = { teamId: 'team-123', overtakes: 0, successfulDefenses: 0, raceId: 'race-456', }; const events = TeamDrivingRatingCalculator.calculateFromOvertakeStats(stats); expect(events.length).toBe(0); }); }); describe('Edge cases', () => { it('should handle extreme field sizes', () => { const result: TeamDrivingRaceResult = { teamId: 'team-123', position: 1, incidents: 0, status: 'finished', fieldSize: 100, strengthOfField: 55, raceId: 'race-456', }; const events = TeamDrivingRatingCalculator.calculateFromRaceFinish(result); expect(events.length).toBeGreaterThan(0); expect(events[0].delta.value).toBeGreaterThan(0); }); it('should handle many incidents', () => { const result: TeamDrivingRaceResult = { teamId: 'team-123', position: 5, incidents: 20, status: 'finished', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', }; const events = TeamDrivingRatingCalculator.calculateFromRaceFinish(result); const incidentEvent = events.find(e => e.reason.code === 'RACE_INCIDENTS'); expect(incidentEvent).toBeDefined(); // Should be capped at 20 expect(incidentEvent?.delta.value).toBe(-20); }); it('should handle low ratings', () => { const result: TeamDrivingRaceResult = { teamId: 'team-123', position: 5, incidents: 0, status: 'finished', fieldSize: 10, strengthOfField: 55, raceId: 'race-456', pace: 10, consistency: 15, teamwork: 20, sportsmanship: 25, }; const events = TeamDrivingRatingCalculator.calculateFromRaceFinish(result); const paceEvent = events.find(e => e.reason.code === 'RACE_PACE'); expect(paceEvent?.delta.value).toBeLessThan(0); const consistencyEvent = events.find(e => e.reason.code === 'RACE_CONSISTENCY'); expect(consistencyEvent?.delta.value).toBeLessThan(0); const teamworkEvent = events.find(e => e.reason.code === 'RACE_TEAMWORK'); expect(teamworkEvent?.delta.value).toBeLessThan(0); const sportsmanshipEvent = events.find(e => e.reason.code === 'RACE_SPORTSMANSHIP'); expect(sportsmanshipEvent?.delta.value).toBeLessThan(0); }); it('should handle high ratings', () => { const result: TeamDrivingRaceResult = { teamId: 'team-123', position: 1, incidents: 0, status: 'finished', fieldSize: 10, strengthOfField: 65, raceId: 'race-456', pace: 95, consistency: 98, teamwork: 92, sportsmanship: 97, }; const events = TeamDrivingRatingCalculator.calculateFromRaceFinish(result); const paceEvent = events.find(e => e.reason.code === 'RACE_PACE'); expect(paceEvent?.delta.value).toBeGreaterThan(0); const consistencyEvent = events.find(e => e.reason.code === 'RACE_CONSISTENCY'); expect(consistencyEvent?.delta.value).toBeGreaterThan(0); const teamworkEvent = events.find(e => e.reason.code === 'RACE_TEAMWORK'); expect(teamworkEvent?.delta.value).toBeGreaterThan(0); const sportsmanshipEvent = events.find(e => e.reason.code === 'RACE_SPORTSMANSHIP'); expect(sportsmanshipEvent?.delta.value).toBeGreaterThan(0); }); }); });