2018-04-18 20:08:47 +02:00
|
|
|
'use strict'
|
|
|
|
|
|
|
|
const a = require('assert')
|
|
|
|
const {defaultValidators} = require('validate-fptf')
|
2018-04-25 12:48:05 +02:00
|
|
|
const anyOf = require('validate-fptf/lib/any-of')
|
2018-04-18 20:08:47 +02:00
|
|
|
|
2018-05-14 00:35:21 +02:00
|
|
|
const {assertValidWhen} = require('./util')
|
2018-04-18 20:08:47 +02:00
|
|
|
|
|
|
|
const isObj = o => o !== null && 'object' === typeof o && !Array.isArray(o)
|
|
|
|
const is = val => val !== null && val !== undefined
|
|
|
|
|
|
|
|
const createValidateStation = (cfg) => {
|
2018-04-25 12:48:05 +02:00
|
|
|
const validateStation = (val, s, name = 'station') => {
|
|
|
|
defaultValidators.station(val, s, name)
|
2018-04-18 20:08:47 +02:00
|
|
|
|
|
|
|
if (!cfg.stationCoordsOptional) {
|
|
|
|
a.ok(is(s.location), `missing ${name}.location`)
|
|
|
|
}
|
|
|
|
a.ok(isObj(s.products), name + '.products must be an object')
|
|
|
|
for (let product of cfg.products) {
|
|
|
|
const msg = name + `.products[${product.id}] must be a boolean`
|
|
|
|
a.strictEqual(typeof s.products[product.id], 'boolean', msg)
|
|
|
|
}
|
|
|
|
|
|
|
|
if ('lines' in s) {
|
|
|
|
a.ok(Array.isArray(s.lines), name + `.lines must be an array`)
|
|
|
|
for (let i = 0; i < s.lines.length; i++) {
|
2018-04-25 12:48:05 +02:00
|
|
|
val.line(val, s.lines[i], name + `.lines[${i}]`)
|
2018-04-18 20:08:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return validateStation
|
|
|
|
}
|
|
|
|
|
2018-04-25 12:48:05 +02:00
|
|
|
const validatePoi = (val, poi, name = 'location') => {
|
|
|
|
defaultValidators.location(val, poi, name)
|
|
|
|
val.ref(val, poi.id, name + '.id')
|
2018-04-18 20:08:47 +02:00
|
|
|
a.ok(poi.name, name + '.name must not be empty')
|
|
|
|
}
|
|
|
|
|
2018-04-25 12:48:05 +02:00
|
|
|
const validateAddress = (val, addr, name = 'location') => {
|
|
|
|
defaultValidators.location(val, addr, name)
|
2018-04-18 20:08:47 +02:00
|
|
|
a.strictEqual(typeof addr.address, 'string', name + '.address must be a string')
|
|
|
|
a.ok(addr.address, name + '.address must not be empty')
|
|
|
|
}
|
|
|
|
|
2018-04-25 12:48:05 +02:00
|
|
|
const validateLocation = (val, loc, name = 'location') => {
|
2018-04-18 20:08:47 +02:00
|
|
|
a.ok(isObj(loc), name + ' must be an object')
|
2018-04-25 12:48:05 +02:00
|
|
|
if (loc.type === 'station') val.station(val, loc, name)
|
|
|
|
else if ('id' in loc) validatePoi(val, loc, name)
|
2018-04-19 15:59:07 +02:00
|
|
|
else if (!('name' in loc) && ('address' in loc)) {
|
2018-04-25 12:48:05 +02:00
|
|
|
validateAddress(val, loc, name)
|
|
|
|
} else defaultValidators.location(val, loc, name)
|
2018-04-18 20:08:47 +02:00
|
|
|
}
|
|
|
|
|
2018-04-25 12:48:05 +02:00
|
|
|
const validateLocations = (val, locs, name = 'locations') => {
|
2018-04-18 23:54:09 +02:00
|
|
|
a.ok(Array.isArray(locs), name + ' must be an array')
|
|
|
|
a.ok(locs.length > 0, name + ' must not be empty')
|
|
|
|
for (let i = 0; i < locs.length; i++) {
|
2018-05-07 12:33:53 +02:00
|
|
|
val.location(val, locs[i], name + `[${i}]`)
|
2018-04-18 23:54:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-18 20:08:47 +02:00
|
|
|
const createValidateLine = (cfg) => {
|
|
|
|
const validLineModes = []
|
|
|
|
for (let product of cfg.products) {
|
|
|
|
if (!validLineModes.includes(product.mode)) {
|
|
|
|
validLineModes.push(product.mode)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-25 12:48:05 +02:00
|
|
|
const validateLine = (val, line, name = 'line') => {
|
|
|
|
defaultValidators.line(val, line, name)
|
2018-04-20 11:04:54 +02:00
|
|
|
a.ok(validLineModes.includes(line.mode), name + '.mode is invalid')
|
2018-04-18 20:08:47 +02:00
|
|
|
}
|
|
|
|
return validateLine
|
|
|
|
}
|
|
|
|
|
|
|
|
const createValidateStopover = (cfg) => {
|
2018-04-25 12:48:05 +02:00
|
|
|
const validateStopover = (val, s, name = 'stopover') => {
|
2018-04-18 20:08:47 +02:00
|
|
|
if (is(s.arrival)) {
|
2018-04-25 12:48:05 +02:00
|
|
|
val.date(val, s.arrival, name + '.arrival')
|
2018-05-14 00:35:21 +02:00
|
|
|
assertValidWhen(s.arrival, cfg.when, name)
|
2018-04-18 20:08:47 +02:00
|
|
|
}
|
|
|
|
if (is(s.departure)) {
|
2018-04-25 12:48:05 +02:00
|
|
|
val.date(val, s.departure, name + '.departure')
|
2018-05-14 00:35:21 +02:00
|
|
|
assertValidWhen(s.departure, cfg.when, name)
|
2018-04-18 20:08:47 +02:00
|
|
|
}
|
|
|
|
if (!is(s.arrival) && !is(s.departure)) {
|
2018-04-19 15:59:07 +02:00
|
|
|
a.fail(name + ' contains neither arrival nor departure')
|
2018-04-18 20:08:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (is(s.arrivalDelay)) {
|
|
|
|
const msg = name + '.arrivalDelay must be a number'
|
|
|
|
a.strictEqual(typeof s.arrivalDelay, 'number', msg)
|
|
|
|
}
|
|
|
|
if (is(s.departureDelay)) {
|
|
|
|
const msg = name + '.departureDelay must be a number'
|
|
|
|
a.strictEqual(typeof s.departureDelay, 'number', msg)
|
|
|
|
}
|
|
|
|
|
2018-06-22 13:41:35 +02:00
|
|
|
if (is(s.arrivalPlatform)) {
|
|
|
|
const msg = name + '.arrivalPlatform must '
|
|
|
|
a.strictEqual(typeof s.arrivalPlatform, 'string', msg + 'be a string')
|
|
|
|
a.ok(s.arrivalPlatform, msg + 'not be empty')
|
|
|
|
}
|
|
|
|
if (is(s.departureDelay)) {
|
|
|
|
const msg = name + '.departurePlatform must '
|
|
|
|
a.strictEqual(typeof s.departurePlatform, 'string', msg + 'be a string')
|
|
|
|
a.ok(s.departurePlatform, msg + 'not be empty')
|
|
|
|
}
|
|
|
|
|
|
|
|
val.station(val, s.stop, name + '.stop')
|
2018-04-18 20:08:47 +02:00
|
|
|
}
|
|
|
|
return validateStopover
|
|
|
|
}
|
|
|
|
|
2018-04-25 12:48:05 +02:00
|
|
|
const validateTicket = (val, ti, name = 'ticket') => {
|
2018-04-18 20:08:47 +02:00
|
|
|
a.strictEqual(typeof ti.name, 'string', name + '.name must be a string')
|
|
|
|
a.ok(ti.name, name + '.name must not be empty')
|
|
|
|
|
|
|
|
if (is(ti.price)) {
|
|
|
|
a.strictEqual(typeof ti.price, 'number', name + '.price must be a number')
|
|
|
|
a.ok(ti.price > 0, name + '.price must be >0')
|
|
|
|
}
|
|
|
|
if (is(ti.amount)) {
|
|
|
|
a.strictEqual(typeof ti.amount, 'number', name + '.amount must be a number')
|
|
|
|
a.ok(ti.amount > 0, name + '.amount must be >0')
|
|
|
|
}
|
|
|
|
|
|
|
|
// todo: move to VBB tests
|
|
|
|
if ('bike' in ti) {
|
|
|
|
a.strictEqual(typeof ti.bike, 'boolean', name + '.bike must be a boolean')
|
|
|
|
}
|
|
|
|
if ('shortTrip' in ti) {
|
|
|
|
a.strictEqual(typeof ti.shortTrip, 'boolean', name + '.shortTrip must be a boolean')
|
|
|
|
}
|
|
|
|
if ('group' in ti) {
|
|
|
|
a.strictEqual(typeof ti.group, 'boolean', name + '.group must be a boolean')
|
|
|
|
}
|
|
|
|
if ('fullDay' in ti) {
|
|
|
|
a.strictEqual(typeof ti.fullDay, 'boolean', name + '.fullDay must be a boolean')
|
|
|
|
}
|
|
|
|
if ('tariff' in ti) {
|
|
|
|
a.strictEqual(typeof ti.tariff, 'string', name + '.tariff must be a string')
|
|
|
|
a.ok(ti.tariff, name + '.tariff must not be empty')
|
|
|
|
}
|
|
|
|
if ('coverage' in ti) {
|
|
|
|
a.strictEqual(typeof ti.coverage, 'string', name + '.coverage must be a string')
|
|
|
|
a.ok(ti.coverage, name + '.coverage must not be empty')
|
|
|
|
}
|
|
|
|
if ('variant' in ti) {
|
|
|
|
a.strictEqual(typeof ti.variant, 'string', name + '.variant must be a string')
|
|
|
|
a.ok(ti.variant, name + '.variant must not be empty')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const createValidateJourneyLeg = (cfg) => {
|
2018-04-25 12:48:05 +02:00
|
|
|
const validateJourneyLeg = (val, leg, name = 'journeyLeg') => {
|
2018-04-18 20:08:47 +02:00
|
|
|
const withFakeScheduleAndOperator = Object.assign({
|
|
|
|
schedule: 'foo', // todo: let hafas-client parse a schedule ID
|
|
|
|
operator: 'bar' // todo: let hafas-client parse the operator
|
|
|
|
}, leg)
|
2018-04-25 12:48:05 +02:00
|
|
|
defaultValidators.journeyLeg(val, withFakeScheduleAndOperator, name)
|
2018-04-18 20:08:47 +02:00
|
|
|
|
|
|
|
if (leg.arrival !== null) {
|
2018-05-14 00:35:21 +02:00
|
|
|
assertValidWhen(leg.arrival, cfg.when, name + '.arrival')
|
2018-04-18 20:08:47 +02:00
|
|
|
}
|
|
|
|
if (leg.departure !== null) {
|
2018-05-14 00:35:21 +02:00
|
|
|
assertValidWhen(leg.departure, cfg.when, name + '.departure')
|
2018-04-18 20:08:47 +02:00
|
|
|
}
|
2018-04-19 15:59:07 +02:00
|
|
|
// todo: leg.arrivalPlatform !== null
|
|
|
|
if (is(leg.arrivalPlatform)) {
|
2018-04-19 14:55:17 +02:00
|
|
|
const msg = name + '.arrivalPlatform must be a string'
|
|
|
|
a.strictEqual(typeof leg.arrivalPlatform, 'string', msg)
|
|
|
|
a.ok(leg.arrivalPlatform, name + '.arrivalPlatform must not be empty')
|
|
|
|
}
|
2018-04-19 15:59:07 +02:00
|
|
|
// todo: leg.departurePlatform !== null
|
|
|
|
if (is(leg.departurePlatform)) {
|
2018-04-19 14:55:17 +02:00
|
|
|
const msg = name + '.departurePlatform must be a string'
|
|
|
|
a.strictEqual(typeof leg.departurePlatform, 'string', msg)
|
|
|
|
a.ok(leg.departurePlatform, name + '.departurePlatform must not be empty')
|
|
|
|
}
|
2018-04-18 20:08:47 +02:00
|
|
|
|
2018-06-13 20:35:06 +02:00
|
|
|
if ('stopovers' in leg) {
|
|
|
|
a.ok(Array.isArray(leg.stopovers), name + '.stopovers must be an array')
|
|
|
|
a.ok(leg.stopovers.length > 0, name + '.stopovers must not be empty')
|
2018-04-18 20:08:47 +02:00
|
|
|
|
2018-06-13 20:35:06 +02:00
|
|
|
for (let i = 0; i < leg.stopovers.length; i++) {
|
|
|
|
val.stopover(val, leg.stopovers[i], name + `.stopovers[${i}]`)
|
2018-04-18 20:08:47 +02:00
|
|
|
}
|
|
|
|
}
|
2018-04-19 14:55:17 +02:00
|
|
|
|
|
|
|
if (leg.mode !== 'walking') {
|
|
|
|
const msg = name + '.direction must be a string'
|
|
|
|
a.strictEqual(typeof leg.direction, 'string', msg)
|
|
|
|
a.ok(leg.direction, name + '.direction must not be empty')
|
|
|
|
}
|
2018-06-13 20:25:56 +02:00
|
|
|
|
|
|
|
// todo: validate polyline
|
2018-04-18 20:08:47 +02:00
|
|
|
}
|
|
|
|
return validateJourneyLeg
|
|
|
|
}
|
|
|
|
|
2018-04-25 12:48:05 +02:00
|
|
|
const validateJourney = (val, j, name = 'journey') => {
|
2018-04-18 20:08:47 +02:00
|
|
|
const withFakeId = Object.assign({
|
|
|
|
id: 'foo' // todo: let hafas-client parse a journey ID
|
|
|
|
}, j)
|
2018-04-25 12:48:05 +02:00
|
|
|
defaultValidators.journey(val, withFakeId, name)
|
2018-04-18 20:08:47 +02:00
|
|
|
|
|
|
|
if ('tickets' in j) {
|
|
|
|
a.ok(Array.isArray(j.tickets), name + '.tickets must be an array')
|
|
|
|
a.ok(j.tickets.length > 0, name + '.tickets must not be empty')
|
|
|
|
|
|
|
|
for (let i = 0; i < j.tickets.length; i++) {
|
2018-04-25 12:48:05 +02:00
|
|
|
val.ticket(val, j.tickets[i], name + `.tickets[${i}]`)
|
2018-04-18 20:08:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-25 12:48:05 +02:00
|
|
|
const validateJourneys = (val, js, name = 'journeys') => {
|
2018-04-18 23:54:09 +02:00
|
|
|
a.ok(Array.isArray(js), name + ' must be an array')
|
|
|
|
a.ok(js.length > 0, name + ' must not be empty')
|
|
|
|
for (let i = 0; i < js.length; i++) {
|
2018-04-25 12:48:05 +02:00
|
|
|
val.journey(val, js[i], name + `[${i}]`)
|
2018-04-18 23:54:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-26 17:30:46 +02:00
|
|
|
const createValidateArrivalOrDeparture = (cfg) => {
|
|
|
|
const validateArrivalOrDeparture = (val, dep, name = 'arrOrDep') => {
|
2018-04-18 23:54:09 +02:00
|
|
|
a.ok(isObj(dep), name + ' must be an object')
|
|
|
|
// todo: let hafas-client add a .type field
|
|
|
|
|
2018-06-26 14:57:02 +02:00
|
|
|
a.strictEqual(typeof dep.tripId, 'string', name + '.tripId must be a string')
|
|
|
|
a.ok(dep.tripId, name + '.tripId must not be empty')
|
2018-04-18 23:54:09 +02:00
|
|
|
a.strictEqual(typeof dep.trip, 'number', name + '.trip must be a number')
|
|
|
|
|
2018-04-25 12:48:05 +02:00
|
|
|
val.station(val, dep.station, name + '.station')
|
2018-04-18 23:54:09 +02:00
|
|
|
|
2018-05-14 00:35:21 +02:00
|
|
|
assertValidWhen(dep.when, cfg.when, name)
|
2018-04-18 23:54:09 +02:00
|
|
|
if (dep.delay !== null) {
|
|
|
|
const msg = name + '.delay must be a number'
|
|
|
|
a.strictEqual(typeof dep.delay, 'number', msg)
|
|
|
|
}
|
|
|
|
|
2018-06-27 17:17:04 +02:00
|
|
|
if (dep.platform !== null) {
|
|
|
|
const msg = name + '.platform must '
|
|
|
|
a.strictEqual(typeof dep.platform, 'string', msg + 'be a string')
|
|
|
|
a.ok(dep.platform, name + 'not be empty')
|
|
|
|
}
|
|
|
|
|
2018-04-25 12:48:05 +02:00
|
|
|
val.line(val, dep.line, name + '.line')
|
2018-04-19 14:55:17 +02:00
|
|
|
a.strictEqual(typeof dep.direction, 'string', name + '.direction must be a string')
|
|
|
|
a.ok(dep.direction, name + '.direction must not be empty')
|
2018-04-18 23:54:09 +02:00
|
|
|
}
|
2018-06-26 17:30:46 +02:00
|
|
|
return validateArrivalOrDeparture
|
2018-04-18 23:54:09 +02:00
|
|
|
}
|
|
|
|
|
2018-06-26 17:30:46 +02:00
|
|
|
const validateArrivals = (val, deps, name = 'arrivals') => {
|
|
|
|
a.ok(Array.isArray(deps), name + ' must be an array')
|
|
|
|
a.ok(deps.length > 0, name + ' must not be empty')
|
|
|
|
for (let i = 0; i < deps.length; i++) {
|
|
|
|
val.arrival(val, deps[i], name + `[${i}]`)
|
|
|
|
}
|
|
|
|
}
|
2018-04-25 12:48:05 +02:00
|
|
|
const validateDepartures = (val, deps, name = 'departures') => {
|
2018-04-18 23:54:09 +02:00
|
|
|
a.ok(Array.isArray(deps), name + ' must be an array')
|
|
|
|
a.ok(deps.length > 0, name + ' must not be empty')
|
|
|
|
for (let i = 0; i < deps.length; i++) {
|
2018-04-25 12:48:05 +02:00
|
|
|
val.departure(val, deps[i], name + `[${i}]`)
|
2018-04-18 23:54:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-25 12:48:05 +02:00
|
|
|
const validateMovement = (val, m, name = 'movement') => {
|
2018-04-18 23:54:09 +02:00
|
|
|
a.ok(isObj(m), name + ' must be an object')
|
|
|
|
// todo: let hafas-client add a .type field
|
|
|
|
|
2018-04-25 12:48:05 +02:00
|
|
|
val.line(val, m.line, name + '.line')
|
2018-04-19 15:59:07 +02:00
|
|
|
a.strictEqual(typeof m.direction, 'string', name + '.direction must be a string')
|
|
|
|
a.ok(m.direction, name + '.direction must not be empty')
|
2018-04-18 23:54:09 +02:00
|
|
|
|
|
|
|
const lName = name + '.location'
|
2018-04-25 12:48:05 +02:00
|
|
|
val.location(val, m.location, lName)
|
2018-04-19 15:59:07 +02:00
|
|
|
a.ok(m.location.latitude <= 55, lName + '.latitude is too small')
|
|
|
|
a.ok(m.location.latitude >= 45, lName + '.latitude is too large')
|
|
|
|
a.ok(m.location.longitude >= 9, lName + '.longitude is too small')
|
|
|
|
a.ok(m.location.longitude <= 15, lName + '.longitude is too small')
|
|
|
|
|
|
|
|
a.ok(Array.isArray(m.nextStops), name + '.nextStops must be an array')
|
|
|
|
for (let i = 0; i < m.nextStops.length; i++) {
|
|
|
|
const st = m.nextStops[i]
|
2018-04-25 12:48:05 +02:00
|
|
|
val.stopover(val, m.nextStops[i], name + `.nextStops[${i}]`)
|
2018-04-18 23:54:09 +02:00
|
|
|
}
|
|
|
|
|
2018-04-19 15:59:07 +02:00
|
|
|
a.ok(Array.isArray(m.frames), name + '.frames must be an array')
|
|
|
|
a.ok(m.frames.length > 0, name + '.frames must not be empty')
|
|
|
|
for (let i = 0; i < m.frames.length; i++) {
|
|
|
|
const f = m.frames[i]
|
2018-04-18 23:54:09 +02:00
|
|
|
const fName = name + `.frames[${i}]`
|
|
|
|
|
|
|
|
a.ok(isObj(f), fName + ' must be an object')
|
2018-04-25 12:48:05 +02:00
|
|
|
anyOf(['location', 'station'], val, f.origin, fName + '.origin')
|
|
|
|
anyOf(['location', 'station'], val, f.destination, fName + '.destination')
|
2018-04-18 23:54:09 +02:00
|
|
|
a.strictEqual(typeof f.t, 'number', fName + '.frames must be a number')
|
|
|
|
}
|
2018-06-13 20:25:56 +02:00
|
|
|
|
|
|
|
// todo: validate polyline
|
2018-04-18 23:54:09 +02:00
|
|
|
}
|
|
|
|
|
2018-04-25 12:48:05 +02:00
|
|
|
const validateMovements = (val, ms, name = 'movements') => {
|
2018-04-18 23:54:09 +02:00
|
|
|
a.ok(Array.isArray(ms), name + ' must be an array')
|
|
|
|
a.ok(ms.length > 0, name + ' must not be empty')
|
|
|
|
for (let i = 0; i < ms.length; i++) {
|
2018-04-25 12:48:05 +02:00
|
|
|
val.movement(val, ms[i], name + `[${i}]`)
|
2018-04-18 23:54:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-18 20:08:47 +02:00
|
|
|
module.exports = {
|
|
|
|
station: createValidateStation,
|
|
|
|
location: () => validateLocation,
|
2018-04-18 23:54:09 +02:00
|
|
|
locations: () => validateLocations,
|
2018-04-18 20:08:47 +02:00
|
|
|
poi: () => validatePoi,
|
|
|
|
address: () => validateAddress,
|
|
|
|
line: createValidateLine,
|
|
|
|
stopover: createValidateStopover,
|
|
|
|
ticket: () => validateTicket,
|
|
|
|
journeyLeg: createValidateJourneyLeg,
|
2018-04-18 23:54:09 +02:00
|
|
|
journey: () => validateJourney,
|
|
|
|
journeys: () => validateJourneys,
|
2018-06-26 17:30:46 +02:00
|
|
|
arrival: createValidateArrivalOrDeparture,
|
|
|
|
departure: createValidateArrivalOrDeparture,
|
2018-04-18 23:54:09 +02:00
|
|
|
departures: () => validateDepartures,
|
2018-06-26 17:30:46 +02:00
|
|
|
arrivals: () => validateArrivals,
|
2018-04-18 23:54:09 +02:00
|
|
|
movement: () => validateMovement,
|
|
|
|
movements: () => validateMovements
|
2018-04-18 20:08:47 +02:00
|
|
|
}
|