Skip to content

Commit

Permalink
front: add unit tests for stdcm simulation report sheet
Browse files Browse the repository at this point in the history
  • Loading branch information
Akctarus committed Jul 18, 2024
1 parent 04da47d commit be414ba
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ import { formatDay } from 'utils/date';
import { getStopTime } from 'utils/timeManipulation';

import styles from './SimulationReportStyleSheet';
import { extractSpeedLimit, getStopDurationTime, formatCreationDate } from '../utils';
import {
extractSpeedLimit,
getStopDurationTime,
formatCreationDate,
} from '../utils/formatSimulationReportSheet';

type SimulationReportSheetProps = {
stdcmData: PostStdcmApiResponse;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { formatDateToString, formatDayV2 } from 'utils/date';

import styles from './SimulationReportStyleSheet';
import type { SimulationReportSheetProps } from '../types';
import { extractSpeedLimit, getStopDurationTime } from '../utils';
import { extractSpeedLimit, getStopDurationTime } from '../utils/formatSimulationReportSheet';

const SimulationReportSheetV2 = ({
stdcmData,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import {
generateCodeNumber,
formatCreationDate,
getStopDurationTime,
extractSpeedLimit,
computeStopDepartureTime,
addMinutesToTime,
getStopDurationBetweenTwoPositions,
} from 'applications/stdcm/utils/formatSimulationReportSheet';

describe('generateCodeNumber', () => {
it('should return a formatted string', () => {
const codeNumber = generateCodeNumber();
expect(codeNumber).toMatch(/^\d{2}\d{2}-\d{3}-\d{3}$/);
});
});

// TODO DROP STDCM V1
describe('formatCreationDate', () => {
it('should format the date correctly', () => {
const departure_time = '2024-07-08T10:20:30Z';
const formattedDate = formatCreationDate(departure_time);
expect(formattedDate).toEqual({
day: '08',
month: '07',
year: 2024,
hours: 10,
minutes: 20,
});
});
});

describe('getStopDurationTime', () => {
it('should return correct time format', () => {
expect(getStopDurationTime(30)).toBe('30 sec');
expect(getStopDurationTime(120)).toBe('2 min');
});
});

describe('extractSpeedLimit', () => {
it('should extract the speed limit correctly', () => {
const speedLimitByTag1 = 'Voyageurs 100 - MA100';
const speedLimitByTag2 = 'Voyageurs';
expect(extractSpeedLimit(speedLimitByTag1)).toBe('MA100');
expect(extractSpeedLimit(speedLimitByTag2)).toBe('Voyageurs');
});
});

describe('computeStopDepartureTime', () => {
it('should compute stop departure time correctly for a standard time', () => {
expect(computeStopDepartureTime('10:30', '15:00')).toBe('10:45');
});
it('should compute stop departure time correctly when changing days', () => {
expect(computeStopDepartureTime('23:59', '01:00')).toBe('00:00');
expect(computeStopDepartureTime('23:59', '02:00')).toBe('00:01');
});
});

describe('addMinutesToTime', () => {
it('should should add minutes to time correctly for a standard time', () => {
expect(addMinutesToTime(0, 5, 30)).toBe('00:35');
expect(addMinutesToTime(6, 9, 5)).toBe('06:14');
expect(addMinutesToTime(10, 30, 15)).toBe('10:45');
});
it('should should add minutes to time correctly when changing days', () => {
expect(addMinutesToTime(23, 59, 1)).toBe('00:00');
expect(addMinutesToTime(23, 45, 30)).toBe('00:15');
});
});

describe('getStopDurationBetweenTwoPositions', () => {
it('should return stop duration correctly', () => {
const trainPositions = [1, 2, 2, 3];
const trainTimes = [10000, 120000, 180000];
expect(getStopDurationBetweenTwoPositions(2, trainPositions, trainTimes)).toBe(60000);
expect(getStopDurationBetweenTwoPositions(1, trainPositions, trainTimes)).toBeNull();
});
});
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import type { SimulationResponse } from 'common/api/generatedEditoastApi';
import type { SuggestedOP } from 'modules/trainschedule/components/ManageTrainSchedule/types';

import type { StdcmResultsOperationalPointsList } from './types';
import type { StdcmResultsOperationalPointsList } from '../types';

function generateRandomString(length: number): string {
return Array.from({ length }, () => Math.floor(Math.random() * 10)).join('');
}

// TODO: The number must be calculated from a hash of stdcm inputs (to have a stable number). It is currently generated randomly, so there could be duplicates.
/** TODO The number must be calculated from a hash of stdcm inputs (to have a stable number).
* It is currently generated randomly, so there could be duplicates. Once done, don't forget to update the tests.
*/
export function generateCodeNumber(): string {
const currentDate = new Date();
const year = currentDate.getFullYear().toString().substr(-2);
Expand All @@ -17,7 +19,7 @@ export function generateCodeNumber(): string {
return `${month}${year}-${randomPart1}-${randomPart2}`;
}

// TODO: This function is only used for V1, so it must be deleted when V1 is abandoned.
// TODO DROP STDCM V1
export function formatCreationDate(date: string) {
const creationDate = new Date(date);
const day = creationDate.getDate();
Expand Down Expand Up @@ -67,53 +69,65 @@ function timeStringToSeconds(time: string): number {
}

/**
* Based on a stop arrival time and a stop duration, calculate the departure time on this stop
* @param arrivalTime format: hh:mm (24h format) of the arrival time
* @param duration format: mm:ss of the duration of the stop
* @returns The departure time of the stop in the format hh:mm
*/
function computeStopDepartureTime(hhmm: string, mmss: string): string {
const [hh, mm] = hhmm.split(':').map(Number);
export function computeStopDepartureTime(arrivalTime: string, duration: string): string {
const [hh, mm] = arrivalTime.split(':').map(Number);
const totalSeconds1 = hh * 3600 + mm * 60;
const totalSeconds2 = timeStringToSeconds(mmss);
const totalSeconds2 = timeStringToSeconds(duration);

const totalSeconds = totalSeconds1 + totalSeconds2;
const hours = Math.floor(totalSeconds / 3600);
const hours = Math.floor(totalSeconds / 3600) % 24;
const minutes = Math.floor((totalSeconds % 3600) / 60);

return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`;
}

// Function to add minutes to the departure time
const addMinutesToTime = (baseHour: number, baseMinute: number, minutesToAdd: number): string => {
export function addMinutesToTime(
baseHour: number,
baseMinute: number,
minutesToAdd: number
): string {
const totalMinutes = baseHour * 60 + baseMinute + minutesToAdd;
const finalHour = Math.floor(totalMinutes / 60) % 24;
const finalMinutes = totalMinutes % 60;
return `${String(finalHour).padStart(2, '0')}:${String(finalMinutes).padStart(2, '0')}`;
};
}

const getTimeAtPosition = (
function getTimeAtPosition(
trainPosition: number,
trainPositions: number[],
trainTimes: number[],
trainDepartureHour: number,
trainDepartureMinute: number
): string => {
): string {
const index = trainPositions.findIndex((pos) => pos >= trainPosition);
const timeInMillis = trainTimes[index];
const timeInMinutes = Math.floor(timeInMillis / 60000);
return addMinutesToTime(trainDepartureHour, trainDepartureMinute, timeInMinutes);
};
}

const getStopDurationBetweenToPositions = (
/**
* @param position format: Distance from the beginning of the path in mm
* @param positionsList format: List of positions of a train in mm.
* @param timesList format: List of times in milliseconds corresponding to the positions in trainPositions.
* @returns The duration in milliseconds between the first and last occurrence of the position in the trainPositions array
*/
export function getStopDurationBetweenTwoPositions(
position: number,
trainPositions: number[],
trainTimes: number[]
): number | null => {
const firstIndex = trainPositions.indexOf(position);
const lastIndex = trainPositions.lastIndexOf(position);
positionsList: number[],
timesList: number[]
): number | null {
const firstIndex = positionsList.indexOf(position);
const lastIndex = positionsList.lastIndexOf(position);
if (firstIndex !== -1 && lastIndex !== -1 && firstIndex !== lastIndex) {
return trainTimes[lastIndex] - trainTimes[firstIndex];
return timesList[lastIndex] - timesList[firstIndex];
}
return null;
};
}

export function getOperationalPointsWithTimes(
operationalPoints: SuggestedOP[],
Expand All @@ -136,7 +150,7 @@ export function getOperationalPointsWithTimes(
departureMinute
);

const duration = getStopDurationBetweenToPositions(op.positionOnPath, positions, times);
const duration = getStopDurationBetweenTwoPositions(op.positionOnPath, positions, times);
const durationInSeconds = duration !== null ? duration / 1000 : 0;
const durationToString = secondsToTimeString(durationInSeconds);
const stopEndTime = computeStopDepartureTime(formattedTime, durationToString);
Expand All @@ -147,7 +161,6 @@ export function getOperationalPointsWithTimes(
time: formattedTime,
name: op.name,
ch: op.ch,
stop: op.stopFor,
duration: durationInSeconds,
departureTime,
stopEndTime,
Expand Down
2 changes: 1 addition & 1 deletion front/src/applications/stdcm/views/StdcmResults.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import SpeedSpaceChart from 'modules/simulationResult/components/SpeedSpaceChart
import type { AllowancesSettings } from 'reducers/osrdsimulation/types';

import SimulationReportSheet from '../components/SimulationReportSheet';
import { generateCodeNumber } from '../utils';
import { generateCodeNumber } from '../utils/formatSimulationReportSheet';

type StcdmResultsProps = {
mapCanvas?: string;
Expand Down
5 changes: 4 additions & 1 deletion front/src/applications/stdcm/views/StdcmResultsV2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import type { TimeScaleDomain } from 'modules/simulationResult/types';
import SimulationReportSheetV2 from '../components/SimulationReportSheetV2';
import { STDCM_TRAIN_ID } from '../consts';
import type { StdcmV2Results } from '../types';
import { generateCodeNumber, getOperationalPointsWithTimes } from '../utils';
import {
generateCodeNumber,
getOperationalPointsWithTimes,
} from '../utils/formatSimulationReportSheet';

type StcdmResultsProps = {
mapCanvas?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import { useTranslation } from 'react-i18next';
import type { ManageTrainSchedulePathProperties } from 'applications/operationalStudies/types';
import SimulationReportSheetV2 from 'applications/stdcm/components/SimulationReportSheetV2';
import type { StdcmV2SuccessResponse } from 'applications/stdcm/types';
import { generateCodeNumber, getOperationalPointsWithTimes } from 'applications/stdcm/utils';
import {
generateCodeNumber,
getOperationalPointsWithTimes,
} from 'applications/stdcm/utils/formatSimulationReportSheet';
import { Map } from 'modules/trainschedule/components/ManageTrainSchedule';
import { dateTimeFormatting } from 'utils/date';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {
StdcmResultsOperationalPointsList,
StdcmV2SuccessResponse,
} from 'applications/stdcm/types';
import { getStopDurationTime } from 'applications/stdcm/utils';
import { getStopDurationTime } from 'applications/stdcm/utils/formatSimulationReportSheet';

type SimulationTableProps = {
stdcmData: StdcmV2SuccessResponse;
Expand Down

0 comments on commit be414ba

Please sign in to comment.