const proxyquire = require('proxyquire').noCallThru(); const libpostal = require('../../../controller/libpostal'); const _ = require('lodash'); const mock_logger = require('pelias-mock-logger'); module.exports.tests = {}; module.exports.tests.interface = (test, common) => { test('valid interface', (t) => { t.equal(typeof libpostal, 'function', 'libpostal is a function'); t.equal(typeof libpostal(), 'function', 'libpostal returns a controller'); t.end(); }); }; module.exports.tests.early_exit_conditions = (test, common) => { test('should_execute returning false should not call service', t => { const service = () => { t.fail('service should not have been called'); }; const should_execute = (req) => { // req and res should be passed to should_execute t.deepEquals(req, { clean: { text: 'original query' } }); return false; }; const controller = libpostal(service, should_execute); const req = { clean: { text: 'original query' } }; controller(req, undefined, () => { t.deepEquals(req, { clean: { text: 'original query' } }, 'req should not have been modified'); t.end(); }); }); }; module.exports.tests.error_conditions = (test, common) => { test('service returning error should append and not modify req.clean', t => { const service = (req, callback) => { callback('libpostal service error', []); }; const controller = libpostal(service, () => true); const req = { clean: { text: 'original query' }, errors: [] }; controller(req, undefined, () => { t.deepEquals(req, { clean: { text: 'original query' }, errors: ['libpostal service error'] }, 'req should not have been modified'); t.end(); }); }); }; module.exports.tests.failure_conditions = (test, common) => { test('service returning 2 or more of a label should return undefined and log message', t => { const logger = mock_logger(); const service = (req, callback) => { const response = [ { label: 'road', value: 'road value 1' }, { label: 'city', value: 'city value' }, { label: 'road', value: 'road value 2' } ]; callback(null, response); }; const controller = proxyquire('../../../controller/libpostal', { 'pelias-logger': logger })(service, () => true); const req = { clean: { text: 'query value' }, errors: [] }; controller(req, undefined, () => { t.ok(logger.isWarnMessage('discarding libpostal parse of \'query value\' due to duplicate field assignments')); t.deepEquals(req, { clean: { text: 'query value' }, errors: [] }, 'req should not have been modified'); t.end(); }); }); test('service returning empty array should not set parsed_text or parser', t => { const logger = mock_logger(); const service = (req, callback) => { callback(null, []); }; const controller = proxyquire('../../../controller/libpostal', { 'pelias-logger': logger })(service, () => true); const req = { clean: { text: 'query value' }, errors: [] }; controller(req, undefined, () => { t.deepEquals(req, { clean: { text: 'query value' }, errors: [] }, 'req should not have been modified'); t.end(); }); }); }; module.exports.tests.success_conditions = (test, common) => { test('service returning valid response should convert and append', t => { const service = (req, callback) => { const response = [ { label: 'island', value: 'island value' }, { label: 'category', value: 'category value' }, { label: 'house', value: 'house value' }, { label: 'house_number', value: 'house_number value' }, { label: 'road', value: 'road value' }, { label: 'suburb', value: 'suburb value' }, { label: 'city_district', value: 'city_district value' }, { label: 'city', value: 'city value' }, { label: 'state_district', value: 'state_district value' }, { label: 'state', value: 'state value' }, { label: 'postcode', value: 'postcode value' }, { label: 'country', value: 'country value' } ]; callback(null, response); }; const controller = libpostal(service, () => true); const req = { clean: { text: 'original query' }, errors: [] }; controller(req, undefined, () => { t.deepEquals(req, { clean: { text: 'original query', parser: 'libpostal', parsed_text: { island: 'island value', category: 'category value', query: 'house value', number: 'house_number value', street: 'road value', neighbourhood: 'suburb value', borough: 'city_district value', city: 'city value', county: 'state_district value', state: 'state value', postalcode: 'postcode value', country: 'country value' } }, errors: [] }, 'req should not have been modified'); t.end(); }); }); test('ISO-2 country should be converted to ISO-3', t => { const service = (req, callback) => { const response = [ { label: 'country', value: 'ca' } ]; callback(null, response); }; const controller = libpostal(service, () => true); const req = { clean: { text: 'original query' }, errors: [] }; controller(req, undefined, () => { t.deepEquals(req, { clean: { text: 'original query', parser: 'libpostal', parsed_text: { country: 'CAN' } }, errors: [] }, 'req should not have been modified'); t.end(); }); }); }; module.exports.tests.bug_fixes = (test, common) => { test('bug fix: incorrect parsing of diagonal directionals', t => { const service = (req, callback) => { const response =[ { 'label': 'house_number', 'value': '4004' }, { 'label': 'road', 'value': 'nw' }, { 'label': 'suburb', 'value': 'beaverton-hillsdale' }, { 'label': 'city', 'value': 'portland' } ]; callback(null, response); }; const controller = libpostal(service, () => true); const req = { clean: { text: 'original query' }, errors: [] }; controller(req, undefined, () => { t.deepEquals(req, { clean: { text: 'original query', parser: 'libpostal', parsed_text: { number: '4004', street: 'nw beaverton-hillsdale', city: 'portland' } }, errors: [] }, 'req should not have been modified'); t.end(); }); }); test('bug fix: incorrect parsing of diagonal directionals - no subsequent element', t => { const service = (req, callback) => { const response = [ { 'label': 'test', 'value': 'test' }, { 'label': 'road', 'value': 'nw' } ]; callback(null, response); }; const controller = libpostal(service, () => true); const req = { clean: { text: 'original query' }, errors: [] }; controller(req, undefined, () => { t.deepEquals(req, { clean: { text: 'original query', parser: 'libpostal', parsed_text: { street: 'nw' } }, errors: [] }, 'req should not have been modified'); t.end(); }); }); test('bug fix: recast label for "zoo" from borough/city_district to house', t => { const service = (req, callback) => { const response = [ { 'label': 'city_district', 'value': 'zoo' } ]; callback(null, response); }; const controller = libpostal(service, () => true); const req = { clean: { text: 'original query' }, errors: [] }; controller(req, undefined, () => { t.deepEquals(req, { clean: { text: 'original query', parser: 'libpostal', parsed_text: { query: 'zoo' } }, errors: [] }, 'req should not have been modified'); t.end(); }); }); test('bug fix: correctly parse australian-style unit numbers', t => { const service = (req, callback) => { const response = [ { 'label': 'house_number', 'value': '11/1015' }, { 'label': 'road', 'value': 'nudgee road' }, { 'label': 'suburb', 'value': 'banyo' }, { 'label': 'postcode', 'value': '4014' }, { 'label': 'state', 'value': 'qld' } ]; callback(null, response); }; const controller = libpostal(service, () => true); const req = { clean: { text: 'original query' }, errors: [] }; controller(req, undefined, () => { t.deepEquals(req, { clean: { text: 'original query', parser: 'libpostal', parsed_text: { unit: '11', number: '1015', street: 'nudgee road', neighbourhood: 'banyo', postalcode: '4014', state: 'qld' } }, errors: [] }, 'req should not have been modified'); t.end(); }); }); test('bug fix: correctly parse australian-style unit numbers - with plus', t => { const service = (req, callback) => { const response = [ { 'label': 'house_number', 'value': '2+3/32' }, { 'label': 'road', 'value': 'dixon street' }, { 'label': 'suburb', 'value': 'strathpine' }, { 'label': 'postcode', 'value': '4500' }, { 'label': 'state', 'value': 'qld' } ]; callback(null, response); }; const controller = libpostal(service, () => true); const req = { clean: { text: 'original query' }, errors: [] }; controller(req, undefined, () => { t.deepEquals(req, { clean: { text: 'original query', parser: 'libpostal', parsed_text: { unit: '2+3', number: '32', street: 'dixon street', neighbourhood: 'strathpine', postalcode: '4500', state: 'qld' } }, errors: [] }, 'req should not have been modified'); t.end(); }); }); test('bug fix: correctly parse australian-style unit numbers - with unit spelled out', t => { const service = (req, callback) => { const response = [ { 'label': 'house_number', 'value': 'unit 3 /30' }, { 'label': 'road', 'value': 'dan rees street' }, { 'label': 'suburb', 'value': 'wallsend' }, { 'label': 'postcode', 'value': '2287' }, { 'label': 'state', 'value': 'nsw' } ]; callback(null, response); }; const controller = libpostal(service, () => true); const req = { clean: { text: 'original query' }, errors: [] }; controller(req, undefined, () => { t.deepEquals(req, { clean: { text: 'original query', parser: 'libpostal', parsed_text: { unit: 'unit 3', number: '30', street: 'dan rees street', neighbourhood: 'wallsend', postalcode: '2287', state: 'nsw' } }, errors: [] }, 'req should not have been modified'); t.end(); }); }); test('bug fix: correctly parse australian-style unit numbers - no-op if "unit" already assigned', t => { const service = (req, callback) => { const response = [ { 'label': 'unit', 'value': '99' }, { 'label': 'house_number', 'value': '11/1015' }, { 'label': 'road', 'value': 'nudgee road' }, { 'label': 'suburb', 'value': 'banyo' }, { 'label': 'postcode', 'value': '4014' }, { 'label': 'state', 'value': 'qld' } ]; callback(null, response); }; const controller = libpostal(service, () => true); const req = { clean: { text: 'original query' }, errors: [] }; controller(req, undefined, () => { t.deepEquals(req, { clean: { text: 'original query', parser: 'libpostal', parsed_text: { unit: '99', number: '11/1015', street: 'nudgee road', neighbourhood: 'banyo', postalcode: '4014', state: 'qld' } }, errors: [] }, 'req should not have been modified'); t.end(); }); }); }; module.exports.all = (tape, common) => { function test(name, testFunction) { return tape(`GET /libpostal ${name}`, testFunction); } for( const testCase in module.exports.tests ){ module.exports.tests[testCase](test, common); } };