Browse Source

Refactored layers and sources into a common targets module

pull/250/head
Diana Shkolnikov 9 years ago
parent
commit
c069933d5b
  1. 25
      helper/layers.js
  2. 10
      helper/query_parser.js
  3. 1
      package.json
  4. 15
      query/layers.js
  5. 1
      routes/v1.js
  6. 52
      sanitiser/_layers.js
  7. 44
      sanitiser/_sources.js
  8. 57
      sanitiser/_targets.js
  9. 27
      sanitiser/reverse.js
  10. 12
      sanitiser/search.js
  11. 7
      test/unit/helper/query_parser.js
  12. 1
      test/unit/run.js
  13. 93
      test/unit/sanitiser/_layers.js
  14. 6
      test/unit/sanitiser/_sources.js
  15. 85
      test/unit/sanitiser/reverse.js
  16. 88
      test/unit/sanitiser/search.js

25
helper/layers.js

@ -1,25 +0,0 @@
module.exports = function(alias_layers) {
// make a copy of the array so, you are not modifying original ref
var layers = alias_layers.slice(0);
// expand aliases
var expand_aliases = function(alias, layers, layer_indeces) {
var alias_index = layers.indexOf(alias);
if (alias_index !== -1 ) {
layers.splice(alias_index, 1);
layers = layers.concat(layer_indeces);
}
return layers;
};
layers = expand_aliases('poi', layers, ['geoname','osmnode','osmway']);
layers = expand_aliases('admin', layers, ['admin0','admin1','admin2','neighborhood','locality','local_admin']);
layers = expand_aliases('address', layers, ['osmaddress','openaddresses']);
// de-dupe
layers = layers.filter(function(item, pos) {
return layers.indexOf(item) === pos;
});
return layers;
};

10
helper/query_parser.js

@ -1,26 +1,20 @@
var parser = require('addressit');
var extend = require('extend');
var get_layers_helper = require('../helper/layers');
var layers_map = require('../query/layers');
var delim = ',';
module.exports = {};
module.exports.get_layers = function get_layers(query) {
var tokenized = query.split(/[ ,]+/);
var hasNumber = /\d/.test(query);
if (query.length <= 3 ) {
// no address parsing required
return get_layers_helper(['admin']);
return layers_map.coarse;
}
};
module.exports.get_parsed_address = function get_parsed_address(query) {
var tokenized = query.split(/[ ,]+/);
var hasNumber = /\d/.test(query);
var getAdminPartsBySplittingOnDelim = function(query) {
// naive approach - for admin matching during query time
// split 'flatiron, new york, ny' into 'flatiron' and 'new york, ny'

1
package.json

@ -44,6 +44,7 @@
"geolib": "^2.0.18",
"geopipes-elasticsearch-backend": "^0.2.0",
"is-object": "^1.0.1",
"lodash": "^3.10.1",
"markdown": "0.5.0",
"microtime": "1.4.0",
"morgan": "1.5.2",

15
query/layers.js

@ -0,0 +1,15 @@
/*
* Mapping from data layers to type values
*/
module.exports = {
'venue': ['geoname','osmnode','osmway'],
'address': ['osmaddress','openaddresses'],
'country': ['admin0'],
'region': ['admin1'],
'county': ['admin2'],
'locality': ['locality'],
'localadmin': ['local_admin'],
'neighbourhood': ['neighborhood'],
'coarse': ['admin0','admin1','admin2','neighborhood','locality','local_admin'],
};

1
routes/v1.js

@ -69,6 +69,7 @@ function addRoutes(app, peliasConfig) {
]),
reverse: createRouter([
sanitisers.reverse.middleware,
middleware.types,
controllers.search(undefined, reverseQuery),
// TODO: add confidence scores
postProc.distances(),

52
sanitiser/_layers.js

@ -1,52 +0,0 @@
var isObject = require('is-object'),
types = require('../query/types'),
get_layers = require('../helper/layers');
// validate inputs, convert types and apply defaults
function sanitize( req ){
var clean = req.clean || {};
var params= req.query;
clean.types = clean.types || {};
// ensure the input params are a valid object
if( !isObject( params ) ){
params = {};
}
// default case (no layers specified in GET params)
// don't even set the from_layers key in this case
if('string' !== typeof params.layers || !params.layers.length){
return { 'error': false };
}
// decide which layers can be queried
var alias_layers = ['poi', 'admin', 'address'];
var alias_types = types.concat(alias_layers);
// parse GET params
var layers = params.layers.split(',').map( function( layer ){
return layer.toLowerCase(); // lowercase inputs
});
// validate layer names
for( var x=0; x<layers.length; x++ ){
if( -1 === alias_types.indexOf( layers[x] ) ){
return {
'error': true,
'message': 'invalid param \'layers\': must be one or more of ' + alias_types.join(',')
};
}
}
// pass validated params to next middleware
clean.types.from_layers = get_layers(layers);
req.clean = clean;
return { 'error': false };
}
// export function
module.exports = sanitize;

44
sanitiser/_sources.js

@ -1,44 +0,0 @@
var isObject = require('is-object');
var sources_map = require( '../query/sources' );
function sanitize( req ) {
var params = req.query || {};
req.clean = req.clean || {};
req.clean.types = req.clean.types || {};
// default case (no sources specified in GET params)
if (params.hasOwnProperty('sources') === false) {
return { error: false };
}
params.sources = params.sources.trim();
if (params.sources.trim().length === 0) {
return {
error: true,
message: '`sources` parameter cannot be an empty string. Valid options: ' + Object.keys(sources_map).join(', ')
};
}
var sources = params.sources.split(',');
var invalid_sources = sources.filter(function(source) {
return sources_map.hasOwnProperty(source) === false;
});
if (invalid_sources.length > 0) {
return {
error: true,
message: '`' + invalid_sources[0] + '` is an invalid source parameter. Valid options: ' + Object.keys(sources_map).join(', ')
};
}
req.clean.types.from_sources = sources.reduce(function(acc, source) {
return acc.concat(sources_map[source]);
}, []);
return { error: false };
}
module.exports = sanitize;

57
sanitiser/_targets.js

@ -0,0 +1,57 @@
var _ = require('lodash');
function setup(paramName, targetMap) {
return function (req ) {
return sanitize(paramName, targetMap, req);
};
}
function sanitize( paramName, targetMap, req ) {
var params = req.query || {};
req.clean = req.clean || {};
req.clean.types = req.clean.types || {};
// default case (no sources specified in GET params)
// there is a case where the property is present, but set to null or undefined
if (params.hasOwnProperty(paramName) === false || typeof params[paramName] === 'undefined') {
return { error: false };
}
params[paramName] = params[paramName].trim();
if (params[paramName].length === 0) {
return {
error: true,
message: paramName + ' parameter cannot be an empty string. Valid options: ' + Object.keys(targetMap).join(', ')
};
}
var targets = params[paramName].split(',').map( function( target ){
return target.toLowerCase(); // lowercase inputs
});
var invalidTargets = targets.filter(function(target) {
return targetMap.hasOwnProperty(target) === false;
});
if (invalidTargets.length > 0) {
return {
error: true,
message: invalidTargets[0] + ' is an invalid ' + paramName + ' parameter. Valid options: ' + Object.keys(targetMap).join(', ')
};
}
var cleanPropName = 'from_' + paramName;
req.clean.types[cleanPropName] = targets.reduce(function(acc, target) {
return acc.concat(targetMap[target]);
}, []);
// dedupe in case aliases expanded to common things or user typed in duplicates
req.clean.types[cleanPropName] = _.unique(req.clean.types[cleanPropName]);
return { error: false };
}
module.exports = setup;

27
sanitiser/reverse.js

@ -1,15 +1,16 @@
var _sanitize = require('../sanitiser/_sanitize'),
sanitiser = {
latlonzoom: require('../sanitiser/_geo_reverse'),
layers: require('../sanitiser/_layers'),
suorce: require('../sanitiser/_sources'),
details: require('../sanitiser/_details'),
size: require('../sanitiser/_size'),
categories: function ( req ) {
var categories = require('../sanitiser/_categories');
return categories(req);
}
};
var _sanitize = require('../sanitiser/_sanitize');
var sanitiser = {
latlonzoom: require('../sanitiser/_geo_reverse'),
layers: require('../sanitiser/_targets')('layers', require('../query/layers')),
sources: require('../sanitiser/_targets')('sources', require('../query/sources')),
details: require('../sanitiser/_details'),
size: require('../sanitiser/_size'),
categories: function (req) {
var categories = require('../sanitiser/_categories');
return categories(req);
}
};
var sanitize = function(req, cb) { _sanitize(req, sanitiser, cb); };
@ -27,3 +28,5 @@ module.exports.middleware = function( req, res, next ){
next();
});
};
module.exports.sanitiser_list = sanitiser;

12
sanitiser/search.js

@ -3,10 +3,14 @@ var _sanitize = require('../sanitiser/_sanitize'),
sanitizers = {
text: require('../sanitiser/_text'),
size: require('../sanitiser/_size'),
layers: require('../sanitiser/_layers'),
source: require('../sanitiser/_sources'),
layers: require('../sanitiser/_targets')('layers', require( '../query/layers' )),
sources: require('../sanitiser/_targets')('sources', require( '../query/sources' )),
details: require('../sanitiser/_details'),
latlonzoom: require('../sanitiser/_geo_search')
latlonzoom: require('../sanitiser/_geo_search'),
categories: function (req) {
var categories = require('../sanitiser/_categories');
return categories(req);
}
};
var sanitize = function(req, cb) { _sanitize(req, sanitizers, cb); };
@ -25,3 +29,5 @@ module.exports.middleware = function( req, res, next ){
next();
});
};
module.exports.sanitiser_list = sanitizers;

7
test/unit/helper/query_parser.js

@ -1,6 +1,6 @@
var parser = require('../../../helper/query_parser');
var get_layers = require('../../../helper/layers');
var layers_map = require('../../../query/layers');
module.exports.tests = {};
@ -43,7 +43,7 @@ module.exports.tests.parse_three_chars_or_less = function(test, common) {
var testParse = function(query) {
test('query length < 3 (' + query + ')', function(t) {
var address = parser.get_parsed_address(query);
var target_layer = get_layers(['admin']);
var target_layer = layers_map.coarse;
var layers = parser.get_layers(query);
t.equal(typeof address, 'object', 'valid object');
@ -67,7 +67,7 @@ module.exports.tests.parse_one_or_more_tokens = function(test, common) {
var testParse = function(query, parse_address) {
test('query with one or more tokens (' + query + ')', function(t) {
var address = parser.get_parsed_address(query);
var target_layer = get_layers(['admin', 'poi']);
var target_layer = layers_map.coarse.concat(layers_map.venue);
var layers = parser.get_layers(query);
t.equal(typeof address, 'object', 'valid object');
@ -119,7 +119,6 @@ module.exports.tests.parse_address = function(test, common) {
query_string = query_string.substring(1);
var address = parser.get_parsed_address(query_string);
var non_address_layer = get_layers(['admin', 'poi']);
t.equal(typeof address, 'object', 'valid object for the address ('+query_string+')');

1
test/unit/run.js

@ -10,6 +10,7 @@ var tests = [
require('./service/search'),
require('./sanitiser/_sources'),
require('./sanitiser/search'),
require('./sanitiser/_layers'),
require('./sanitiser/reverse'),
require('./sanitiser/place'),
require('./query/types'),

93
test/unit/sanitiser/_layers.js

@ -0,0 +1,93 @@
var sanitize = require('../../../sanitiser/_targets')('layers', require('../../../query/layers'));
module.exports.tests = {};
module.exports.tests.sanitize_layers = function(test, common) {
test('unspecified', function(t) {
var res = sanitize({ query: { layers: undefined } });
t.equal(res.error, false);
t.end();
});
test('invalid layer', function(t) {
var req = { query: { layers: 'test_layer' } };
var res = sanitize(req);
var msg = ' is an invalid layers parameter. Valid options: ';
t.true(res.error, 'error flag set');
t.true(res.message.match(msg), 'invalid layer requested');
t.true(res.message.length > msg.length, 'invalid error message');
t.end();
});
test('venue (alias) layer', function(t) {
var venue_layers = ['geoname','osmnode','osmway'];
var req = { query: { layers: 'venue' } };
sanitize(req);
t.deepEqual(req.clean.types.from_layers, venue_layers, 'venue layers set');
t.end();
});
test('coarse (alias) layer', function(t) {
var admin_layers = ['admin0','admin1','admin2','neighborhood','locality','local_admin'];
var req = { query: { layers: 'coarse' } };
sanitize(req);
t.deepEqual(req.clean.types.from_layers, admin_layers, 'coarse layers set');
t.end();
});
test('address (alias) layer', function(t) {
var address_layers = ['osmaddress','openaddresses'];
var req = { query: { layers: 'address' } };
sanitize(req);
t.deepEqual(req.clean.types.from_layers, address_layers, 'address layers set');
t.end();
});
test('venue alias layer plus regular layers', function(t) {
var venue_layers = ['geoname','osmnode','osmway'];
var reg_layers = ['admin0', 'admin1'];
var req = { query: { layers: 'venue,country,region' } };
sanitize(req);
t.deepEqual(req.clean.types.from_layers, venue_layers.concat(reg_layers), 'venue + regular layers');
t.end();
});
test('coarse alias layer plus regular layers', function(t) {
var admin_layers = ['admin0','admin1','admin2','neighborhood','locality','local_admin'];
var reg_layers = ['geoname', 'osmnode', 'osmway'];
var req = { query: { layers: 'coarse,venue,country' } };
sanitize(req);
t.deepEqual(req.clean.types.from_layers, admin_layers.concat(reg_layers), 'coarse + regular layers set');
t.end();
});
test('address alias layer plus regular layers', function(t) {
var address_layers = ['osmaddress','openaddresses'];
var reg_layers = ['admin0', 'locality'];
var req = { query: { layers: 'address,country,locality' } };
sanitize(req);
t.deepEqual(req.clean.types.from_layers, address_layers.concat(reg_layers), 'address + regular layers set');
t.end();
});
test('alias layer plus regular layers (no duplicates)', function(t) {
var venue_layers = ['geoname','osmnode','osmway','admin0'];
var req = { query: { layers: 'venue,country' } };
sanitize(req);
t.deepEqual(req.clean.types.from_layers, venue_layers, 'venue layers found (no duplicates)');
t.end();
});
test('multiple alias layers (no duplicates)', function(t) {
var alias_layers = ['geoname','osmnode','osmway','admin0','admin1','admin2','neighborhood','locality','local_admin'];
var req = { query: { layers: 'venue,coarse' } };
sanitize(req);
t.deepEqual(req.clean.types.from_layers, alias_layers, 'all layers found (no duplicates)');
t.end();
});
};
module.exports.all = function (tape, common) {
function test(name, testFunction) {
return tape('SANTIZE _layers ' + name, testFunction);
}
for( var testCase in module.exports.tests ){
module.exports.tests[testCase](test, common);
}
};

6
test/unit/sanitiser/_sources.js

@ -1,4 +1,4 @@
var sanitize = require( '../../../sanitiser/_sources' );
var sanitize = require( '../../../sanitiser/_targets' )('sources', require('../../../query/sources'));
var success_response = { error: false };
@ -26,7 +26,7 @@ module.exports.tests.no_sources = function(test, common) {
var expected_response = {
error: true,
message: '`sources` parameter cannot be an empty string. ' +
message: 'sources parameter cannot be an empty string. ' +
'Valid options: gn, geonames, oa, openaddresses, qs, quattroshapes, osm, openstreetmap'
};
@ -98,7 +98,7 @@ module.exports.tests.invalid_sources = function(test, common) {
};
var expected_response = {
error: true,
message: '`notasource` is an invalid source parameter. ' +
message: 'notasource is an invalid sources parameter. ' +
'Valid options: gn, geonames, oa, openaddresses, qs, quattroshapes, osm, openstreetmap'
};

85
test/unit/sanitiser/reverse.js

@ -2,7 +2,6 @@
var suggest = require('../../../sanitiser/reverse'),
_sanitize = suggest.sanitize,
middleware = suggest.middleware,
delim = ',',
defaultError = 'missing param \'lat\'',
defaultClean = { lat:0,
types: {
@ -29,6 +28,14 @@ module.exports.tests.interface = function(test, common) {
});
};
module.exports.tests.sanitisers = function(test, common) {
test('check sanitiser list', function (t) {
var expected = ['latlonzoom', 'layers', 'sources', 'details', 'size', 'categories'];
t.deepEqual(Object.keys(suggest.sanitiser_list), expected);
t.end();
});
};
module.exports.tests.sanitize_lat = function(test, common) {
var lats = {
invalid: [],
@ -154,82 +161,6 @@ module.exports.tests.sanitize_details = function(test, common) {
});
};
module.exports.tests.sanitize_layers = function(test, common) {
test('unspecified', function(t) {
sanitize({ layers: undefined, 'point.lat': 0, 'point.lon': 0 }, function( err, clean ){
t.deepEqual(clean.types.from_layers, defaultClean.types.from_layers, 'default layers set');
t.end();
});
});
test('invalid layer', function(t) {
sanitize({ layers: 'test_layer', 'point.lat': 0, 'point.lon': 0 }, function( err, clean ){
var msg = 'invalid param \'layers\': must be one or more of ';
t.true(err.match(msg), 'invalid layer requested');
t.true(err.length > msg.length, 'invalid error message');
t.end();
});
});
test('poi (alias) layer', function(t) {
var poi_layers = ['geoname','osmnode','osmway'];
sanitize({ layers: 'poi', 'point.lat': 0, 'point.lon': 0 }, function( err, clean ){
t.deepEqual(clean.types.from_layers, poi_layers, 'poi layers set');
t.end();
});
});
test('admin (alias) layer', function(t) {
var admin_layers = ['admin0','admin1','admin2','neighborhood','locality','local_admin'];
sanitize({ layers: 'admin', 'point.lat': 0, 'point.lon': 0 }, function( err, clean ){
t.deepEqual(clean.types.from_layers, admin_layers, 'admin layers set');
t.end();
});
});
test('address (alias) layer', function(t) {
var address_layers = ['osmaddress','openaddresses'];
sanitize({ layers: 'address', 'point.lat': 0, 'point.lon': 0 }, function( err, clean ){
t.deepEqual(clean.types.from_layers, address_layers, 'address layers set');
t.end();
});
});
test('poi alias layer plus regular layers', function(t) {
var poi_layers = ['geoname','osmnode','osmway'];
var reg_layers = ['admin0', 'admin1'];
sanitize({ layers: 'poi,admin0,admin1', 'point.lat': 0, 'point.lon': 0 }, function( err, clean ){
t.deepEqual(clean.types.from_layers, reg_layers.concat(poi_layers), 'poi + regular layers');
t.end();
});
});
test('admin alias layer plus regular layers', function(t) {
var admin_layers = ['admin0','admin1','admin2','neighborhood','locality','local_admin'];
var reg_layers = ['geoname', 'osmway'];
sanitize({ layers: 'admin,geoname,osmway', 'point.lat': 0, 'point.lon': 0 }, function( err, clean ){
t.deepEqual(clean.types.from_layers, reg_layers.concat(admin_layers), 'admin + regular layers set');
t.end();
});
});
test('address alias layer plus regular layers', function(t) {
var address_layers = ['osmaddress','openaddresses'];
var reg_layers = ['geoname', 'osmway'];
sanitize({ layers: 'address,geoname,osmway', 'point.lat': 0, 'point.lon': 0 }, function( err, clean ){
t.deepEqual(clean.types.from_layers, reg_layers.concat(address_layers), 'address + regular layers set');
t.end();
});
});
test('alias layer plus regular layers (no duplicates)', function(t) {
var poi_layers = ['geoname','osmnode','osmway'];
sanitize({ layers: 'poi,geoname,osmnode', 'point.lat': 0, 'point.lon': 0 }, function( err, clean ){
t.deepEqual(clean.types.from_layers, poi_layers, 'poi layers found (no duplicates)');
t.end();
});
});
test('multiple alias layers (no duplicates)', function(t) {
var alias_layers = ['geoname','osmnode','osmway','admin0','admin1','admin2','neighborhood','locality','local_admin'];
sanitize({ layers: 'poi,admin', 'point.lat': 0, 'point.lon': 0 }, function( err, clean ){
t.deepEqual(clean.types.from_layers, alias_layers, 'all layers found (no duplicates)');
t.end();
});
});
};
module.exports.tests.sanitize_categories = function(test, common) {
var queryParams = { 'point.lat': 0, 'point.lon': 0 };
test('unspecified', function(t) {

88
test/unit/sanitiser/search.js

@ -5,7 +5,6 @@ var search = require('../../../sanitiser/search'),
defaultParsed = _text.defaultParsed,
_sanitize = search.sanitize,
middleware = search.middleware,
delim = ',',
defaultError = 'invalid param \'text\': text length, must be >0',
defaultClean = { text: 'test',
types: {
@ -26,7 +25,15 @@ module.exports.tests.interface = function(test, common) {
});
test('middleware interface', function(t) {
t.equal(typeof middleware, 'function', 'middleware is a function');
t.equal(middleware.length, 3, 'sanitizee has a valid middleware');
t.equal(middleware.length, 3, 'sanitize has a valid middleware');
t.end();
});
};
module.exports.tests.sanitisers = function(test, common) {
test('check sanitiser list', function (t) {
var expected = ['text', 'size', 'layers', 'sources', 'details', 'latlonzoom', 'categories' ];
t.deepEqual(Object.keys(search.sanitiser_list), expected);
t.end();
});
};
@ -273,83 +280,6 @@ module.exports.tests.sanitize_details = function(test, common) {
});
};
module.exports.tests.sanitize_layers = function(test, common) {
test('unspecified', function(t) {
sanitize({ layers: undefined, text: 'test' }, function( err, clean ){
t.deepEqual(clean.types.from_layers, defaultClean.types.from_layers, 'default layers set');
t.end();
});
});
test('invalid layer', function(t) {
sanitize({ layers: 'test_layer', text: 'test' }, function( err, clean ){
var msg = 'invalid param \'layers\': must be one or more of ';
t.true(err.match(msg), 'invalid layer requested');
t.true(err.length > msg.length, 'invalid error message');
t.end();
});
});
test('poi (alias) layer', function(t) {
var poi_layers = ['geoname','osmnode','osmway'];
sanitize({ layers: 'poi', text: 'test' }, function( err, clean ){
t.deepEqual(clean.types.from_layers, poi_layers, 'poi layers set');
t.end();
});
});
test('admin (alias) layer', function(t) {
var admin_layers = ['admin0','admin1','admin2','neighborhood','locality','local_admin'];
sanitize({ layers: 'admin', text: 'test' }, function( err, clean ){
t.deepEqual(clean.types.from_layers, admin_layers, 'admin layers set');
t.end();
});
});
test('address (alias) layer', function(t) {
var address_layers = ['osmaddress','openaddresses'];
sanitize({ layers: 'address', text: 'test' }, function( err, clean ){
t.deepEqual(clean.types.from_layers, address_layers, 'types from layers set');
t.deepEqual(clean.types.from_address_parser, _text.allLayers, 'address parser uses default layers');
t.end();
});
});
test('poi alias layer plus regular layers', function(t) {
var poi_layers = ['geoname','osmnode','osmway'];
var reg_layers = ['admin0', 'admin1'];
sanitize({ layers: 'poi,admin0,admin1', text: 'test' }, function( err, clean ){
t.deepEqual(clean.types.from_layers, reg_layers.concat(poi_layers), 'poi + regular layers');
t.end();
});
});
test('admin alias layer plus regular layers', function(t) {
var admin_layers = ['admin0','admin1','admin2','neighborhood','locality','local_admin'];
var reg_layers = ['geoname', 'osmway'];
sanitize({ layers: 'admin,geoname,osmway', text: 'test' }, function( err, clean ){
t.deepEqual(clean.types.from_layers, reg_layers.concat(admin_layers), 'admin + regular layers set');
t.end();
});
});
test('address alias layer plus regular layers', function(t) {
var address_layers = ['osmaddress','openaddresses'];
var reg_layers = ['geoname', 'osmway'];
sanitize({ layers: 'address,geoname,osmway', text: 'test' }, function( err, clean ){
t.deepEqual(clean.types.from_layers, reg_layers.concat(address_layers), 'address + regular layers set');
t.end();
});
});
test('alias layer plus regular layers (no duplicates)', function(t) {
var poi_layers = ['geoname','osmnode','osmway'];
sanitize({ layers: 'poi,geoname,osmnode', text: 'test' }, function( err, clean ){
t.deepEqual(clean.types.from_layers, poi_layers, 'poi layers found (no duplicates)');
t.end();
});
});
test('multiple alias layers (no duplicates)', function(t) {
var alias_layers = ['geoname','osmnode','osmway','admin0','admin1','admin2','neighborhood','locality','local_admin'];
sanitize({ layers: 'poi,admin', text: 'test' }, function( err, clean ){
t.deepEqual(clean.types.from_layers, alias_layers, 'all layers found (no duplicates)');
t.end();
});
});
};
module.exports.tests.invalid_params = function(test, common) {
test('invalid text params', function(t) {
sanitize( undefined, function( err, clean ){

Loading…
Cancel
Save