Browse Source

Refactored to use a function for looking up value for a label

The reason for this switch is that special case logic is needed to determine the US state name to display.  All other fields can be looked up by name.

The burden of fallback functionality is now in `helper/labelSchema` so the burden of unit testing is now in `test/unit/helper/labelSchema.js`
pull/430/head
Stephen Hess 9 years ago committed by Julian Simioni
parent
commit
0f6059c05a
  1. 17
      helper/labelGenerator.js
  2. 65
      helper/labelSchema.js
  3. 13
      test/unit/helper/labelGenerator_USA.js
  4. 661
      test/unit/helper/labelSchema.js

17
helper/labelGenerator.js

@ -1,6 +1,5 @@
var _ = require('lodash'),
check = require('check-types'),
schemas = require('./labelSchema');
module.exports = function( record ){
@ -8,19 +7,11 @@ module.exports = function( record ){
var labelParts = getInitialLabel(record);
var buildOutput = function(parts, schemaArr, record) {
for (var i=0; i<schemaArr.length; i++) {
var fieldValue = record[schemaArr[i]];
if (check.nonEmptyString(fieldValue) && !_.includes(parts, fieldValue)) {
parts.push( fieldValue );
return parts;
}
}
return parts;
};
for (var key in schema) {
labelParts = buildOutput(labelParts, schema[key], record);
var valueFunction = schema[key];
labelParts = valueFunction(record, labelParts);
}
// NOTE: while it may seem odd to call `uniq` on the list of label parts,

65
helper/labelSchema.js

@ -1,23 +1,66 @@
var _ = require('lodash'),
check = require('check-types');
module.exports = {
'USA': {
'local': ['localadmin', 'locality', 'neighbourhood', 'county'],
'regional': ['region_a', 'region'],
'country': ['country_a']
'local': getFirstProperty(['localadmin', 'locality', 'neighbourhood', 'county']),
'regional': getUsState,
'country': getFirstProperty(['country_a'])
},
'GBR': {
'local': ['neighbourhood', 'county', 'localadmin', 'locality', 'region'],
'regional': ['county','country','region']
'local': getFirstProperty(['neighbourhood', 'county', 'localadmin', 'locality', 'region']),
'regional': getFirstProperty(['county','country','region'])
},
'SGP': {
'local': ['neighbourhood', 'region', 'county', 'localadmin', 'locality'],
'regional': ['county','country','region']
'local': getFirstProperty(['neighbourhood', 'region', 'county', 'localadmin', 'locality']),
'regional': getFirstProperty(['county','country','region'])
},
'SWE': {
'local': ['neighbourhood', 'region', 'county', 'localadmin', 'locality'],
'regional': ['country']
'local': getFirstProperty(['neighbourhood', 'region', 'county', 'localadmin', 'locality']),
'regional': getFirstProperty(['country'])
},
'default': {
'local': ['localadmin', 'locality', 'neighbourhood', 'county', 'region'],
'regional': ['country']
'local': getFirstProperty(['localadmin', 'locality', 'neighbourhood', 'county', 'region']),
'regional': getFirstProperty(['country'])
}
};
// find the first field of record that has a non-empty value that's not already in labelParts
function getFirstProperty(fields) {
return function(record, labelParts) {
for (var i = 0; i < fields.length; i++) {
var fieldValue = record[fields[i]];
if (check.nonEmptyString(fieldValue) && !_.includes(labelParts, fieldValue)) {
labelParts.push( fieldValue );
return labelParts;
}
}
return labelParts;
};
}
// this function is exclusively used for figuring out which field to use for US States
// 1. if a US state is the most granular bit of info entered, the label should contain
// the full state name, eg: Pennsylvania, USA
// 2. otherwise, the state abbreviation should be used, eg: Lancaster, PA, USA
// 3. if for some reason the abbreviation isn't available, use the full state name
function getUsState(record, labelParts) {
if ('region' === record.layer && record.region) {
// add full state name when state is the most granular piece of info
labelParts.push(record.region);
} else if (record.region_a) {
// otherwise just add the region code when available
labelParts.push(record.region_a);
} else if (record.region) {
// add the full name when there's no region code available ()
labelParts.push(record.region);
}
return labelParts;
}

13
test/unit/helper/labelGenerator_USA.js

@ -1,4 +1,3 @@
var generator = require('../../../helper/labelGenerator');
module.exports.tests = {};
@ -101,7 +100,7 @@ module.exports.tests.region_geonames = function(test, common) {
'source': 'geonames',
'layer': 'region'
};
t.equal(generator(doc),'Region Abbr, USA');
t.equal(generator(doc),'Region Name, USA');
t.end();
});
};
@ -110,7 +109,7 @@ module.exports.tests.region_geonames = function(test, common) {
module.exports.tests.region_whosonfirst = function(test, common) {
test('default name should not be prepended when source=whosonfirst and layer=region', function(t) {
var doc = {
'name': { 'default': 'California' },
'name': { 'default': 'Region Name' },
'country_a': 'USA',
'country': 'United States',
'region': 'Region Name',
@ -118,16 +117,16 @@ module.exports.tests.region_whosonfirst = function(test, common) {
'source': 'whosonfirst',
'layer': 'region'
};
t.equal(generator(doc),'Region Abbr, USA');
t.equal(generator(doc),'Region Name, USA');
t.end();
});
};
// USA non-geonames/whosonfirst state
module.exports.tests.region_other_source = function(test, common) {
test('default name should not be prepended when source=whosonfirst and layer=region', function(t) {
test('default name should be prepended when layer=region and source is not whosonfirst or geonames', function(t) {
var doc = {
'name': { 'default': 'Region Name' },
'name': { 'default': 'Default Name' },
'country_a': 'USA',
'country': 'United States',
'region': 'Region Name',
@ -135,7 +134,7 @@ module.exports.tests.region_other_source = function(test, common) {
'source': 'not geonames or whosonfirst',
'layer': 'region'
};
t.equal(generator(doc),'Region Name, Region Abbr, USA');
t.equal(generator(doc),'Default Name, Region Name, USA',generator(doc));
t.end();
});
};

661
test/unit/helper/labelSchema.js

@ -12,36 +12,637 @@ module.exports.tests.interface = function(test, common) {
});
};
module.exports.tests.valid = function(test, common) {
var valid_keys = ['localadmin', 'locality', 'neighbourhood', 'county', 'region_a', 'region', 'country', 'country_a'];
var default_schema = {
local: ['localadmin', 'locality', 'neighbourhood', 'county', 'region'],
regional: ['country']
};
var isValid = function(keys, schema) {
test('valid key/object (' + keys + ')' , function(t) {
if (keys === 'default') {
t.deepEqual(schema, default_schema, 'valid default schema');
} else {
t.equal(alpha3.hasOwnProperty(keys), true, 'valid key');
}
t.equal(typeof schema, 'object', 'valid object');
t.notEqual(Object.getOwnPropertyNames(schema).length, 0, 'object not empty');
for (var levels in schema) {
t.equal(Object.prototype.toString.call(schema[levels]), '[object Array]', levels+' is an array');
for (var i=0;i<schema[levels].length;i++) {
var key = schema[levels][i];
t.notEqual(valid_keys.indexOf(key), -1, key + ' is valid');
}
}
t.end();
});
};
for (var keys in schemas) {
isValid(keys, schemas[keys]);
}
module.exports.tests.supported_countries = function(test, common) {
test('support countries', function(t) {
var supported_countries = Object.keys(schemas);
t.notEquals(supported_countries.indexOf('USA'), -1);
t.notEquals(supported_countries.indexOf('GBR'), -1);
t.notEquals(supported_countries.indexOf('SGP'), -1);
t.notEquals(supported_countries.indexOf('SWE'), -1);
t.notEquals(supported_countries.indexOf('default'), -1);
t.equals(supported_countries.length, 5);
t.equals(Object.keys(schemas.USA).length, 3);
t.equals(Object.keys(schemas.GBR).length, 2);
t.equals(Object.keys(schemas.SGP).length, 2);
t.equals(Object.keys(schemas.SWE).length, 2);
t.equals(Object.keys(schemas.default).length, 2);
t.end();
});
};
module.exports.tests.usa = function(test, common) {
test('USA.local should use localadmin value over locality, neighbourhood, and county', function(t) {
var record = {
localadmin: 'localadmin value',
locality: 'locality value',
neighbourhood: 'neighbourhood value',
county: 'county value'
};
var labelParts = ['initial value'];
var f = schemas.USA.local;
t.deepEqual(f(record, labelParts), ['initial value', 'localadmin value']);
t.end();
});
test('USA.local should use locality value over neighbourhood and county when no localadmin', function(t) {
var record = {
locality: 'locality value',
neighbourhood: 'neighbourhood value',
county: 'county value'
};
var labelParts = ['initial value'];
var f = schemas.USA.local;
t.deepEqual(f(record, labelParts), ['initial value', 'locality value']);
t.end();
});
test('USA.local should use neighbourhood value over county when no localadmin or locality', function(t) {
var record = {
neighbourhood: 'neighbourhood value',
county: 'county value'
};
var labelParts = ['initial value'];
var f = schemas.USA.local;
t.deepEqual(f(record, labelParts), ['initial value', 'neighbourhood value']);
t.end();
});
test('USA.local should use county value when no localadmin, locality, or neighbourhood', function(t) {
var record = {
county: 'county value'
};
var labelParts = ['initial value'];
var f = schemas.USA.local;
t.deepEqual(f(record, labelParts), ['initial value', 'county value']);
t.end();
});
test('USA.local should not modify labelParts if none of localadmin, locality, neighbourhood, or county is available', function(t) {
var record = {};
var labelParts = ['initial value'];
var f = schemas.USA.local;
t.deepEqual(f(record, labelParts), ['initial value']);
t.end();
});
test('USA.regional should use region when layer=region and region is available', function(t) {
var record = {
layer: 'region',
region: 'region name',
region_a: 'region_a name'
};
var labelParts = ['initial value'];
var f = schemas.USA.regional;
t.deepEqual(f(record, labelParts), ['initial value', 'region name']);
t.end();
});
test('USA.regional should use region_a when layer=region and region is unavailable', function(t) {
var record = {
layer: 'region',
region_a: 'region_a name'
};
var labelParts = ['initial value'];
var f = schemas.USA.regional;
t.deepEqual(f(record, labelParts), ['initial value', 'region_a name']);
t.end();
});
test('USA.regional should use region_a when layer!=region and both region and region_a are available', function(t) {
var record = {
layer: 'not region',
region: 'region name',
region_a: 'region_a name'
};
var labelParts = ['initial value'];
var f = schemas.USA.regional;
t.deepEqual(f(record, labelParts), ['initial value', 'region_a name']);
t.end();
});
test('USA.regional should use region when layer!=region and region_a is unavailable', function(t) {
var record = {
layer: 'region',
region: 'region name',
region_a: 'region_a name'
};
var labelParts = ['initial value'];
var f = schemas.USA.regional;
t.deepEqual(f(record, labelParts), ['initial value', 'region name'], 'region should have been appended');
t.end();
});
test('USA.regional should not append anything when neither region nor region_a are available', function(t) {
var record = {
layer: 'region',
};
var labelParts = ['initial value'];
var f = schemas.USA.regional;
t.deepEqual(f(record, labelParts), ['initial value'], 'no USA.region should have appended');
t.end();
});
test('USA.country should append country_a when available', function(t) {
var record = {
country_a: 'country_a name',
country: 'country name'
};
var labelParts = ['initial value'];
var f = schemas.USA.country;
t.deepEqual(f(record, labelParts), ['initial value', 'country_a name'], 'country_a should have appended');
t.end();
});
test('USA.country should not append anything when country_a is unavailable', function(t) {
var record = {
country: 'country name'
};
var labelParts = ['initial value'];
var f = schemas.USA.country;
t.deepEqual(f(record, labelParts), ['initial value'], 'no USA.country should have appended');
t.end();
});
};
module.exports.tests.gbr = function(test, common) {
test('GBR.local should use neighbourhood value over county, localadmin, locality, region', function(t) {
var record = {
neighbourhood: 'neighbourhood value',
county: 'county value',
localadmin: 'localadmin value',
locality: 'locality value',
region: 'region value'
};
var labelParts = ['initial value'];
var f = schemas.GBR.local;
t.deepEqual(f(record, labelParts), ['initial value', 'neighbourhood value']);
t.end();
});
test('GBR.local should use county value over county, localadmin, locality, region', function(t) {
var record = {
county: 'county value',
localadmin: 'localadmin value',
locality: 'locality value',
region: 'region value'
};
var labelParts = ['initial value'];
var f = schemas.GBR.local;
t.deepEqual(f(record, labelParts), ['initial value', 'county value']);
t.end();
});
test('GBR.local should use localadmin value over locality, region', function(t) {
var record = {
localadmin: 'localadmin value',
locality: 'locality value',
region: 'region value'
};
var labelParts = ['initial value'];
var f = schemas.GBR.local;
t.deepEqual(f(record, labelParts), ['initial value', 'localadmin value']);
t.end();
});
test('GBR.local should use locality value over region', function(t) {
var record = {
locality: 'locality value',
region: 'region value'
};
var labelParts = ['initial value'];
var f = schemas.GBR.local;
t.deepEqual(f(record, labelParts), ['initial value', 'locality value']);
t.end();
});
test('GBR.local should use region value when nothing else is available', function(t) {
var record = {
region: 'region value'
};
var labelParts = ['initial value'];
var f = schemas.GBR.local;
t.deepEqual(f(record, labelParts), ['initial value', 'region value']);
t.end();
});
test('GBR.local should not append anything when none of neighbourhood, county, localadmin, locality, region are available', function(t) {
var record = {};
var labelParts = ['initial value'];
var f = schemas.GBR.local;
t.deepEqual(f(record, labelParts), ['initial value']);
t.end();
});
test('GBR.regional should use county over country and region', function(t) {
var record = {
county: 'county value',
country: 'country value',
region: 'region value'
};
var labelParts = ['initial value'];
var f = schemas.GBR.regional;
t.deepEqual(f(record, labelParts), ['initial value', 'county value']);
t.end();
});
test('GBR.regional should use country over region', function(t) {
var record = {
country: 'country value',
region: 'region value'
};
var labelParts = ['initial value'];
var f = schemas.GBR.regional;
t.deepEqual(f(record, labelParts), ['initial value', 'country value']);
t.end();
});
test('GBR.regional should use region when county and country aren not available', function(t) {
var record = {
region: 'region value'
};
var labelParts = ['initial value'];
var f = schemas.GBR.regional;
t.deepEqual(f(record, labelParts), ['initial value', 'region value']);
t.end();
});
test('GBR.regional should not append anything when none of county, country, or region are available', function(t) {
var record = {};
var labelParts = ['initial value'];
var f = schemas.GBR.regional;
t.deepEqual(f(record, labelParts), ['initial value']);
t.end();
});
};
module.exports.tests.sgp = function(test, common) {
test('SGP.local should use neighbourhood value over region, county, localadmin, locality', function(t) {
var record = {
neighbourhood: 'neighbourhood value',
county: 'county value',
localadmin: 'localadmin value',
locality: 'locality value',
region: 'region value'
};
var labelParts = ['initial value'];
var f = schemas.SGP.local;
t.deepEqual(f(record, labelParts), ['initial value', 'neighbourhood value']);
t.end();
});
test('SGP.local should use region value over county, localadmin, locality', function(t) {
var record = {
county: 'county value',
localadmin: 'localadmin value',
locality: 'locality value',
region: 'region value'
};
var labelParts = ['initial value'];
var f = schemas.SGP.local;
t.deepEqual(f(record, labelParts), ['initial value', 'region value']);
t.end();
});
test('SGP.local should use county value over localadmin, locality', function(t) {
var record = {
localadmin: 'localadmin value',
locality: 'locality value',
county: 'county value'
};
var labelParts = ['initial value'];
var f = schemas.SGP.local;
t.deepEqual(f(record, labelParts), ['initial value', 'county value']);
t.end();
});
test('SGP.local should use localadmin value over locality', function(t) {
var record = {
localadmin: 'localadmin value',
locality: 'locality value'
};
var labelParts = ['initial value'];
var f = schemas.SGP.local;
t.deepEqual(f(record, labelParts), ['initial value', 'localadmin value']);
t.end();
});
test('SGP.local should use locality value when nothing else is available', function(t) {
var record = {
locality: 'locality value'
};
var labelParts = ['initial value'];
var f = schemas.SGP.local;
t.deepEqual(f(record, labelParts), ['initial value', 'locality value']);
t.end();
});
test('SGP.local should not append anything when none of neighbourhood, region, county, localadmin, locality are available', function(t) {
var record = {};
var labelParts = ['initial value'];
var f = schemas.SGP.local;
t.deepEqual(f(record, labelParts), ['initial value']);
t.end();
});
test('SGP.regional should use county over country and region', function(t) {
var record = {
county: 'county value',
country: 'country value',
region: 'region value'
};
var labelParts = ['initial value'];
var f = schemas.SGP.regional;
t.deepEqual(f(record, labelParts), ['initial value', 'county value']);
t.end();
});
test('SGP.regional should use country over region', function(t) {
var record = {
country: 'country value',
region: 'region value'
};
var labelParts = ['initial value'];
var f = schemas.SGP.regional;
t.deepEqual(f(record, labelParts), ['initial value', 'country value']);
t.end();
});
test('SGP.regional should use region when county and country aren not available', function(t) {
var record = {
region: 'region value'
};
var labelParts = ['initial value'];
var f = schemas.SGP.regional;
t.deepEqual(f(record, labelParts), ['initial value', 'region value']);
t.end();
});
test('SGP.regional should not append anything when none of county, country, or region are available', function(t) {
var record = {};
var labelParts = ['initial value'];
var f = schemas.SGP.regional;
t.deepEqual(f(record, labelParts), ['initial value']);
t.end();
});
};
module.exports.tests.swe = function(test, common) {
test('SWE.local should use neighbourhood value over region, county, localadmin, locality', function(t) {
var record = {
neighbourhood: 'neighbourhood value',
county: 'county value',
localadmin: 'localadmin value',
locality: 'locality value',
region: 'region value'
};
var labelParts = ['initial value'];
var f = schemas.SWE.local;
t.deepEqual(f(record, labelParts), ['initial value', 'neighbourhood value']);
t.end();
});
test('SWE.local should use region value over county, localadmin, locality', function(t) {
var record = {
county: 'county value',
localadmin: 'localadmin value',
locality: 'locality value',
region: 'region value'
};
var labelParts = ['initial value'];
var f = schemas.SWE.local;
t.deepEqual(f(record, labelParts), ['initial value', 'region value']);
t.end();
});
test('SWE.local should use county value over localadmin, locality', function(t) {
var record = {
localadmin: 'localadmin value',
locality: 'locality value',
county: 'county value'
};
var labelParts = ['initial value'];
var f = schemas.SWE.local;
t.deepEqual(f(record, labelParts), ['initial value', 'county value']);
t.end();
});
test('SWE.local should use localadmin value over locality', function(t) {
var record = {
localadmin: 'localadmin value',
locality: 'locality value'
};
var labelParts = ['initial value'];
var f = schemas.SWE.local;
t.deepEqual(f(record, labelParts), ['initial value', 'localadmin value']);
t.end();
});
test('SWE.local should use locality value when nothing else is available', function(t) {
var record = {
locality: 'locality value'
};
var labelParts = ['initial value'];
var f = schemas.SWE.local;
t.deepEqual(f(record, labelParts), ['initial value', 'locality value']);
t.end();
});
test('SWE.local should not append anything when none of neighbourhood, region, county, localadmin, locality are available', function(t) {
var record = {};
var labelParts = ['initial value'];
var f = schemas.SWE.local;
t.deepEqual(f(record, labelParts), ['initial value']);
t.end();
});
test('SGP.regional should use country when available', function(t) {
var record = {
country: 'country value',
country_a: 'country_a value',
};
var labelParts = ['initial value'];
var f = schemas.SGP.regional;
t.deepEqual(f(record, labelParts), ['initial value', 'country value']);
t.end();
});
test('SGP.regional should not append anything when country is not available', function(t) {
var record = {
country_a: 'country_a value'
};
var labelParts = ['initial value'];
var f = schemas.SGP.regional;
t.deepEqual(f(record, labelParts), ['initial value']);
t.end();
});
};
module.exports.all = function (tape, common) {

Loading…
Cancel
Save