From 582e5d0ef7610d7592837eebd69141ee9e6bad90 Mon Sep 17 00:00:00 2001 From: Johannes Filter Date: Mon, 26 Feb 2018 22:14:11 +0100 Subject: [PATCH 01/14] add minimal working INSA endpoint --- p/insa/example.js | 22 +++++++++++++ p/insa/index.js | 62 +++++++++++++++++++++++++++++++++++ p/insa/products.js | 81 ++++++++++++++++++++++++++++++++++++++++++++++ p/insa/readme.md | 18 +++++++++++ 4 files changed, 183 insertions(+) create mode 100644 p/insa/example.js create mode 100644 p/insa/index.js create mode 100644 p/insa/products.js create mode 100644 p/insa/readme.md diff --git a/p/insa/example.js b/p/insa/example.js new file mode 100644 index 00000000..e56e3d1b --- /dev/null +++ b/p/insa/example.js @@ -0,0 +1,22 @@ +'use strict' + +const createClient = require('../..') +const insaProfile = require('.') + +const client = createClient(insaProfile) + +// from Magdeburg-Neustadt to Magdeburg-Buckau +client.journeys('008010226', '008013456', {results: 1}) +// client.departures('008010226', {duration: 5}) +// client.locations('Magdeburg', {results: 2}) +// client.location('008010226') // Magdeburg-Neustadt +// client.nearby({ +// type: 'location', +// latitude: 52.148842, +// longitude: 11.641705 +// }, {distance: 200}) + +.then((data) => { + console.log(require('util').inspect(data, {depth: null})) +}) +.catch(console.error) diff --git a/p/insa/index.js b/p/insa/index.js new file mode 100644 index 00000000..8102e4ca --- /dev/null +++ b/p/insa/index.js @@ -0,0 +1,62 @@ +'use strict' + +const products = require('./products') +const createParseBitmask = require('../../parse/products-bitmask') +const createFormatBitmask = require('../../format/products-bitmask') + +const defaultProducts = { + nationalExp: true, + national: true, + regional: true, + suburban: true, + bus: true, + tram: true, + tourismTrain: true, +} + + +const transformReqBody = (body) => { + body.client = { + type: 'IPH', + id: 'NASA', + v: '4000200', + name: 'nasaPROD', + os: 'iPhone OS 11.2.5' + } + body.ver = '1.11' + body.auth = {aid: "nasa-apps"} + body.lang = 'en' // todo: `de`? + + return body +} + + + +const formatProducts = (products) => { + products = Object.assign(Object.create(null), defaultProducts, products) + return { + type: 'PROD', + mode: 'INC', + value: formatBitmask(products) + '' + } +} + +const formatBitmask = createFormatBitmask(products) + + +const insaProfile = { + locale: 'de-DE', + timezone: 'Europe/Berlin', + endpoint: 'http://reiseauskunft.insa.de/bin/mgate.exe', + products: products.allProducts, + transformReqBody, + + defaultProducts, + parseProducts: createParseBitmask(products.bitmasks), + formatProducts + + // todo: journeyLeg? + // todo: radar? +} + +module.exports = insaProfile; diff --git a/p/insa/products.js b/p/insa/products.js new file mode 100644 index 00000000..81cb82f7 --- /dev/null +++ b/p/insa/products.js @@ -0,0 +1,81 @@ +'use strict' + +// TODO Jannis R.: DRY +const p = { + nationalExp: { + bitmask: 1, + name: 'InterCityExpress', + short: 'ICE', + mode: 'train', + product: 'nationalExp' + }, + national: { + bitmask: 2, + name: 'InterCity & EuroCity', + short: 'IC/EC', + mode: 'train', + product: 'national' + }, + regional: { + bitmask: 8, + name: 'RegionalExpress & RegionalBahn', + short: 'RE/RB', + mode: 'train', + product: 'regional' + }, + suburban: { + bitmask: 16, + name: 'S-Bahn', + short: 'S', + mode: 'train', + product: 'suburban' + }, + tram: { + bitmask: 32, + name: 'Tram', + short: 'T', + mode: 'train', + product: 'tram' + }, + bus: { + bitmask: 64+128, + name: 'Bus', + short: 'B', + mode: 'bus', + product: 'bus' + }, + tourismTrain: { + bitmask: 256, + name: 'Tourism Train', + short: 'TT', + mode: 'train', + product: 'tourismTrain' + }, + unknown: { + bitmask: 0, + name: 'unknown', + short: '?', + product: 'unknown' + } +} + +p.bitmasks = [] +p.bitmasks[1] = p.nationalExp +p.bitmasks[2] = p.national +p.bitmasks[8] = p.regional +p.bitmasks[16] = p.suburban +p.bitmasks[32] = p.tram +p.bitmasks[64+128] = p.bus +p.bitmasks[256] = p.tourismTrain + +p.allProducts = [ + p.nationalExp, + p.national, + p.regional, + p.suburban, + p.tram, + p.bus, + p.tourismTrain +] + +module.exports = p diff --git a/p/insa/readme.md b/p/insa/readme.md new file mode 100644 index 00000000..4918b2b4 --- /dev/null +++ b/p/insa/readme.md @@ -0,0 +1,18 @@ +# INSA profile for `hafas-client` + +The [Nahverkehr Sachsen-Anhalt (NASA)](https://de.wikipedia.org/wiki/Nahverkehrsservice_Sachsen-Anhalt) offers [Informationssystem Nahverkehr Sachsen-Anhalt (INSA)](https://insa.de) to distribute their public transport data. + +## Usage + +```js +const createClient = require('hafas-client') +const insaProfile = require('hafas-client/p/insa') + +// create a client with INSA profile +const client = createClient(insaProfile) +``` + + +## Customisations + +- parses *INSA*-specific products (such as *Tourism Train*) From dbaa795fce96566ae475d8960570c8adaa17cca0 Mon Sep 17 00:00:00 2001 From: Johannes Filter Date: Mon, 26 Feb 2018 23:23:00 +0100 Subject: [PATCH 02/14] =?UTF-8?q?add=20test=20for=20insa,=20edge=20cases?= =?UTF-8?q?=20not=20working=20=F0=9F=98=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- p/insa/example.js | 45 ++++--- test/insa.js | 321 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 349 insertions(+), 17 deletions(-) create mode 100644 test/insa.js diff --git a/p/insa/example.js b/p/insa/example.js index e56e3d1b..c0aaede9 100644 --- a/p/insa/example.js +++ b/p/insa/example.js @@ -1,22 +1,33 @@ -'use strict' +"use strict"; -const createClient = require('../..') -const insaProfile = require('.') +const createClient = require("../.."); +const insaProfile = require("."); -const client = createClient(insaProfile) +const client = createClient(insaProfile); // from Magdeburg-Neustadt to Magdeburg-Buckau -client.journeys('008010226', '008013456', {results: 1}) -// client.departures('008010226', {duration: 5}) -// client.locations('Magdeburg', {results: 2}) -// client.location('008010226') // Magdeburg-Neustadt -// client.nearby({ -// type: 'location', -// latitude: 52.148842, -// longitude: 11.641705 -// }, {distance: 200}) +// client.journeys('008010226', '008013456', {results: 1}) +client + .departures("008010226", { duration: 5 }) + // client; + // .locations("Magdeburg Hbf", { + // results: 2 + // }) + // .locations("Kunstmuseum Kloster Unser Lieben Frauen Magdeburg", { + // results: 2 + // }) + // client.location('008010226') // Magdeburg-Neustadt + // client + // .nearby( + // { + // type: "location", + // latitude: 52.148842, + // longitude: 11.641705 + // }, + // { distance: 200 } + // ) -.then((data) => { - console.log(require('util').inspect(data, {depth: null})) -}) -.catch(console.error) + .then(data => { + console.log(require("util").inspect(data, { depth: null })); + }) + .catch(console.error); diff --git a/test/insa.js b/test/insa.js new file mode 100644 index 00000000..671cd0ad --- /dev/null +++ b/test/insa.js @@ -0,0 +1,321 @@ +"use strict"; + +const tapePromise = require("tape-promise").default; +const tape = require("tape"); +const isRoughlyEqual = require("is-roughly-equal"); +const validateFptf = require("validate-fptf"); + +const co = require("./co"); +const createClient = require(".."); +const insaProfile = require("../p/insa"); +const products = require("../p/insa/products"); +const { + assertValidStation, + assertValidPoi, + assertValidAddress, + assertValidLocation, + assertValidLine, + assertValidStopover, + hour, + createWhen, + assertValidWhen +} = require("./util.js"); + +const when = createWhen("Europe/Berlin", "de-DE"); + +const assertValidStationProducts = (t, p) => { + return null; // todo + t.ok(p); + t.equal(typeof p.nationalExp, "boolean"); + t.equal(typeof p.national, "boolean"); + t.equal(typeof p.regional, "boolean"); + t.equal(typeof p.suburban, "boolean"); + t.equal(typeof p.tram, "boolean"); + t.equal(typeof p.bus, "boolean"); + // console.error(p); // todo + t.equal(typeof p.tourismTrain, "boolean"); +}; + +const isMagdeburgHbf = s => { + return ( + s.type === "station" && + (s.id === "8010224" || s.id === "008010224") && + s.name === "Magdeburg Hbf" && + s.location && + isRoughlyEqual(s.location.latitude, 52.130352, 0.001) && + isRoughlyEqual(s.location.longitude, 11.626891, 0.001) + ); +}; + +const assertIsMagdeburgHbf = (t, s) => { + t.equal(s.type, "station"); + t.ok(s.id === "8010224" || s.id === "008010224", "id should be 8010224"); + t.equal(s.name, "Magdeburg Hbf"); + t.ok(s.location); + t.ok(isRoughlyEqual(s.location.latitude, 52.130352, 0.001)); + t.ok(isRoughlyEqual(s.location.longitude, 11.626891, 0.001)); +}; + +// todo: this doesnt seem to work +// todo: DRY with assertValidStationProducts +const assertValidProducts = (t, p) => { + for (let k of Object.keys(products)) { + t.ok("boolean", typeof products[k], "mode " + k + " must be a boolean"); + } +}; + +const test = tapePromise(tape); +const client = createClient(insaProfile); + +test( + "Magdeburg Hbf to Magdeburg-Buckau", + co(function*(t) { + const magdeburgHbf = "8010224"; + const magdeburgBuckau = "8013456"; + const journeys = yield client.journeys(magdeburgHbf, magdeburgBuckau, { + when, + passedStations: true + }); + + t.ok(Array.isArray(journeys)); + t.ok(journeys.length > 0, "no journeys"); + for (let journey of journeys) { + assertValidStation(t, journey.origin); + assertValidStationProducts(t, journey.origin.products); + if (journey.origin.products) { + assertValidProducts(t, journey.origin.products); + } + assertValidWhen(t, journey.departure, when); + + assertValidStation(t, journey.destination); + assertValidStationProducts(t, journey.origin.products); + if (journey.destination.products) { + assertValidProducts(t, journey.destination.products); + } + assertValidWhen(t, journey.arrival, when); + + t.ok(Array.isArray(journey.legs)); + t.ok(journey.legs.length > 0, "no legs"); + const leg = journey.legs[0]; + + assertValidStation(t, leg.origin); + assertValidStationProducts(t, leg.origin.products); + assertValidWhen(t, leg.departure, when); + t.equal(typeof leg.departurePlatform, "string"); + + assertValidStation(t, leg.destination); + assertValidStationProducts(t, leg.origin.products); + assertValidWhen(t, leg.arrival, when); + t.equal(typeof leg.arrivalPlatform, "string"); + + assertValidLine(t, leg.line); + + t.ok(Array.isArray(leg.passed)); + for (let stopover of leg.passed) assertValidStopover(t, stopover); + + // if (journey.price) assertValidPrice(t, journey.price); + } + + t.end(); + }) +); + +test( + "Magdeburg Hbf to 39104 Magdeburg, Sternstr. 10", + co(function*(t) { + const magdeburgHbf = "8010224"; + const sternStr = { + type: "location", + latitude: 52.118745, + longitude: 11.627117, + address: "39104 Magdeburg, Sternstr. 10" + }; + + const journeys = yield client.journeys(magdeburgHbf, sternStr, { + when + }); + + t.ok(Array.isArray(journeys)); + t.ok(journeys.length >= 1, "no journeys"); + const journey = journeys[0]; + const firstLeg = journey.legs[0]; + const lastLeg = journey.legs[journey.legs.length - 1]; + + assertValidStation(t, firstLeg.origin); + assertValidStationProducts(t, firstLeg.origin.products); + if (firstLeg.origin.products) + assertValidProducts(t, firstLeg.origin.products); + assertValidWhen(t, firstLeg.departure, when); + assertValidWhen(t, firstLeg.arrival, when); + assertValidWhen(t, lastLeg.departure, when); + assertValidWhen(t, lastLeg.arrival, when); + + const d = lastLeg.destination; + assertValidAddress(t, d); + t.equal(d.address, "39104 Magdeburg, Sternstr. 10"); + t.ok(isRoughlyEqual(0.0001, d.latitude, 52.118745)); + t.ok(isRoughlyEqual(0.0001, d.longitude, 11.627117)); + + t.end(); + }) +); + +test( + "Kloster Unser Lieben Frauen to Magdeburg Hbf", + co(function*(t) { + const kloster = { + type: "location", + latitude: 52.127601, + longitude: 11.636437, + name: "Magdeburg, Kloster Unser Lieben Frauen (Denkmal)", + id: "970012223" + }; + const magdeburgHbf = "8010224"; + const journeys = yield client.journeys(kloster, magdeburgHbf, { + when + }); + + t.ok(Array.isArray(journeys)); + t.ok(journeys.length >= 1, "no journeys"); + const journey = journeys[0]; + const firstLeg = journey.legs[0]; + const lastLeg = journey.legs[journey.legs.length - 1]; + + const o = firstLeg.origin; + assertValidPoi(t, o); + t.equal(o.name, "Magdeburg, Kloster Unser Lieben Frauen (Denkmal)"); + t.ok(isRoughlyEqual(0.0001, o.latitude, 52.127601)); + t.ok(isRoughlyEqual(0.0001, o.longitude, 11.636437)); + + assertValidWhen(t, firstLeg.departure, when); + assertValidWhen(t, firstLeg.arrival, when); + assertValidWhen(t, lastLeg.departure, when); + assertValidWhen(t, lastLeg.arrival, when); + + assertValidStation(t, lastLeg.destination); + assertValidStationProducts(t, lastLeg.destination.products); + if (lastLeg.destination.products) + assertValidProducts(t, lastLeg.destination.products); + + t.end(); + }) +); + +test( + "Magdeburg-Buckau to Magdeburg-Neustadt with stopover at Magdeburg Hbf", + co(function*(t) { + const magdeburgBuckau = "8013456"; + const magdeburgNeustadt = "8010226"; + const magdeburgHbf = "8010224"; + const [journey] = yield client.journeys( + magdeburgBuckau, + magdeburgNeustadt, + { + via: magdeburgHbf, + results: 1, + when + } + ); + + const i1 = journey.legs.findIndex( + leg => leg.destination.id === magdeburgHbf + ); + t.ok(i1 >= 0, "no leg with Magdeburg Hbf as destination"); + + const i2 = journey.legs.findIndex( + leg => leg.origin.id === magdeburgHbf + ); + t.ok(i2 >= 0, "no leg with Magdeburg Hbf as origin"); + t.ok( + i2 > i1, + "leg with Magdeburg Hbf as origin must be after leg to it" + ); + + t.end(); + }) +); + +test( + "departures at Magdeburg Hbf", + co(function*(t) { + const magdeburgHbf = "8010224"; + const deps = yield client.departures(magdeburgHbf, { + duration: 5, + when + }); + + t.ok(Array.isArray(deps)); + for (let dep of deps) { + assertValidStation(t, dep.station); + assertValidStationProducts(t, dep.station.products); + if (dep.station.products) + assertValidProducts(t, dep.station.products); + assertValidWhen(t, dep.when, when); + } + + t.end(); + }) +); + +test( + "nearby Magdeburg Hbf", + co(function*(t) { + const magdeburgHbfPosition = { + type: "location", + latitude: 52.130352, + longitude: 11.626891 + }; + const nearby = yield client.nearby(magdeburgHbfPosition, { + results: 2, + distance: 400 + }); + + t.ok(Array.isArray(nearby)); + t.equal(nearby.length, 2); + + assertIsMagdeburgHbf(t, nearby[0]); + t.ok(nearby[0].distance >= 0); + t.ok(nearby[0].distance <= 100); + + for (let n of nearby) { + if (n.type === "station") assertValidStation(t, n); + else assertValidLocation(t, n); + } + + t.end(); + }) +); + +test( + "locations named Magdeburg", + co(function*(t) { + const locations = yield client.locations("Magdeburg", { + results: 10 + }); + + t.ok(Array.isArray(locations)); + t.ok(locations.length > 0); + t.ok(locations.length <= 10); + + for (let l of locations) { + if (l.type === "station") assertValidStation(t, l); + else assertValidLocation(t, l); + } + t.ok(locations.some(isMagdeburgHbf)); + + t.end(); + }) +); + +test( + "location", + co(function*(t) { + const magdeburgBuckau = "8013456"; + const loc = yield client.location(magdeburgBuckau); + + assertValidStation(t, loc); + t.equal(loc.id, magdeburgBuckau); + + t.end(); + }) +); From 094e95c9cc35e14ae87dacb2b5b492dd38d98029 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Mon, 12 Mar 2018 22:43:50 +0100 Subject: [PATCH 03/14] restore former code style :shirt: --- p/insa/example.js | 46 ++--- test/insa.js | 501 ++++++++++++++++++++++------------------------ 2 files changed, 252 insertions(+), 295 deletions(-) diff --git a/p/insa/example.js b/p/insa/example.js index c0aaede9..2531ec5b 100644 --- a/p/insa/example.js +++ b/p/insa/example.js @@ -1,33 +1,23 @@ -"use strict"; +'use strict' -const createClient = require("../.."); -const insaProfile = require("."); +const createClient = require('../..') +const insaProfile = require('.') -const client = createClient(insaProfile); +const client = createClient(insaProfile) // from Magdeburg-Neustadt to Magdeburg-Buckau -// client.journeys('008010226', '008013456', {results: 1}) -client - .departures("008010226", { duration: 5 }) - // client; - // .locations("Magdeburg Hbf", { - // results: 2 - // }) - // .locations("Kunstmuseum Kloster Unser Lieben Frauen Magdeburg", { - // results: 2 - // }) - // client.location('008010226') // Magdeburg-Neustadt - // client - // .nearby( - // { - // type: "location", - // latitude: 52.148842, - // longitude: 11.641705 - // }, - // { distance: 200 } - // ) +client.journeys('008010226', '008013456', {results: 1}) +// client.departures('008010226', { duration: 5 }) +// client.locations('Magdeburg Hbf', {results: 2}) +// client.locations('Kunstmuseum Kloster Unser Lieben Frauen Magdeburg', {results: 2}) +// client.location('008010226') // Magdeburg-Neustadt +// client.nearby({ +// type: 'location', +// latitude: 52.148842, +// longitude: 11.641705 +// }, {distance: 200}) - .then(data => { - console.log(require("util").inspect(data, { depth: null })); - }) - .catch(console.error); +.then(data => { + console.log(require('util').inspect(data, { depth: null })) +}) +.catch(console.error) diff --git a/test/insa.js b/test/insa.js index 671cd0ad..940f36d3 100644 --- a/test/insa.js +++ b/test/insa.js @@ -1,14 +1,14 @@ -"use strict"; +'use strict' -const tapePromise = require("tape-promise").default; -const tape = require("tape"); -const isRoughlyEqual = require("is-roughly-equal"); -const validateFptf = require("validate-fptf"); +const tapePromise = require('tape-promise').default +const tape = require('tape') +const isRoughlyEqual = require('is-roughly-equal') +const validateFptf = require('validate-fptf') -const co = require("./co"); -const createClient = require(".."); -const insaProfile = require("../p/insa"); -const products = require("../p/insa/products"); +const co = require('./co') +const createClient = require('..') +const insaProfile = require('../p/insa') +const products = require('../p/insa/products') const { assertValidStation, assertValidPoi, @@ -19,303 +19,270 @@ const { hour, createWhen, assertValidWhen -} = require("./util.js"); +} = require('./util.js') -const when = createWhen("Europe/Berlin", "de-DE"); +const when = createWhen('Europe/Berlin', 'de-DE') const assertValidStationProducts = (t, p) => { return null; // todo - t.ok(p); - t.equal(typeof p.nationalExp, "boolean"); - t.equal(typeof p.national, "boolean"); - t.equal(typeof p.regional, "boolean"); - t.equal(typeof p.suburban, "boolean"); - t.equal(typeof p.tram, "boolean"); - t.equal(typeof p.bus, "boolean"); + t.ok(p) + t.equal(typeof p.nationalExp, 'boolean') + t.equal(typeof p.national, 'boolean') + t.equal(typeof p.regional, 'boolean') + t.equal(typeof p.suburban, 'boolean') + t.equal(typeof p.tram, 'boolean') + t.equal(typeof p.bus, 'boolean') // console.error(p); // todo - t.equal(typeof p.tourismTrain, "boolean"); -}; + t.equal(typeof p.tourismTrain, 'boolean') +} const isMagdeburgHbf = s => { return ( - s.type === "station" && - (s.id === "8010224" || s.id === "008010224") && - s.name === "Magdeburg Hbf" && + s.type === 'station' && + (s.id === '8010224' || s.id === '008010224') && + s.name === 'Magdeburg Hbf' && s.location && isRoughlyEqual(s.location.latitude, 52.130352, 0.001) && isRoughlyEqual(s.location.longitude, 11.626891, 0.001) - ); -}; + ) +} const assertIsMagdeburgHbf = (t, s) => { - t.equal(s.type, "station"); - t.ok(s.id === "8010224" || s.id === "008010224", "id should be 8010224"); - t.equal(s.name, "Magdeburg Hbf"); - t.ok(s.location); - t.ok(isRoughlyEqual(s.location.latitude, 52.130352, 0.001)); - t.ok(isRoughlyEqual(s.location.longitude, 11.626891, 0.001)); -}; + t.equal(s.type, 'station') + t.ok(s.id === '8010224' || s.id === '008010224', 'id should be 8010224') + t.equal(s.name, 'Magdeburg Hbf') + t.ok(s.location) + t.ok(isRoughlyEqual(s.location.latitude, 52.130352, 0.001)) + t.ok(isRoughlyEqual(s.location.longitude, 11.626891, 0.001)) +} // todo: this doesnt seem to work // todo: DRY with assertValidStationProducts const assertValidProducts = (t, p) => { for (let k of Object.keys(products)) { - t.ok("boolean", typeof products[k], "mode " + k + " must be a boolean"); + t.ok('boolean', typeof products[k], 'mode ' + k + ' must be a boolean') } -}; +} -const test = tapePromise(tape); -const client = createClient(insaProfile); +const test = tapePromise(tape) +const client = createClient(insaProfile) -test( - "Magdeburg Hbf to Magdeburg-Buckau", - co(function*(t) { - const magdeburgHbf = "8010224"; - const magdeburgBuckau = "8013456"; - const journeys = yield client.journeys(magdeburgHbf, magdeburgBuckau, { - when, - passedStations: true - }); +test('Magdeburg Hbf to Magdeburg-Buckau', co(function*(t) { + const magdeburgHbf = '8010224' + const magdeburgBuckau = '8013456' + const journeys = yield client.journeys(magdeburgHbf, magdeburgBuckau, { + when, + passedStations: true + }) - t.ok(Array.isArray(journeys)); - t.ok(journeys.length > 0, "no journeys"); - for (let journey of journeys) { - assertValidStation(t, journey.origin); - assertValidStationProducts(t, journey.origin.products); - if (journey.origin.products) { - assertValidProducts(t, journey.origin.products); - } - assertValidWhen(t, journey.departure, when); - - assertValidStation(t, journey.destination); - assertValidStationProducts(t, journey.origin.products); - if (journey.destination.products) { - assertValidProducts(t, journey.destination.products); - } - assertValidWhen(t, journey.arrival, when); - - t.ok(Array.isArray(journey.legs)); - t.ok(journey.legs.length > 0, "no legs"); - const leg = journey.legs[0]; - - assertValidStation(t, leg.origin); - assertValidStationProducts(t, leg.origin.products); - assertValidWhen(t, leg.departure, when); - t.equal(typeof leg.departurePlatform, "string"); - - assertValidStation(t, leg.destination); - assertValidStationProducts(t, leg.origin.products); - assertValidWhen(t, leg.arrival, when); - t.equal(typeof leg.arrivalPlatform, "string"); - - assertValidLine(t, leg.line); - - t.ok(Array.isArray(leg.passed)); - for (let stopover of leg.passed) assertValidStopover(t, stopover); - - // if (journey.price) assertValidPrice(t, journey.price); + t.ok(Array.isArray(journeys)) + t.ok(journeys.length > 0, 'no journeys') + for (let journey of journeys) { + assertValidStation(t, journey.origin) + assertValidStationProducts(t, journey.origin.products) + if (journey.origin.products) { + assertValidProducts(t, journey.origin.products) } + assertValidWhen(t, journey.departure, when) - t.end(); - }) -); - -test( - "Magdeburg Hbf to 39104 Magdeburg, Sternstr. 10", - co(function*(t) { - const magdeburgHbf = "8010224"; - const sternStr = { - type: "location", - latitude: 52.118745, - longitude: 11.627117, - address: "39104 Magdeburg, Sternstr. 10" - }; - - const journeys = yield client.journeys(magdeburgHbf, sternStr, { - when - }); - - t.ok(Array.isArray(journeys)); - t.ok(journeys.length >= 1, "no journeys"); - const journey = journeys[0]; - const firstLeg = journey.legs[0]; - const lastLeg = journey.legs[journey.legs.length - 1]; - - assertValidStation(t, firstLeg.origin); - assertValidStationProducts(t, firstLeg.origin.products); - if (firstLeg.origin.products) - assertValidProducts(t, firstLeg.origin.products); - assertValidWhen(t, firstLeg.departure, when); - assertValidWhen(t, firstLeg.arrival, when); - assertValidWhen(t, lastLeg.departure, when); - assertValidWhen(t, lastLeg.arrival, when); - - const d = lastLeg.destination; - assertValidAddress(t, d); - t.equal(d.address, "39104 Magdeburg, Sternstr. 10"); - t.ok(isRoughlyEqual(0.0001, d.latitude, 52.118745)); - t.ok(isRoughlyEqual(0.0001, d.longitude, 11.627117)); - - t.end(); - }) -); - -test( - "Kloster Unser Lieben Frauen to Magdeburg Hbf", - co(function*(t) { - const kloster = { - type: "location", - latitude: 52.127601, - longitude: 11.636437, - name: "Magdeburg, Kloster Unser Lieben Frauen (Denkmal)", - id: "970012223" - }; - const magdeburgHbf = "8010224"; - const journeys = yield client.journeys(kloster, magdeburgHbf, { - when - }); - - t.ok(Array.isArray(journeys)); - t.ok(journeys.length >= 1, "no journeys"); - const journey = journeys[0]; - const firstLeg = journey.legs[0]; - const lastLeg = journey.legs[journey.legs.length - 1]; - - const o = firstLeg.origin; - assertValidPoi(t, o); - t.equal(o.name, "Magdeburg, Kloster Unser Lieben Frauen (Denkmal)"); - t.ok(isRoughlyEqual(0.0001, o.latitude, 52.127601)); - t.ok(isRoughlyEqual(0.0001, o.longitude, 11.636437)); - - assertValidWhen(t, firstLeg.departure, when); - assertValidWhen(t, firstLeg.arrival, when); - assertValidWhen(t, lastLeg.departure, when); - assertValidWhen(t, lastLeg.arrival, when); - - assertValidStation(t, lastLeg.destination); - assertValidStationProducts(t, lastLeg.destination.products); - if (lastLeg.destination.products) - assertValidProducts(t, lastLeg.destination.products); - - t.end(); - }) -); - -test( - "Magdeburg-Buckau to Magdeburg-Neustadt with stopover at Magdeburg Hbf", - co(function*(t) { - const magdeburgBuckau = "8013456"; - const magdeburgNeustadt = "8010226"; - const magdeburgHbf = "8010224"; - const [journey] = yield client.journeys( - magdeburgBuckau, - magdeburgNeustadt, - { - via: magdeburgHbf, - results: 1, - when - } - ); - - const i1 = journey.legs.findIndex( - leg => leg.destination.id === magdeburgHbf - ); - t.ok(i1 >= 0, "no leg with Magdeburg Hbf as destination"); - - const i2 = journey.legs.findIndex( - leg => leg.origin.id === magdeburgHbf - ); - t.ok(i2 >= 0, "no leg with Magdeburg Hbf as origin"); - t.ok( - i2 > i1, - "leg with Magdeburg Hbf as origin must be after leg to it" - ); - - t.end(); - }) -); - -test( - "departures at Magdeburg Hbf", - co(function*(t) { - const magdeburgHbf = "8010224"; - const deps = yield client.departures(magdeburgHbf, { - duration: 5, - when - }); - - t.ok(Array.isArray(deps)); - for (let dep of deps) { - assertValidStation(t, dep.station); - assertValidStationProducts(t, dep.station.products); - if (dep.station.products) - assertValidProducts(t, dep.station.products); - assertValidWhen(t, dep.when, when); + assertValidStation(t, journey.destination) + assertValidStationProducts(t, journey.origin.products) + if (journey.destination.products) { + assertValidProducts(t, journey.destination.products) } + assertValidWhen(t, journey.arrival, when) - t.end(); + t.ok(Array.isArray(journey.legs)) + t.ok(journey.legs.length > 0, 'no legs') + const leg = journey.legs[0] + + assertValidStation(t, leg.origin) + assertValidStationProducts(t, leg.origin.products) + assertValidWhen(t, leg.departure, when) + t.equal(typeof leg.departurePlatform, 'string') + + assertValidStation(t, leg.destination) + assertValidStationProducts(t, leg.origin.products) + assertValidWhen(t, leg.arrival, when) + t.equal(typeof leg.arrivalPlatform, 'string') + + assertValidLine(t, leg.line) + + t.ok(Array.isArray(leg.passed)) + for (let stopover of leg.passed) assertValidStopover(t, stopover) + + // todo + // if (journey.price) assertValidPrice(t, journey.price) + } + + t.end() +})) + +test('Magdeburg Hbf to 39104 Magdeburg, Sternstr. 10', co(function*(t) { + const magdeburgHbf = '8010224' + const sternStr = { + type: 'location', + latitude: 52.118745, + longitude: 11.627117, + address: '39104 Magdeburg, Sternstr. 10' + } + + const journeys = yield client.journeys(magdeburgHbf, sternStr, { + when }) -); -test( - "nearby Magdeburg Hbf", - co(function*(t) { - const magdeburgHbfPosition = { - type: "location", - latitude: 52.130352, - longitude: 11.626891 - }; - const nearby = yield client.nearby(magdeburgHbfPosition, { - results: 2, - distance: 400 - }); + t.ok(Array.isArray(journeys)) + t.ok(journeys.length >= 1, 'no journeys') + const journey = journeys[0] + const firstLeg = journey.legs[0] + const lastLeg = journey.legs[journey.legs.length - 1] - t.ok(Array.isArray(nearby)); - t.equal(nearby.length, 2); + assertValidStation(t, firstLeg.origin) + assertValidStationProducts(t, firstLeg.origin.products) + if (firstLeg.origin.products) + assertValidProducts(t, firstLeg.origin.products) + assertValidWhen(t, firstLeg.departure, when) + assertValidWhen(t, firstLeg.arrival, when) + assertValidWhen(t, lastLeg.departure, when) + assertValidWhen(t, lastLeg.arrival, when) - assertIsMagdeburgHbf(t, nearby[0]); - t.ok(nearby[0].distance >= 0); - t.ok(nearby[0].distance <= 100); + const d = lastLeg.destination + assertValidAddress(t, d) + t.equal(d.address, '39104 Magdeburg, Sternstr. 10') + t.ok(isRoughlyEqual(0.0001, d.latitude, 52.118745)) + t.ok(isRoughlyEqual(0.0001, d.longitude, 11.627117)) - for (let n of nearby) { - if (n.type === "station") assertValidStation(t, n); - else assertValidLocation(t, n); + t.end() +})) + +test('Kloster Unser Lieben Frauen to Magdeburg Hbf', co(function*(t) { + const kloster = { + type: 'location', + latitude: 52.127601, + longitude: 11.636437, + name: 'Magdeburg, Kloster Unser Lieben Frauen (Denkmal)', + id: '970012223' + } + const magdeburgHbf = '8010224' + const journeys = yield client.journeys(kloster, magdeburgHbf, { + when + }) + + t.ok(Array.isArray(journeys)) + t.ok(journeys.length >= 1, 'no journeys') + const journey = journeys[0] + const firstLeg = journey.legs[0] + const lastLeg = journey.legs[journey.legs.length - 1] + + const o = firstLeg.origin + assertValidPoi(t, o) + t.equal(o.name, 'Magdeburg, Kloster Unser Lieben Frauen (Denkmal)') + t.ok(isRoughlyEqual(0.0001, o.latitude, 52.127601)) + t.ok(isRoughlyEqual(0.0001, o.longitude, 11.636437)) + + assertValidWhen(t, firstLeg.departure, when) + assertValidWhen(t, firstLeg.arrival, when) + assertValidWhen(t, lastLeg.departure, when) + assertValidWhen(t, lastLeg.arrival, when) + + assertValidStation(t, lastLeg.destination) + assertValidStationProducts(t, lastLeg.destination.products) + if (lastLeg.destination.products) + assertValidProducts(t, lastLeg.destination.products) + + t.end() +})) + +test('Magdeburg-Buckau to Magdeburg-Neustadt with stopover at Magdeburg Hbf', co(function*(t) { + const magdeburgBuckau = '8013456' + const magdeburgNeustadt = '8010226' + const magdeburgHbf = '8010224' + const [journey] = yield client.journeys(magdeburgBuckau, magdeburgNeustadt, { + via: magdeburgHbf, + results: 1, + when + }) + + const i1 = journey.legs.findIndex(leg => leg.destination.id === magdeburgHbf) + t.ok(i1 >= 0, 'no leg with Magdeburg Hbf as destination') + + const i2 = journey.legs.findIndex(leg => leg.origin.id === magdeburgHbf) + t.ok(i2 >= 0, 'no leg with Magdeburg Hbf as origin') + t.ok(i2 > i1, 'leg with Magdeburg Hbf as origin must be after leg to it') + + t.end() +})) + +test('departures at Magdeburg Hbf', co(function*(t) { + const magdeburgHbf = '8010224' + const deps = yield client.departures(magdeburgHbf, { + duration: 5, + when + }) + + t.ok(Array.isArray(deps)) + for (let dep of deps) { + assertValidStation(t, dep.station) + assertValidStationProducts(t, dep.station.products) + if (dep.station.products) { + assertValidProducts(t, dep.station.products) } + assertValidWhen(t, dep.when, when) + } - t.end(); + t.end() +})) + +test('nearby Magdeburg Hbf', co(function*(t) { + const magdeburgHbfPosition = { + type: 'location', + latitude: 52.130352, + longitude: 11.626891 + } + const nearby = yield client.nearby(magdeburgHbfPosition, { + results: 2, + distance: 400 }) -); -test( - "locations named Magdeburg", - co(function*(t) { - const locations = yield client.locations("Magdeburg", { - results: 10 - }); + t.ok(Array.isArray(nearby)) + t.equal(nearby.length, 2) - t.ok(Array.isArray(locations)); - t.ok(locations.length > 0); - t.ok(locations.length <= 10); + assertIsMagdeburgHbf(t, nearby[0]) + t.ok(nearby[0].distance >= 0) + t.ok(nearby[0].distance <= 100) - for (let l of locations) { - if (l.type === "station") assertValidStation(t, l); - else assertValidLocation(t, l); - } - t.ok(locations.some(isMagdeburgHbf)); + for (let n of nearby) { + if (n.type === 'station') assertValidStation(t, n) + else assertValidLocation(t, n) + } - t.end(); + t.end() +})) + +test('locations named Magdeburg', co(function*(t) { + const locations = yield client.locations('Magdeburg', { + results: 10 }) -); -test( - "location", - co(function*(t) { - const magdeburgBuckau = "8013456"; - const loc = yield client.location(magdeburgBuckau); + t.ok(Array.isArray(locations)) + t.ok(locations.length > 0) + t.ok(locations.length <= 10) - assertValidStation(t, loc); - t.equal(loc.id, magdeburgBuckau); + for (let l of locations) { + if (l.type === 'station') assertValidStation(t, l) + else assertValidLocation(t, l) + } + t.ok(locations.some(isMagdeburgHbf)) - t.end(); - }) -); + t.end() +})) + +test('location', co(function*(t) { + const magdeburgBuckau = '8013456' + const loc = yield client.location(magdeburgBuckau) + + assertValidStation(t, loc) + t.equal(loc.id, magdeburgBuckau) + + t.end() +})) From f6c615531b3d98e9f6ba928cf550e97ba2f8a4ab Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 13 Mar 2018 02:28:51 +0100 Subject: [PATCH 04/14] INSA: adapt tests to 1.16 protocol, add to test/index.js --- test/index.js | 1 + test/insa.js | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/test/index.js b/test/index.js index b278e8d2..8fbdc852 100644 --- a/test/index.js +++ b/test/index.js @@ -3,4 +3,5 @@ require('./db') require('./vbb') require('./oebb') +require('./insa') require('./throttle') diff --git a/test/insa.js b/test/insa.js index 940f36d3..86008982 100644 --- a/test/insa.js +++ b/test/insa.js @@ -122,9 +122,9 @@ test('Magdeburg Hbf to 39104 Magdeburg, Sternstr. 10', co(function*(t) { const magdeburgHbf = '8010224' const sternStr = { type: 'location', - latitude: 52.118745, - longitude: 11.627117, - address: '39104 Magdeburg, Sternstr. 10' + latitude: 52.118414, + longitude: 11.422332, + address: 'Magdeburg - Altenstadt, Sternstraße 10' } const journeys = yield client.journeys(magdeburgHbf, sternStr, { @@ -148,9 +148,9 @@ test('Magdeburg Hbf to 39104 Magdeburg, Sternstr. 10', co(function*(t) { const d = lastLeg.destination assertValidAddress(t, d) - t.equal(d.address, '39104 Magdeburg, Sternstr. 10') - t.ok(isRoughlyEqual(0.0001, d.latitude, 52.118745)) - t.ok(isRoughlyEqual(0.0001, d.longitude, 11.627117)) + t.equal(d.address, 'Magdeburg - Altenstadt, Sternstraße 10') + t.ok(isRoughlyEqual(0.0001, d.latitude, 52.118414)) + t.ok(isRoughlyEqual(0.0001, d.longitude, 11.422332)) t.end() })) From f7b9cdfac698f3b5ea19053b82a8a1c6dfdf3c01 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 13 Mar 2018 02:29:09 +0100 Subject: [PATCH 05/14] INSA: parse line mode --- p/insa/index.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/p/insa/index.js b/p/insa/index.js index 8102e4ca..f0b90c64 100644 --- a/p/insa/index.js +++ b/p/insa/index.js @@ -1,5 +1,6 @@ 'use strict' +const _createParseLine = require('../../parse/line') const products = require('./products') const createParseBitmask = require('../../parse/products-bitmask') const createFormatBitmask = require('../../format/products-bitmask') @@ -30,7 +31,25 @@ const transformReqBody = (body) => { return body } +const createParseLine = (profile, operators) => { + const parseLine = _createParseLine(profile, operators) + const parseLineWithMode = (l) => { + const res = parseLine(l) + + res.mode = res.product = null + if ('class' in res) { + const data = products.bitmasks[parseInt(res.class)] + if (data) { + res.mode = data.mode + res.product = data.product + } + } + + return res + } + return parseLineWithMode +} const formatProducts = (products) => { products = Object.assign(Object.create(null), defaultProducts, products) @@ -53,7 +72,9 @@ const insaProfile = { defaultProducts, parseProducts: createParseBitmask(products.bitmasks), - formatProducts + formatProducts, + + parseLine: createParseLine // todo: journeyLeg? // todo: radar? From 73c419fadb184735544240449b26064ef22bc2ca Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 13 Mar 2018 03:23:03 +0100 Subject: [PATCH 06/14] fix products parsing :bug:, fix tests for it :white_check_mark: --- p/db/index.js | 2 +- p/insa/index.js | 2 +- p/oebb/index.js | 2 +- p/vbb/index.js | 2 +- parse/products-bitmask.js | 31 +++++++++++++++++++++++-------- test/db.js | 9 +++++---- test/insa.js | 9 +++++---- test/oebb.js | 9 +++++---- 8 files changed, 42 insertions(+), 24 deletions(-) diff --git a/p/db/index.js b/p/db/index.js index a5973581..f88dc539 100644 --- a/p/db/index.js +++ b/p/db/index.js @@ -140,7 +140,7 @@ const dbProfile = { // todo: parseLocation parseLine: createParseLine, - parseProducts: createParseBitmask(modes.bitmasks), + parseProducts: createParseBitmask(modes.allProducts, defaultProducts), parseJourney: createParseJourney, formatStation, diff --git a/p/insa/index.js b/p/insa/index.js index f0b90c64..b50c02fc 100644 --- a/p/insa/index.js +++ b/p/insa/index.js @@ -71,7 +71,7 @@ const insaProfile = { transformReqBody, defaultProducts, - parseProducts: createParseBitmask(products.bitmasks), + parseProducts: createParseBitmask(products.allProducts, defaultProducts), formatProducts, parseLine: createParseLine diff --git a/p/oebb/index.js b/p/oebb/index.js index 13a61284..5196ab49 100644 --- a/p/oebb/index.js +++ b/p/oebb/index.js @@ -113,7 +113,7 @@ const oebbProfile = { products: products.allProducts, - parseProducts: createParseBitmask(products.bitmasks), + parseProducts: createParseBitmask(products.allProducts, defaultProducts), parseLine: createParseLine, parseLocation, parseMovement: createParseMovement, diff --git a/p/vbb/index.js b/p/vbb/index.js index 307ba0f4..3f9f9ecd 100644 --- a/p/vbb/index.js +++ b/p/vbb/index.js @@ -181,7 +181,7 @@ const vbbProfile = { parseStationName: shorten, parseLocation, parseLine: createParseLine, - parseProducts: createParseBitmask(modes.bitmasks), + parseProducts: createParseBitmask(modes.allProducts, defaultProducts), parseJourney: createParseJourney, parseDeparture: createParseDeparture, parseStopover: createParseStopover, diff --git a/parse/products-bitmask.js b/parse/products-bitmask.js index 04f9b89a..5dc5e8bc 100644 --- a/parse/products-bitmask.js +++ b/parse/products-bitmask.js @@ -1,14 +1,29 @@ 'use strict' -const createParseBitmask = (bitmasks) => { +const createParseBitmask = (allProducts, defaultProducts) => { + allProducts = allProducts.sort((p1, p2) => p2.bitmask - p1.bitmask) // desc + if (allProducts.length === 0) throw new Error('allProducts is empty.') + for (let product of allProducts) { + if ('string' !== typeof product.product) { + throw new Error('allProducts[].product must be a string.') + } + if ('number' !== typeof product.bitmask) { + throw new Error(product.product + '.bitmask must be a number.') + } + } + const parseBitmask = (bitmask) => { - const products = {} - let i = 1 - do { - products[bitmasks[i].product] = products[bitmasks[i].product] || !!(bitmask & i) - i *= 2 - } while (bitmasks[i] && bitmasks[i].product) - return products + const res = Object.assign({}, defaultProducts) + + for (let product of allProducts) { + if (bitmask === 0) break + if ((product.bitmask & bitmask) > 0) { + res[product.product] = true + bitmask -= product.bitmask + } + } + + return res } return parseBitmask } diff --git a/test/db.js b/test/db.js index f38d2ddd..ffaca334 100644 --- a/test/db.js +++ b/test/db.js @@ -8,7 +8,7 @@ const isRoughlyEqual = require('is-roughly-equal') const co = require('./co') const createClient = require('..') const dbProfile = require('../p/db') -const modes = require('../p/db/modes') +const {allProducts} = require('../p/db/modes') const { assertValidStation, assertValidPoi, @@ -69,11 +69,12 @@ const assertIsJungfernheide = (t, s) => { t.ok(isRoughlyEqual(s.location.longitude, 13.299424, .0005)) } -// todo: this doesnt seem to work // todo: DRY with assertValidStationProducts +// todo: DRY with other tests const assertValidProducts = (t, p) => { - for (let k of Object.keys(modes)) { - t.ok('boolean', typeof modes[k], 'mode ' + k + ' must be a boolean') + for (let product of allProducts) { + product = product.product // wat + t.equal(typeof p[product], 'boolean', 'product ' + p + ' must be a boolean') } } diff --git a/test/insa.js b/test/insa.js index 86008982..b23db709 100644 --- a/test/insa.js +++ b/test/insa.js @@ -8,7 +8,7 @@ const validateFptf = require('validate-fptf') const co = require('./co') const createClient = require('..') const insaProfile = require('../p/insa') -const products = require('../p/insa/products') +const {allProducts} = require('../p/insa/products') const { assertValidStation, assertValidPoi, @@ -56,11 +56,12 @@ const assertIsMagdeburgHbf = (t, s) => { t.ok(isRoughlyEqual(s.location.longitude, 11.626891, 0.001)) } -// todo: this doesnt seem to work // todo: DRY with assertValidStationProducts +// todo: DRY with other tests const assertValidProducts = (t, p) => { - for (let k of Object.keys(products)) { - t.ok('boolean', typeof products[k], 'mode ' + k + ' must be a boolean') + for (let product of allProducts) { + product = product.product // wat + t.equal(typeof p[product], 'boolean', 'product ' + p + ' must be a boolean') } } diff --git a/test/oebb.js b/test/oebb.js index 178c58db..73d8c685 100644 --- a/test/oebb.js +++ b/test/oebb.js @@ -12,7 +12,7 @@ const validateLineWithoutMode = require('./validate-line-without-mode') const co = require('./co') const createClient = require('..') const oebbProfile = require('../p/oebb') -const products = require('../p/oebb/products') +const {allProducts} = require('../p/oebb/products') const { assertValidStation, assertValidPoi, @@ -73,11 +73,12 @@ const assertIsSalzburgHbf = (t, s) => { t.ok(isRoughlyEqual(s.location.longitude, 13.045604, .0005)) } -// todo: this doesnt seem to work // todo: DRY with assertValidStationProducts +// todo: DRY with other tests const assertValidProducts = (t, p) => { - for (let k of Object.keys(products)) { - t.ok('boolean', typeof products[k], 'mode ' + k + ' must be a boolean') + for (let product of allProducts) { + product = product.product // wat + t.equal(typeof p[product], 'boolean', 'product ' + p + ' must be a boolean') } } From a10e9487bd7759c8a6d36dedd238f0a75fb587fa Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 13 Mar 2018 03:32:21 +0100 Subject: [PATCH 07/14] minor changes & fixes --- p/insa/index.js | 2 -- readme.md | 1 + test/insa.js | 2 -- 3 files changed, 1 insertion(+), 4 deletions(-) diff --git a/p/insa/index.js b/p/insa/index.js index b50c02fc..439aa6a5 100644 --- a/p/insa/index.js +++ b/p/insa/index.js @@ -67,10 +67,8 @@ const insaProfile = { locale: 'de-DE', timezone: 'Europe/Berlin', endpoint: 'http://reiseauskunft.insa.de/bin/mgate.exe', - products: products.allProducts, transformReqBody, - defaultProducts, parseProducts: createParseBitmask(products.allProducts, defaultProducts), formatProducts, diff --git a/readme.md b/readme.md index a0f71162..09eab5fe 100644 --- a/readme.md +++ b/readme.md @@ -7,6 +7,7 @@ HAFAS endpoint | wrapper library? | docs | example code | source code [Deutsche Bahn](https://en.wikipedia.org/wiki/Deutsche_Bahn) | [`db-hafas`](https://github.com/derhuerst/db-hafas), which has additional features | [docs](p/db/readme.md) | [example code](p/db/example.js) | [src](p/db/index.js) [Berlin & Brandenburg public transport](https://en.wikipedia.org/wiki/Verkehrsverbund_Berlin-Brandenburg) | [`vbb-hafas`](https://github.com/derhuerst/vbb-hafas), which has additional features | [docs](p/vbb/readme.md) | [example code](p/vbb/example.js) | [src](p/vbb/index.js) [Österreichische Bundesbahnen (ÖBB)](https://en.wikipedia.org/wiki/Austrian_Federal_Railways) | – | [docs](p/oebb/readme.md) | [example code](p/oebb/example.js) | [src](p/oebb/index.js) +[Nahverkehr Sachsen-Anhalt (NASA)](https://de.wikipedia.org/wiki/Nahverkehrsservice_Sachsen-Anhalt)/[INSA](https://insa.de) | – | [docs](p/insa/readme.md) | [example code](p/insa/example.js) | [src](p/insa/index.js) [![npm version](https://img.shields.io/npm/v/hafas-client.svg)](https://www.npmjs.com/package/hafas-client) [![build status](https://img.shields.io/travis/derhuerst/hafas-client.svg)](https://travis-ci.org/derhuerst/hafas-client) diff --git a/test/insa.js b/test/insa.js index b23db709..eea792f0 100644 --- a/test/insa.js +++ b/test/insa.js @@ -24,7 +24,6 @@ const { const when = createWhen('Europe/Berlin', 'de-DE') const assertValidStationProducts = (t, p) => { - return null; // todo t.ok(p) t.equal(typeof p.nationalExp, 'boolean') t.equal(typeof p.national, 'boolean') @@ -32,7 +31,6 @@ const assertValidStationProducts = (t, p) => { t.equal(typeof p.suburban, 'boolean') t.equal(typeof p.tram, 'boolean') t.equal(typeof p.bus, 'boolean') - // console.error(p); // todo t.equal(typeof p.tourismTrain, 'boolean') } From 551d2b82155f2fa0d36baa052cbd422224a5076a Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 13 Mar 2018 03:37:25 +0100 Subject: [PATCH 08/14] fix profile and profile validation :bug: --- lib/validate-profile.js | 8 ++++++-- p/insa/index.js | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/validate-profile.js b/lib/validate-profile.js index cfa8a840..19465c3f 100644 --- a/lib/validate-profile.js +++ b/lib/validate-profile.js @@ -7,7 +7,7 @@ const types = { transformReqBody: 'function', transformJourneysQuery: 'function', - products: 'object', + products: 'array', parseDateTime: 'function', parseDeparture: 'function', @@ -36,7 +36,11 @@ const types = { const validateProfile = (profile) => { for (let key of Object.keys(types)) { const type = types[key] - if (type !== typeof profile[key]) { + if (type === 'array') { + if (!Array.isArray(profile[key])) { + throw new Error(`profile.${key} must be an array.`) + } + } else if (type !== typeof profile[key]) { throw new Error(`profile.${key} must be a ${type}.`) } if (type === 'object' && profile[key] === null) { diff --git a/p/insa/index.js b/p/insa/index.js index 439aa6a5..229fbd54 100644 --- a/p/insa/index.js +++ b/p/insa/index.js @@ -69,6 +69,7 @@ const insaProfile = { endpoint: 'http://reiseauskunft.insa.de/bin/mgate.exe', transformReqBody, + products: products.allProducts, parseProducts: createParseBitmask(products.allProducts, defaultProducts), formatProducts, From 93f3bd1987d004f8673f7dfb86ab6eea14c41092 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 13 Mar 2018 19:24:38 +0100 Subject: [PATCH 09/14] INSA: remove test todo, fix bug caused by 73c419f - apparently INSA doesn't return prices --- p/vbb/index.js | 3 ++- test/insa.js | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/p/vbb/index.js b/p/vbb/index.js index 3f9f9ecd..fc97d00e 100644 --- a/p/vbb/index.js +++ b/p/vbb/index.js @@ -153,7 +153,8 @@ const defaultProducts = { bus: true, ferry: true, express: true, - regional: true + regional: true, + taxi: false } const formatProducts = (products) => { products = Object.assign(Object.create(null), defaultProducts, products) diff --git a/test/insa.js b/test/insa.js index eea792f0..67f32352 100644 --- a/test/insa.js +++ b/test/insa.js @@ -109,9 +109,6 @@ test('Magdeburg Hbf to Magdeburg-Buckau', co(function*(t) { t.ok(Array.isArray(leg.passed)) for (let stopover of leg.passed) assertValidStopover(t, stopover) - - // todo - // if (journey.price) assertValidPrice(t, journey.price) } t.end() From 95253adbe118d6e2df2989f2ca85633145ab412b Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 13 Mar 2018 19:30:10 +0100 Subject: [PATCH 10/14] another fix for 73c419f :bug: --- p/db/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/p/db/index.js b/p/db/index.js index f88dc539..d8cc5e6f 100644 --- a/p/db/index.js +++ b/p/db/index.js @@ -112,7 +112,8 @@ const defaultProducts = { national: true, nationalExp: true, regional: true, - regionalExp: true + regionalExp: true, + taxi: false } const formatProducts = (products) => { products = Object.assign(Object.create(null), defaultProducts, products) From 68bf199673f309bc267c6b9e810ce3daac26da54 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 13 Mar 2018 19:45:44 +0100 Subject: [PATCH 11/14] aand another :bug: --- p/vbb/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/p/vbb/index.js b/p/vbb/index.js index fc97d00e..3f9f9ecd 100644 --- a/p/vbb/index.js +++ b/p/vbb/index.js @@ -153,8 +153,7 @@ const defaultProducts = { bus: true, ferry: true, express: true, - regional: true, - taxi: false + regional: true } const formatProducts = (products) => { products = Object.assign(Object.create(null), defaultProducts, products) From ba97275baef92af5c70754c3e4a18121d4abff67 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 13 Mar 2018 21:04:42 +0100 Subject: [PATCH 12/14] INSA: enable journeyLeg --- p/insa/example.js | 5 +++++ p/insa/index.js | 4 ++-- test/insa.js | 28 ++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/p/insa/example.js b/p/insa/example.js index 2531ec5b..1a46a1d6 100644 --- a/p/insa/example.js +++ b/p/insa/example.js @@ -17,6 +17,11 @@ client.journeys('008010226', '008013456', {results: 1}) // longitude: 11.641705 // }, {distance: 200}) +// .then(([journey]) => { +// const leg = journey.legs[0] +// return client.journeyLeg(leg.id, leg.line.name) +// }) + .then(data => { console.log(require('util').inspect(data, { depth: null })) }) diff --git a/p/insa/index.js b/p/insa/index.js index 229fbd54..ee1b8973 100644 --- a/p/insa/index.js +++ b/p/insa/index.js @@ -73,9 +73,9 @@ const insaProfile = { parseProducts: createParseBitmask(products.allProducts, defaultProducts), formatProducts, - parseLine: createParseLine + parseLine: createParseLine, - // todo: journeyLeg? + journeyLeg: true // todo: radar? } diff --git a/test/insa.js b/test/insa.js index 67f32352..09be1d80 100644 --- a/test/insa.js +++ b/test/insa.js @@ -255,6 +255,34 @@ test('nearby Magdeburg Hbf', co(function*(t) { t.end() })) +test('journey leg details', co(function* (t) { + const magdeburgHbf = '8010224' + const magdeburgBuckau = '8013456' + const [journey] = yield client.journeys(magdeburgHbf, magdeburgBuckau, { + results: 1, when + }) + + const p = journey.legs[0] + t.ok(p, 'missing legs[0]') + t.ok(p.id, 'missing legs[0].id') + t.ok(p.line, 'missing legs[0].line') + t.ok(p.line.name, 'missing legs[0].line.name') + const leg = yield client.journeyLeg(p.id, p.line.name, {when}) + + t.equal(typeof leg.id, 'string') + t.ok(leg.id) + + assertValidLine(t, leg.line) + + t.equal(typeof leg.direction, 'string') + t.ok(leg.direction) + + t.ok(Array.isArray(leg.passed)) + for (let passed of leg.passed) assertValidStopover(t, passed) + + t.end() +})) + test('locations named Magdeburg', co(function*(t) { const locations = yield client.locations('Magdeburg', { results: 10 From c123d9e451c002422749198b3f96114002e6d670 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 13 Mar 2018 21:06:27 +0100 Subject: [PATCH 13/14] INSA: enable radar --- p/insa/example.js | 1 + p/insa/index.js | 2 +- p/insa/products.js | 3 ++- parse/location.js | 2 +- test/insa.js | 53 ++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 58 insertions(+), 3 deletions(-) diff --git a/p/insa/example.js b/p/insa/example.js index 1a46a1d6..054ae1f3 100644 --- a/p/insa/example.js +++ b/p/insa/example.js @@ -16,6 +16,7 @@ client.journeys('008010226', '008013456', {results: 1}) // latitude: 52.148842, // longitude: 11.641705 // }, {distance: 200}) +// client.radar(52.148364, 11.600826, 52.108486, 11.651451, {results: 10}) // .then(([journey]) => { // const leg = journey.legs[0] diff --git a/p/insa/index.js b/p/insa/index.js index ee1b8973..4a2de867 100644 --- a/p/insa/index.js +++ b/p/insa/index.js @@ -76,7 +76,7 @@ const insaProfile = { parseLine: createParseLine, journeyLeg: true - // todo: radar? + radar: true } module.exports = insaProfile; diff --git a/p/insa/products.js b/p/insa/products.js index 81cb82f7..d6b343e5 100644 --- a/p/insa/products.js +++ b/p/insa/products.js @@ -65,7 +65,8 @@ p.bitmasks[2] = p.national p.bitmasks[8] = p.regional p.bitmasks[16] = p.suburban p.bitmasks[32] = p.tram -p.bitmasks[64+128] = p.bus +p.bitmasks[64] = p.bus +p.bitmasks[128] = p.bus p.bitmasks[256] = p.tourismTrain p.allProducts = [ diff --git a/parse/location.js b/parse/location.js index c0de893d..e6689e6b 100644 --- a/parse/location.js +++ b/parse/location.js @@ -20,7 +20,7 @@ const parseLocation = (profile, l, lines) => { type: 'station', id: l.extId, name: l.name, - location: res + location: 'number' === typeof res.latitude ? res : null } if ('pCls' in l) station.products = profile.parseProducts(l.pCls) diff --git a/test/insa.js b/test/insa.js index 09be1d80..f22581d6 100644 --- a/test/insa.js +++ b/test/insa.js @@ -310,3 +310,56 @@ test('location', co(function*(t) { t.end() })) + +test('radar', co(function* (t) { + const north = 52.148364 + const west = 11.600826 + const south = 52.108486 + const east = 11.651451 + const vehicles = yield client.radar(north, west, south, east, { + duration: 5 * 60, when, results: 10 + }) + + t.ok(Array.isArray(vehicles)) + t.ok(vehicles.length > 0) + for (let v of vehicles) { + assertValidLine(t, v.line) + + t.equal(typeof v.location.latitude, 'number') + t.ok(v.location.latitude <= 57, 'vehicle is too far away') + t.ok(v.location.latitude >= 47, 'vehicle is too far away') + t.equal(typeof v.location.longitude, 'number') + t.ok(v.location.longitude >= 8, 'vehicle is too far away') + t.ok(v.location.longitude <= 14, 'vehicle is too far away') + + t.ok(Array.isArray(v.nextStops)) + for (let st of v.nextStops) { + assertValidStopover(t, st, true) + + if (st.arrival) { + t.equal(typeof st.arrival, 'string') + const arr = +new Date(st.arrival) + // note that this can be an ICE train + t.ok(isRoughlyEqual(14 * hour, +when, arr)) + } + if (st.departure) { + t.equal(typeof st.departure, 'string') + const dep = +new Date(st.departure) + // note that this can be an ICE train + t.ok(isRoughlyEqual(14 * hour, +when, dep)) + } + } + + t.ok(Array.isArray(v.frames)) + for (let f of v.frames) { + // see #28 + // todo: check if this works by now + assertValidStation(t, f.origin, true) + assertValidStationProducts(t, f.origin.products) + assertValidStation(t, f.destination, true) + assertValidStationProducts(t, f.destination.products) + t.equal(typeof f.t, 'number') + } + } + t.end() +})) From 4fae4efbcba868bd358592b3586f60b6e647f431 Mon Sep 17 00:00:00 2001 From: Jannis R Date: Tue, 13 Mar 2018 21:12:46 +0100 Subject: [PATCH 14/14] stupid mistake :bug: --- p/insa/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p/insa/index.js b/p/insa/index.js index 4a2de867..8b7bea1b 100644 --- a/p/insa/index.js +++ b/p/insa/index.js @@ -75,7 +75,7 @@ const insaProfile = { parseLine: createParseLine, - journeyLeg: true + journeyLeg: true, radar: true }