Functional Weave
Code in TypeScript

fleet.drivers-hours@1.0.0

vectors.json

9,429 bytes · view raw

[
  {"name":"a legal day: 4h30, 45 minute break, 4h30, then daily rest","args":["2026-09-21","06:00",[{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":660}]],"expect":{"compliant":true,"drivingMinutes":540,"breaches":[]}},
  {"name":"five hours without a break passes the 4h30 limit at 10:30","args":["2026-09-21","06:00",[{"kind":"driving","minutes":300},{"kind":"rest","minutes":45}]],"expect":{"compliant":false,"drivingMinutes":300,"breaches":[{"rule":"break","at":"2026-09-21T10:30","actual":300,"limit":270}]}},
  {"name":"a split break of 15 then 30 minutes is legal","args":["2026-09-21","06:00",[{"kind":"driving","minutes":120},{"kind":"rest","minutes":15},{"kind":"driving","minutes":150},{"kind":"rest","minutes":30},{"kind":"driving","minutes":240}]],"expect":{"compliant":true,"drivingMinutes":510,"breaches":[]}},
  {"name":"30 then 15 is not a split break: the second part must be at least 30","args":["2026-09-21","06:00",[{"kind":"driving","minutes":120},{"kind":"rest","minutes":30},{"kind":"driving","minutes":150},{"kind":"rest","minutes":15},{"kind":"driving","minutes":60}]],"expect":{"compliant":false,"drivingMinutes":330,"breaches":[{"rule":"break","at":"2026-09-21T11:15","actual":330,"limit":270}]}},
  {"name":"an hour of other work is not a break","args":["2026-09-21","06:00",[{"kind":"driving","minutes":200},{"kind":"work","minutes":60},{"kind":"driving","minutes":100}]],"expect":{"compliant":false,"drivingMinutes":300,"breaches":[{"rule":"break","at":"2026-09-21T11:30","actual":300,"limit":270}]}},
  {"name":"a period of availability is not a break","args":["2026-09-21","06:00",[{"kind":"driving","minutes":270},{"kind":"availability","minutes":45},{"kind":"driving","minutes":10}]],"expect":{"compliant":false,"drivingMinutes":280,"breaches":[{"rule":"break","at":"2026-09-21T11:15","actual":280,"limit":270}]}},
  {"name":"two rests recorded back to back are one 45 minute break","args":["2026-09-21","06:00",[{"kind":"driving","minutes":270},{"kind":"rest","minutes":20},{"kind":"rest","minutes":25},{"kind":"driving","minutes":270}]],"expect":{"compliant":true,"drivingMinutes":540,"breaches":[]}},
  {"name":"a 15 minute rest before any driving is not the first part of a split break","args":["2026-09-21","06:00",[{"kind":"rest","minutes":15},{"kind":"driving","minutes":200},{"kind":"rest","minutes":30},{"kind":"driving","minutes":100}]],"expect":{"compliant":false,"drivingMinutes":300,"breaches":[{"rule":"break","at":"2026-09-21T11:15","actual":300,"limit":270}]}},
  {"name":"10h30 of driving in a day passes the 10 hour ceiling at 16:30","args":["2026-09-21","05:00",[{"kind":"driving","minutes":240},{"kind":"rest","minutes":45},{"kind":"driving","minutes":240},{"kind":"rest","minutes":45},{"kind":"driving","minutes":150}]],"expect":{"compliant":false,"drivingMinutes":630,"breaches":[{"rule":"daily-driving","at":"2026-09-21T16:30","actual":630,"limit":600}]}},
  {"name":"two 10 hour days in a week are allowed","args":["2026-09-21","06:00",[{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":60},{"kind":"rest","minutes":750},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":60}]],"expect":{"compliant":true,"drivingMinutes":1200,"breaches":[]}},
  {"name":"a third 10 hour day in the same fixed week breaks the 9 hour limit","args":["2026-09-21","06:00",[{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":60},{"kind":"rest","minutes":750},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":60},{"kind":"rest","minutes":750},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":60}]],"expect":{"compliant":false,"drivingMinutes":1800,"breaches":[{"rule":"daily-driving","at":"2026-09-23T16:30","actual":600,"limit":540}]}},
  {"name":"six 9 hour days and 3 hours on Sunday pass 56 hours at 08:00 on Sunday","args":["2026-09-21","06:00",[{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":180}]],"expect":{"compliant":false,"drivingMinutes":3420,"breaches":[{"rule":"weekly-driving","at":"2026-09-27T08:00","actual":3420,"limit":3360}]}},
  {"name":"driving across Sunday midnight is split between the two fixed weeks","args":["2026-09-21","06:00",[{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":1815},{"kind":"driving","minutes":240}]],"expect":{"compliant":true,"drivingMinutes":3480,"breaches":[]}},
  {"name":"54 hours then 36 hours is exactly 90; half an hour more passes the fortnightly limit","args":["2026-09-21","06:00",[{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":2295},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":270},{"kind":"rest","minutes":45},{"kind":"driving","minutes":270},{"kind":"rest","minutes":855},{"kind":"driving","minutes":30}]],"expect":{"compliant":false,"drivingMinutes":5430,"breaches":[{"rule":"fortnightly-driving","at":"2026-10-02T06:00","actual":5430,"limit":5400}]}},
  {"name":"breaches come back in time order","args":["2026-09-21","06:00",[{"kind":"driving","minutes":300},{"kind":"rest","minutes":45},{"kind":"driving","minutes":310}]],"expect":{"compliant":false,"drivingMinutes":610,"breaches":[{"rule":"break","at":"2026-09-21T10:30","actual":300,"limit":270},{"rule":"break","at":"2026-09-21T16:15","actual":310,"limit":270},{"rule":"daily-driving","at":"2026-09-21T16:45","actual":610,"limit":600}]}},
  {"name":"no activities is compliant","args":["2026-09-21","06:00",[]],"expect":{"compliant":true,"drivingMinutes":0,"breaches":[]}},
  {"name":"a start time of 24:00 is refused","args":["2026-09-21","24:00",[{"kind":"driving","minutes":60}]],"expectError":"startTime must be HH:MM, 24-hour"},
  {"name":"a date that is not ISO is refused","args":["21/09/2026","06:00",[{"kind":"driving","minutes":60}]],"expectError":"startDate must be an ISO date (YYYY-MM-DD)"},
  {"name":"an unknown activity kind is refused","args":["2026-09-21","06:00",[{"kind":"sleeping","minutes":60}]],"expectError":"unknown activity kind \"sleeping\""},
  {"name":"a zero-length activity is refused","args":["2026-09-21","06:00",[{"kind":"driving","minutes":0}]],"expectError":"minutes must be a whole number of at least 1"},
  {"name":"a fractional minute is refused","args":["2026-09-21","06:00",[{"kind":"driving","minutes":30.5}]],"expectError":"minutes must be a whole number of at least 1"},
  {"name":"dates before Regulation 561/2006 applied (11 April 2007) are refused","args":["2007-04-10","06:00",[{"kind":"driving","minutes":60}]],"expectError":"no drivers' hours limit"}
]