compute journeys with tests
This commit is contained in:
parent
467d8a84f8
commit
d8df086c6d
|
@ -20,7 +20,7 @@ export abstract class Algorithm {
|
|||
for (const processor of this.processors) {
|
||||
this.candidates = await processor.execute(this.candidates);
|
||||
}
|
||||
console.log(JSON.stringify(this.candidates, null, 2));
|
||||
// console.log(JSON.stringify(this.candidates, null, 2));
|
||||
return this.candidates.map((candidate: CandidateEntity) =>
|
||||
MatchEntity.create({ adId: candidate.id }),
|
||||
);
|
||||
|
|
|
@ -63,14 +63,16 @@ export class CalendarTools {
|
|||
};
|
||||
|
||||
/**
|
||||
* Returns a date from a date and time as strings, adding optional seconds
|
||||
* Returns a date from a date (as a date) and a time (as a string), adding optional seconds
|
||||
*/
|
||||
static datetimeFromString = (
|
||||
date: string,
|
||||
static datetimeWithSeconds = (
|
||||
date: Date,
|
||||
time: string,
|
||||
additionalSeconds = 0,
|
||||
): Date => {
|
||||
const datetime = new Date(`${date}T${time}:00Z`);
|
||||
const datetime: Date = new Date(date);
|
||||
datetime.setUTCHours(parseInt(time.split(':')[0]));
|
||||
datetime.setUTCMinutes(parseInt(time.split(':')[1]));
|
||||
datetime.setUTCSeconds(additionalSeconds);
|
||||
return datetime;
|
||||
};
|
||||
|
@ -79,7 +81,7 @@ export class CalendarTools {
|
|||
* Returns dates from a day and time based on unix epoch day
|
||||
* (1970-01-01 is day 4)
|
||||
* The method returns an array of dates because for edges (day 0 and 6)
|
||||
* we need to return 2 possibilities
|
||||
* we need to return 2 possibilities : one for the previous week, one for the next week
|
||||
*/
|
||||
static epochDaysFromTime = (weekDay: number, time: string): Date[] => {
|
||||
if (weekDay < 0 || weekDay > 6)
|
||||
|
|
|
@ -46,6 +46,7 @@ export class CandidateEntity extends AggregateRoot<CandidateProps> {
|
|||
|
||||
/**
|
||||
* Create the journeys based on the driver schedule (the driver 'drives' the carpool !)
|
||||
* This is a tedious process : additional information can be found in deeper methods !
|
||||
*/
|
||||
createJourneys = (): CandidateEntity => {
|
||||
this.props.journeys = this.props.driverSchedule.map(
|
||||
|
@ -90,6 +91,13 @@ export class CandidateEntity extends AggregateRoot<CandidateProps> {
|
|||
this._createJourneyItem(carpoolPathItem, index, driverScheduleItem),
|
||||
) as JourneyItem[];
|
||||
|
||||
/**
|
||||
* Create a journey item based on a carpool path item and driver schedule item
|
||||
* The stepIndex is used to get the duration to reach the carpool path item
|
||||
* from the steps prop (computed previously by a georouter)
|
||||
* There MUST be a one/one relation between the carpool path items indexes
|
||||
* and the steps indexes.
|
||||
*/
|
||||
private _createJourneyItem = (
|
||||
carpoolPathItem: CarpoolPathItem,
|
||||
stepIndex: number,
|
||||
|
@ -123,42 +131,55 @@ export class CandidateEntity extends AggregateRoot<CandidateProps> {
|
|||
actor.target == Target.START
|
||||
? 0
|
||||
: duration;
|
||||
const firstDate: Date = CalendarTools.firstDate(
|
||||
scheduleItem.day,
|
||||
this.props.dateInterval,
|
||||
);
|
||||
const lastDate: Date = CalendarTools.lastDate(
|
||||
scheduleItem.day,
|
||||
this.props.dateInterval,
|
||||
);
|
||||
return new ActorTime({
|
||||
role: actor.role,
|
||||
target: actor.target,
|
||||
firstDatetime: CalendarTools.datetimeFromString(
|
||||
this.props.dateInterval.lowerDate,
|
||||
firstDatetime: CalendarTools.datetimeWithSeconds(
|
||||
firstDate,
|
||||
scheduleItem.time,
|
||||
effectiveDuration,
|
||||
),
|
||||
firstMinDatetime: CalendarTools.datetimeFromString(
|
||||
this.props.dateInterval.lowerDate,
|
||||
firstMinDatetime: CalendarTools.datetimeWithSeconds(
|
||||
firstDate,
|
||||
scheduleItem.time,
|
||||
-scheduleItem.margin + effectiveDuration,
|
||||
),
|
||||
firstMaxDatetime: CalendarTools.datetimeFromString(
|
||||
this.props.dateInterval.lowerDate,
|
||||
firstMaxDatetime: CalendarTools.datetimeWithSeconds(
|
||||
firstDate,
|
||||
scheduleItem.time,
|
||||
scheduleItem.margin + effectiveDuration,
|
||||
),
|
||||
lastDatetime: CalendarTools.datetimeFromString(
|
||||
this.props.dateInterval.higherDate,
|
||||
lastDatetime: CalendarTools.datetimeWithSeconds(
|
||||
lastDate,
|
||||
scheduleItem.time,
|
||||
effectiveDuration,
|
||||
),
|
||||
lastMinDatetime: CalendarTools.datetimeFromString(
|
||||
this.props.dateInterval.higherDate,
|
||||
lastMinDatetime: CalendarTools.datetimeWithSeconds(
|
||||
lastDate,
|
||||
scheduleItem.time,
|
||||
-scheduleItem.margin + effectiveDuration,
|
||||
),
|
||||
lastMaxDatetime: CalendarTools.datetimeFromString(
|
||||
this.props.dateInterval.higherDate,
|
||||
lastMaxDatetime: CalendarTools.datetimeWithSeconds(
|
||||
lastDate,
|
||||
scheduleItem.time,
|
||||
scheduleItem.margin + effectiveDuration,
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the closest (in time) passenger schedule item for a given driver schedule item
|
||||
* This is mandatory as we can't rely only on the day of the schedule item :
|
||||
* items on different days can match when playing with margins around midnight
|
||||
*/
|
||||
private _closestPassengerScheduleItem = (
|
||||
driverScheduleItem: ScheduleItem,
|
||||
): ScheduleItem =>
|
||||
|
@ -179,8 +200,12 @@ export class CandidateEntity extends AggregateRoot<CandidateProps> {
|
|||
: currentScheduleItemGap,
|
||||
).scheduleItem;
|
||||
|
||||
/**
|
||||
* Find the passenger schedule item with the minimum duration between a given date and the dates of the passenger schedule
|
||||
*/
|
||||
private _minPassengerScheduleItemGapForDate = (date: Date): ScheduleItemGap =>
|
||||
this.props.passengerSchedule
|
||||
// first map the passenger schedule to "real" dates (we use unix epoch date as base)
|
||||
.map(
|
||||
(scheduleItem: ScheduleItem) =>
|
||||
<ScheduleItemRange>{
|
||||
|
@ -191,16 +216,21 @@ export class CandidateEntity extends AggregateRoot<CandidateProps> {
|
|||
),
|
||||
},
|
||||
)
|
||||
// then compute the duration in seconds to the given date
|
||||
// for each "real" date computed in step 1
|
||||
.map((scheduleItemRange: ScheduleItemRange) => ({
|
||||
scheduleItem: scheduleItemRange.scheduleItem,
|
||||
gap: scheduleItemRange.range
|
||||
// compute the duration
|
||||
.map((scheduleDate: Date) =>
|
||||
Math.round(Math.abs(scheduleDate.getTime() - date.getTime())),
|
||||
)
|
||||
// keep the lowest duration
|
||||
.reduce((previousGap: number, currentGap: number) =>
|
||||
previousGap < currentGap ? previousGap : currentGap,
|
||||
),
|
||||
}))
|
||||
// finally, keep the passenger schedule item with the lowest duration
|
||||
.reduce(
|
||||
(
|
||||
previousScheduleItemGap: ScheduleItemGap,
|
||||
|
|
|
@ -90,27 +90,26 @@ describe('Calendar tools service', () => {
|
|||
|
||||
describe('Datetime from string', () => {
|
||||
it('should return a date with time from a string without additional seconds', () => {
|
||||
const datetime: Date = CalendarTools.datetimeFromString(
|
||||
'2023-09-01',
|
||||
const datetime: Date = CalendarTools.datetimeWithSeconds(
|
||||
new Date('2023-09-01'),
|
||||
'07:12',
|
||||
);
|
||||
expect(datetime.getUTCMinutes()).toBe(12);
|
||||
});
|
||||
it('should return a date with time from a string with additional seconds', () => {
|
||||
const datetime: Date = CalendarTools.datetimeFromString(
|
||||
'2023-09-01',
|
||||
const datetime: Date = CalendarTools.datetimeWithSeconds(
|
||||
new Date('2023-09-01'),
|
||||
'07:12',
|
||||
60,
|
||||
);
|
||||
expect(datetime.getUTCMinutes()).toBe(13);
|
||||
});
|
||||
it('should return a date with time from a string with negative additional seconds', () => {
|
||||
const datetime: Date = CalendarTools.datetimeFromString(
|
||||
'2023-09-01',
|
||||
const datetime: Date = CalendarTools.datetimeWithSeconds(
|
||||
new Date('2023-09-01'),
|
||||
'07:00',
|
||||
-60,
|
||||
);
|
||||
console.log(datetime);
|
||||
expect(datetime.getUTCHours()).toBe(6);
|
||||
expect(datetime.getUTCMinutes()).toBe(59);
|
||||
});
|
||||
|
|
|
@ -1,7 +1,244 @@
|
|||
import { Role } from '@modules/ad/core/domain/ad.types';
|
||||
import { CandidateEntity } from '@modules/ad/core/domain/candidate.entity';
|
||||
import { Target } from '@modules/ad/core/domain/candidate.types';
|
||||
import {
|
||||
SpacetimeDetourRatio,
|
||||
Target,
|
||||
} from '@modules/ad/core/domain/candidate.types';
|
||||
import { Actor } from '@modules/ad/core/domain/value-objects/actor.value-object';
|
||||
import { CarpoolPathItemProps } from '@modules/ad/core/domain/value-objects/carpool-path-item.value-object';
|
||||
import { Journey } from '@modules/ad/core/domain/value-objects/journey.value-object';
|
||||
import { PointProps } from '@modules/ad/core/domain/value-objects/point.value-object';
|
||||
import { ScheduleItemProps } from '@modules/ad/core/domain/value-objects/schedule-item.value-object';
|
||||
import { StepProps } from '@modules/ad/core/domain/value-objects/step.value-object';
|
||||
|
||||
const waypointsSet1: PointProps[] = [
|
||||
{
|
||||
lat: 48.678454,
|
||||
lon: 6.189745,
|
||||
},
|
||||
{
|
||||
lat: 48.84877,
|
||||
lon: 2.398457,
|
||||
},
|
||||
];
|
||||
|
||||
const waypointsSet2: PointProps[] = [
|
||||
{
|
||||
lat: 48.689445,
|
||||
lon: 6.17651,
|
||||
},
|
||||
{
|
||||
lat: 48.8566,
|
||||
lon: 2.3522,
|
||||
},
|
||||
];
|
||||
|
||||
const schedule1: ScheduleItemProps[] = [
|
||||
{
|
||||
day: 1,
|
||||
time: '07:00',
|
||||
margin: 900,
|
||||
},
|
||||
];
|
||||
|
||||
const schedule2: ScheduleItemProps[] = [
|
||||
{
|
||||
day: 1,
|
||||
time: '07:10',
|
||||
margin: 900,
|
||||
},
|
||||
];
|
||||
|
||||
const schedule3: ScheduleItemProps[] = [
|
||||
{
|
||||
day: 1,
|
||||
time: '06:30',
|
||||
margin: 900,
|
||||
},
|
||||
{
|
||||
day: 2,
|
||||
time: '06:30',
|
||||
margin: 900,
|
||||
},
|
||||
{
|
||||
day: 3,
|
||||
time: '06:00',
|
||||
margin: 900,
|
||||
},
|
||||
{
|
||||
day: 4,
|
||||
time: '06:30',
|
||||
margin: 900,
|
||||
},
|
||||
{
|
||||
day: 5,
|
||||
time: '06:30',
|
||||
margin: 900,
|
||||
},
|
||||
];
|
||||
|
||||
const schedule4: ScheduleItemProps[] = [
|
||||
{
|
||||
day: 1,
|
||||
time: '06:50',
|
||||
margin: 900,
|
||||
},
|
||||
{
|
||||
day: 2,
|
||||
time: '06:50',
|
||||
margin: 900,
|
||||
},
|
||||
{
|
||||
day: 4,
|
||||
time: '06:50',
|
||||
margin: 900,
|
||||
},
|
||||
{
|
||||
day: 5,
|
||||
time: '06:50',
|
||||
margin: 900,
|
||||
},
|
||||
];
|
||||
|
||||
const schedule5: ScheduleItemProps[] = [
|
||||
{
|
||||
day: 0,
|
||||
time: '00:10',
|
||||
margin: 900,
|
||||
},
|
||||
{
|
||||
day: 1,
|
||||
time: '07:05',
|
||||
margin: 900,
|
||||
},
|
||||
];
|
||||
|
||||
const schedule6: ScheduleItemProps[] = [
|
||||
{
|
||||
day: 1,
|
||||
time: '23:10',
|
||||
margin: 900,
|
||||
},
|
||||
{
|
||||
day: 6,
|
||||
time: '23:45',
|
||||
margin: 900,
|
||||
},
|
||||
];
|
||||
|
||||
const spacetimeDetourRatio: SpacetimeDetourRatio = {
|
||||
maxDistanceDetourRatio: 0.3,
|
||||
maxDurationDetourRatio: 0.3,
|
||||
};
|
||||
|
||||
const carpoolPath1: CarpoolPathItemProps[] = [
|
||||
{
|
||||
lat: 48.689445,
|
||||
lon: 6.17651,
|
||||
actors: [
|
||||
new Actor({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
}),
|
||||
new Actor({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.START,
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
lat: 48.8566,
|
||||
lon: 2.3522,
|
||||
actors: [
|
||||
new Actor({
|
||||
role: Role.DRIVER,
|
||||
target: Target.FINISH,
|
||||
}),
|
||||
new Actor({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.FINISH,
|
||||
}),
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const carpoolPath2: CarpoolPathItemProps[] = [
|
||||
{
|
||||
lat: 48.689445,
|
||||
lon: 6.17651,
|
||||
actors: [
|
||||
new Actor({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
lat: 48.678451,
|
||||
lon: 6.168784,
|
||||
actors: [
|
||||
new Actor({
|
||||
role: Role.DRIVER,
|
||||
target: Target.NEUTRAL,
|
||||
}),
|
||||
new Actor({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.START,
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
lat: 48.848715,
|
||||
lon: 2.36985,
|
||||
actors: [
|
||||
new Actor({
|
||||
role: Role.DRIVER,
|
||||
target: Target.NEUTRAL,
|
||||
}),
|
||||
new Actor({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.FINISH,
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
lat: 48.8566,
|
||||
lon: 2.3522,
|
||||
actors: [
|
||||
new Actor({
|
||||
role: Role.DRIVER,
|
||||
target: Target.FINISH,
|
||||
}),
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const steps: StepProps[] = [
|
||||
{
|
||||
lat: 48.689445,
|
||||
lon: 6.17651,
|
||||
duration: 0,
|
||||
distance: 0,
|
||||
},
|
||||
{
|
||||
lat: 48.678451,
|
||||
lon: 6.168784,
|
||||
duration: 1254,
|
||||
distance: 33462,
|
||||
},
|
||||
{
|
||||
lat: 48.848715,
|
||||
lon: 2.36985,
|
||||
duration: 12477,
|
||||
distance: 343654,
|
||||
},
|
||||
{
|
||||
lat: 48.8566,
|
||||
lon: 2.3522,
|
||||
duration: 13548,
|
||||
distance: 350145,
|
||||
},
|
||||
];
|
||||
|
||||
describe('Candidate entity', () => {
|
||||
it('should create a new candidate entity', () => {
|
||||
|
@ -12,46 +249,13 @@ describe('Candidate entity', () => {
|
|||
lowerDate: '2023-08-28',
|
||||
higherDate: '2023-08-28',
|
||||
},
|
||||
driverWaypoints: [
|
||||
{
|
||||
lat: 48.678454,
|
||||
lon: 6.189745,
|
||||
},
|
||||
{
|
||||
lat: 48.84877,
|
||||
lon: 2.398457,
|
||||
},
|
||||
],
|
||||
passengerWaypoints: [
|
||||
{
|
||||
lat: 48.689445,
|
||||
lon: 6.17651,
|
||||
},
|
||||
{
|
||||
lat: 48.8566,
|
||||
lon: 2.3522,
|
||||
},
|
||||
],
|
||||
driverWaypoints: waypointsSet1,
|
||||
passengerWaypoints: waypointsSet2,
|
||||
driverDistance: 350145,
|
||||
driverDuration: 13548,
|
||||
driverSchedule: [
|
||||
{
|
||||
day: 0,
|
||||
time: '07:00',
|
||||
margin: 900,
|
||||
},
|
||||
],
|
||||
passengerSchedule: [
|
||||
{
|
||||
day: 0,
|
||||
time: '07:10',
|
||||
margin: 900,
|
||||
},
|
||||
],
|
||||
spacetimeDetourRatio: {
|
||||
maxDistanceDetourRatio: 0.3,
|
||||
maxDurationDetourRatio: 0.3,
|
||||
},
|
||||
driverSchedule: schedule1,
|
||||
passengerSchedule: schedule2,
|
||||
spacetimeDetourRatio,
|
||||
});
|
||||
expect(candidateEntity.id.length).toBe(36);
|
||||
});
|
||||
|
@ -64,76 +268,14 @@ describe('Candidate entity', () => {
|
|||
lowerDate: '2023-08-28',
|
||||
higherDate: '2023-08-28',
|
||||
},
|
||||
driverWaypoints: [
|
||||
{
|
||||
lat: 48.689445,
|
||||
lon: 6.17651,
|
||||
},
|
||||
{
|
||||
lat: 48.8566,
|
||||
lon: 2.3522,
|
||||
},
|
||||
],
|
||||
passengerWaypoints: [
|
||||
{
|
||||
lat: 48.689445,
|
||||
lon: 6.17651,
|
||||
},
|
||||
{
|
||||
lat: 48.8566,
|
||||
lon: 2.3522,
|
||||
},
|
||||
],
|
||||
driverWaypoints: waypointsSet2,
|
||||
passengerWaypoints: waypointsSet2,
|
||||
driverDistance: 350145,
|
||||
driverDuration: 13548,
|
||||
driverSchedule: [
|
||||
{
|
||||
day: 0,
|
||||
time: '07:00',
|
||||
margin: 900,
|
||||
},
|
||||
],
|
||||
passengerSchedule: [
|
||||
{
|
||||
day: 0,
|
||||
time: '07:10',
|
||||
margin: 900,
|
||||
},
|
||||
],
|
||||
spacetimeDetourRatio: {
|
||||
maxDistanceDetourRatio: 0.3,
|
||||
maxDurationDetourRatio: 0.3,
|
||||
},
|
||||
}).setCarpoolPath([
|
||||
{
|
||||
lat: 48.689445,
|
||||
lon: 6.17651,
|
||||
actors: [
|
||||
new Actor({
|
||||
role: Role.DRIVER,
|
||||
target: Target.START,
|
||||
}),
|
||||
new Actor({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.START,
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
lat: 48.8566,
|
||||
lon: 2.3522,
|
||||
actors: [
|
||||
new Actor({
|
||||
role: Role.DRIVER,
|
||||
target: Target.FINISH,
|
||||
}),
|
||||
new Actor({
|
||||
role: Role.PASSENGER,
|
||||
target: Target.FINISH,
|
||||
}),
|
||||
],
|
||||
},
|
||||
]);
|
||||
driverSchedule: schedule1,
|
||||
passengerSchedule: schedule2,
|
||||
spacetimeDetourRatio,
|
||||
}).setCarpoolPath(carpoolPath1);
|
||||
expect(candidateEntity.getProps().carpoolPath).toHaveLength(2);
|
||||
});
|
||||
|
||||
|
@ -145,46 +287,13 @@ describe('Candidate entity', () => {
|
|||
lowerDate: '2023-08-28',
|
||||
higherDate: '2023-08-28',
|
||||
},
|
||||
driverWaypoints: [
|
||||
{
|
||||
lat: 48.678454,
|
||||
lon: 6.189745,
|
||||
},
|
||||
{
|
||||
lat: 48.84877,
|
||||
lon: 2.398457,
|
||||
},
|
||||
],
|
||||
passengerWaypoints: [
|
||||
{
|
||||
lat: 48.689445,
|
||||
lon: 6.17651,
|
||||
},
|
||||
{
|
||||
lat: 48.8566,
|
||||
lon: 2.3522,
|
||||
},
|
||||
],
|
||||
driverWaypoints: waypointsSet1,
|
||||
passengerWaypoints: waypointsSet2,
|
||||
driverDistance: 350145,
|
||||
driverDuration: 13548,
|
||||
driverSchedule: [
|
||||
{
|
||||
day: 0,
|
||||
time: '07:00',
|
||||
margin: 900,
|
||||
},
|
||||
],
|
||||
passengerSchedule: [
|
||||
{
|
||||
day: 0,
|
||||
time: '07:10',
|
||||
margin: 900,
|
||||
},
|
||||
],
|
||||
spacetimeDetourRatio: {
|
||||
maxDistanceDetourRatio: 0.3,
|
||||
maxDurationDetourRatio: 0.3,
|
||||
},
|
||||
driverSchedule: schedule1,
|
||||
passengerSchedule: schedule2,
|
||||
spacetimeDetourRatio,
|
||||
}).setMetrics(352688, 14587);
|
||||
expect(candidateEntity.getProps().distance).toBe(352688);
|
||||
expect(candidateEntity.getProps().duration).toBe(14587);
|
||||
|
@ -199,46 +308,13 @@ describe('Candidate entity', () => {
|
|||
lowerDate: '2023-08-28',
|
||||
higherDate: '2023-08-28',
|
||||
},
|
||||
driverWaypoints: [
|
||||
{
|
||||
lat: 48.678454,
|
||||
lon: 6.189745,
|
||||
},
|
||||
{
|
||||
lat: 48.84877,
|
||||
lon: 2.398457,
|
||||
},
|
||||
],
|
||||
passengerWaypoints: [
|
||||
{
|
||||
lat: 48.849445,
|
||||
lon: 6.68651,
|
||||
},
|
||||
{
|
||||
lat: 47.18746,
|
||||
lon: 2.89742,
|
||||
},
|
||||
],
|
||||
driverWaypoints: waypointsSet1,
|
||||
passengerWaypoints: waypointsSet2,
|
||||
driverDistance: 350145,
|
||||
driverDuration: 13548,
|
||||
driverSchedule: [
|
||||
{
|
||||
day: 0,
|
||||
time: '07:00',
|
||||
margin: 900,
|
||||
},
|
||||
],
|
||||
passengerSchedule: [
|
||||
{
|
||||
day: 0,
|
||||
time: '07:10',
|
||||
margin: 900,
|
||||
},
|
||||
],
|
||||
spacetimeDetourRatio: {
|
||||
maxDistanceDetourRatio: 0.3,
|
||||
maxDurationDetourRatio: 0.3,
|
||||
},
|
||||
driverSchedule: schedule1,
|
||||
passengerSchedule: schedule2,
|
||||
spacetimeDetourRatio,
|
||||
}).setMetrics(458690, 13980);
|
||||
expect(candidateEntity.isDetourValid()).toBeFalsy();
|
||||
});
|
||||
|
@ -250,52 +326,120 @@ describe('Candidate entity', () => {
|
|||
lowerDate: '2023-08-28',
|
||||
higherDate: '2023-08-28',
|
||||
},
|
||||
driverWaypoints: [
|
||||
{
|
||||
lat: 48.678454,
|
||||
lon: 6.189745,
|
||||
},
|
||||
{
|
||||
lat: 48.84877,
|
||||
lon: 2.398457,
|
||||
},
|
||||
],
|
||||
passengerWaypoints: [
|
||||
{
|
||||
lat: 48.849445,
|
||||
lon: 6.68651,
|
||||
},
|
||||
{
|
||||
lat: 47.18746,
|
||||
lon: 2.89742,
|
||||
},
|
||||
],
|
||||
driverWaypoints: waypointsSet1,
|
||||
passengerWaypoints: waypointsSet2,
|
||||
driverDistance: 350145,
|
||||
driverDuration: 13548,
|
||||
driverSchedule: [
|
||||
{
|
||||
day: 0,
|
||||
time: '07:00',
|
||||
margin: 900,
|
||||
},
|
||||
],
|
||||
passengerSchedule: [
|
||||
{
|
||||
day: 0,
|
||||
time: '07:10',
|
||||
margin: 900,
|
||||
},
|
||||
],
|
||||
spacetimeDetourRatio: {
|
||||
maxDistanceDetourRatio: 0.3,
|
||||
maxDurationDetourRatio: 0.3,
|
||||
},
|
||||
driverSchedule: schedule1,
|
||||
passengerSchedule: schedule2,
|
||||
spacetimeDetourRatio,
|
||||
}).setMetrics(352368, 18314);
|
||||
expect(candidateEntity.isDetourValid()).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('Journeys', () => {
|
||||
it('should create journeys', () => {});
|
||||
it('should create journeys for a single date', () => {
|
||||
const candidateEntity: CandidateEntity = CandidateEntity.create({
|
||||
id: '5600ccfb-ab69-4d03-aa30-0fbe84fcedc0',
|
||||
role: Role.PASSENGER,
|
||||
dateInterval: {
|
||||
lowerDate: '2023-08-28',
|
||||
higherDate: '2023-08-28',
|
||||
},
|
||||
driverWaypoints: waypointsSet1,
|
||||
passengerWaypoints: waypointsSet2,
|
||||
driverDistance: 350145,
|
||||
driverDuration: 13548,
|
||||
driverSchedule: schedule1,
|
||||
passengerSchedule: schedule2,
|
||||
spacetimeDetourRatio,
|
||||
})
|
||||
.setCarpoolPath(carpoolPath2)
|
||||
.setSteps(steps)
|
||||
.createJourneys();
|
||||
expect(candidateEntity.getProps().journeys).toHaveLength(1);
|
||||
});
|
||||
it('should create journeys for multiple dates', () => {
|
||||
const candidateEntity: CandidateEntity = CandidateEntity.create({
|
||||
id: '5600ccfb-ab69-4d03-aa30-0fbe84fcedc0',
|
||||
role: Role.PASSENGER,
|
||||
dateInterval: {
|
||||
lowerDate: '2023-09-01',
|
||||
higherDate: '2024-09-01',
|
||||
},
|
||||
driverWaypoints: waypointsSet1,
|
||||
passengerWaypoints: waypointsSet2,
|
||||
driverDistance: 350145,
|
||||
driverDuration: 13548,
|
||||
driverSchedule: schedule3,
|
||||
passengerSchedule: schedule4,
|
||||
spacetimeDetourRatio,
|
||||
})
|
||||
.setCarpoolPath(carpoolPath2)
|
||||
.setSteps(steps)
|
||||
.createJourneys();
|
||||
expect(candidateEntity.getProps().journeys).toHaveLength(5);
|
||||
expect(
|
||||
(
|
||||
candidateEntity.getProps().journeys as Journey[]
|
||||
)[0].firstDate.getDate(),
|
||||
).toBe(4);
|
||||
expect(
|
||||
(
|
||||
candidateEntity.getProps().journeys as Journey[]
|
||||
)[0].journeyItems[1].actorTimes[1].firstMinDatetime.getDate(),
|
||||
).toBe(4);
|
||||
expect(
|
||||
(
|
||||
candidateEntity.getProps().journeys as Journey[]
|
||||
)[1].journeyItems[1].actorTimes[1].firstMinDatetime.getDate(),
|
||||
).toBe(5);
|
||||
});
|
||||
it('should create journeys for multiple dates, including week edges (saturday/sunday)', () => {
|
||||
const candidateEntity: CandidateEntity = CandidateEntity.create({
|
||||
id: '5600ccfb-ab69-4d03-aa30-0fbe84fcedc0',
|
||||
role: Role.PASSENGER,
|
||||
dateInterval: {
|
||||
lowerDate: '2023-09-01',
|
||||
higherDate: '2024-09-01',
|
||||
},
|
||||
driverWaypoints: waypointsSet1,
|
||||
passengerWaypoints: waypointsSet2,
|
||||
driverDistance: 350145,
|
||||
driverDuration: 13548,
|
||||
driverSchedule: schedule5,
|
||||
passengerSchedule: schedule6,
|
||||
spacetimeDetourRatio,
|
||||
})
|
||||
.setCarpoolPath(carpoolPath2)
|
||||
.setSteps(steps)
|
||||
.createJourneys();
|
||||
expect(candidateEntity.getProps().journeys).toHaveLength(2);
|
||||
expect(
|
||||
(candidateEntity.getProps().journeys as Journey[])[0].journeyItems[1]
|
||||
.actorTimes[0].target,
|
||||
).toBe(Target.NEUTRAL);
|
||||
expect(
|
||||
(
|
||||
candidateEntity.getProps().journeys as Journey[]
|
||||
)[0].journeyItems[1].actorTimes[0].firstDatetime.getUTCHours(),
|
||||
).toBe(0);
|
||||
expect(
|
||||
(
|
||||
candidateEntity.getProps().journeys as Journey[]
|
||||
)[0].journeyItems[1].actorTimes[0].firstDatetime.getUTCMinutes(),
|
||||
).toBe(30);
|
||||
expect(
|
||||
(
|
||||
candidateEntity.getProps().journeys as Journey[]
|
||||
)[0].journeyItems[1].actorTimes[1].firstMinDatetime.getUTCHours(),
|
||||
).toBe(23);
|
||||
expect(
|
||||
(
|
||||
candidateEntity.getProps().journeys as Journey[]
|
||||
)[0].journeyItems[1].actorTimes[1].firstMinDatetime.getUTCMinutes(),
|
||||
).toBe(30);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue