diff --git a/src/node_osrm.cpp b/src/node_osrm.cpp index 600c51e..8df325d 100644 --- a/src/node_osrm.cpp +++ b/src/node_osrm.cpp @@ -79,17 +79,55 @@ NAN_METHOD(Engine::New) try { libosrm_config lib_config; if (args.Length() == 1) { - std::string base = *String::Utf8Value(args[0]->ToString()); - lib_config.server_paths["base"] = base; - lib_config.use_shared_memory = false; - } else if (args.Length() >= 2) { - if (!args[1]->IsUint32()) { - NanThrowError("the maximum number of locations in the distance table must be an unsigned integer"); + std::string base; + bool shared_memory_defined = false; + if (args[0]->IsString()) { + base = *String::Utf8Value(args[0]->ToString()); + } else if (args[0]->IsObject()) { + Local params = args[0]->ToObject(); + + Local path = params->Get(NanNew("path")); + if (!path->IsUndefined()) { + base = *String::Utf8Value(path->ToString()); + } + + Local max_locations_distance_table = params->Get(NanNew("distance_table")); + if (!max_locations_distance_table->IsUndefined()) { + if (!max_locations_distance_table->IsUint32()) { + NanThrowError("the maximum number of locations in the distance table must be an unsigned integer"); + NanReturnUndefined(); + } else { + lib_config.max_locations_distance_table = max_locations_distance_table->ToUint32()->Value(); + } + } + + Local shared_memory = params->Get(NanNew("shared_memory")); + if (!shared_memory->IsUndefined()) { + if (!shared_memory->IsBoolean()) { + NanThrowError("shared_memory option must be a boolean"); + NanReturnUndefined(); + } else { + lib_config.use_shared_memory = shared_memory->ToBoolean()->Value(); + if (base.empty() && lib_config.use_shared_memory == false) { + NanThrowError("shared_memory must be enabled if no path is specified"); + NanReturnUndefined(); + } + shared_memory_defined = true; + } + } + + } else { + NanThrowError("first argument must be a path string or params object"); NanReturnUndefined(); } - lib_config.max_locations_distance_table = args[1]->ToUint32()->Value(); - } + if (!base.empty()) { + lib_config.server_paths["base"] = base; + } + if (shared_memory_defined == false && !base.empty()) { + lib_config.use_shared_memory = false; + } + } auto im = new Engine(lib_config); im->Wrap(args.This()); NanReturnValue(args.This()); @@ -118,15 +156,11 @@ NAN_METHOD(Engine::route) } if (!args[0]->IsObject()) { - NanThrowTypeError("two arguments required"); + NanThrowTypeError("first arg must be an object"); NanReturnUndefined(); } Local obj = args[0]->ToObject(); - if (obj->IsNull() || obj->IsUndefined()) { - NanThrowError("first arg must be an object"); - NanReturnUndefined(); - } route_parameters_ptr params = make_unique(); @@ -260,11 +294,11 @@ NAN_METHOD(Engine::match) NanReturnUndefined(); } - Local obj = args[0]->ToObject(); - if (obj->IsNull() || obj->IsUndefined()) { + if (args[0]->IsNull() || args[0]->IsUndefined()) { NanThrowError("first arg must be an object"); NanReturnUndefined(); } + Local obj = args[0]->ToObject(); Local coordinates = obj->Get(NanNew("coordinates")); if (!coordinates->IsArray()) { @@ -279,7 +313,7 @@ NAN_METHOD(Engine::match) } Local timestamps = obj->Get(NanNew("timestamps")); - if (!coordinates->IsArray() && !timestamps->IsUndefined()) { + if (!timestamps->IsArray() && !timestamps->IsUndefined()) { NanThrowError("timestamps must be an array of integers (or undefined)"); NanReturnUndefined(); } @@ -306,6 +340,10 @@ NAN_METHOD(Engine::match) // add all timestamps for (uint32_t i = 0; i < timestamps_array->Length(); ++i) { + if (!timestamps_array->Get(i)->IsNumber()) { + NanThrowError("timestamps array items must be numbers"); + NanReturnUndefined(); + } params->timestamps.emplace_back(static_cast(timestamps_array->Get(i)->NumberValue())); } } @@ -342,11 +380,11 @@ NAN_METHOD(Engine::table) NanReturnUndefined(); } - Local obj = args[0]->ToObject(); - if (obj->IsNull() || obj->IsUndefined()) { + if (args[0]->IsNull() || args[0]->IsUndefined()) { NanThrowError("first arg must be an object"); NanReturnUndefined(); } + Local obj = args[0]->ToObject(); Local coordinates = obj->Get(NanNew("coordinates")); if (!coordinates->IsArray()) { diff --git a/test/osrm.test.js b/test/osrm.test.js index 9d97b8a..f675986 100644 --- a/test/osrm.test.js +++ b/test/osrm.test.js @@ -1,26 +1,99 @@ var OSRM = require('../'); var assert = require('assert'); -it('throws if new keyword is not used', function(done) { +it('constructor: throws if new keyword is not used', function(done) { assert.throws(function() { OSRM(); }, /Cannot call constructor as function, you need to use 'new' keyword/); done(); }); -it('throws if necessary files do not exist', function(done) { +it('constructor: throws if necessary files do not exist', function(done) { assert.throws(function() { new OSRM("missing.osrm"); }, /hsgr not found/); done(); }); -it('throws if insufficient coordinates given', function() { +it('constructor: takes a distance table length argument', function(done) { + var osrm = new OSRM({path: "berlin-latest.osrm", distance_table: 30000}); + osrm.route({coordinates: [[52.519930,13.438640], [52.513191,13.415852]]}, function(err, route) { + assert.ifError(err); + done(); + }); +}); + +it('constructor: takes a shared memory argument', function(done) { + var osrm = new OSRM({path: "berlin-latest.osrm", shared_memory: false}); + osrm.route({coordinates: [[52.519930,13.438640], [52.513191,13.415852]]}, function(err, route) { + assert.ifError(err); + done(); + }); +}); + +it('constructor: throws if shared_memory==false with no path defined', function() { + assert.throws(function() { var osrm = new OSRM({shared_memory: false}); }, + /shared_memory must be enabled if no path is specified/); +}); + +it('constructor: throws if given a non-bool shared_memory option', function() { + assert.throws(function() { var osrm = new OSRM({path: "berlin-latest.osrm", shared_memory: "a"}); }, + /shared_memory option must be a boolean/); +}); + +it('constructor: throws if given a non-uint distance_table option', function() { + assert.throws(function() { var osrm = new OSRM({path: "berlin-latest.osrm", distance_table: -4}); }, + /the maximum number of locations in the distance table must be an unsigned integer/); +}); + +it('constructor: throws if given a non-string/obj argument', function() { + assert.throws(function() { var osrm = new OSRM(true); }, + /first argument must be a path string or params object/); +}); + +it('route: routes Berlin', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + osrm.route({coordinates: [[52.519930,13.438640], [52.513191,13.415852]]}, function(err, route) { + assert.ifError(err); + assert.equal(route.status_message, 'Found route between points'); + done(); + }); +}); + +it('route: throws with too few or invalid args', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + assert.throws(function() { osrm.route({coordinates: [[52.519930,13.438640], [52.513191,13.415852]]}) }, + /two arguments required/); + assert.throws(function() { osrm.route(null, function(err, route) {}) }, + /first arg must be an object/); + done(); +}); + +it('route: throws with bad params', function(done) { var osrm = new OSRM("berlin-latest.osrm"); assert.throws(function () { osrm.route({coordinates: []}, function(err) {}) }); + assert.throws(function() { osrm.route({}, function(err, route) {}) }, + /must provide a coordinates property/); + assert.throws(function() { osrm.route({coordinates: null}, function(err, route) {}) }, + "coordinates must be an array of (lat/long) pairs"); + assert.throws(function() { osrm.route({coordinates: [52.519930, 13.438640]}, function(err, route) {}) }, + "coordinates must be an array of (lat/long) pairs"); + assert.throws(function() { osrm.route({coordinates: [[52.519930], [13.438640]]}, function(err, route) {}) }, + "coordinates must be an array of (lat/long) pairs"); + assert.throws(function() { osrm.route({coordinates: [[52.519930,13.438640], [52.513191,13.415852]], hints: null}, function(err, route) {}) }, + "hints must be an array of strings/null"); + var options = { + coordinates: [[52.519930,13.438640], [52.513191,13.415852]], + alternateRoute: false, + printInstructions: false, + hints: [[52.519930,13.438640]] + }; + assert.throws(function() { osrm.route(options, function(err, route) {}) }, + /hint must be null or string/); + done(); }); -it('routes Berlin', function(done) { +it('route: takes jsonp parameter', function(done) { var osrm = new OSRM("berlin-latest.osrm"); - osrm.route({coordinates: [[52.519930,13.438640], [52.513191,13.415852]]}, function(err, route) { + osrm.route({coordinates: [[52.519930,13.438640], [52.513191,13.415852]], jsonpParameter: 'function'}, function(err, route) { assert.ifError(err); assert.equal(route.status_message, 'Found route between points'); done(); @@ -29,9 +102,9 @@ it('routes Berlin', function(done) { if (process.platform === 'darwin') { // shared memory does not work on Mac OS for now. - it.skip('routes Berlin using shared memory', function(done) {}); + it.skip('route: routes Berlin using shared memory', function(done) {}); } else { - it('routes Berlin using shared memory', function(done) { + it('route: routes Berlin using shared memory', function(done) { var osrm = new OSRM(); osrm.route({coordinates: [[52.519930,13.438640], [52.513191,13.415852]]}, function(err, route) { assert.ifError(err); @@ -41,7 +114,7 @@ if (process.platform === 'darwin') { }); } -it('routes Berlin with options', function(done) { +it('route: routes Berlin with options', function(done) { var osrm = new OSRM("berlin-latest.osrm"); var options = { coordinates: [[52.519930,13.438640], [52.513191,13.415852]], @@ -58,7 +131,45 @@ it('routes Berlin with options', function(done) { }); }); -it('distance table in Berlin', function(done) { +it('route: routes Berlin with hints', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + var options = { + coordinates: [[52.519930,13.438640], [52.513191,13.415852]], + alternateRoute: false, + printInstructions: false + }; + osrm.route(options, function(err, first) { + assert.ifError(err); + assert.equal(first.status_message, 'Found route between points'); + var checksum = first.hint_data.checksum; + assert.equal("number", typeof(checksum)); + + options.hints = first.hint_data.locations; + options.checksum = checksum; + + osrm.route(options, function(err, second) { + assert.ifError(err); + assert.deepEqual(first, second); + done(); + }); + }); +}); + +it('route: routes Berlin with null hints', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + var options = { + coordinates: [[52.519930,13.438640], [52.513191,13.415852]], + alternateRoute: false, + printInstructions: false, + hints: ['', '', ''] + }; + osrm.route(options, function(err, second) { + assert.ifError(err); + done(); + }); +}); + +it('table: distance table in Berlin', function(done) { var osrm = new OSRM("berlin-latest.osrm"); var options = { coordinates: [[52.519930,13.438640], [52.513191,13.415852]] @@ -86,7 +197,34 @@ it('distance table in Berlin', function(done) { }); }); -it('match in Berlin', function(done) { +it('table: throws on invalid arguments', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + var options = {}; + assert.throws(function() { osrm.table(options); }, + /two arguments required/); + options.coordinates = null; + assert.throws(function() { osrm.table(options, function() {}); }, + "coordinates must be an array of (lat/long) pairs"); + options.coordinates = [[52.542648,13.393252]]; + assert.throws(function() { osrm.table(options, function(err, response) {}) }, + /at least two coordinates must be provided/); + options.coordinates = [52.542648,13.393252]; + assert.throws(function() { osrm.table(options, function(err, response) {}) }, + "coordinates must be an array of (lat/long) pairs"); + options.coordinates = [[52.542648],[13.393252]]; + assert.throws(function() { osrm.table(options, function(err, response) {}) }, + "coordinates must be an array of (lat/long) pairs"); + done(); +}); + +it('table: throws on invalid arguments', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + assert.throws(function() { osrm.table(null, function() {}); }, + /first arg must be an object/); + done(); +}); + +it('match: match in Berlin', function(done) { var osrm = new OSRM("berlin-latest.osrm"); var options = { coordinates: [[52.542648,13.393252], [52.543079,13.394780], [52.542107,13.397389]], @@ -99,7 +237,7 @@ it('match in Berlin', function(done) { }); }); -it('match in Berlin without timestamps', function(done) { +it('match: match in Berlin without timestamps', function(done) { var osrm = new OSRM("berlin-latest.osrm"); var options = { coordinates: [[52.542648,13.393252], [52.543079,13.394780], [52.542107,13.397389]] @@ -111,7 +249,7 @@ it('match in Berlin without timestamps', function(done) { }); }); -it('match in Berlin with all options', function(done) { +it('match: match in Berlin with all options', function(done) { var osrm = new OSRM("berlin-latest.osrm"); var options = { coordinates: [[52.542648,13.393252], [52.543079,13.394780], [52.542107,13.397389]], @@ -128,28 +266,54 @@ it('match in Berlin with all options', function(done) { }); }); -it('routes Berlin with hints', function(done) { +it('match: throws on missing arguments', function(done) { var osrm = new OSRM("berlin-latest.osrm"); - var options = { - coordinates: [[52.519930,13.438640], [52.513191,13.415852]], - alternateRoute: false, - printInstructions: false - }; - osrm.route(options, function(err, first) { - assert.ifError(err); - assert.equal(first.status_message, 'Found route between points'); - var checksum = first.hint_data.checksum; - assert.equal("number", typeof(checksum)); + assert.throws(function() { osrm.match({}) }, + /two arguments required/); + done(); +}); - options.hints = first.hint_data.locations; - options.checksum = checksum; +it('match: throws on non-object arg', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + assert.throws(function() { osrm.match(null, function(err, response) {}) }, + /first arg must be an object/); + done(); +}); - osrm.route(options, function(err, second) { - assert.ifError(err); - assert.deepEqual(first, second); - done(); - }); - }); +it('match: throws on invalid coordinates param', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + var options = { + coordinates: '' + } + assert.throws(function() { osrm.match(options, function(err, response) {}) }, + "coordinates must be an array of (lat/long) pairs"); + options.coordinates = [[52.542648,13.393252]]; + assert.throws(function() { osrm.match(options, function(err, response) {}) }, + /at least two coordinates must be provided/); + options.coordinates = [52.542648,13.393252]; + assert.throws(function() { osrm.match(options, function(err, response) {}) }, + "coordinates must be an array of (lat/long) pairs"); + options.coordinates = [[52.542648],[13.393252]]; + assert.throws(function() { osrm.match(options, function(err, response) {}) }, + "coordinates must be an array of (lat/long) pairs"); + done(); +}); + +it('match: throws on invalid timestamps param', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + var options = { + coordinates: [[52.542648,13.393252], [52.543079,13.394780], [52.542107,13.397389]], + timestamps: "timestamps" + } + assert.throws(function() { osrm.match(options, function(err, response) {}) }, + "timestamps must be an array of integers (or undefined)"); + options.timestamps = ['invalid', 'timestamp', 'array']; + assert.throws(function() { osrm.match(options, function(err, response) {}) }, + /timestamps array items must be numbers/); + options.timestamps = [1424684612, 1424684616]; + assert.throws(function() { osrm.match(options, function(err, response) {}) }, + /timestamp array must have the same size as the coordinates array/); + done(); }); it('nearest', function(done) { @@ -163,6 +327,19 @@ it('nearest', function(done) { }); }); +it('nearest: throws on invalid args', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + var options = {}; + assert.throws(function() { osrm.nearest(options); }, + /two arguments required/); + assert.throws(function() { osrm.nearest(null, function(err, res) {}); }, + /first argument must be an array of lat, long/); + options.coordinates = [52.4224]; + assert.throws(function() { osrm.nearest(options, function(err, res) {}); }, + /first argument must be an array of lat, long/); + done(); +}); + it('locate', function(done) { var osrm = new OSRM("berlin-latest.osrm"); osrm.locate([52.4224, 13.333086], function(err, result) { @@ -172,3 +349,19 @@ it('locate', function(done) { done(); }); }); + +it('locate: throws on incorrect number of args', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + assert.throws(function() { osrm.locate([52.4224, 13.333086]) }, + /two arguments required/); + done(); +}); + +it('locate: throws on invalid coordinate arg', function(done) { + var osrm = new OSRM("berlin-latest.osrm"); + assert.throws(function() { osrm.locate(52.4224, function(err, result) {}) }, + /first argument must be an array of lat, long/); + assert.throws(function() { osrm.locate([52.4224], function(err, result) {}) }, + /first argument must be an array of lat, long/); + done(); +});