Browse Source

progress commit

pull/280/head
Peter Johnson 9 years ago
parent
commit
82ab899ecc
  1. 39
      middleware/_types.js
  2. 38
      query/reverse.js
  3. 32
      query/search.js
  4. 26
      sanitiser/_boundary_country.js
  5. 4
      sanitiser/_geo_autocomplete.js
  6. 176
      sanitiser/_geo_common.js
  7. 19
      sanitiser/_geo_reverse.js
  8. 8
      sanitiser/_geo_search.js
  9. 5
      test/ciao/autocomplete/null_island.coffee
  10. 4
      test/ciao/reverse/basic_reverse.coffee
  11. 38
      test/ciao/reverse/boundary_circle_invalid_radius.coffee
  12. 37
      test/ciao/reverse/boundary_circle_valid_radius.coffee
  13. 34
      test/ciao/reverse/boundary_country_invalid_alpha2.coffee
  14. 34
      test/ciao/reverse/boundary_country_invalid_alpha3.coffee
  15. 34
      test/ciao/reverse/boundary_country_invalid_iso3166.coffee
  16. 33
      test/ciao/reverse/boundary_country_valid_alpha2.coffee
  17. 33
      test/ciao/reverse/boundary_country_valid_alpha3.coffee
  18. 35
      test/ciao/reverse/point_invalid_lat.coffee
  19. 35
      test/ciao/reverse/point_invalid_lon.coffee
  20. 35
      test/ciao/reverse/point_missing_lat.coffee
  21. 35
      test/ciao/reverse/point_missing_lon.coffee
  22. 8
      test/ciao/reverse/point_null_island.coffee
  23. 34
      test/ciao/reverse/point_valid_duo.coffee
  24. 33
      test/ciao/reverse/size_over_max.coffee
  25. 33
      test/ciao/reverse/size_under_min.coffee
  26. 32
      test/ciao/reverse/size_valid.coffee
  27. 37
      test/ciao/search/boundary_circle_invalid_lat_lon_types.coffee
  28. 37
      test/ciao/search/boundary_circle_invalid_radius.coffee
  29. 37
      test/ciao/search/boundary_circle_missing_lat.coffee
  30. 37
      test/ciao/search/boundary_circle_missing_lon.coffee
  31. 36
      test/ciao/search/boundary_circle_valid_duo.coffee
  32. 36
      test/ciao/search/boundary_circle_valid_trio.coffee
  33. 35
      test/ciao/search/boundary_country_invalid_alpha2.coffee
  34. 35
      test/ciao/search/boundary_country_invalid_alpha3.coffee
  35. 35
      test/ciao/search/boundary_country_invalid_iso3166.coffee
  36. 34
      test/ciao/search/boundary_country_valid_alpha2.coffee
  37. 34
      test/ciao/search/boundary_country_valid_alpha3.coffee
  38. 38
      test/ciao/search/boundary_rect_partially_specified.coffee
  39. 37
      test/ciao/search/boundary_rect_valid.coffee
  40. 36
      test/ciao/search/focus_point_invalid_lat.coffee
  41. 36
      test/ciao/search/focus_point_invalid_lon.coffee
  42. 36
      test/ciao/search/focus_point_missing_lat.coffee
  43. 36
      test/ciao/search/focus_point_missing_lon.coffee
  44. 6
      test/ciao/search/focus_point_null_island.coffee
  45. 35
      test/ciao/search/focus_point_valid_duo.coffee
  46. 35
      test/ciao/search/layers_alias_address.coffee
  47. 35
      test/ciao/search/layers_alias_coarse.coffee
  48. 36
      test/ciao/search/layers_invalid.coffee
  49. 36
      test/ciao/search/layers_mix_invalid_valid.coffee
  50. 35
      test/ciao/search/layers_multiple.coffee
  51. 35
      test/ciao/search/layers_single.coffee
  52. 34
      test/ciao/search/privacy_false.coffee
  53. 34
      test/ciao/search/privacy_true.coffee
  54. 34
      test/ciao/search/size_over_max.coffee
  55. 34
      test/ciao/search/size_under_min.coffee
  56. 33
      test/ciao/search/size_valid.coffee
  57. 36
      test/ciao/search/sources_invalid.coffee
  58. 37
      test/ciao/search/sources_layers_invalid_combo.coffee
  59. 35
      test/ciao/search/sources_layers_valid_combo.coffee
  60. 35
      test/ciao/search/sources_multiple.coffee
  61. 35
      test/ciao/search/sources_single.coffee
  62. 45
      test/unit/query/reverse.js
  63. 20
      test/unit/query/search.js
  64. 14
      test/unit/sanitiser/_boundary_country.js
  65. 354
      test/unit/sanitiser/_geo_common.js
  66. 11
      test/unit/sanitiser/reverse.js
  67. 68
      test/unit/sanitiser/search.js

39
middleware/_types.js

@ -10,25 +10,34 @@ var types_helper = require( '../helper/types' );
function middleware(req, res, next) { function middleware(req, res, next) {
req.clean = req.clean || {}; req.clean = req.clean || {};
if (req.clean.hasOwnProperty('types') === false) { if (req.clean.hasOwnProperty('types')) {
return next();
} try {
var types = types_helper(req.clean.types);
if ((types instanceof Array) && types.length === 0) {
var err = 'You have specified both the `sources` and `layers` ' +
'parameters in a combination that will return no results.';
req.errors.push( err );
}
try { else {
var types = types_helper(req.clean.types); req.clean.type = types;
}
if ((types instanceof Array) && types.length === 0) {
var err = 'You have specified both the `sources` and `layers` ' +
'parameters in a combination that will return no results.';
res.status(400); // 400 Bad Request
return next(err);
} }
req.clean.type = types; // @todo: refactor this flow, it is confusing as `types_helper()` can throw
} // with an error "clean_types should not be null or undefined" which is
catch (err) { // not returned to the user yet the return value CAN trigger a user error.
// this means there were no types specified // I would have liked to throw for BOTH cases and then handle the users errors
delete req.clean.types; // inside the 'catch' but this is not possible.
// also: why are we deleting things from $clean?
catch (err) {
// this means there were no types specified
delete req.clean.types;
}
} }
next(); next();

38
query/reverse.js

@ -24,7 +24,8 @@ function generateQuery( clean ){
// set defaults // set defaults
vs.set({ vs.set({
'size': 1 'size': 1,
'boundary:circle:radius': '500km'
}); });
// set size // set size
@ -32,30 +33,33 @@ function generateQuery( clean ){
vs.var( 'size', clean.size ); vs.var( 'size', clean.size );
} }
// set radius, default to 500km if not specified in request // focus point to score by distance
var radius = 500; if( check.number(clean['point.lat']) &&
if (clean.hasOwnProperty('boundary.circle.radius')) { check.number(clean['point.lon']) ){
radius = clean['boundary.circle.radius'];
}
// focus point centroid
if( check.number(clean['point.lat']) && check.number(clean['point.lon']) ){
vs.set({ vs.set({
// focus point to score by distance
'focus:point:lat': clean['point.lat'], 'focus:point:lat': clean['point.lat'],
'focus:point:lon': clean['point.lon'], 'focus:point:lon': clean['point.lon']
});
}
// bounding circle // bounding circle
'boundary:circle:lat': clean['point.lat'], // note: the sanitizers will take care of the case
'boundary:circle:lon': clean['point.lon'], // where point.lan/point.lon are provided in the
'boundary:circle:radius': radius + 'km' // absense of boundary.circle.lat/boundary.circle.lon
if( check.number(clean['boundary.circle.lat']) &&
check.number(clean['boundary.circle.lon']) &&
check.number(clean['boundary.circle.radius']) ){
vs.set({
'boundary:circle:lat': clean['boundary.circle.lat'],
'boundary:circle:lon': clean['boundary.circle.lon'],
'boundary:circle:radius': clean['boundary.circle.radius'] + 'km'
}); });
} }
// boundary country // boundary country
if( clean.boundary && clean.boundary.country ){ if( check.string(clean['boundary.country']) ){
vs.set({ vs.set({
'boundary:country': clean.boundary.country 'boundary:country': clean['boundary.country']
}); });
} }

32
query/search.js

@ -59,7 +59,8 @@ function generateQuery( clean ){
} }
// focus point // focus point
if( check.number(clean['focus.point.lat']) && check.number(clean['focus.point.lon']) ){ if( check.number(clean['focus.point.lat']) &&
check.number(clean['focus.point.lon']) ){
vs.set({ vs.set({
'focus:point:lat': clean['focus.point.lat'], 'focus:point:lat': clean['focus.point.lat'],
'focus:point:lon': clean['focus.point.lon'] 'focus:point:lon': clean['focus.point.lon']
@ -78,27 +79,36 @@ function generateQuery( clean ){
} }
// boundary rect // boundary rect
if( clean.bbox ){ if( check.number(clean['boundary.rect.min_lat']) &&
check.number(clean['boundary.rect.max_lat']) &&
check.number(clean['boundary.rect.min_lon']) &&
check.number(clean['boundary.rect.max_lon']) ){
vs.set({ vs.set({
'boundary:rect:top': clean.bbox.top, 'boundary:rect:top': clean['boundary.rect.min_lat'],
'boundary:rect:right': clean.bbox.right, 'boundary:rect:right': clean['boundary.rect.max_lon'],
'boundary:rect:bottom': clean.bbox.bottom, 'boundary:rect:bottom': clean['boundary.rect.max_lat'],
'boundary:rect:left': clean.bbox.left 'boundary:rect:left': clean['boundary.rect.min_lon']
}); });
} }
// boundary circle // boundary circle
// @todo: change these to the correct request variable names // @todo: change these to the correct request variable names
if( clean.boundary && clean.boundary.circle ){ if( check.number(clean['boundary.circle.lat']) &&
check.number(clean['boundary.circle.lon']) ){
vs.set({ vs.set({
'boundary:circle:lat': clean.boundary.circle.lat, 'boundary:circle:lat': clean['boundary.circle.lat'],
'boundary:circle:lon': clean.boundary.circle.lon, 'boundary:circle:lon': clean['boundary.circle.lon']
'boundary:circle:radius': clean.boundary.circle.radius + 'm'
}); });
if( check.number(clean['boundary.circle.radius']) ){
vs.set({
'boundary:circle:radius': Math.round( clean['boundary.circle.radius'] ) + 'km'
});
}
} }
// boundary country // boundary country
if( clean['boundary.country'] ){ if( check.string(clean['boundary.country']) ){
vs.set({ vs.set({
'boundary:country': clean['boundary.country'] 'boundary:country': clean['boundary.country']
}); });

26
sanitiser/_boundary_country.js

@ -5,37 +5,37 @@ function sanitize(raw, clean) {
// error & warning messages // error & warning messages
var messages = { errors: [], warnings: [] }; var messages = { errors: [], warnings: [] };
// init clean.boundary (if not already init) // target input param
clean.boundary = clean.boundary || {}; var country = raw['boundary.country'];
if (check.assigned(raw['boundary.country'])) { // param 'boundary.country' is optional and should not
var country = raw['boundary.country']; // error when simply not set by the user
if (check.assigned(country)){
if (!check.string(country)) { // must be valid string
if (!check.unemptyString(country)) {
messages.errors.push('boundary.country is not a string'); messages.errors.push('boundary.country is not a string');
delete clean.boundary.country;
} }
// must be a valid ISO 3166 code
else if (!containsIsoCode(country.toUpperCase())) { else if (!containsIsoCode(country.toUpperCase())) {
messages.errors.push(country + ' is not a valid ISO2/ISO3 country code'); messages.errors.push(country + ' is not a valid ISO2/ISO3 country code');
delete clean.boundary.country;
} }
// valid ISO 3166 country code, set alpha3 code on 'clean.boundary.country'
else { else {
// the only way for boundary.country to be assigned is if input is // the only way for boundary.country to be assigned is if input is
// a string and a known ISO2 or ISO3 // a string and a known ISO2 or ISO3
clean.boundary.country = iso3166.to3(country.toUpperCase()); clean['boundary.country'] = iso3166.to3(country.toUpperCase());
} }
} else {
delete clean.boundary.country;
} }
return messages; return messages;
} }
function containsIsoCode(isoCode) { function containsIsoCode(isoCode) {
return iso3166.list().some(function(row) { return iso3166.list().some(function(row) {
return row.alpha2 === isoCode || row.alpha3 === isoCode; return row.alpha2 === isoCode || row.alpha3 === isoCode;
}); });
} }

4
sanitiser/_geo_autocomplete.js

@ -8,8 +8,8 @@ module.exports = function sanitize( raw, clean ){
var messages = { errors: [], warnings: [] }; var messages = { errors: [], warnings: [] };
try { try {
geo_common.sanitize_coord( 'lat', clean, raw['focus.point.lat'], LAT_LON_IS_REQUIRED ); geo_common.sanitize_coord( 'focus.point.lat', clean, raw['focus.point.lat'], LAT_LON_IS_REQUIRED );
geo_common.sanitize_coord( 'lon', clean, raw['focus.point.lon'], LAT_LON_IS_REQUIRED ); geo_common.sanitize_coord( 'focus.point.lon', clean, raw['focus.point.lon'], LAT_LON_IS_REQUIRED );
} }
catch (err) { catch (err) {
messages.errors.push( err.message ); messages.errors.push( err.message );

176
sanitiser/_geo_common.js

@ -5,89 +5,157 @@ var util = require('util'),
check = require('check-types'); check = require('check-types');
/** /**
* Parse and validate bbox parameter * Parse and validate rect parameter
* bbox = bottom_left lon, bottom_left lat, top_right lon, top_right lat
* bbox = left, bottom, right, top
* bbox = min Longitude, min Latitude, max Longitude, max Latitude
* *
* @param {object} raw * @param {string} key_prefix
* @param {object} clean * @param {object} clean
* @param {object} raw
* @param {bool} bbox_is_required
*/ */
function sanitize_bbox( raw, clean ) { function sanitize_rect( key_prefix, clean, raw, bbox_is_required ) {
if( !check.unemptyString( raw.bbox ) ) {
return;
}
var bboxArr = raw.bbox.split( ',' ); // the names we use to define the corners of the rect
var mandatoryProps = [ 'min_lat', 'max_lat', 'min_lon', 'max_lon' ];
if( Array.isArray( bboxArr ) && bboxArr.length === 4 ) { // count up how many fields the user actually specified
var bbox = bboxArr.map(parseFloat); var totalFieldsSpecified = 0;
mandatoryProps.forEach( function( prop ){
if (bbox.some(isNaN)) { if( raw.hasOwnProperty( key_prefix + '.' + prop ) ){
return; totalFieldsSpecified++;
} }
});
clean.bbox = { // all fields specified
right: Math.max( bbox[0], bbox[2] ), if( 4 === totalFieldsSpecified ) {
top: Math.max( bbox[1], bbox[3] ), // reuse the coord sanitizer and set required:true so we get a fatal error if
left: Math.min( bbox[0], bbox[2] ), // any one of the corners is not specified.
bottom: Math.min( bbox[1], bbox[3] ) sanitize_coord( key_prefix + '.min_lat', clean, raw[ key_prefix + '.min_lat' ], true );
}; sanitize_coord( key_prefix + '.max_lat', clean, raw[ key_prefix + '.max_lat' ], true );
sanitize_coord( key_prefix + '.min_lon', clean, raw[ key_prefix + '.min_lon' ], true );
sanitize_coord( key_prefix + '.max_lon', clean, raw[ key_prefix + '.max_lon' ], true );
}
// fields only partially specified
else if( totalFieldsSpecified > 0 ){
var format1 = 'missing rect param \'%s\' requires all of: \'%s\' to be present';
throw new Error( util.format( format1, key_prefix, mandatoryProps.join('\',\'') ) );
}
// fields required, eg. ( totalFieldsSpecified === 0 && bbox_is_required === true )
else if( bbox_is_required ){
var format2 = 'missing rect param \'%s\' requires all of: \'%s\' to be present';
throw new Error( util.format( format2, key_prefix, mandatoryProps.join('\',\'') ) );
} }
} }
/** /**
* Validate lat,lon values * Parse and validate circle parameter
* *
* @param {string} coord lat|lon * @param {string} key_prefix
* @param {object} clean * @param {object} clean
* @param {string} param * @param {object} raw
* @param {bool} latlon_is_required * @param {bool} circle_is_required
*/ */
function sanitize_coord( coord, clean, param, latlon_is_required ) { function sanitize_circle( key_prefix, clean, raw, circle_is_required ) {
var value = parseFloat( param );
if ( !isNaN( value ) ) { // the names we use to define the centroid
clean[coord] = value; var mandatoryProps = [ 'lat', 'lon' ];
// count up how many fields the user actually specified
var totalFieldsSpecified = 0;
mandatoryProps.forEach( function( prop ){
if( raw.hasOwnProperty( key_prefix + '.' + prop ) ){
totalFieldsSpecified++;
}
});
// all fields specified
if( 2 === totalFieldsSpecified ) {
// reuse the coord sanitizer and set required:true so we get a fatal error if
// any one of the coords is not specified.
sanitize_coord( key_prefix + '.lat', clean, raw[ key_prefix + '.lat' ], true );
sanitize_coord( key_prefix + '.lon', clean, raw[ key_prefix + '.lon' ], true );
if( check.assigned( raw[ key_prefix + '.radius' ] ) ){
sanitize_coord( key_prefix + '.radius', clean, raw[ key_prefix + '.radius' ], true );
}
} }
else if (latlon_is_required) { // fields only partially specified
throw new Error( util.format( 'missing param \'%s\'', coord ) ); else if( totalFieldsSpecified > 0 ){
var format1 = 'missing circle param \'%s\' requires all of: \'%s\' to be present';
throw new Error( util.format( format1, key_prefix, mandatoryProps.join('\',\'') ) );
}
// radius was specified without lat or lon
else if( raw.hasOwnProperty( key_prefix + '.radius' ) ){
var format2 = 'missing circle param \'%s\' requires all of: \'%s\' to be present';
throw new Error( util.format( format2, key_prefix, mandatoryProps.join('\',\'') ) );
}
// fields required, eg. ( totalFieldsSpecified === 0 && bbox_is_required === true )
else if( circle_is_required ){
var format3 = 'missing circle param \'%s\' requires all of: \'%s\' to be present';
throw new Error( util.format( format3, key_prefix, mandatoryProps.join('\',\'') ) );
} }
} }
/** /**
* Validate circle geometry values * Parse and validate point parameter
* *
* @param {string} key_prefix
* @param {object} clean * @param {object} clean
* @param {object} params * @param {object} raw
* @param {bool} is_required * @param {bool} point_is_required
* @param {bool} all_required
*/ */
function sanitize_boundary_circle( clean, params, is_required, all_required ) { function sanitize_point( key_prefix, clean, raw, point_is_required ) {
var props = {
lat: 'boundary.circle.lat',
lon: 'boundary.circle.lon',
rad: 'boundary.circle.radius'
};
// get values for each property // the names we use to define the point
sanitize_coord(props.lat, clean, params['boundary.circle.lat'], all_required && is_required); var mandatoryProps = [ 'lat', 'lon' ];
sanitize_coord(props.lon, clean, params['boundary.circle.lon'], all_required && is_required);
sanitize_coord(props.rad, clean, params['boundary.circle.radius'], all_required && is_required); // count up how many fields the user actually specified
var totalFieldsSpecified = 0;
mandatoryProps.forEach( function( prop ){
if( raw.hasOwnProperty( key_prefix + '.' + prop ) ){
totalFieldsSpecified++;
}
});
// if all are required, check if some are set but not all, throw an error if missing // all fields specified
if (all_required && if( 2 === totalFieldsSpecified ) {
(clean.hasOwnProperty(props.lat) || clean.hasOwnProperty(props.lon) || clean.hasOwnProperty(props.rad)) && // reuse the coord sanitizer and set required:true so we get a fatal error if
!(clean.hasOwnProperty(props.lat) && clean.hasOwnProperty(props.lon) && clean.hasOwnProperty(props.rad))) { // any one of the coords is not specified.
throw new Error('missing part of circle: needs lat,lon,radius'); sanitize_coord( key_prefix + '.lat', clean, raw[ key_prefix + '.lat' ], true );
sanitize_coord( key_prefix + '.lon', clean, raw[ key_prefix + '.lon' ], true );
} }
// fields only partially specified
else if( totalFieldsSpecified > 0 ){
var format1 = 'missing point param \'%s\' requires all of: \'%s\' to be present';
throw new Error( util.format( format1, key_prefix, mandatoryProps.join('\',\'') ) );
}
// fields required, eg. ( totalFieldsSpecified === 0 && bbox_is_required === true )
else if( point_is_required ){
var format2 = 'missing point param \'%s\' requires all of: \'%s\' to be present';
throw new Error( util.format( format2, key_prefix, mandatoryProps.join('\',\'') ) );
}
}
if (is_required && !(clean.hasOwnProperty(props.lat) || clean.hasOwnProperty(props.lon) || clean.hasOwnProperty(props.rad))) { /**
throw new Error('missing param boundary.circle: should be a trio of lat,lon,radius'); * Validate lat,lon values
*
* @param {string} key
* @param {object} clean
* @param {string} param
* @param {bool} latlon_is_required
*/
function sanitize_coord( key, clean, param, latlon_is_required ) {
var value = parseFloat( param );
if ( !isNaN( value ) ) {
clean[key] = value;
}
else if (latlon_is_required) {
throw new Error( util.format( 'missing param \'%s\'', key ) );
} }
} }
module.exports = { module.exports = {
sanitize_bbox: sanitize_bbox, sanitize_rect: sanitize_rect,
sanitize_coord: sanitize_coord, sanitize_coord: sanitize_coord,
sanitize_boundary_circle: sanitize_boundary_circle sanitize_circle: sanitize_circle,
sanitize_point: sanitize_point
}; };

19
sanitiser/_geo_reverse.js

@ -11,19 +11,18 @@ module.exports = function sanitize( raw, clean ){
var messages = { errors: [], warnings: [] }; var messages = { errors: [], warnings: [] };
try { try {
geo_common.sanitize_coord( 'point.lat', clean, raw['point.lat'], LAT_LON_IS_REQUIRED ); geo_common.sanitize_point( 'point', clean, raw, LAT_LON_IS_REQUIRED );
geo_common.sanitize_coord( 'point.lon', clean, raw['point.lon'], LAT_LON_IS_REQUIRED );
// remove both if only one is set // this hack is to allow point.lat/point.lon to be used interchanagbly
// @todo: clean this up! // with boundary.circle.lat/boundary.circle/lon
if( !clean.hasOwnProperty('point.lat') || !clean.hasOwnProperty('point.lon') ){ if( !clean.hasOwnProperty('boundary.circle.lat') && clean.hasOwnProperty('point.lat') ){
delete clean['point.lat']; raw['boundary.circle.lat'] = clean['point.lat'];
delete clean['point.lon']; }
if( !clean.hasOwnProperty('boundary.circle.lon') && clean.hasOwnProperty('point.lon') ){
raw['boundary.circle.lon'] = clean['point.lon'];
} }
// boundary.circle.* is not mandatory, and only specifying radius is fine, geo_common.sanitize_circle( 'boundary.circle', clean, raw, CIRCLE_IS_REQUIRED );
// as point.lat/lon will be used to fill those values by default
geo_common.sanitize_boundary_circle( clean, raw, CIRCLE_IS_REQUIRED, CIRCLE_MUST_BE_COMPLETE);
} }
catch (err) { catch (err) {
messages.errors.push( err.message ); messages.errors.push( err.message );

8
sanitiser/_geo_search.js

@ -1,5 +1,7 @@
var geo_common = require ('./_geo_common'); var geo_common = require ('./_geo_common');
var LAT_LON_IS_REQUIRED = false; var LAT_LON_IS_REQUIRED = false;
var RECT_IS_REQUIRED = false;
var CIRCLE_IS_REQUIRED = false;
// validate inputs, convert types and apply defaults // validate inputs, convert types and apply defaults
module.exports = function sanitize( raw, clean ){ module.exports = function sanitize( raw, clean ){
@ -8,9 +10,9 @@ module.exports = function sanitize( raw, clean ){
var messages = { errors: [], warnings: [] }; var messages = { errors: [], warnings: [] };
try { try {
geo_common.sanitize_coord( 'focus.point.lat', clean, raw['focus.point.lat'], LAT_LON_IS_REQUIRED ); geo_common.sanitize_point( 'focus.point', clean, raw, LAT_LON_IS_REQUIRED );
geo_common.sanitize_coord( 'focus.point.lon', clean, raw['focus.point.lon'], LAT_LON_IS_REQUIRED ); geo_common.sanitize_rect( 'boundary.rect', clean, raw, RECT_IS_REQUIRED );
geo_common.sanitize_bbox(raw, clean); geo_common.sanitize_circle( 'boundary.circle', clean, raw, CIRCLE_IS_REQUIRED );
} }
catch (err) { catch (err) {
messages.errors.push( err.message ); messages.errors.push( err.message );

5
test/ciao/autocomplete/null_island.coffee

@ -29,6 +29,7 @@ should.not.exist json.geocoding.errors
should.not.exist json.geocoding.warnings should.not.exist json.geocoding.warnings
#? inputs #? inputs
json.geocoding.query['lat'].should.eql 0 json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['lon'].should.eql 0 json.geocoding.query['focus.point.lat'].should.eql 0
json.geocoding.query['focus.point.lon'].should.eql 0
json.geocoding.query['size'].should.eql 10 json.geocoding.query['size'].should.eql 10

4
test/ciao/reverse/basic_reverse.coffee

@ -29,6 +29,6 @@ should.not.exist json.geocoding.errors
should.not.exist json.geocoding.warnings should.not.exist json.geocoding.warnings
#? inputs #? inputs
json.geocoding.query['lat'].should.eql 1 json.geocoding.query['point.lat'].should.eql 1
json.geocoding.query['lon'].should.eql 2 json.geocoding.query['point.lon'].should.eql 2
json.geocoding.query['size'].should.eql 10 json.geocoding.query['size'].should.eql 10

38
test/ciao/reverse/boundary_circle_invalid_radius.coffee

@ -0,0 +1,38 @@
#> bounding circle
path: '/v1/reverse?point.lat=40.744243&point.lon=-73.990342&boundary.circle.radius=foo'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'missing param \'boundary.circle.radius\'' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['size'].should.eql 10
json.geocoding.query['point.lat'].should.eql 40.744243
json.geocoding.query['point.lon'].should.eql -73.990342
json.geocoding.query['boundary.circle.lat'].should.eql 40.744243
json.geocoding.query['boundary.circle.lon'].should.eql -73.990342
should.not.exist json.geocoding.query['boundary.circle.radius']

37
test/ciao/reverse/boundary_circle_valid_radius.coffee

@ -0,0 +1,37 @@
#> bounding circle
path: '/v1/reverse?point.lat=40.744243&point.lon=-73.990342&boundary.circle.radius=999.9'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['size'].should.eql 10
json.geocoding.query['point.lat'].should.eql 40.744243
json.geocoding.query['point.lon'].should.eql -73.990342
json.geocoding.query['boundary.circle.lat'].should.eql 40.744243
json.geocoding.query['boundary.circle.lon'].should.eql -73.990342
json.geocoding.query['boundary.circle.radius'].should.eql 999.9

34
test/ciao/reverse/boundary_country_invalid_alpha2.coffee

@ -0,0 +1,34 @@
#> bounding country
path: '/v1/reverse?point.lat=1&point.lon=1&boundary.country=ZZ'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'ZZ is not a valid ISO2/ISO3 country code' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['boundary.country']

34
test/ciao/reverse/boundary_country_invalid_alpha3.coffee

@ -0,0 +1,34 @@
#> bounding country
path: '/v1/reverse?point.lat=1&point.lon=1&boundary.country=ZZZ'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'ZZZ is not a valid ISO2/ISO3 country code' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['boundary.country']

34
test/ciao/reverse/boundary_country_invalid_iso3166.coffee

@ -0,0 +1,34 @@
#> bounding country
path: '/v1/reverse?point.lat=1&point.lon=1&boundary.country=FOOBAR'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'FOOBAR is not a valid ISO2/ISO3 country code' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['boundary.country']

33
test/ciao/reverse/boundary_country_valid_alpha2.coffee

@ -0,0 +1,33 @@
#> bounding country
path: '/v1/reverse?point.lat=1&point.lon=1&boundary.country=US'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['size'].should.eql 10
json.geocoding.query['boundary.country'].should.eql 'USA'

33
test/ciao/reverse/boundary_country_valid_alpha3.coffee

@ -0,0 +1,33 @@
#> bounding country
path: '/v1/reverse?point.lat=1&point.lon=1&boundary.country=USA'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['size'].should.eql 10
json.geocoding.query['boundary.country'].should.eql 'USA'

35
test/ciao/reverse/point_invalid_lat.coffee

@ -0,0 +1,35 @@
#> point
path: '/v1/reverse?point.lat=foo&point.lon=-73.990342'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'missing param \'point.lat\'' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['point.lat']
should.not.exist json.geocoding.query['point.lon']

35
test/ciao/reverse/point_invalid_lon.coffee

@ -0,0 +1,35 @@
#> point
path: '/v1/reverse?point.lat=40.744243&point.lon='
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'missing param \'point.lon\'' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['size'].should.eql 10
json.geocoding.query['point.lat'].should.eql 40.744243
should.not.exist json.geocoding.query['point.lon']

35
test/ciao/reverse/point_missing_lat.coffee

@ -0,0 +1,35 @@
#> point
path: '/v1/reverse?point.lon=-73.990342'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'missing point param \'point\' requires all of: \'lat\',\'lon\' to be present' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['point.lat']
should.not.exist json.geocoding.query['point.lon']

35
test/ciao/reverse/point_missing_lon.coffee

@ -0,0 +1,35 @@
#> point
path: '/v1/reverse?point.lat=40.744243'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'missing point param \'point\' requires all of: \'lat\',\'lon\' to be present' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['point.lat']
should.not.exist json.geocoding.query['point.lon']

8
test/ciao/reverse/null_island.coffee → test/ciao/reverse/point_null_island.coffee

@ -1,5 +1,5 @@
#> null island #> point null island
path: '/v1/reverse?point.lat=0&point.lon=0' path: '/v1/reverse?point.lat=0&point.lon=0'
#? 200 ok #? 200 ok
@ -29,6 +29,6 @@ should.not.exist json.geocoding.errors
should.not.exist json.geocoding.warnings should.not.exist json.geocoding.warnings
#? inputs #? inputs
json.geocoding.query['lat'].should.eql 0 json.geocoding.query['size'].should.eql 10
json.geocoding.query['lon'].should.eql 0 json.geocoding.query['point.lat'].should.eql 0
json.geocoding.query['size'].should.eql 10 json.geocoding.query['point.lon'].should.eql 0

34
test/ciao/reverse/point_valid_duo.coffee

@ -0,0 +1,34 @@
#> point
path: '/v1/reverse?point.lat=40.744243&point.lon=-73.990342'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['size'].should.eql 10
json.geocoding.query['point.lat'].should.eql 40.744243
json.geocoding.query['point.lon'].should.eql -73.990342

33
test/ciao/reverse/size_over_max.coffee

@ -0,0 +1,33 @@
#> set size
path: '/v1/reverse?point.lat=1&point.lon=1&size=999'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.exist json.geocoding.warnings
json.geocoding.warnings.should.eql [ 'out-of-range integer \'size\', using MAX_SIZE' ]
#? inputs
json.geocoding.query['size'].should.eql 40

33
test/ciao/reverse/size_under_min.coffee

@ -0,0 +1,33 @@
#> set size
path: '/v1/reverse?point.lat=1&point.lon=1&size=0'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.exist json.geocoding.warnings
json.geocoding.warnings.should.eql [ 'out-of-range integer \'size\', using MIN_SIZE' ]
#? inputs
json.geocoding.query['size'].should.eql 1

32
test/ciao/reverse/size_valid.coffee

@ -0,0 +1,32 @@
#> set size
path: '/v1/reverse?point.lat=1&point.lon=1&size=3'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['size'].should.eql 3

37
test/ciao/search/boundary_circle_invalid_lat_lon_types.coffee

@ -0,0 +1,37 @@
#> bounding circle
path: '/v1/search?text=a&boundary.circle.lat=foo&boundary.circle.lon=bar'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'missing param \'boundary.circle.lat\'' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['boundary.circle.lat']
should.not.exist json.geocoding.query['boundary.circle.lon']
should.not.exist json.geocoding.query['boundary.circle.radius']

37
test/ciao/search/boundary_circle_invalid_radius.coffee

@ -0,0 +1,37 @@
#> bounding circle
path: '/v1/search?text=a&boundary.circle.lat=40.744243&boundary.circle.lon=-73.990342&boundary.circle.radius=foo'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'missing param \'boundary.circle.radius\'' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
json.geocoding.query['boundary.circle.lat'].should.eql 40.744243
json.geocoding.query['boundary.circle.lon'].should.eql -73.990342
should.not.exist json.geocoding.query['boundary.circle.radius']

37
test/ciao/search/boundary_circle_missing_lat.coffee

@ -0,0 +1,37 @@
#> bounding circle
path: '/v1/search?text=a&boundary.circle.lon=-73.990342&boundary.circle.radius=100'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'missing circle param \'boundary.circle\' requires all of: \'lat\',\'lon\' to be present' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['boundary.circle.lat']
should.not.exist json.geocoding.query['boundary.circle.lon']
should.not.exist json.geocoding.query['boundary.circle.radius']

37
test/ciao/search/boundary_circle_missing_lon.coffee

@ -0,0 +1,37 @@
#> bounding circle
path: '/v1/search?text=a&boundary.circle.lat=40.744243&boundary.circle.radius=100'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'missing circle param \'boundary.circle\' requires all of: \'lat\',\'lon\' to be present' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['boundary.circle.lat']
should.not.exist json.geocoding.query['boundary.circle.lon']
should.not.exist json.geocoding.query['boundary.circle.radius']

36
test/ciao/search/boundary_circle_valid_duo.coffee

@ -0,0 +1,36 @@
#> bounding circle
path: '/v1/search?text=a&boundary.circle.lat=40.744243&boundary.circle.lon=-73.990342'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
json.geocoding.query['boundary.circle.lat'].should.eql 40.744243
json.geocoding.query['boundary.circle.lon'].should.eql -73.990342
should.not.exist json.geocoding.query['boundary.circle.radius']

36
test/ciao/search/boundary_circle_valid_trio.coffee

@ -0,0 +1,36 @@
#> bounding circle
path: '/v1/search?text=a&boundary.circle.lat=40.744243&boundary.circle.lon=-73.990342&boundary.circle.radius=100'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
json.geocoding.query['boundary.circle.lat'].should.eql 40.744243
json.geocoding.query['boundary.circle.lon'].should.eql -73.990342
json.geocoding.query['boundary.circle.radius'].should.eql 100

35
test/ciao/search/boundary_country_invalid_alpha2.coffee

@ -0,0 +1,35 @@
#> bounding country
path: '/v1/search?text=a&boundary.country=ZZ'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'ZZ is not a valid ISO2/ISO3 country code' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['boundary.country']

35
test/ciao/search/boundary_country_invalid_alpha3.coffee

@ -0,0 +1,35 @@
#> bounding country
path: '/v1/search?text=a&boundary.country=ZZZ'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'ZZZ is not a valid ISO2/ISO3 country code' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['boundary.country']

35
test/ciao/search/boundary_country_invalid_iso3166.coffee

@ -0,0 +1,35 @@
#> bounding country
path: '/v1/search?text=a&boundary.country=FOOBAR'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'FOOBAR is not a valid ISO2/ISO3 country code' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['boundary.country']

34
test/ciao/search/boundary_country_valid_alpha2.coffee

@ -0,0 +1,34 @@
#> bounding country
path: '/v1/search?text=a&boundary.country=US'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
json.geocoding.query['boundary.country'].should.eql 'USA'

34
test/ciao/search/boundary_country_valid_alpha3.coffee

@ -0,0 +1,34 @@
#> bounding country
path: '/v1/search?text=a&boundary.country=USA'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
json.geocoding.query['boundary.country'].should.eql 'USA'

38
test/ciao/search/boundary_rect_partially_specified.coffee

@ -0,0 +1,38 @@
#> bounding rectangle
path: '/v1/search?text=a&boundary.rect.min_lat=-40.659'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'missing rect param \'boundary.rect\' requires all of: \'min_lat\',\'max_lat\',\'min_lon\',\'max_lon\' to be present' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['boundary.rect.min_lat']
should.not.exist json.geocoding.query['boundary.rect.max_lat']
should.not.exist json.geocoding.query['boundary.rect.min_lon']
should.not.exist json.geocoding.query['boundary.rect.max_lon']

37
test/ciao/search/boundary_rect_valid.coffee

@ -0,0 +1,37 @@
#> bounding rectangle
path: '/v1/search?text=a&boundary.rect.min_lat=-40.659&boundary.rect.max_lat=-41.614&boundary.rect.min_lon=174.612&boundary.rect.max_lon=176.333'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
json.geocoding.query['boundary.rect.min_lat'].should.eql -40.659
json.geocoding.query['boundary.rect.max_lat'].should.eql -41.614
json.geocoding.query['boundary.rect.min_lon'].should.eql 174.612
json.geocoding.query['boundary.rect.max_lon'].should.eql 176.333

36
test/ciao/search/focus_point_invalid_lat.coffee

@ -0,0 +1,36 @@
#> focus point
path: '/v1/search?text=a&focus.point.lat=foo&focus.point.lon=-73.990342'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'missing param \'focus.point.lat\'' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['focus.point.lat']
should.not.exist json.geocoding.query['focus.point.lon']

36
test/ciao/search/focus_point_invalid_lon.coffee

@ -0,0 +1,36 @@
#> focus point
path: '/v1/search?text=a&focus.point.lat=40.744243&focus.point.lon='
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'missing param \'focus.point.lon\'' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
json.geocoding.query['focus.point.lat'].should.eql 40.744243
should.not.exist json.geocoding.query['focus.point.lon']

36
test/ciao/search/focus_point_missing_lat.coffee

@ -0,0 +1,36 @@
#> focus point
path: '/v1/search?text=a&focus.point.lon=-73.990342'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'missing point param \'focus.point\' requires all of: \'lat\',\'lon\' to be present' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['focus.point.lat']
should.not.exist json.geocoding.query['focus.point.lon']

36
test/ciao/search/focus_point_missing_lon.coffee

@ -0,0 +1,36 @@
#> focus point
path: '/v1/search?text=a&focus.point.lat=40.744243'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'missing point param \'focus.point\' requires all of: \'lat\',\'lon\' to be present' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['focus.point.lat']
should.not.exist json.geocoding.query['focus.point.lon']

6
test/ciao/search/null_island.coffee → test/ciao/search/focus_point_null_island.coffee

@ -1,5 +1,5 @@
#> null island #> focus point null island
path: '/v1/search?text=a&focus.point.lat=0&focus.point.lon=0' path: '/v1/search?text=a&focus.point.lat=0&focus.point.lon=0'
#? 200 ok #? 200 ok
@ -31,5 +31,5 @@ should.not.exist json.geocoding.warnings
#? inputs #? inputs
json.geocoding.query['text'].should.eql 'a' json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10 json.geocoding.query['size'].should.eql 10
json.geocoding.query['lat'].should.eql 0 json.geocoding.query['focus.point.lat'].should.eql 0
json.geocoding.query['lon'].should.eql 0 json.geocoding.query['focus.point.lon'].should.eql 0

35
test/ciao/search/focus_point_valid_duo.coffee

@ -0,0 +1,35 @@
#> focus point
path: '/v1/search?text=a&focus.point.lat=40.744243&focus.point.lon=-73.990342'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
json.geocoding.query['focus.point.lat'].should.eql 40.744243
json.geocoding.query['focus.point.lon'].should.eql -73.990342

35
test/ciao/search/layers_alias_address.coffee

@ -0,0 +1,35 @@
#> layer alias
path: '/v1/search?text=a&layers=address'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
json.geocoding.query.types['from_layers'].should.eql ["osmaddress","openaddresses"]
json.geocoding.query['type'].should.eql ["osmaddress","openaddresses"]

35
test/ciao/search/layers_alias_coarse.coffee

@ -0,0 +1,35 @@
#> layer alias
path: '/v1/search?text=a&layers=coarse'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
json.geocoding.query.types['from_layers'].should.eql ["admin0","admin1","admin2","neighborhood","locality","local_admin"]
json.geocoding.query['type'].should.eql ["admin0","admin1","admin2","neighborhood","locality","local_admin"]

36
test/ciao/search/layers_invalid.coffee

@ -0,0 +1,36 @@
#> layer alias
path: '/v1/search?text=a&layers=notlayer'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ '\'notlayer\' is an invalid layers parameter. Valid options: venue,address,country,region,county,locality,localadmin,neighbourhood,coarse' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['types']
should.not.exist json.geocoding.query['type']

36
test/ciao/search/layers_mix_invalid_valid.coffee

@ -0,0 +1,36 @@
#> layer alias
path: '/v1/search?text=a&layers=country,notlayer'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ '\'notlayer\' is an invalid layers parameter. Valid options: venue,address,country,region,county,locality,localadmin,neighbourhood,coarse' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['types']
should.not.exist json.geocoding.query['type']

35
test/ciao/search/layers_multiple.coffee

@ -0,0 +1,35 @@
#> layer alias
path: '/v1/search?text=a&layers=country,region'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
json.geocoding.query.types['from_layers'].should.eql ["admin0","admin1"]
json.geocoding.query['type'].should.eql ["admin0","admin1"]

35
test/ciao/search/layers_single.coffee

@ -0,0 +1,35 @@
#> layer alias
path: '/v1/search?text=a&layers=country'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
json.geocoding.query.types['from_layers'].should.eql ["admin0"]
json.geocoding.query['type'].should.eql ["admin0"]

34
test/ciao/search/privacy_false.coffee

@ -0,0 +1,34 @@
#> accept privacy var
path: '/v1/search?text=a&private=false'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
json.geocoding.query['private'].should.eql false

34
test/ciao/search/privacy_true.coffee

@ -0,0 +1,34 @@
#> accept privacy var
path: '/v1/search?text=a&private=true'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
json.geocoding.query['private'].should.eql true

34
test/ciao/search/size_over_max.coffee

@ -0,0 +1,34 @@
#> set size
path: '/v1/search?text=a&size=999'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.exist json.geocoding.warnings
json.geocoding.warnings.should.eql [ 'out-of-range integer \'size\', using MAX_SIZE' ]
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 40

34
test/ciao/search/size_under_min.coffee

@ -0,0 +1,34 @@
#> set size
path: '/v1/search?text=a&size=0'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.exist json.geocoding.warnings
json.geocoding.warnings.should.eql [ 'out-of-range integer \'size\', using MIN_SIZE' ]
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 1

33
test/ciao/search/size_valid.coffee

@ -0,0 +1,33 @@
#> set size
path: '/v1/search?text=a&size=3'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 3

36
test/ciao/search/sources_invalid.coffee

@ -0,0 +1,36 @@
#> sources filter
path: '/v1/search?text=a&sources=openstreetmap,notasource'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ '\'notasource\' is an invalid sources parameter. Valid options: gn,geonames,oa,openaddresses,qs,quattroshapes,osm,openstreetmap' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
should.not.exist json.geocoding.query['types']
should.not.exist json.geocoding.query['type']

37
test/ciao/search/sources_layers_invalid_combo.coffee

@ -0,0 +1,37 @@
#> sources and layers specified (invalid combo)
path: '/v1/search?text=a&sources=quattroshapes&layers=address'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.exist json.geocoding.errors
json.geocoding.errors.should.eql [ 'You have specified both the `sources` and `layers` parameters in a combination that will return no results.' ]
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
json.geocoding.query.types['from_layers'].should.eql ["osmaddress","openaddresses"]
json.geocoding.query.types['from_sources'].should.eql ["admin0","admin1","admin2","neighborhood","locality","local_admin"]
should.not.exist json.geocoding.query['type']

35
test/ciao/search/sources_layers_valid_combo.coffee

@ -0,0 +1,35 @@
#> sources and layers specified
path: '/v1/search?text=a&sources=openaddresses&layers=address'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
json.geocoding.query.types['from_layers'].should.eql ["osmaddress","openaddresses"]
json.geocoding.query['type'].should.eql ["openaddresses"]

35
test/ciao/search/sources_multiple.coffee

@ -0,0 +1,35 @@
#> sources filter
path: '/v1/search?text=a&sources=openstreetmap,geonames'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
json.geocoding.query.types['from_sources'].should.eql ["osmaddress","osmnode","osmway","geoname"]
json.geocoding.query['type'].should.eql ["osmaddress","osmnode","osmway","geoname"]

35
test/ciao/search/sources_single.coffee

@ -0,0 +1,35 @@
#> sources filter
path: '/v1/search?text=a&sources=openstreetmap'
#? 200 ok
response.statusCode.should.be.equal 200
response.should.have.header 'charset', 'utf8'
response.should.have.header 'content-type', 'application/json; charset=utf-8'
#? valid geocoding block
should.exist json.geocoding
should.exist json.geocoding.version
should.exist json.geocoding.attribution
should.exist json.geocoding.query
should.exist json.geocoding.engine
should.exist json.geocoding.engine.name
should.exist json.geocoding.engine.author
should.exist json.geocoding.engine.version
should.exist json.geocoding.timestamp
#? valid geojson
json.type.should.be.equal 'FeatureCollection'
json.features.should.be.instanceof Array
#? expected errors
should.not.exist json.geocoding.errors
#? expected warnings
should.not.exist json.geocoding.warnings
#? inputs
json.geocoding.query['text'].should.eql 'a'
json.geocoding.query['size'].should.eql 10
json.geocoding.query.types['from_sources'].should.eql ["osmaddress","osmnode","osmway"]
json.geocoding.query['type'].should.eql ["osmaddress","osmnode","osmway"]

45
test/unit/query/reverse.js

@ -12,7 +12,11 @@ module.exports.tests.interface = function(test, common) {
module.exports.tests.query = function(test, common) { module.exports.tests.query = function(test, common) {
test('valid query', function(t) { test('valid query', function(t) {
var query = generate({ var query = generate({
'point.lat': 29.49136, 'point.lon': -82.50622 'point.lat': 29.49136,
'point.lon': -82.50622,
'boundary.circle.lat': 29.49136,
'boundary.circle.lon': -82.50622,
'boundary.circle.radius': 500
}); });
var compiled = JSON.parse( JSON.stringify( query ) ); var compiled = JSON.parse( JSON.stringify( query ) );
@ -22,9 +26,13 @@ module.exports.tests.query = function(test, common) {
t.end(); t.end();
}); });
test('valid query', function(t) { test('valid query - null island', function(t) {
var query = generate({ var query = generate({
'point.lat': 0, 'point.lon': 0 'point.lat': 0,
'point.lon': 0,
'boundary.circle.lat': 0,
'boundary.circle.lon': 0,
'boundary.circle.radius': 500
}); });
var compiled = JSON.parse( JSON.stringify( query ) ); var compiled = JSON.parse( JSON.stringify( query ) );
@ -36,29 +44,36 @@ module.exports.tests.query = function(test, common) {
test('valid query with radius', function(t) { test('valid query with radius', function(t) {
var query = generate({ var query = generate({
'point.lat': 29.49136, 'point.lon': -82.50622, 'boundary.circle.radius': 123 'point.lat': 29.49136,
'point.lon': -82.50622,
'boundary.circle.lat': 29.49136,
'boundary.circle.lon': -82.50622,
'boundary.circle.radius': 123
}); });
var compiled = JSON.parse( JSON.stringify( query )).query.filtered.filter.bool.must[0].geo_distance.distance; var compiled = JSON.parse( JSON.stringify( query ) );
var expected = '123km'; var expected = '123km';
t.deepEqual(compiled, expected, 'distance set to boundary circle radius'); t.deepEqual(compiled.query.filtered.filter.bool.must[0].geo_distance.distance, expected, 'distance set to boundary circle radius');
t.end(); t.end();
}); });
test('valid query with boundary.circle lat/lon/radius', function(t) { test('boundary.circle lat/lon/radius - overrides point.lat/lon when set', function(t) {
var clean = { var clean = {
'point.lat': 29.49136, 'point.lat': 29.49136,
'point.lon': -82.50622, 'point.lon': -82.50622,
'boundary.circle.lat': 111, 'boundary.circle.lat': 111,
'boundary.circle.long': 333 'boundary.circle.lon': 333,
'boundary.circle.radius': 500
}; };
var query = generate(clean); var query = generate(clean);
var compiled = JSON.parse( JSON.stringify( query ) );
var compiled = JSON.parse( JSON.stringify( query )).query.filtered.filter.bool.must[0].geo_distance.center_point; // this should not equal `point.lat` and `point.lon` as it was explitely specified
var expected = { lat: clean['point.lat'], lon: clean['point.lon'] }; var expected = { lat: clean['boundary.circle.lat'], lon: clean['boundary.circle.lon'] };
var centroid = compiled.query.filtered.filter.bool.must[0].geo_distance.center_point;
t.deepEqual(compiled, expected, 'point.lat/lon overrides boundary.circle.lat/lon'); t.deepEqual(centroid, expected, 'boundary.circle/lon overrides point.lat/lon');
t.end(); t.end();
}); });
@ -78,8 +93,12 @@ module.exports.tests.query = function(test, common) {
test('valid boundary.country reverse search', function(t) { test('valid boundary.country reverse search', function(t) {
var query = generate({ var query = generate({
'point.lat': 29.49136, 'point.lon': -82.50622, 'point.lat': 29.49136,
boundary: { country: 'ABC' } 'point.lon': -82.50622,
'boundary.circle.lat': 29.49136,
'boundary.circle.lon': -82.50622,
'boundary.circle.radius': 500,
'boundary.country': 'ABC'
}); });
var compiled = JSON.parse( JSON.stringify( query ) ); var compiled = JSON.parse( JSON.stringify( query ) );

20
test/unit/query/search.js

@ -17,12 +17,10 @@ module.exports.tests.query = function(test, common) {
var query = generate({ var query = generate({
text: 'test', size: 10, text: 'test', size: 10,
'focus.point.lat': 29.49136, 'focus.point.lon': -82.50622, 'focus.point.lat': 29.49136, 'focus.point.lon': -82.50622,
bbox: { 'boundary.rect.min_lat': 47.47,
top: 47.47, 'boundary.rect.max_lon': -61.84,
right: -61.84, 'boundary.rect.max_lat': 11.51,
bottom: 11.51, 'boundary.rect.min_lon': -103.16,
left: -103.16
},
layers: ['test'] layers: ['test']
}); });
@ -37,12 +35,10 @@ module.exports.tests.query = function(test, common) {
test('valid search + bbox', function(t) { test('valid search + bbox', function(t) {
var query = generate({ var query = generate({
text: 'test', size: 10, text: 'test', size: 10,
bbox: { 'boundary.rect.min_lat': 47.47,
top: 47.47, 'boundary.rect.max_lon': -61.84,
right: -61.84, 'boundary.rect.max_lat': 11.51,
bottom: 11.51, 'boundary.rect.min_lon': -103.16,
left: -103.16
},
layers: ['test'] layers: ['test']
}); });

14
test/unit/sanitiser/_boundary_country.js

@ -7,7 +7,7 @@ module.exports.tests.sanitize_boundary_country = function(test, common) {
var raw = { }; var raw = { };
var clean = {}; var clean = {};
var errorsAndWarnings = sanitize(raw, clean); var errorsAndWarnings = sanitize(raw, clean);
t.equals(clean.boundary.country, undefined, 'should be undefined'); t.equals(clean['boundary.country'], undefined, 'should be undefined');
t.deepEquals(errorsAndWarnings, { errors: [], warnings: [] }, 'no warnings or errors'); t.deepEquals(errorsAndWarnings, { errors: [], warnings: [] }, 'no warnings or errors');
t.end(); t.end();
}); });
@ -16,7 +16,7 @@ module.exports.tests.sanitize_boundary_country = function(test, common) {
var raw = { 'boundary.country': undefined }; var raw = { 'boundary.country': undefined };
var clean = {}; var clean = {};
var errorsAndWarnings = sanitize(raw, clean); var errorsAndWarnings = sanitize(raw, clean);
t.equals(clean.boundary.country, undefined, 'should be undefined'); t.equals(clean['boundary.country'], undefined, 'should be undefined');
t.deepEquals(errorsAndWarnings, { errors: [], warnings: [] }, 'no warnings or errors'); t.deepEquals(errorsAndWarnings, { errors: [], warnings: [] }, 'no warnings or errors');
t.end(); t.end();
}); });
@ -25,7 +25,7 @@ module.exports.tests.sanitize_boundary_country = function(test, common) {
var raw = { 'boundary.country': ['this isn\'t a string primitive'] }; var raw = { 'boundary.country': ['this isn\'t a string primitive'] };
var clean = {}; var clean = {};
var errorsAndWarnings = sanitize(raw, clean); var errorsAndWarnings = sanitize(raw, clean);
t.equals(clean.boundary.country, undefined, 'should be undefined'); t.equals(clean['boundary.country'], undefined, 'should be undefined');
t.deepEquals(errorsAndWarnings, { errors: ['boundary.country is not a string'], warnings: [] }, 'non-string country warning'); t.deepEquals(errorsAndWarnings, { errors: ['boundary.country is not a string'], warnings: [] }, 'non-string country warning');
t.end(); t.end();
}); });
@ -34,7 +34,7 @@ module.exports.tests.sanitize_boundary_country = function(test, common) {
var raw = { 'boundary.country': 'aq' }; var raw = { 'boundary.country': 'aq' };
var clean = {}; var clean = {};
var errorsAndWarnings = sanitize(raw, clean); var errorsAndWarnings = sanitize(raw, clean);
t.equals(clean.boundary.country, 'ATA', 'should be uppercased ISO3'); t.equals(clean['boundary.country'], 'ATA', 'should be uppercased ISO3');
t.deepEquals(errorsAndWarnings, { errors: [], warnings: [] }, 'no warnings or errors'); t.deepEquals(errorsAndWarnings, { errors: [], warnings: [] }, 'no warnings or errors');
t.end(); t.end();
}); });
@ -43,7 +43,7 @@ module.exports.tests.sanitize_boundary_country = function(test, common) {
var raw = { 'boundary.country': 'aTa' }; var raw = { 'boundary.country': 'aTa' };
var clean = {}; var clean = {};
var errorsAndWarnings = sanitize(raw, clean); var errorsAndWarnings = sanitize(raw, clean);
t.equals(clean.boundary.country, 'ATA', 'should be uppercased ISO3'); t.equals(clean['boundary.country'], 'ATA', 'should be uppercased ISO3');
t.deepEquals(errorsAndWarnings, { errors: [], warnings: [] }, 'no warnings or errors'); t.deepEquals(errorsAndWarnings, { errors: [], warnings: [] }, 'no warnings or errors');
t.end(); t.end();
}); });
@ -52,7 +52,7 @@ module.exports.tests.sanitize_boundary_country = function(test, common) {
var raw = { 'boundary.country': 'zq' }; var raw = { 'boundary.country': 'zq' };
var clean = {}; var clean = {};
var errorsAndWarnings = sanitize(raw, clean); var errorsAndWarnings = sanitize(raw, clean);
t.equals(clean.boundary.country, undefined, 'should be undefined'); t.equals(clean['boundary.country'], undefined, 'should be undefined');
t.deepEquals(errorsAndWarnings, { errors: ['zq is not a valid ISO2/ISO3 country code'], warnings: [] }, 'country not found warning`'); t.deepEquals(errorsAndWarnings, { errors: ['zq is not a valid ISO2/ISO3 country code'], warnings: [] }, 'country not found warning`');
t.end(); t.end();
}); });
@ -61,7 +61,7 @@ module.exports.tests.sanitize_boundary_country = function(test, common) {
var raw = { 'boundary.country': 'zqx' }; var raw = { 'boundary.country': 'zqx' };
var clean = {}; var clean = {};
var errorsAndWarnings = sanitize(raw, clean); var errorsAndWarnings = sanitize(raw, clean);
t.equals(clean.boundary.country, undefined, 'should be undefined'); t.equals(clean['boundary.country'], undefined, 'should be undefined');
t.deepEquals(errorsAndWarnings, { errors: ['zqx is not a valid ISO2/ISO3 country code'], warnings: [] }, 'country not found warning`'); t.deepEquals(errorsAndWarnings, { errors: ['zqx is not a valid ISO2/ISO3 country code'], warnings: [] }, 'country not found warning`');
t.end(); t.end();
}); });

354
test/unit/sanitiser/_geo_common.js

@ -4,14 +4,212 @@ module.exports.tests = {};
module.exports.tests.interface = function(test, common) { module.exports.tests.interface = function(test, common) {
test('valid interface', function(t) { test('valid interface', function(t) {
t.equal(typeof sanitize.sanitize_bbox, 'function', 'sanitize_bbox is a valid function'); t.equal(typeof sanitize.sanitize_rect, 'function', 'sanitize_rect is a valid function');
t.equal(typeof sanitize.sanitize_coord, 'function', 'sanitize_coord is a valid function'); t.equal(typeof sanitize.sanitize_coord, 'function', 'sanitize_coord is a valid function');
t.equal(typeof sanitize.sanitize_boundary_circle, 'function', 'sanitize_boundary_circle is a valid function'); t.equal(typeof sanitize.sanitize_circle, 'function', 'sanitize_circle is a valid function');
t.equal(typeof sanitize.sanitize_point, 'function', 'sanitize_point is a valid function');
t.end(); t.end();
}); });
}; };
module.exports.tests.sanitize = function(test, common) { module.exports.tests.coord = function(test, common) {
test('valid coord', function (t) {
var clean = {};
var params = {
'foo': -40.659
};
var mandatory = false;
sanitize.sanitize_coord( 'foo', clean, params.foo, mandatory );
t.equal(clean.foo, params.foo);
t.end();
});
test('invalid coord', function (t) {
var clean = {};
var params = {
'foo': 'bar'
};
var mandatory = false;
sanitize.sanitize_coord( 'foo', clean, params.foo, mandatory );
t.equal(clean.foo, undefined, 'not set');
t.end();
});
test('nothing specified', function (t) {
var clean = {};
var params = {};
var mandatory = false;
t.doesNotThrow( function(){
sanitize.sanitize_coord( 'foo', clean, params.foo, mandatory );
});
t.end();
});
test('nothing specified - mandatory', function (t) {
var clean = {};
var params = {};
var mandatory = true;
t.throws( function(){
sanitize.sanitize_coord( 'foo', clean, params.foo, mandatory );
});
t.end();
});
};
module.exports.tests.point = function(test, common) {
test('valid point duo', function (t) {
var clean = {};
var params = {
'foo.bar.lat': 11,
'foo.bar.lon': 22
};
var mandatory = false;
sanitize.sanitize_point( 'foo.bar', clean, params, mandatory );
t.equal(clean['foo.bar.lat'], params['foo.bar.lat'], 'lat approved');
t.equal(clean['foo.bar.lon'], params['foo.bar.lon'], 'lon approved');
t.end();
});
test('invalid point, lat only', function (t) {
var clean = {};
var params = {
'foo.bar.lat': 11
};
var mandatory = false;
t.throws( function(){
sanitize.sanitize_point( 'foo.bar', clean, params, mandatory );
});
t.end();
});
test('invalid point, lon only', function (t) {
var clean = {};
var params = {
'foo.bar.lon': 22,
};
var mandatory = false;
t.throws( function(){
sanitize.sanitize_point( 'foo.bar', clean, params, mandatory );
});
t.end();
});
test('invalid lat value specified', function (t) {
var clean = {};
var params = {
'foo.bar.lat': 'foobar',
'foo.bar.lon': 22,
};
var mandatory = false;
t.throws( function(){
sanitize.sanitize_point( 'foo.bar', clean, params, mandatory );
});
t.end();
});
test('invalid lon value specified', function (t) {
var clean = {};
var params = {
'foo.bar.lat': 11,
'foo.bar.lon': 'foobar'
};
var mandatory = false;
t.throws( function(){
sanitize.sanitize_point( 'foo.bar', clean, params, mandatory );
});
t.end();
});
test('nothing specified', function (t) {
var clean = {};
var params = {};
var mandatory = false;
t.doesNotThrow( function(){
sanitize.sanitize_point( 'foo.bar', clean, params, mandatory );
});
t.end();
});
test('nothing specified - mandatory', function (t) {
var clean = {};
var params = {};
var mandatory = true;
t.throws( function(){
sanitize.sanitize_point( 'foo.bar', clean, params, mandatory );
});
t.end();
});
};
module.exports.tests.rect = function(test, common) {
test('valid rect quad', function (t) {
var clean = {};
var params = {
'boundary.rect.min_lat': -40.659,
'boundary.rect.max_lat': -41.614,
'boundary.rect.min_lon': 174.612,
'boundary.rect.max_lon': 176.333
};
var mandatory = false;
sanitize.sanitize_rect( 'boundary.rect', clean, params, mandatory );
t.equal(clean['boundary.rect.min_lat'], params['boundary.rect.min_lat'], 'min_lat approved');
t.equal(clean['boundary.rect.max_lat'], params['boundary.rect.max_lat'], 'min_lat approved');
t.equal(clean['boundary.rect.min_lon'], params['boundary.rect.min_lon'], 'min_lat approved');
t.equal(clean['boundary.rect.max_lon'], params['boundary.rect.max_lon'], 'min_lat approved');
t.end();
});
test('invalid rect - partially specified', function (t) {
var clean = {};
var params = {
'boundary.rect.min_lat': -40.659
};
var mandatory = false;
t.throws( function(){
sanitize.sanitize_rect( 'boundary.rect', clean, params, mandatory );
});
t.end();
});
test('nothing specified', function (t) {
var clean = {};
var params = {};
var mandatory = false;
t.doesNotThrow( function(){
sanitize.sanitize_rect( 'boundary.rect', clean, params, mandatory );
});
t.end();
});
test('nothing specified - mandatory', function (t) {
var clean = {};
var params = {};
var mandatory = true;
t.throws( function(){
sanitize.sanitize_rect( 'boundary.rect', clean, params, mandatory );
});
t.end();
});
};
module.exports.tests.circle = function(test, common) {
test('valid circle trio', function (t) { test('valid circle trio', function (t) {
var clean = {}; var clean = {};
var params = { var params = {
@ -19,26 +217,160 @@ module.exports.tests.sanitize = function(test, common) {
'boundary.circle.lon': 22, 'boundary.circle.lon': 22,
'boundary.circle.radius': 33 'boundary.circle.radius': 33
}; };
var is_required = true; var mandatory = false;
var all_required = true;
sanitize.sanitize_boundary_circle(clean, params, is_required, all_required); sanitize.sanitize_circle( 'boundary.circle', clean, params, mandatory );
t.equal(clean['boundary.circle.lat'], params['boundary.circle.lat'], 'lat approved'); t.equal(clean['boundary.circle.lat'], params['boundary.circle.lat'], 'lat approved');
t.equal(clean['boundary.circle.lon'], params['boundary.circle.lon'], 'lon approved'); t.equal(clean['boundary.circle.lon'], params['boundary.circle.lon'], 'lon approved');
t.equal(clean['boundary.circle.radius'], params['boundary.circle.radius'], 'radius approved'); t.equal(clean['boundary.circle.radius'], params['boundary.circle.radius'], 'radius approved');
t.end(); t.end();
}); });
test('valid circle, radius only, all not required', function (t) { test('valid circle duo', function (t) {
var clean = {};
var params = {
'boundary.circle.lat': 11,
'boundary.circle.lon': 22
};
var mandatory = false;
sanitize.sanitize_circle( 'boundary.circle', clean, params, mandatory );
t.equal(clean['boundary.circle.lat'], params['boundary.circle.lat'], 'lat approved');
t.equal(clean['boundary.circle.lon'], params['boundary.circle.lon'], 'lon approved');
t.end();
});
test('invalid circle, lat only', function (t) {
var clean = {};
var params = {
'boundary.circle.lat': 11,
};
var mandatory = false;
t.throws( function(){
sanitize.sanitize_circle( 'boundary.circle', clean, params, mandatory );
});
t.end();
});
test('invalid circle, lon only', function (t) {
var clean = {};
var params = {
'boundary.circle.lon': 22,
};
var mandatory = false;
t.throws( function(){
sanitize.sanitize_circle( 'boundary.circle', clean, params, mandatory );
});
t.end();
});
test('invalid circle, radius only', function (t) {
var clean = {}; var clean = {};
var params = { var params = {
'boundary.circle.radius': 33 'boundary.circle.radius': 33
}; };
var is_required = true; var mandatory = false;
var all_required = false;
sanitize.sanitize_boundary_circle(clean, params, is_required, all_required); t.throws( function(){
t.equal(clean['boundary.circle.radius'], params['boundary.circle.radius'], 'radius approved'); sanitize.sanitize_circle( 'boundary.circle', clean, params, mandatory );
});
t.end();
});
test('invalid circle, lon and radius only', function (t) {
var clean = {};
var params = {
'boundary.circle.lon': 22,
'boundary.circle.radius': 33
};
var mandatory = false;
t.throws( function(){
sanitize.sanitize_circle( 'boundary.circle', clean, params, mandatory );
});
t.end();
});
test('invalid circle, lat and radius only', function (t) {
var clean = {};
var params = {
'boundary.circle.lat': 11,
'boundary.circle.radius': 33
};
var mandatory = false;
t.throws( function(){
sanitize.sanitize_circle( 'boundary.circle', clean, params, mandatory );
});
t.end();
});
test('invalid lat value specified', function (t) {
var clean = {};
var params = {
'boundary.circle.lat': 'foobar',
'boundary.circle.lon': 22,
'boundary.circle.radius': 33
};
var mandatory = false;
t.throws( function(){
sanitize.sanitize_circle( 'boundary.circle', clean, params, mandatory );
});
t.end();
});
test('invalid lon value specified', function (t) {
var clean = {};
var params = {
'boundary.circle.lat': 11,
'boundary.circle.lon': 'foobar',
'boundary.circle.radius': 33
};
var mandatory = false;
t.throws( function(){
sanitize.sanitize_circle( 'boundary.circle', clean, params, mandatory );
});
t.end();
});
test('invalid radius value specified', function (t) {
var clean = {};
var params = {
'boundary.circle.lat': 11,
'boundary.circle.lon': 22,
'boundary.circle.radius': 'foobar'
};
var mandatory = false;
t.throws( function(){
sanitize.sanitize_circle( 'boundary.circle', clean, params, mandatory );
});
t.end();
});
test('nothing specified', function (t) {
var clean = {};
var params = {};
var mandatory = false;
t.doesNotThrow( function(){
sanitize.sanitize_circle( 'boundary.circle', clean, params, mandatory );
});
t.end();
});
test('nothing specified - mandatory', function (t) {
var clean = {};
var params = {};
var mandatory = true;
t.throws( function(){
sanitize.sanitize_circle( 'boundary.circle', clean, params, mandatory );
});
t.end(); t.end();
}); });
}; };

11
test/unit/sanitiser/reverse.js

@ -6,17 +6,18 @@ var reverse = require('../../../sanitiser/reverse'),
middleware = reverse.middleware, middleware = reverse.middleware,
defaultError = 'missing param \'lat\'', defaultError = 'missing param \'lat\'',
defaultClean = { 'point.lat': 0, defaultClean = { 'point.lat': 0,
'point.lon': 0,
'boundary.circle.lat': 0,
'boundary.circle.lon': 0,
types: { types: {
}, },
'point.lon': 0,
size: 10, size: 10,
private: false, private: false
boundary: { }
}; };
// these are the default values you would expect when no input params are specified. // these are the default values you would expect when no input params are specified.
// @todo: why is this different from $defaultClean? // @todo: why is this different from $defaultClean?
var emptyClean = { boundary: {}, private: false, size: 10, types: {} }; var emptyClean = { private: false, size: 10, types: {} };
module.exports.tests = {}; module.exports.tests = {};
@ -101,7 +102,7 @@ module.exports.tests.sanitize_lon = function(test, common) {
var req = { query: { 'point.lat': 0, 'point.lon': lon } }; var req = { query: { 'point.lat': 0, 'point.lon': lon } };
// @todo: why is lat set? // @todo: why is lat set?
var expected = { boundary: {}, 'point.lat': 0, private: false, size: 10, types: {} }; var expected = { 'point.lat': 0, private: false, size: 10, types: {} };
sanitize(req, function(){ sanitize(req, function(){
t.equal(req.errors[0], 'missing param \'point.lon\'', 'longitude is a required field'); t.equal(req.errors[0], 'missing param \'point.lon\'', 'longitude is a required field');
t.deepEqual(req.clean, expected, 'clean only has default values set'); t.deepEqual(req.clean, expected, 'clean only has default values set');

68
test/unit/sanitiser/search.js

@ -1,11 +1,12 @@
var search = require('../../../sanitiser/search'), var extend = require('extend'),
search = require('../../../sanitiser/search'),
parser = require('../../../helper/query_parser'), parser = require('../../../helper/query_parser'),
sanitize = search.sanitize, sanitize = search.sanitize,
middleware = search.middleware, middleware = search.middleware,
defaultError = 'invalid param \'text\': text length, must be >0'; defaultError = 'invalid param \'text\': text length, must be >0';
// these are the default values you would expect when no input params are specified. // these are the default values you would expect when no input params are specified.
// @todo: why is this different from $defaultClean? // @todo: why is this different from $defaultClean?
var emptyClean = { boundary: {}, private: false, size: 10, types: {} }; var emptyClean = { private: false, size: 10, types: {} };
module.exports.tests = {}; module.exports.tests = {};
@ -166,8 +167,9 @@ module.exports.tests.sanitize_optional_geo = function(test, common) {
var req = { query: { text: 'test', 'focus.point.lon': 0 } }; var req = { query: { text: 'test', 'focus.point.lon': 0 } };
sanitize(req, function(){ sanitize(req, function(){
var expected_lon = 0; var expected_lon = 0;
t.equal(req.errors[0], undefined, 'no error'); t.equal(req.errors[0], 'missing point param \'focus.point\' requires all of: \'lat\',\'lon\' to be present');
t.deepEqual(req.clean['focus.point.lon'], expected_lon, 'clean set correctly (without any lat)'); t.equal(req.clean['focus.point.lat'], undefined);
t.equal(req.clean['focus.point.lon'], undefined);
}); });
t.end(); t.end();
}); });
@ -175,14 +177,28 @@ module.exports.tests.sanitize_optional_geo = function(test, common) {
var req = { query: { text: 'test', 'focus.point.lat': 0 } }; var req = { query: { text: 'test', 'focus.point.lat': 0 } };
sanitize(req, function(){ sanitize(req, function(){
var expected_lat = 0; var expected_lat = 0;
t.equal(req.errors[0], undefined, 'no error'); t.equal(req.errors[0], 'missing point param \'focus.point\' requires all of: \'lat\',\'lon\' to be present');
t.deepEqual(req.clean['focus.point.lat'], expected_lat, 'clean set correctly (without any lon)'); t.equal(req.clean['focus.point.lat'], undefined);
t.equal(req.clean['focus.point.lon'], undefined);
}); });
t.end(); t.end();
}); });
}; };
module.exports.tests.sanitize_bbox = function(test, common) { module.exports.tests.sanitize_bounding_rect = function(test, common) {
// convernience function to avoid refactoring the succict geojson bbox
// fixtures in to the more verbose bounding.rect format.
var mapGeoJsonBboxFormatToBoundingRectFormat = function( bbox ){
var split = bbox.split(',');
return {
'boundary.rect.min_lon': split[0],
'boundary.rect.max_lat': split[1],
'boundary.rect.max_lon': split[2],
'boundary.rect.min_lat': split[3]
};
};
var bboxes = { var bboxes = {
invalid: [ invalid: [
'91;-181,-91,181', // invalid - semicolon between coordinates '91;-181,-91,181', // invalid - semicolon between coordinates
@ -192,7 +208,8 @@ module.exports.tests.sanitize_bbox = function(test, common) {
'91, -181, -91', // invalid - missing a coordinate '91, -181, -91', // invalid - missing a coordinate
'123,12', // invalid - missing coordinates '123,12', // invalid - missing coordinates
'' // invalid - empty param '' // invalid - empty param
], ].map(mapGeoJsonBboxFormatToBoundingRectFormat),
valid: [ valid: [
'-179,90,34,-80', // valid top_right lon/lat, bottom_left lon/lat '-179,90,34,-80', // valid top_right lon/lat, bottom_left lon/lat
'0,0,0,0', '0,0,0,0',
@ -207,34 +224,33 @@ module.exports.tests.sanitize_bbox = function(test, common) {
'-181,91,181,-91', '-181,91,181,-91',
'91, -181,-91,11', '91, -181,-91,11',
'91, -11,-91,181' '91, -11,-91,181'
] ].map(mapGeoJsonBboxFormatToBoundingRectFormat)
}; };
test('invalid bbox', function(t) {
test('invalid bounding rect', function(t) {
bboxes.invalid.forEach( function( bbox ){ bboxes.invalid.forEach( function( bbox ){
var req = { query: { text: 'test', bbox: bbox } }; var req = { query: { text: 'test' } };
extend( req.query, bbox );
sanitize(req, function(){ sanitize(req, function(){
t.equal(req.errors[0], undefined, 'no error'); t.equal(req.clean['boundary.rect.min_lon'], undefined);
t.equal(req.clean.bbox, undefined, 'falling back on 50km distance from centroid'); t.equal(req.clean['boundary.rect.max_lat'], undefined);
t.equal(req.clean['boundary.rect.max_lon'], undefined);
t.equal(req.clean['boundary.rect.min_lat'], undefined);
t.equal(req.errors.length, 1, 'bounding error');
}); });
}); });
t.end(); t.end();
}); });
test('valid bbox', function(t) { test('valid bounding rect', function(t) {
bboxes.valid.forEach( function( bbox ){ bboxes.valid.forEach( function( bbox ){
var req = { query: { text: 'test', bbox: bbox } }; var req = { query: { text: 'test' } };
extend( req.query, bbox );
sanitize(req, function(){ sanitize(req, function(){
var bboxArray = bbox.split(',').map(function(i) {
return parseInt(i, 10);
});
var expected_bbox = {
right: Math.max(bboxArray[0], bboxArray[2]),
top: Math.max(bboxArray[1], bboxArray[3]),
left: Math.min(bboxArray[0], bboxArray[2]),
bottom: Math.min(bboxArray[1], bboxArray[3])
};
t.equal(req.errors[0], undefined, 'no error'); t.equal(req.errors[0], undefined, 'no error');
t.deepEqual(req.clean.bbox, expected_bbox, 'clean set correctly (' + bbox + ')'); t.equal(req.clean['boundary.rect.min_lon'], parseFloat(bbox['boundary.rect.min_lon']));
t.equal(req.clean['boundary.rect.max_lat'], parseFloat(bbox['boundary.rect.max_lat']));
t.equal(req.clean['boundary.rect.max_lon'], parseFloat(bbox['boundary.rect.max_lon']));
t.equal(req.clean['boundary.rect.min_lat'], parseFloat(bbox['boundary.rect.min_lat']));
}); });
}); });
t.end(); t.end();

Loading…
Cancel
Save