From 1c6436d12377a8b6708b201df091d35d711f9f3c Mon Sep 17 00:00:00 2001 From: Diana Shkolnikov Date: Tue, 24 May 2016 16:32:54 -0400 Subject: [PATCH] Update categories sanitizer and implement unit tests for it --- sanitiser/_categories.js | 42 +++++--- test/unit/run.js | 1 + test/unit/sanitiser/_categories.js | 151 +++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+), 13 deletions(-) create mode 100644 test/unit/sanitiser/_categories.js diff --git a/sanitiser/_categories.js b/sanitiser/_categories.js index 29737922..63d6324e 100644 --- a/sanitiser/_categories.js +++ b/sanitiser/_categories.js @@ -1,34 +1,50 @@ var check = require('check-types'); +var ERRORS = { + empty: 'Categories parameter cannot be left blank. See documentation of service for valid options.', + invalid: 'Invalid categories parameter value(s). See documentation of service for valid options.' +}; + // validate inputs, convert types and apply defaults -function sanitize( raw, clean ){ +function sanitize( raw, clean, validCategories ) { // error & warning messages - var messages = { errors: [], warnings: [] }; + var messages = {errors: [], warnings: []}; - // default case (no categories specified in GET params) - clean.categories = []; + // it's not a required parameter, so if it's not provided just move on + if (!raw.hasOwnProperty('categories')) { + return messages; + } - // if categories string has been set - if( check.nonEmptyString( raw.categories ) ){ + if (!check.nonEmptyString(raw.categories)) { + messages.errors.push(ERRORS.empty); + return messages; + } - // map input categories to valid format + // if categories string has been set + // map input categories to valid format + try { clean.categories = raw.categories.split(',') .map(function (cat) { return cat.toLowerCase().trim(); // lowercase inputs }) - .filter( function( cat ) { - return ( cat.length > 0 ); + .filter(function (cat) { + if (check.nonEmptyString(cat) && validCategories && validCategories.indexOf(cat) !== -1) { + return true; + } + throw new Error('Empty string value'); }); + } catch (err) { + // remove everything from the list if there was any error + delete clean.categories; + } - if( !clean.categories.length ){ - messages.warnings.push( 'invalid \'categories\': no valid category strings found'); - } + if (check.undefined(clean.categories) || check.emptyArray(clean.categories)) { + messages.errors.push(ERRORS.invalid); } return messages; - } // export function diff --git a/test/unit/run.js b/test/unit/run.js index 2a89b161..b6e40c71 100644 --- a/test/unit/run.js +++ b/test/unit/run.js @@ -51,6 +51,7 @@ var tests = [ require('./sanitiser/_text'), require('./sanitiser/_tokenizer'), require('./sanitiser/_deprecate_quattroshapes'), + require('./sanitiser/_categories'), require('./src/backend'), require('./sanitiser/autocomplete'), require('./sanitiser/place'), diff --git a/test/unit/sanitiser/_categories.js b/test/unit/sanitiser/_categories.js new file mode 100644 index 00000000..b896915d --- /dev/null +++ b/test/unit/sanitiser/_categories.js @@ -0,0 +1,151 @@ +var sanitize = require( '../../../sanitiser/_categories'); + +module.exports.tests = {}; + +module.exports.tests.no_categories = function(test, common) { + test('categories not set', function(t) { + var req = { + query: { }, + clean: { } + }; + + var messages = sanitize(req.query, req.clean); + + t.equal(req.clean.categories, undefined, 'no categories should be defined'); + t.deepEqual(messages.errors, [], 'no error returned'); + t.deepEqual(messages.warnings, [], 'no warnings returned'); + t.end(); + }); + + test('categories is empty string', function(t) { + var req = { + query: { + categories: '' + }, + clean: { } + }; + + var expected_error = 'Categories parameter cannot be left blank. See documentation of service for valid options.'; + + var messages = sanitize(req.query, req.clean); + + t.equal(req.clean.categories, undefined, 'no categories should be defined'); + t.deepEqual(messages.errors.length, 1, 'error returned'); + t.deepEqual(messages.errors[0], expected_error, 'error returned'); + t.deepEqual(messages.warnings, [], 'no warnings returned'); + t.end(); + }); + + test('categories is an array of empty strings', function(t) { + var req = { + query: { + categories: ',,' + }, + clean: { } + }; + + var expected_error = 'Invalid categories parameter value(s). See documentation of service for valid options.'; + + var messages = sanitize(req.query, req.clean); + + t.equal(req.clean.categories, undefined, 'no categories should be defined'); + t.deepEqual(messages.errors.length, 1, 'error returned'); + t.deepEqual(messages.errors[0], expected_error, 'error returned'); + t.deepEqual(messages.warnings, [], 'no warnings returned'); + t.end(); + }); +}; + +module.exports.tests.valid_categories = function(test, common) { + var validCategories = ['food','health','financial','education','government']; + + test('single category', function(t) { + var req = { + query: { + categories: 'food' + }, + clean: { } + }; + + var messages = sanitize(req.query, req.clean, validCategories); + + t.deepEqual(req.clean.categories, ['food'], 'categories should contain food'); + t.deepEqual(messages.errors, [], 'no error returned'); + t.deepEqual(messages.warnings, [], 'no warnings returned'); + + t.end(); + }); + + test('multiple categories', function(t) { + var req = { + query: { + categories: 'food,health' + }, + clean: { } + }; + + var messages = sanitize(req.query, req.clean, validCategories); + + t.deepEqual(req.clean.categories, ['food', 'health'], + 'clean.categories should be an array with proper values'); + t.deepEqual(messages.errors, [], 'no error returned'); + t.deepEqual(messages.warnings, [], 'no warnings returned'); + t.end(); + }); +}; + +module.exports.tests.invalid_categories = function(test, common) { + var validCategories = ['food','health','financial','education','government']; + + test('garbage category', function(t) { + var req = { + query: { + categories: 'barf' + }, + clean: { } + }; + var expected_messages = { + errors: [ + 'Invalid categories parameter value(s). See documentation of service for valid options.' + ], + warnings: [] + }; + + var messages = sanitize(req.query, req.clean, validCategories); + + t.deepEqual(messages, expected_messages, 'error with message returned'); + t.equal(req.clean.categories, undefined, 'clean.categories should remain empty'); + t.end(); + }); + + test('all garbage categories', function(t) { + var req = { + query: { + categories: 'barf,bleh' + }, + clean: { } + }; + var expected_messages = { + errors: [ + 'Invalid categories parameter value(s). See documentation of service for valid options.' + ], + warnings: [] + }; + + var messages = sanitize(req.query, req.clean); + + t.deepEqual(messages, expected_messages, 'error with message returned'); + t.equal(req.clean.categories, undefined, 'clean.categories should remain empty'); + t.end(); + }); +}; + +module.exports.all = function (tape, common) { + function test(name, testFunction) { + return tape('SANTIZE _categories ' + name, testFunction); + } + + for( var testCase in module.exports.tests ){ + module.exports.tests[testCase](test, common); + } +};