@@ -2,7 +2,7 @@ import { describe, expect, it, vi } from 'vitest';
22import type { Session , Telemetry } from '@irdashies/types' ;
33import { FuelProjectionProcessor } from './FuelProjectionProcessor' ;
44
5- const frame = ( values : Record < string , number > ) : Telemetry =>
5+ const frame = ( values : Record < string , number | boolean > ) : Telemetry =>
66 Object . fromEntries (
77 Object . entries ( values ) . map ( ( [ key , entry ] ) => [ key , { value : [ entry ] } ] )
88 ) as unknown as Telemetry ;
@@ -76,6 +76,98 @@ describe('FuelProjectionProcessor', () => {
7676 } ) ;
7777 } ) ;
7878
79+ it ( 'preserves boolean track and pit state in the snapshot' , ( ) => {
80+ const processor = new FuelProjectionProcessor ( ) ;
81+
82+ processor . onFrame (
83+ frame ( { FuelLevel : 20 , IsOnTrack : true , OnPitRoad : true } )
84+ ) ;
85+
86+ expect ( processor . snapshot ( ) . isOnTrack ) . toBe ( true ) ;
87+ expect ( processor . snapshot ( ) . engine . wasOnPitRoad ) . toBe ( true ) ;
88+ } ) ;
89+
90+ it ( 'projects timed-race distance using class pace' , ( ) => {
91+ const processor = new FuelProjectionProcessor ( ) ;
92+ processor . init ( {
93+ DriverInfo : {
94+ DriverCarIdx : 0 ,
95+ Drivers : [ { CarIdx : 0 , CarClassEstLapTime : 90 } ] ,
96+ } ,
97+ SessionInfo : {
98+ Sessions : [
99+ { SessionNum : 0 , SessionType : 'Race' , SessionLaps : 'unlimited' } ,
100+ ] ,
101+ } ,
102+ } as unknown as Session ) ;
103+
104+ const timedRaceFrame = {
105+ FuelLevel : { value : [ 45.39 ] } ,
106+ Lap : { value : [ 2 ] } ,
107+ LapDistPct : { value : [ 0.1 ] } ,
108+ SessionNum : { value : [ 0 ] } ,
109+ SessionState : { value : [ 4 ] } ,
110+ SessionLapsRemain : { value : [ 32767 ] } ,
111+ SessionTimeRemain : { value : [ 1620 ] } ,
112+ SessionTimeTotal : { value : [ 1800 ] } ,
113+ CamCarIdx : { value : [ 0 ] } ,
114+ CarIdxLap : { value : [ 2 ] } ,
115+ CarIdxLapDistPct : { value : [ 0.1 ] } ,
116+ CarIdxPosition : { value : [ 1 ] } ,
117+ CarIdxLastLapTime : { value : [ 1 ] } ,
118+ CarIdxBestLapTime : { value : [ 1 ] } ,
119+ } as unknown as Telemetry ;
120+ processor . onFrame ( timedRaceFrame ) ;
121+
122+ expect ( processor . snapshot ( ) ) . toMatchObject ( {
123+ calculatedTotalRaceLaps : 19.1 ,
124+ isFixedLapRace : false ,
125+ } ) ;
126+
127+ processor . onFrame ( {
128+ ...timedRaceFrame ,
129+ CarIdxLastLapTime : { value : [ 100 ] } ,
130+ } as unknown as Telemetry ) ;
131+ expect ( processor . snapshot ( ) . calculatedTotalRaceLaps ) . toBeCloseTo ( 19.1 ) ;
132+
133+ processor . onFrame ( {
134+ ...timedRaceFrame ,
135+ CarIdxLastLapTime : { value : [ 110 ] } ,
136+ } as unknown as Telemetry ) ;
137+ expect ( processor . snapshot ( ) . calculatedTotalRaceLaps ) . toBeCloseTo ( 19.1 ) ;
138+ } ) ;
139+
140+ it ( 'uses fractional distance when correcting a timed race for lapping' , ( ) => {
141+ const processor = new FuelProjectionProcessor ( ) ;
142+ processor . init ( {
143+ DriverInfo : {
144+ DriverCarIdx : 1 ,
145+ Drivers : [
146+ { CarIdx : 0 , CarClassEstLapTime : 100 } ,
147+ { CarIdx : 1 , CarClassEstLapTime : 100 } ,
148+ ] ,
149+ } ,
150+ SessionInfo : {
151+ Sessions : [
152+ { SessionNum : 0 , SessionType : 'Race' , SessionLaps : 'unlimited' } ,
153+ ] ,
154+ } ,
155+ } as unknown as Session ) ;
156+
157+ processor . onFrame ( {
158+ SessionNum : { value : [ 0 ] } ,
159+ SessionState : { value : [ 4 ] } ,
160+ SessionTimeRemain : { value : [ 900 ] } ,
161+ CamCarIdx : { value : [ 1 ] } ,
162+ CarIdxLap : { value : [ 10 , 8 ] } ,
163+ CarIdxLapDistPct : { value : [ 0.1 , 0.8 ] } ,
164+ CarIdxPosition : { value : [ 1 , 10 ] } ,
165+ CarIdxBestLapTime : { value : [ 100 , 100 ] } ,
166+ } as unknown as Telemetry ) ;
167+
168+ expect ( processor . snapshot ( ) . calculatedTotalRaceLaps ) . toBeCloseTo ( 17.1 ) ;
169+ } ) ;
170+
79171 it ( 'resets completed laps when the session number changes' , ( ) => {
80172 const processor = new FuelProjectionProcessor ( ) ;
81173 processor . onFrame (
0 commit comments