diff --git a/.eslintignore b/.eslintignore index fa53de375..4627fe57a 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,2 @@ validator.js -validator.min.js -test \ No newline at end of file +validator.min.js \ No newline at end of file diff --git a/package.json b/package.json index ffe1cbb57..78ad40ecf 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "uglify-js": "latest" }, "scripts": { - "lint": "eslint src", + "lint": "eslint src test", "clean:node": "rm -rf index.js lib", "clean:browser": "rm -rf validator*.js", "clean": "npm run clean:node && npm run clean:browser", diff --git a/test/.eslintrc b/test/.eslintrc index 690a31bf7..cbefe6878 100644 --- a/test/.eslintrc +++ b/test/.eslintrc @@ -6,6 +6,8 @@ "rules": { "no-var": 0, "vars-on-top": 0, - "prefer-arrow-callback": 0 + "prefer-arrow-callback": 0, + "object-shorthand": [0], + "quote-props": 0 } } \ No newline at end of file diff --git a/test/client-side.js b/test/client-side.js index b33d3892e..18a8f17c9 100644 --- a/test/client-side.js +++ b/test/client-side.js @@ -1,26 +1,27 @@ -var assert = require('assert') - , validator = require('../validator') - , min = require('../validator.min'); +var assert = require('assert'); +var validator = require('../validator'); +var min = require('../validator.min'); describe('Minified version', function () { + it('should export the same things as the server-side version', function () { + for (var key in validator) { + if ({}.hasOwnProperty.call(validator, key)) { + assert.equal(typeof validator[key], + typeof min[key], 'Minified version did not export ' + key); + } + } + }); - it('should export the same things as the server-side version', function () { - for (var key in validator) { - assert.equal(typeof validator[key], typeof min[key], 'Minified version did not export ' + key); - } - }); + it('should be up to date', function () { + assert.equal(min.version, validator.version, 'Minified version mismatch. Run `make min`'); + }); - it('should be up to date', function () { - assert.equal(min.version, validator.version, 'Minified version mismatch. Run `make min`'); - }); - - it('should validate strings', function () { - assert.equal(min.isEmail('foo@bar.com'), true); - assert.equal(min.isEmail('foo'), false); - }); - - it('should sanitize strings', function () { - assert.equal(min.toBoolean('1'), true); - }); + it('should validate strings', function () { + assert.equal(min.isEmail('foo@bar.com'), true); + assert.equal(min.isEmail('foo'), false); + }); + it('should sanitize strings', function () { + assert.equal(min.toBoolean('1'), true); + }); }); diff --git a/test/exports.js b/test/exports.js index ec04c1665..3cbe1e178 100644 --- a/test/exports.js +++ b/test/exports.js @@ -1,21 +1,19 @@ -var assert = require('assert') - , validator = require('../index'); +var assert = require('assert'); +var validator = require('../index'); describe('Exports', function () { + it('should export validators', function () { + assert.equal(typeof validator.isEmail, 'function'); + assert.equal(typeof validator.isAlpha, 'function'); + }); - it('should export validators', function () { - assert.equal(typeof validator.isEmail, 'function'); - assert.equal(typeof validator.isAlpha, 'function'); - }); - - it('should export sanitizers', function () { - assert.equal(typeof validator.toBoolean, 'function'); - assert.equal(typeof validator.toFloat, 'function'); - }); - - it('should export the version number', function () { - assert.equal(validator.version, require('../package.json').version, - 'Version number mismatch in "package.json" vs. "validator.js"'); - }); + it('should export sanitizers', function () { + assert.equal(typeof validator.toBoolean, 'function'); + assert.equal(typeof validator.toFloat, 'function'); + }); + it('should export the version number', function () { + assert.equal(validator.version, require('../package.json').version, + 'Version number mismatch in "package.json" vs. "validator.js"'); + }); }); diff --git a/test/sanitizers.js b/test/sanitizers.js index fee2fd793..60bacb561 100644 --- a/test/sanitizers.js +++ b/test/sanitizers.js @@ -1,239 +1,252 @@ -var validator = require('../index') - , format = require('util').format; +var validator = require('../index'); +var format = require('util').format; function test(options) { - var args = options.args || []; - args.unshift(null); - Object.keys(options.expect).forEach(function (input) { - args[0] = input; - var result = validator[options.sanitizer].apply(validator, args) - , expected = options.expect[input]; - if (isNaN(result) && !result.length && isNaN(expected)) { - return; - } - if (result !== expected) { - var warning = format('validator.%s(%s) returned "%s" but should have returned "%s"', - options.sanitizer, args.join(', '), result, expected); - throw new Error(warning); - } - }); + var args = options.args || []; + + args.unshift(null); + + Object.keys(options.expect).forEach(function (input) { + args[0] = input; + var result = validator[options.sanitizer].apply(validator, args); + var expected = options.expect[input]; + if (isNaN(result) && !result.length && isNaN(expected)) { + return; + } + + if (result !== expected) { + var warning = format('validator.%s(%s) returned "%s" but should have returned "%s"', + options.sanitizer, args.join(', '), result, expected); + + throw new Error(warning); + } + }); } describe('Sanitizers', function () { + it('should sanitize boolean strings', function () { + test({ + sanitizer: 'toBoolean', + expect: { + '0': false, + '': false, + '1': true, + 'true': true, + 'foobar': true, + ' ': true, + }, + }); + test({ + sanitizer: 'toBoolean', + args: [true], // strict + expect: { + '0': false, + '': false, + '1': true, + 'true': true, + 'foobar': false, + ' ': false, + }, + }); + }); + + it('should trim whitespace', function () { + test({ + sanitizer: 'trim', + expect: { ' \r\n\tfoo \r\n\t ': 'foo' }, + }); + + test({ + sanitizer: 'ltrim', + expect: { ' \r\n\tfoo \r\n\t ': 'foo \r\n\t ' }, + }); + + test({ + sanitizer: 'rtrim', + expect: { ' \r\n\tfoo \r\n\t ': ' \r\n\tfoo' }, + }); + }); + + it('should trim custom characters', function () { + test({ + sanitizer: 'trim', + args: ['01'], + expect: { '010100201000': '2' }, + }); + + test({ + sanitizer: 'ltrim', + args: ['01'], + expect: { '010100201000': '201000' }, + }); + + test({ + sanitizer: 'rtrim', + args: ['01'], + expect: { '010100201000': '0101002' }, + }); + }); + + it('should convert strings to integers', function () { + test({ + sanitizer: 'toInt', + expect: { + '3': 3, + ' 3 ': 3, + '2.4': 2, + 'foo': NaN, + }, + }); - it('should sanitize boolean strings', function () { - test({ - sanitizer: 'toBoolean' - , expect: { - '0': false - , '': false - , '1': true - , 'true': true - , 'foobar': true - , ' ': true - } - }); - test({ - sanitizer: 'toBoolean' - , args: [ true ] //strict - , expect: { - '0': false - , '': false - , '1': true - , 'true': true - , 'foobar': false - , ' ': false - } - }); - }); - - it('should trim whitespace', function () { - test({ - sanitizer: 'trim' - , expect: { ' \r\n\tfoo \r\n\t ': 'foo' } - }); - test({ - sanitizer: 'ltrim' - , expect: { ' \r\n\tfoo \r\n\t ': 'foo \r\n\t ' } - }); - test({ - sanitizer: 'rtrim' - , expect: { ' \r\n\tfoo \r\n\t ': ' \r\n\tfoo' } - }); - }); - - it('should trim custom characters', function () { - test({ - sanitizer: 'trim' - , args: [ '01' ] - , expect: { '010100201000': '2' } - }); - test({ - sanitizer: 'ltrim' - , args: [ '01' ] - , expect: { '010100201000': '201000' } - }); - test({ - sanitizer: 'rtrim' - , args: [ '01' ] - , expect: { '010100201000': '0101002' } - }); - }); - - it('should convert strings to integers', function () { - test({ - sanitizer: 'toInt' - , expect: { - '3': 3 - , ' 3 ': 3 - , '2.4': 2 - , 'foo': NaN - } - }); - test({ - sanitizer: 'toInt' - , args: [ 16 ] - , expect: { 'ff': 255 } - }); - }); - - it('should convert strings to floats', function () { - test({ - sanitizer: 'toFloat' - , expect: { - '2': 2.0 - , '2.': 2.0 - , '-2.5': -2.5 - , '.5': 0.5 - , 'foo': NaN - } - }); - }); - - it('should escape HTML', function () { - test({ - sanitizer: 'escape' - , expect: { - '': '<script> alert("xss&fun"); </script>' - , "": '<script> alert('xss&fun'); </script>' - , 'Backtick: `': 'Backtick: `' - } - }); - }); - - it('should remove control characters (<32 and 127)', function () { - // Check basic functionality - test({ - sanitizer: 'stripLow' - , expect: { - "foo\x00": "foo" - , "\x7Ffoo\x02": "foo" - , "\x01\x09": "" - , "foo\x0A\x0D": "foo" - } - }); - // Unicode safety - test({ - sanitizer: 'stripLow' - , expect: { - "perch\u00e9": "perch\u00e9" - , "\u20ac": "\u20ac" - , "\u2206\x0A": "\u2206" - , "\ud83d\ude04": "\ud83d\ude04" - } - }); - // Preserve newlines - test({ - sanitizer: 'stripLow' - , args: [ true ] //keep_new_lines - , expect: { - "foo\x0A\x0D": "foo\x0A\x0D" - , "\x03foo\x0A\x0D": "foo\x0A\x0D" - } - }); - }); - - - it('should sanitize a string based on a whitelist', function () { - test({ - sanitizer: 'whitelist' - , args: [ 'abc' ] - , expect: { - 'abcdef': 'abc' - , 'aaaaaaaaaabbbbbbbbbb': 'aaaaaaaaaabbbbbbbbbb' - , 'a1b2c3': 'abc' - , ' ': '' - } - }); - }); - - it('should sanitize a string based on a blacklist', function () { - test({ - sanitizer: 'blacklist' - , args: [ 'abc' ] - , expect: { - 'abcdef': 'def' - , 'aaaaaaaaaabbbbbbbbbb': '' - , 'a1b2c3': '123' - , ' ': ' ' - } - }); - }); - - it('should normalize an email based on domain', function () { - test({ - sanitizer: 'normalizeEmail' - , expect: { - 'test@me.com': 'test@me.com' - , 'some.name@gmail.com': 'somename@gmail.com' - , 'some.name@googleMail.com': 'somename@gmail.com' - , 'some.name+extension@gmail.com': 'somename@gmail.com' - , 'some.Name+extension@GoogleMail.com': 'somename@gmail.com' - , 'some.name.middleName+extension@gmail.com': 'somenamemiddlename@gmail.com' - , 'some.name.middleName+extension@GoogleMail.com': 'somenamemiddlename@gmail.com' - , 'some.name.midd.leNa.me.+extension@gmail.com': 'somenamemiddlename@gmail.com' - , 'some.name.midd.leNa.me.+extension@GoogleMail.com': 'somenamemiddlename@gmail.com' - , 'some.name+extension@unknown.com': 'some.name+extension@unknown.com' - , 'hans@m端ller.com': 'hans@m端ller.com' - , 'an invalid email address': false - , '': false - , '+extension@gmail.com': false - , '...@gmail.com': false - , '.+extension@googlemail.com': false - , 'some.name.midd..leNa...me...+extension@GoogleMail.com': 'somenamemiddlename@gmail.com' - } - }); - test({ - sanitizer: 'normalizeEmail' - , args: [{lowercase: false}] - , expect: { - 'test@me.com': 'test@me.com' - , 'hans@m端ller.com': 'hans@m端ller.com' - , 'test@ME.COM': 'test@me.com' // Hostname is always lowercased - , 'TEST@me.com': 'TEST@me.com' - , 'TEST@ME.COM': 'TEST@me.com' - , 'blAH@x.com': 'blAH@x.com' - - // Domains that are known for being case-insensitive are always lowercased - , 'SOME.name@GMAIL.com': 'somename@gmail.com' - , 'SOME.name.middleName+extension@GoogleMail.com': 'somenamemiddlename@gmail.com' - , 'SOME.name.midd.leNa.me.+extension@gmail.com': 'somenamemiddlename@gmail.com' - } - }); - test({ - sanitizer: 'normalizeEmail' - , args: [{remove_dots: false}] - , expect: { - 'SOME.name@GMAIL.com': 'some.name@gmail.com' - } - }); - test({ - sanitizer: 'normalizeEmail' - , args: [{remove_extension: false}] - , expect: { - 'foo+bar@gmail.com': 'foo+bar@gmail.com' - } - }); + test({ + sanitizer: 'toInt', + args: [16], + expect: { 'ff': 255 }, }); + }); + it('should convert strings to floats', function () { + test({ + sanitizer: 'toFloat', + expect: { + '2': 2.0, + '2.': 2.0, + '-2.5': -2.5, + '.5': 0.5, + 'foo': NaN, + }, + }); + }); + + it('should escape HTML', function () { + test({ + sanitizer: 'escape', + expect: { + '': + '<script> alert("xss&fun"); </script>', + + "": + '<script> alert('xss&fun'); </script>', + + 'Backtick: `': + 'Backtick: `', + }, + }); + }); + + it('should remove control characters (<32 and 127)', function () { + // Check basic functionality + test({ + sanitizer: 'stripLow', + expect: { + 'foo\x00': 'foo', + '\x7Ffoo\x02': 'foo', + '\x01\x09': '', + 'foo\x0A\x0D': 'foo', + }, + }); + // Unicode safety + test({ + sanitizer: 'stripLow', + expect: { + 'perch\u00e9': 'perch\u00e9', + '\u20ac': '\u20ac', + '\u2206\x0A': '\u2206', + '\ud83d\ude04': '\ud83d\ude04', + }, + }); + // Preserve newlines + test({ + sanitizer: 'stripLow', + args: [true], // keep_new_lines + expect: { + 'foo\x0A\x0D': 'foo\x0A\x0D', + '\x03foo\x0A\x0D': 'foo\x0A\x0D', + }, + }); + }); + + it('should sanitize a string based on a whitelist', function () { + test({ + sanitizer: 'whitelist', + args: ['abc'], + expect: { + 'abcdef': 'abc', + 'aaaaaaaaaabbbbbbbbbb': 'aaaaaaaaaabbbbbbbbbb', + 'a1b2c3': 'abc', + ' ': '', + }, + }); + }); + + it('should sanitize a string based on a blacklist', function () { + test({ + sanitizer: 'blacklist', + args: ['abc'], + expect: { + 'abcdef': 'def', + 'aaaaaaaaaabbbbbbbbbb': '', + 'a1b2c3': '123', + ' ': ' ', + }, + }); + }); + + it('should normalize an email based on domain', function () { + test({ + sanitizer: 'normalizeEmail', + expect: { + 'test@me.com': 'test@me.com', + 'some.name@gmail.com': 'somename@gmail.com', + 'some.name@googleMail.com': 'somename@gmail.com', + 'some.name+extension@gmail.com': 'somename@gmail.com', + 'some.Name+extension@GoogleMail.com': 'somename@gmail.com', + 'some.name.middleName+extension@gmail.com': 'somenamemiddlename@gmail.com', + 'some.name.middleName+extension@GoogleMail.com': 'somenamemiddlename@gmail.com', + 'some.name.midd.leNa.me.+extension@gmail.com': 'somenamemiddlename@gmail.com', + 'some.name.midd.leNa.me.+extension@GoogleMail.com': 'somenamemiddlename@gmail.com', + 'some.name+extension@unknown.com': 'some.name+extension@unknown.com', + 'hans@m端ller.com': 'hans@m端ller.com', + 'an invalid email address': false, + '': false, + '+extension@gmail.com': false, + '...@gmail.com': false, + '.+extension@googlemail.com': false, + 'some.name.midd..leNa...me...+extension@GoogleMail.com': 'somenamemiddlename@gmail.com', + }, + }); + + test({ + sanitizer: 'normalizeEmail', + args: [{ lowercase: false }], + expect: { + 'test@me.com': 'test@me.com', + 'hans@m端ller.com': 'hans@m端ller.com', + 'test@ME.COM': 'test@me.com', // Hostname is always lowercased, + 'TEST@me.com': 'TEST@me.com', + 'TEST@ME.COM': 'TEST@me.com', + 'blAH@x.com': 'blAH@x.com', + // Domains that are known for being case-insensitive are always lowercased, + 'SOME.name@GMAIL.com': 'somename@gmail.com', + 'SOME.name.middleName+extension@GoogleMail.com': 'somenamemiddlename@gmail.com', + 'SOME.name.midd.leNa.me.+extension@gmail.com': 'somenamemiddlename@gmail.com', + }, + }); + + test({ + sanitizer: 'normalizeEmail', + args: [{ remove_dots: false }], + expect: { + 'SOME.name@GMAIL.com': 'some.name@gmail.com', + }, + }); + + test({ + sanitizer: 'normalizeEmail', + args: [{ remove_extension: false }], + expect: { + 'foo+bar@gmail.com': 'foo+bar@gmail.com', + }, + }); + }); }); diff --git a/test/validators.js b/test/validators.js index 81b6c8fd7..d6a215db0 100644 --- a/test/validators.js +++ b/test/validators.js @@ -1,2705 +1,2800 @@ -var validator = require('../index') - , format = require('util').format - , assert = require('assert') - , path = require('path') - , fs = require('fs') - , vm = require('vm'); +var validator = require('../index'), + format = require('util').format, + assert = require('assert'), + path = require('path'), + fs = require('fs'), + vm = require('vm'); var validator_js = fs.readFileSync(path.join(__dirname, '../validator.js')).toString(); function test(options) { - var args = options.args || []; - args.unshift(null); - if (options.valid) { - options.valid.forEach(function (valid) { - args[0] = valid; - if (validator[options.validator].apply(validator, args) !== true) { - var warning = format('validator.%s(%s) failed but should have passed', + var args = options.args || []; + args.unshift(null); + if (options.valid) { + options.valid.forEach(function (valid) { + args[0] = valid; + if (validator[options.validator].apply(validator, args) !== true) { + var warning = format('validator.%s(%s) failed but should have passed', options.validator, args.join(', ')); - throw new Error(warning); - } - }); - } - if (options.invalid) { - options.invalid.forEach(function (invalid) { - args[0] = invalid; - if (validator[options.validator].apply(validator, args) !== false) { - var warning = format('validator.%s(%s) passed but should have failed', + throw new Error(warning); + } + }); + } + if (options.invalid) { + options.invalid.forEach(function (invalid) { + args[0] = invalid; + if (validator[options.validator].apply(validator, args) !== false) { + var warning = format('validator.%s(%s) passed but should have failed', options.validator, args.join(', ')); - throw new Error(warning); - } - }); - } + throw new Error(warning); + } + }); + } } function repeat(str, count) { - var result = ''; - while (count--) { - result += str; - } - return result; + var result = ''; + while (count--) { + result += str; + } + return result; } describe('Validators', function () { + it('should validate email addresses', function () { + test({ + validator: 'isEmail', + valid: [ + 'foo@bar.com', + 'x@x.au', + 'foo@bar.com.au', + 'foo+bar@bar.com', + 'hans.m端ller@test.com', + 'hans@m端ller.com', + 'test|123@m端ller.com', + 'test+ext@gmail.com', + 'some.name.midd.leNa.me.+extension@GoogleMail.com', + 'gmail...ignores...dots...@gmail.com', + '"foobar"@example.com', + '" foo m端ller "@example.com', + '"foo\\@bar"@example.com', + repeat('a', 64) + '@' + repeat('a', 252) + '.com', + ], + invalid: [ + 'invalidemail@', + 'invalid.com', + '@invalid.com', + 'foo@bar.com.', + 'somename@gmail.com', + 'foo@bar.co.uk.', + 'z@co.c', + 'gmailgmailgmailgmailgmail@gmail.com', + repeat('a', 64) + '@' + repeat('a', 253) + '.com', + repeat('a', 65) + '@' + repeat('a', 252) + '.com', + ], + }); + }); - it('should validate email addresses', function () { - test({ - validator: 'isEmail' - , valid: [ - 'foo@bar.com' - , 'x@x.au' - , 'foo@bar.com.au' - , 'foo+bar@bar.com' - , 'hans.m端ller@test.com' - , 'hans@m端ller.com' - , 'test|123@m端ller.com' - , 'test+ext@gmail.com' - , 'some.name.midd.leNa.me.+extension@GoogleMail.com' - , 'gmail...ignores...dots...@gmail.com' - , '"foobar"@example.com' - , '" foo m端ller "@example.com' - , '"foo\\@bar"@example.com' - , repeat('a', 64) + '@' + repeat('a', 252) + '.com' - ] - , invalid: [ - 'invalidemail@' - , 'invalid.com' - , '@invalid.com' - , 'foo@bar.com.' - , 'somename@gmail.com' - , 'foo@bar.co.uk.' - , 'z@co.c' - , 'gmailgmailgmailgmailgmail@gmail.com' - , repeat('a', 64) + '@' + repeat('a', 253) + '.com' - , repeat('a', 65) + '@' + repeat('a', 252) + '.com' - ] - }); - }); - - it('should validate email addresses without UTF8 characters in local part', function () { - test({ - validator: 'isEmail' - , args: [{ allow_utf8_local_part: false }] - , valid: [ - 'foo@bar.com' - , 'x@x.au' - , 'foo@bar.com.au' - , 'foo+bar@bar.com' - , 'hans@m端ller.com' - , 'test|123@m端ller.com' - , 'test+ext@gmail.com' - , 'some.name.midd.leNa.me.+extension@GoogleMail.com' - , '"foobar"@example.com' - , '"foo\\@bar"@example.com' - , '" foo bar "@example.com' - ] - , invalid: [ - 'invalidemail@' - , 'invalid.com' - , '@invalid.com' - , 'foo@bar.com.' - , 'foo@bar.co.uk.' - , 'somename@gmail.com' - , 'hans.m端ller@test.com' - , 'z@co.c' - ] - }); - }); - - it('should validate email addresses with display names', function () { - test({ - validator: 'isEmail' - , args: [{ allow_display_name: true }] - , valid: [ - 'foo@bar.com' - , 'x@x.au' - , 'foo@bar.com.au' - , 'foo+bar@bar.com' - , 'hans.m端ller@test.com' - , 'hans@m端ller.com' - , 'test|123@m端ller.com' - , 'test+ext@gmail.com' - , 'some.name.midd.leNa.me.+extension@GoogleMail.com' - , 'Some Name ' - , 'Some Name ' - , 'Some Name ' - , 'Some Name ' - , 'Some Name ' - , 'Some Name ' - , 'Some Name ' - , 'Some Name ' - , 'Some Name ' - , 'Some Middle Name ' - , 'Name ' - , 'Name' - ] - , invalid: [ - 'invalidemail@' - , 'invalid.com' - , '@invalid.com' - , 'foo@bar.com.' - , 'foo@bar.co.uk.' - , 'Some Name ' - , 'Some Name ' - , 'Some Name <@invalid.com>' - , 'Some Name ' - , 'Some Name ' - , 'Some Name foo@bar.co.uk.>' - , 'Some Name ' - , 'Name foo@bar.co.uk' - ] - }); - }); - - it('should validate URLs', function () { - test({ - validator: 'isURL' - , valid: [ - 'foobar.com' - , 'www.foobar.com' - , 'foobar.com/' - , 'valid.au' - , 'http://www.foobar.com/' - , 'http://www.foobar.com:23/' - , 'http://www.foobar.com:65535/' - , 'http://www.foobar.com:5/' - , 'https://www.foobar.com/' - , 'ftp://www.foobar.com/' - , 'http://www.foobar.com/~foobar' - , 'http://user:pass@www.foobar.com/' - , 'http://user:@www.foobar.com/' - , 'http://127.0.0.1/' - , 'http://10.0.0.0/' - , 'http://189.123.14.13/' - , 'http://duckduckgo.com/?q=%2F' - , 'http://foobar.com/t$-_.+!*\'(),' - , 'http://localhost:3000/' - , 'http://foobar.com/?foo=bar#baz=qux' - , 'http://foobar.com?foo=bar' - , 'http://foobar.com#baz=qux' - , 'http://www.xn--froschgrn-x9a.net/' - , 'http://xn--froschgrn-x9a.com/' - , 'http://foo--bar.com' - , 'http://høyfjellet.no' - , 'http://xn--j1aac5a4g.xn--j1amh' - , 'http://xn------eddceddeftq7bvv7c4ke4c.xn--p1ai' - , 'http://кулік.укр' - ] - , invalid: [ - 'xyz://foobar.com' - , 'invalid/' - , 'invalid.x' - , 'invalid.' - , '.com' - , 'http://com/' - , 'http://300.0.0.1/' - , 'mailto:foo@bar.com' - , 'rtmp://foobar.com' - , 'http://www.xn--.com/' - , 'http://xn--.com/' - , 'http://www.foobar.com:0/' - , 'http://www.foobar.com:70000/' - , 'http://www.foobar.com:99999/' - , 'http://www.-foobar.com/' - , 'http://www.foobar-.com/' - , 'http://www.foo---bar.com/' - , 'http://foobar/# lol' - , 'http://foobar/? lol' - , 'http://foobar/ lol/' - , 'http://lol @foobar.com/' - , 'http://lol:lol @foobar.com/' - , 'http://lol:lol:lol@foobar.com/' - , 'http://lol: @foobar.com/' - , 'http://www.foo_bar.com/' - , 'http://www.foobar.com/\t' - , 'http://\n@www.foobar.com/' - , '' - , 'http://foobar.com/' + new Array(2083).join('f') - , 'http://*.foo.com' - , '*.foo.com' - , '!.foo.com' - , 'http://example.com.' - , 'http://localhost:61500this is an invalid url!!!!' - , '////foobar.com' - , 'http:////foobar.com' - ] - }); - }); - - it('should validate URLs with custom protocols', function () { - test({ - validator: 'isURL' - , args: [{ - protocols: [ 'rtmp' ] - }] - , valid: [ - 'rtmp://foobar.com' - ] - , invalid: [ - 'http://foobar.com' - ] - }); - }); - - it('should validate URLs with any protocol', function () { - test({ - validator: 'isURL' - , args: [{ - require_valid_protocol: false - }] - , valid: [ - 'rtmp://foobar.com', - 'http://foobar.com', - 'test://foobar.com' - ] - , invalid: [ - 'mailto:test@example.com' - ] - }); - }); - - it('should validate URLs with underscores', function () { - test({ - validator: 'isURL' - , args: [{ - allow_underscores: true - }] - , valid: [ - 'http://foo_bar.com' - , 'http://pr.example_com.294.example.com/' - ] - , invalid: [ - 'http://foo__bar.com' - ] - }); - }); - - it('should validate URLs that do not have a TLD', function () { - test({ - validator: 'isURL' - , args: [{ - require_tld: false - }] - , valid: [ - 'http://foobar.com/' - , 'http://foobar/' - , 'foobar/' - , 'foobar' - ] - , invalid: [ - ] - }); - }); - - it('should validate URLs with a trailing dot option', function () { - test({ - validator: 'isURL' - , args: [{ - allow_trailing_dot: true - , require_tld: false - }] - , valid: [ - 'http://example.com.' - , 'foobar.' - ] - }); - }); - - it('should validate protocol relative URLs', function () { - test({ - validator: 'isURL' - , args: [{ - allow_protocol_relative_urls: true - }] - , valid: [ - '//foobar.com' - , 'http://foobar.com' - , 'foobar.com' - ] - , invalid: [ - '://foobar.com' - , '/foobar.com' - , '////foobar.com' - , 'http:////foobar.com' - ] - }); - }); - - it('should not validate protocol relative URLs when require protocol is true', function () { - test({ - validator: 'isURL' - , args: [{ - allow_protocol_relative_urls: true, - require_protocol: true - }] - , valid: [ - 'http://foobar.com' - ] - , invalid: [ - '//foobar.com' - , '://foobar.com' - , '/foobar.com' - , 'foobar.com' - ] - }); - }); - - it('should let users specify whether URLs require a protocol', function () { - test({ - validator: 'isURL' - , args: [{ - require_protocol: true - }] - , valid: [ - 'http://foobar.com/' - , 'http://localhost/' - ] - , invalid: [ - 'foobar.com' - , 'foobar' - ] - }); - }); - - it('should let users specify a host whitelist', function () { - test({ - validator: 'isURL' - , args: [{ - host_whitelist: ['foo.com', 'bar.com'] - }] - , valid: [ - 'http://bar.com/' - , 'http://foo.com/' - ] - , invalid: [ - 'http://foobar.com' - , 'http://foo.bar.com/' - , 'http://qux.com' - ] - }); - }); - - it('should let users specify a host blacklist', function () { - test({ - validator: 'isURL' - , args: [{ - host_blacklist: ['foo.com', 'bar.com'] - }] - , valid: [ - 'http://foobar.com' - , 'http://foo.bar.com/' - , 'http://qux.com' - ] - , invalid: [ - 'http://bar.com/' - , 'http://foo.com/' - ] - }); - }); - - it('should validate MAC addresses', function () { - test({ - validator: 'isMACAddress', - valid: [ - 'ab:ab:ab:ab:ab:ab', - 'FF:FF:FF:FF:FF:FF', - '01:02:03:04:05:ab', - '01:AB:03:04:05:06' - ], - invalid: [ - 'abc', - '01:02:03:04:05', - '01:02:03:04::ab', - '1:2:3:4:5:6', - 'AB:CD:EF:GH:01:02' - ] - }); - }); - - it('should validate IP addresses', function () { - test({ - validator: 'isIP' - , valid: [ - '127.0.0.1' - , '0.0.0.0' - , '255.255.255.255' - , '1.2.3.4' - , '::1' - , '2001:db8:0000:1:1:1:1:1' - , '2001:41d0:2:a141::1' - , '::ffff:127.0.0.1' - , '::0000' - , '0000::' - , '1::' - , '1111:1:1:1:1:1:1:1' - , 'fe80::a6db:30ff:fe98:e946' - , '::' - , '::ffff:127.0.0.1' - , '0:0:0:0:0:ffff:127.0.0.1' - ] - , invalid: [ - 'abc' - , '256.0.0.0' - , '0.0.0.256' - , '26.0.0.256' - , '0200.200.200.200' - , '200.0200.200.200' - , '200.200.0200.200' - , '200.200.200.0200' - , '::banana' - , 'banana::' - , '::1banana' - , '::1::' - , '1:' - , ':1' - , ':1:1:1::2' - , '1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1' - , '::11111' - , '11111:1:1:1:1:1:1:1' - , '2001:db8:0000:1:1:1:1::1' - , '0:0:0:0:0:0:ffff:127.0.0.1' - , '0:0:0:0:ffff:127.0.0.1' - ] - }); - test({ - validator: 'isIP' - , args: [ 4 ] - , valid: [ - '127.0.0.1' - , '0.0.0.0' - , '255.255.255.255' - , '1.2.3.4' - ] - , invalid: [ - '::1' - , '2001:db8:0000:1:1:1:1:1' - , '::ffff:127.0.0.1' - ] - }); - test({ - validator: 'isIP' - , args: [ 6 ] - , valid: [ - '::1' - , '2001:db8:0000:1:1:1:1:1' - , '::ffff:127.0.0.1' - ] - , invalid: [ - '127.0.0.1' - , '0.0.0.0' - , '255.255.255.255' - , '1.2.3.4' - , '::ffff:287.0.0.1' - ] - }); - test({ - validator: 'isIP' - , args: [ 10 ] - , valid: [ - ] - , invalid: [ - '127.0.0.1' - , '0.0.0.0' - , '255.255.255.255' - , '1.2.3.4' - , '::1' - , '2001:db8:0000:1:1:1:1:1' - ] - }); - }); - - it('should validate FQDN', function () { - test({ - validator: 'isFQDN' - , valid: [ - 'domain.com' - , 'dom.plato' - , 'a.domain.co' - , 'foo--bar.com' - , 'xn--froschgrn-x9a.com' - , 'rebecca.blackfriday' - ] - , invalid: [ - 'abc' - , '256.0.0.0' - , '_.com' - , '*.some.com' - , 's!ome.com' - , 'domain.com/' - , '/more.com' - ] - }); - }); - it('should validate FQDN with trailing dot option', function() { - test({ - validator: 'isFQDN' - , args: [ - {allow_trailing_dot:true} - ] - , valid: [ - 'example.com.' - ] - }); - }); - - it('should validate alpha strings', function () { - test({ - validator: 'isAlpha' - , valid: [ - 'abc' - , 'ABC' - , 'FoObar' - ] - , invalid: [ - 'abc1' - , ' foo ' - , '' - , 'ÄBC' - , 'FÜübar' - , 'Jön' - , 'Heiß' - ] - }); - }); - - it('should validate german alpha strings', function () { - test({ - validator: 'isAlpha' - , args: ['de-DE'] - , valid: [ - 'äbc' - , 'ÄBC' - , 'FöÖbär' - , 'Heiß' - ] - , invalid: [ - 'äbc1' - , ' föö ' - , '' - ] - }); - }); - - it('should validate alphanumeric strings', function () { - test({ - validator: 'isAlphanumeric' - , valid: [ - 'abc123' - , 'ABC11' - ] - , invalid: [ - 'abc ' - , 'foo!!' - , 'ÄBC' - , 'FÜübar' - , 'Jön' - ] - }); - }); - - it('should validate defined english aliases', function () { - test({ - validator: 'isAlphanumeric' - , args: ['en-GB'] - , valid: [ - 'abc123' - , 'ABC11' - ] - , invalid: [ - 'abc ' - , 'foo!!' - , 'ÄBC' - , 'FÜübar' - , 'Jön' - ] - }); - }); - - it('should validate german alphanumeric strings', function () { - test({ - validator: 'isAlphanumeric' - , args: ['de-DE'] - , valid: [ - 'äbc123' - , 'ÄBC11' - ] - , invalid: [ - 'äca ' - , 'föö!!' - ] - }); - }); - - it('should validate spanish alphanumeric strings', function () { - test({ - validator: 'isAlphanumeric' - , args: ['es-ES'] - , valid: [ - 'ábcó123' - , 'ÁBCÓ11' - ] - , invalid: [ - 'äca ' - , 'abcß' - , 'föö!!' - ] - }); - }); - - it('should error on invalid locale', function () { - try { - validator.isAlphanumeric("abc123", "in-INVALID"); - assert(false); - } catch (err) { - assert(true); - } - }); - - it('should validate numeric strings', function () { - test({ - validator: 'isNumeric' - , valid: [ - '123' - , '00123' - , '-00123' - , '0' - , '-0' - , '+123' - ] - , invalid: [ - '123.123' - , ' ' - , '.' - ] - }); - }); - - it('should validate decimal numbers', function () { - test({ - validator: 'isDecimal' - , valid: [ - '123' - , '00123' - , '-00123' - , '0' - , '-0' - , '+123' - , '0.01' - , '.1' - , '1.0' - , '-.25' - , '-0' - , '0.0000000000001' - ] - , invalid: [ - '....' - , ' ' - , '' - , '-' - , '+' - , '.' - , '0.1a' - , 'a' - , '\n' - ] - }); - }); - - it('should validate lowercase strings', function () { - test({ - validator: 'isLowercase' - , valid: [ - 'abc' - , 'abc123' - , 'this is lowercase.' - , 'tr竪s 端ber' - ] - , invalid: [ - 'fooBar' - , '123A' - ] - }); - }); - - it('should validate uppercase strings', function () { - test({ - validator: 'isUppercase' - , valid: [ - 'ABC' - , 'ABC123' - , 'ALL CAPS IS FUN.' - , ' .' - ] - , invalid: [ - 'fooBar' - , '123abc' - ] - }); - }); - - it('should validate integers', function () { - test({ - validator: 'isInt' - , valid: [ - '13' - , '123' - , '0' - , '123' - , '-0' - , '+1' - ] - , invalid: [ - '01' - , '-01' - , '000' - , '100e10' - , '123.123' - , ' ' - , '' - ] - }); - test({ - validator: 'isInt' - , args: [{ - min: 10 - }] - , valid: [ - '15' - , '80' - , '99' - ] - , invalid: [ - '9' - , '6' - , '3.2' - , 'a' - ] - }); - test({ - validator: 'isInt' - , args: [{ - min: 10 - , max: 15 - }] - , valid: [ - '15' - , '11' - , '13' - ] - , invalid: [ - '9' - , '2' - , '17' - , '3.2' - , '33' - , 'a' - ] - }); - }); - - it('should validate floats', function () { - test({ - validator: 'isFloat' - , valid: [ - '123' - , '123.' - , '123.123' - , '-123.123' - , '-0.123' - , '+0.123' - , '0.123' - , '.0' - , '01.123' - , '-0.22250738585072011e-307' - ] - , invalid: [ - '-.123' - , ' ' - , '' - , '.' - , 'foo' - ] - }); - test({ - validator: 'isFloat' - , args: [{ - min: 3.7 - }] - , valid: [ - '3.888' - , '3.92' - , '4.5' - , '50' - , '3.7' - , '3.71' - ] - , invalid: [ - '3.6' - , '3.69' - , '3' - , '1.5' - , 'a' - ] - }); - test({ - validator: 'isFloat' - , args: [{ - min: 0.1 - , max: 1.0 - }] - , valid: [ - '0.1' - , '1.0' - , '0.15' - , '0.33' - , '0.57' - , '0.7' - ] - , invalid: [ - '0' - , '0.0' - , 'a' - , '1.3' - , '0.05' - , '5' - ] - }); - }); - - it('should validate hexadecimal strings', function () { - test({ - validator: 'isHexadecimal' - , valid: [ - 'deadBEEF' - , 'ff0044' - ] - , invalid: [ - 'abcdefg' - , '' - , '..' - ] - }); - }); - - it('should validate hexadecimal color strings', function () { - test({ - validator: 'isHexColor' - , valid: [ - '#ff0034' - , '#CCCCCC' - , 'fff' - , '#f00' - ] - , invalid: [ - '#ff' - , 'fff0' - , '#ff12FG' - ] - }); - }); - - it('should validate null strings', function () { - test({ - validator: 'isNull' - , valid: [ - '' - ] - , invalid: [ - ' ' - , 'foo' - , '3' - ] - }); - }); - - it('should validate strings against an expected value', function () { - test({ validator: 'equals', args: ['abc'], valid: ['abc'], invalid: ['Abc', '123'] }); - }); - - it('should validate strings contain another string', function () { - test({ validator: 'contains', args: ['foo'], valid: ['foo', 'foobar', 'bazfoo'], - invalid: ['bar', 'fobar'] }); + it('should validate email addresses without UTF8 characters in local part', function () { + test({ + validator: 'isEmail', + args: [{ allow_utf8_local_part: false }], + valid: [ + 'foo@bar.com', + 'x@x.au', + 'foo@bar.com.au', + 'foo+bar@bar.com', + 'hans@m端ller.com', + 'test|123@m端ller.com', + 'test+ext@gmail.com', + 'some.name.midd.leNa.me.+extension@GoogleMail.com', + '"foobar"@example.com', + '"foo\\@bar"@example.com', + '" foo bar "@example.com', + ], + invalid: [ + 'invalidemail@', + 'invalid.com', + '@invalid.com', + 'foo@bar.com.', + 'foo@bar.co.uk.', + 'somename@gmail.com', + 'hans.m端ller@test.com', + 'z@co.c', + ], + }); + }); + + it('should validate email addresses with display names', function () { + test({ + validator: 'isEmail', + args: [{ allow_display_name: true }], + valid: [ + 'foo@bar.com', + 'x@x.au', + 'foo@bar.com.au', + 'foo+bar@bar.com', + 'hans.m端ller@test.com', + 'hans@m端ller.com', + 'test|123@m端ller.com', + 'test+ext@gmail.com', + 'some.name.midd.leNa.me.+extension@GoogleMail.com', + 'Some Name ', + 'Some Name ', + 'Some Name ', + 'Some Name ', + 'Some Name ', + 'Some Name ', + 'Some Name ', + 'Some Name ', + 'Some Name ', + 'Some Middle Name ', + 'Name ', + 'Name', + ], + invalid: [ + 'invalidemail@', + 'invalid.com', + '@invalid.com', + 'foo@bar.com.', + 'foo@bar.co.uk.', + 'Some Name ', + 'Some Name ', + 'Some Name <@invalid.com>', + 'Some Name ', + 'Some Name ', + 'Some Name foo@bar.co.uk.>', + 'Some Name ', + 'Name foo@bar.co.uk', + ], + }); + }); + + it('should validate URLs', function () { + test({ + validator: 'isURL', + valid: [ + 'foobar.com', + 'www.foobar.com', + 'foobar.com/', + 'valid.au', + 'http://www.foobar.com/', + 'http://www.foobar.com:23/', + 'http://www.foobar.com:65535/', + 'http://www.foobar.com:5/', + 'https://www.foobar.com/', + 'ftp://www.foobar.com/', + 'http://www.foobar.com/~foobar', + 'http://user:pass@www.foobar.com/', + 'http://user:@www.foobar.com/', + 'http://127.0.0.1/', + 'http://10.0.0.0/', + 'http://189.123.14.13/', + 'http://duckduckgo.com/?q=%2F', + 'http://foobar.com/t$-_.+!*\'(),', + 'http://localhost:3000/', + 'http://foobar.com/?foo=bar#baz=qux', + 'http://foobar.com?foo=bar', + 'http://foobar.com#baz=qux', + 'http://www.xn--froschgrn-x9a.net/', + 'http://xn--froschgrn-x9a.com/', + 'http://foo--bar.com', + 'http://høyfjellet.no', + 'http://xn--j1aac5a4g.xn--j1amh', + 'http://xn------eddceddeftq7bvv7c4ke4c.xn--p1ai', + 'http://кулік.укр', + ], + invalid: [ + 'xyz://foobar.com', + 'invalid/', + 'invalid.x', + 'invalid.', + '.com', + 'http://com/', + 'http://300.0.0.1/', + 'mailto:foo@bar.com', + 'rtmp://foobar.com', + 'http://www.xn--.com/', + 'http://xn--.com/', + 'http://www.foobar.com:0/', + 'http://www.foobar.com:70000/', + 'http://www.foobar.com:99999/', + 'http://www.-foobar.com/', + 'http://www.foobar-.com/', + 'http://www.foo---bar.com/', + 'http://foobar/# lol', + 'http://foobar/? lol', + 'http://foobar/ lol/', + 'http://lol @foobar.com/', + 'http://lol:lol @foobar.com/', + 'http://lol:lol:lol@foobar.com/', + 'http://lol: @foobar.com/', + 'http://www.foo_bar.com/', + 'http://www.foobar.com/\t', + 'http://\n@www.foobar.com/', + '', + 'http://foobar.com/' + new Array(2083).join('f'), + 'http://*.foo.com', + '*.foo.com', + '!.foo.com', + 'http://example.com.', + 'http://localhost:61500this is an invalid url!!!!', + '////foobar.com', + 'http:////foobar.com', + ], + }); + }); + + it('should validate URLs with custom protocols', function () { + test({ + validator: 'isURL', + args: [{ + protocols: ['rtmp'], + }], + valid: [ + 'rtmp://foobar.com', + ], + invalid: [ + 'http://foobar.com', + ], + }); + }); + + it('should validate URLs with any protocol', function () { + test({ + validator: 'isURL', + args: [{ + require_valid_protocol: false, + }], + valid: [ + 'rtmp://foobar.com', + 'http://foobar.com', + 'test://foobar.com', + ], + invalid: [ + 'mailto:test@example.com', + ], }); + }); - it('should validate strings against a pattern', function () { - test({ validator: 'matches', args: [/abc/], valid: ['abc', 'abcdef', '123abc'], + it('should validate URLs with underscores', function () { + test({ + validator: 'isURL', + args: [{ + allow_underscores: true, + }], + valid: [ + 'http://foo_bar.com', + 'http://pr.example_com.294.example.com/', + ], + invalid: [ + 'http://foo__bar.com', + ], + }); + }); + + it('should validate URLs that do not have a TLD', function () { + test({ + validator: 'isURL', + args: [{ + require_tld: false, + }], + valid: [ + 'http://foobar.com/', + 'http://foobar/', + 'foobar/', + 'foobar', + ], + invalid: [], + }); + }); + + it('should validate URLs with a trailing dot option', function () { + test({ + validator: 'isURL', + args: [{ + allow_trailing_dot: true, + require_tld: false, + }], + valid: [ + 'http://example.com.', + 'foobar.', + ], + }); + }); + + it('should validate protocol relative URLs', function () { + test({ + validator: 'isURL', + args: [{ + allow_protocol_relative_urls: true, + }], + valid: [ + '//foobar.com', + 'http://foobar.com', + 'foobar.com', + ], + invalid: [ + '://foobar.com', + '/foobar.com', + '////foobar.com', + 'http:////foobar.com', + ], + }); + }); + + it('should not validate protocol relative URLs when require protocol is true', function () { + test({ + validator: 'isURL', + args: [{ + allow_protocol_relative_urls: true, + require_protocol: true, + }], + valid: [ + 'http://foobar.com', + ], + invalid: [ + '//foobar.com', + '://foobar.com', + '/foobar.com', + 'foobar.com', + ], + }); + }); + + it('should let users specify whether URLs require a protocol', function () { + test({ + validator: 'isURL', + args: [{ + require_protocol: true, + }], + valid: [ + 'http://foobar.com/', + 'http://localhost/', + ], + invalid: [ + 'foobar.com', + 'foobar', + ], + }); + }); + + it('should let users specify a host whitelist', function () { + test({ + validator: 'isURL', + args: [{ + host_whitelist: ['foo.com', 'bar.com'], + }], + valid: [ + 'http://bar.com/', + 'http://foo.com/', + ], + invalid: [ + 'http://foobar.com', + 'http://foo.bar.com/', + 'http://qux.com', + ], + }); + }); + + it('should let users specify a host blacklist', function () { + test({ + validator: 'isURL', + args: [{ + host_blacklist: ['foo.com', 'bar.com'], + }], + valid: [ + 'http://foobar.com', + 'http://foo.bar.com/', + 'http://qux.com', + ], + invalid: [ + 'http://bar.com/', + 'http://foo.com/', + ], + }); + }); + + it('should validate MAC addresses', function () { + test({ + validator: 'isMACAddress', + valid: [ + 'ab:ab:ab:ab:ab:ab', + 'FF:FF:FF:FF:FF:FF', + '01:02:03:04:05:ab', + '01:AB:03:04:05:06', + ], + invalid: [ + 'abc', + '01:02:03:04:05', + '01:02:03:04::ab', + '1:2:3:4:5:6', + 'AB:CD:EF:GH:01:02', + ], + }); + }); + + it('should validate IP addresses', function () { + test({ + validator: 'isIP', + valid: [ + '127.0.0.1', + '0.0.0.0', + '255.255.255.255', + '1.2.3.4', + '::1', + '2001:db8:0000:1:1:1:1:1', + '2001:41d0:2:a141::1', + '::ffff:127.0.0.1', + '::0000', + '0000::', + '1::', + '1111:1:1:1:1:1:1:1', + 'fe80::a6db:30ff:fe98:e946', + '::', + '::ffff:127.0.0.1', + '0:0:0:0:0:ffff:127.0.0.1', + ], + invalid: [ + 'abc', + '256.0.0.0', + '0.0.0.256', + '26.0.0.256', + '0200.200.200.200', + '200.0200.200.200', + '200.200.0200.200', + '200.200.200.0200', + '::banana', + 'banana::', + '::1banana', + '::1::', + '1:', + ':1', + ':1:1:1::2', + '1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1', + '::11111', + '11111:1:1:1:1:1:1:1', + '2001:db8:0000:1:1:1:1::1', + '0:0:0:0:0:0:ffff:127.0.0.1', + '0:0:0:0:ffff:127.0.0.1', + ], + }); + test({ + validator: 'isIP', + args: [4], + valid: [ + '127.0.0.1', + '0.0.0.0', + '255.255.255.255', + '1.2.3.4', + ], + invalid: [ + '::1', + '2001:db8:0000:1:1:1:1:1', + '::ffff:127.0.0.1', + ], + }); + test({ + validator: 'isIP', + args: [6], + valid: [ + '::1', + '2001:db8:0000:1:1:1:1:1', + '::ffff:127.0.0.1', + ], + invalid: [ + '127.0.0.1', + '0.0.0.0', + '255.255.255.255', + '1.2.3.4', + '::ffff:287.0.0.1', + ], + }); + test({ + validator: 'isIP', + args: [10], + valid: [], + invalid: [ + '127.0.0.1', + '0.0.0.0', + '255.255.255.255', + '1.2.3.4', + '::1', + '2001:db8:0000:1:1:1:1:1', + ], + }); + }); + + it('should validate FQDN', function () { + test({ + validator: 'isFQDN', + valid: [ + 'domain.com', + 'dom.plato', + 'a.domain.co', + 'foo--bar.com', + 'xn--froschgrn-x9a.com', + 'rebecca.blackfriday', + ], + invalid: [ + 'abc', + '256.0.0.0', + '_.com', + '*.some.com', + 's!ome.com', + 'domain.com/', + '/more.com', + ], + }); + }); + it('should validate FQDN with trailing dot option', function () { + test({ + validator: 'isFQDN', + args: [ + { allow_trailing_dot: true }, + ], + valid: [ + 'example.com.', + ], + }); + }); + + it('should validate alpha strings', function () { + test({ + validator: 'isAlpha', + valid: [ + 'abc', + 'ABC', + 'FoObar', + ], + invalid: [ + 'abc1', + ' foo ', + '', + 'ÄBC', + 'FÜübar', + 'Jön', + 'Heiß', + ], + }); + }); + + it('should validate german alpha strings', function () { + test({ + validator: 'isAlpha', + args: ['de-DE'], + valid: [ + 'äbc', + 'ÄBC', + 'FöÖbär', + 'Heiß', + ], + invalid: [ + 'äbc1', + ' föö ', + '', + ], + }); + }); + + it('should validate alphanumeric strings', function () { + test({ + validator: 'isAlphanumeric', + valid: [ + 'abc123', + 'ABC11', + ], + invalid: [ + 'abc ', + 'foo!!', + 'ÄBC', + 'FÜübar', + 'Jön', + ], + }); + }); + + it('should validate defined english aliases', function () { + test({ + validator: 'isAlphanumeric', + args: ['en-GB'], + valid: [ + 'abc123', + 'ABC11', + ], + invalid: [ + 'abc ', + 'foo!!', + 'ÄBC', + 'FÜübar', + 'Jön', + ], + }); + }); + + it('should validate german alphanumeric strings', function () { + test({ + validator: 'isAlphanumeric', + args: ['de-DE'], + valid: [ + 'äbc123', + 'ÄBC11', + ], + invalid: [ + 'äca ', + 'föö!!', + ], + }); + }); + + it('should validate spanish alphanumeric strings', function () { + test({ + validator: 'isAlphanumeric', + args: ['es-ES'], + valid: [ + 'ábcó123', + 'ÁBCÓ11', + ], + invalid: [ + 'äca ', + 'abcß', + 'föö!!', + ], + }); + }); + + it('should error on invalid locale', function () { + try { + validator.isAlphanumeric('abc123', 'in-INVALID'); + assert(false); + } catch (err) { + assert(true); + } + }); + + it('should validate numeric strings', function () { + test({ + validator: 'isNumeric', + valid: [ + '123', + '00123', + '-00123', + '0', + '-0', + '+123', + ], + invalid: [ + '123.123', + ' ', + '.', + ], + }); + }); + + it('should validate decimal numbers', function () { + test({ + validator: 'isDecimal', + valid: [ + '123', + '00123', + '-00123', + '0', + '-0', + '+123', + '0.01', + '.1', + '1.0', + '-.25', + '-0', + '0.0000000000001', + ], + invalid: [ + '....', + ' ', + '', + '-', + '+', + '.', + '0.1a', + 'a', + '\n', + ], + }); + }); + + it('should validate lowercase strings', function () { + test({ + validator: 'isLowercase', + valid: [ + 'abc', + 'abc123', + 'this is lowercase.', + 'tr竪s 端ber', + ], + invalid: [ + 'fooBar', + '123A', + ], + }); + }); + + it('should validate uppercase strings', function () { + test({ + validator: 'isUppercase', + valid: [ + 'ABC', + 'ABC123', + 'ALL CAPS IS FUN.', + ' .', + ], + invalid: [ + 'fooBar', + '123abc', + ], + }); + }); + + it('should validate integers', function () { + test({ + validator: 'isInt', + valid: [ + '13', + '123', + '0', + '123', + '-0', + '+1', + ], + invalid: [ + '01', + '-01', + '000', + '100e10', + '123.123', + ' ', + '', + ], + }); + test({ + validator: 'isInt', + args: [{ + min: 10, + }], + valid: [ + '15', + '80', + '99', + ], + invalid: [ + '9', + '6', + '3.2', + 'a', + ], + }); + test({ + validator: 'isInt', + args: [{ + min: 10, + max: 15, + }], + valid: [ + '15', + '11', + '13', + ], + invalid: [ + '9', + '2', + '17', + '3.2', + '33', + 'a', + ], + }); + }); + + it('should validate floats', function () { + test({ + validator: 'isFloat', + valid: [ + '123', + '123.', + '123.123', + '-123.123', + '-0.123', + '+0.123', + '0.123', + '.0', + '01.123', + '-0.22250738585072011e-307', + ], + invalid: [ + '-.123', + ' ', + '', + '.', + 'foo', + ], + }); + test({ + validator: 'isFloat', + args: [{ + min: 3.7, + }], + valid: [ + '3.888', + '3.92', + '4.5', + '50', + '3.7', + '3.71', + ], + invalid: [ + '3.6', + '3.69', + '3', + '1.5', + 'a', + ], + }); + test({ + validator: 'isFloat', + args: [{ + min: 0.1, + max: 1.0, + }], + valid: [ + '0.1', + '1.0', + '0.15', + '0.33', + '0.57', + '0.7', + ], + invalid: [ + '0', + '0.0', + 'a', + '1.3', + '0.05', + '5', + ], + }); + }); + + it('should validate hexadecimal strings', function () { + test({ + validator: 'isHexadecimal', + valid: [ + 'deadBEEF', + 'ff0044', + ], + invalid: [ + 'abcdefg', + '', + '..', + ], + }); + }); + + it('should validate hexadecimal color strings', function () { + test({ + validator: 'isHexColor', + valid: [ + '#ff0034', + '#CCCCCC', + 'fff', + '#f00', + ], + invalid: [ + '#ff', + 'fff0', + '#ff12FG', + ], + }); + }); + + it('should validate null strings', function () { + test({ + validator: 'isNull', + valid: [ + '', + ], + invalid: [ + ' ', + 'foo', + '3', + ], + }); + }); + + it('should validate strings against an expected value', function () { + test({ validator: 'equals', args: ['abc'], valid: ['abc'], invalid: ['Abc', '123'] }); + }); + + it('should validate strings contain another string', function () { + test({ validator: 'contains', args: ['foo'], valid: ['foo', 'foobar', 'bazfoo'], + invalid: ['bar', 'fobar'] }); + }); + + it('should validate strings against a pattern', function () { + test({ validator: 'matches', args: [/abc/], valid: ['abc', 'abcdef', '123abc'], invalid: ['acb', 'Abc'] }); - test({ validator: 'matches', args: ['abc'], valid: ['abc', 'abcdef', '123abc'], + test({ validator: 'matches', args: ['abc'], valid: ['abc', 'abcdef', '123abc'], invalid: ['acb', 'Abc'] }); - test({ validator: 'matches', args: ['abc', 'i'], valid: ['abc', 'abcdef', '123abc', 'AbC'], + test({ validator: 'matches', args: ['abc', 'i'], valid: ['abc', 'abcdef', '123abc', 'AbC'], invalid: ['acb'] }); + }); + + it('should validate strings by length (deprecated api)', function () { + test({ + validator: 'isLength', + args: [2], + valid: ['abc', 'de', 'abcd'], + invalid: ['', 'a'], + }); + test({ + validator: 'isLength', + args: [2, 3], + valid: ['abc', 'de'], + invalid: ['', 'a', 'abcd'], + }); + test({ + validator: 'isLength', + args: [2, 3], + valid: ['干𩸽', '𠮷野家'], + invalid: ['', '𠀋', '千竈通り'], + }); + test({ + validator: 'isLength', + args: [0, 0], + valid: [''], + invalid: ['a', 'ab'], + }); + }); + + it('should validate strings by byte length (deprecated api)', function () { + test({ + validator: 'isByteLength', + args: [2], + valid: ['abc', 'de', 'abcd', 'gmail'], + invalid: ['', 'a'], + }); + test({ + validator: 'isByteLength', + args: [2, 3], + valid: ['abc', 'de', 'g'], + invalid: ['', 'a', 'abcd', 'gm'], + }); + test({ + validator: 'isByteLength', + args: [0, 0], + valid: [''], + invalid: ['g', 'a'], + }); + }); + + it('should validate strings by length', function () { + test({ + validator: 'isLength', + args: [{ min: 2 }], + valid: ['abc', 'de', 'abcd'], + invalid: ['', 'a'], + }); + test({ + validator: 'isLength', + args: [{ min: 2, max: 3 }], + valid: ['abc', 'de'], + invalid: ['', 'a', 'abcd'], + }); + test({ + validator: 'isLength', + args: [{ min: 2, max: 3 }], + valid: ['干𩸽', '𠮷野家'], + invalid: ['', '𠀋', '千竈通り'], + }); + test({ + validator: 'isLength', + args: [{ max: 3 }], + valid: ['abc', 'de', 'a', ''], + invalid: ['abcd'], + }); + test({ + validator: 'isLength', + args: [{ max: 0 }], + valid: [''], + invalid: ['a', 'ab'], }); + }); - it('should validate strings by length (deprecated api)', function () { - test({ validator: 'isLength', args: [2], valid: ['abc', 'de', 'abcd'], invalid: [ '', 'a' ] }); - test({ validator: 'isLength', args: [2, 3], valid: ['abc', 'de'], invalid: [ '', 'a', 'abcd' ] }); - test({ validator: 'isLength', args: [2, 3], valid: ['干𩸽', '𠮷野家'], invalid: [ '', '𠀋', '千竈通り' ] }); - test({ validator: 'isLength', args: [0, 0], valid: [''], invalid: ['a', 'ab'] }); - }); - - it('should validate strings by byte length (deprecated api)', function () { - test({ validator: 'isByteLength', args: [2], valid: ['abc', 'de', 'abcd', 'gmail'], invalid: [ '', 'a' ] }); - test({ validator: 'isByteLength', args: [2, 3], valid: ['abc', 'de', 'g'], invalid: [ '', 'a', 'abcd', 'gm' ] }); - test({ validator: 'isByteLength', args: [0, 0], valid: [''], invalid: ['g', 'a'] }); - }); - - it('should validate strings by length', function () { - test({ validator: 'isLength', args: [{min: 2}], valid: ['abc', 'de', 'abcd'], invalid: ['', 'a'] }); - test({ validator: 'isLength', args: [{min: 2, max: 3}], valid: ['abc', 'de'], invalid: ['', 'a', 'abcd'] }); - test({ validator: 'isLength', args: [{min: 2, max: 3}], valid: ['干𩸽', '𠮷野家'], invalid: [ '', '𠀋', '千竈通り' ] }); - test({ validator: 'isLength', args: [{max: 3}], valid: ['abc', 'de', 'a', ''], invalid: ['abcd'] }); - test({ validator: 'isLength', args: [{max: 0}], valid: [''], invalid: ['a', 'ab'] }); - }); - - it('should validate strings by byte length', function () { - test({ validator: 'isByteLength', args: [{min: 2}], valid: ['abc', 'de', 'abcd', 'gmail'], invalid: ['', 'a'] }); - test({ validator: 'isByteLength', args: [{min: 2, max: 3}], valid: ['abc', 'de', 'g'], invalid: ['', 'a', 'abcd', 'gm'] }); - test({ validator: 'isByteLength', args: [{max: 3}], valid: ['abc', 'de', 'g', 'a', ''], invalid: ['abcd', 'gm'] }); - test({ validator: 'isByteLength', args: [{max: 0}], valid: [''], invalid: ['g', 'a'] }); - }); - - it('should validate UUIDs', function () { - test({ - validator: 'isUUID' - , valid: [ - 'A987FBC9-4BED-3078-CF07-9141BA07C9F3' - , 'A987FBC9-4BED-4078-8F07-9141BA07C9F3' - , 'A987FBC9-4BED-5078-AF07-9141BA07C9F3' - ] - , invalid: [ - '' - , 'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3' - , 'A987FBC9-4BED-3078-CF07-9141BA07C9F3xxx' - , 'A987FBC94BED3078CF079141BA07C9F3' - , '934859' - , '987FBC9-4BED-3078-CF07A-9141BA07C9F3' - , 'AAAAAAAA-1111-1111-AAAG-111111111111' - ] - }); - test({ - validator: 'isUUID' - , args: [ 3 ] - , valid: [ - 'A987FBC9-4BED-3078-CF07-9141BA07C9F3' - ] - , invalid: [ - '' - , 'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3' - , '934859' - , 'AAAAAAAA-1111-1111-AAAG-111111111111' - , 'A987FBC9-4BED-4078-8F07-9141BA07C9F3' - , 'A987FBC9-4BED-5078-AF07-9141BA07C9F3' - ] - }); - test({ - validator: 'isUUID' - , args: [ 4 ] - , valid: [ - '713ae7e3-cb32-45f9-adcb-7c4fa86b90c1' - , '625e63f3-58f5-40b7-83a1-a72ad31acffb' - , '57b73598-8764-4ad0-a76a-679bb6640eb1' - , '9c858901-8a57-4791-81fe-4c455b099bc9' - ] - , invalid: [ - '' - , 'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3' - , '934859' - , 'AAAAAAAA-1111-1111-AAAG-111111111111' - , 'A987FBC9-4BED-5078-AF07-9141BA07C9F3' - , 'A987FBC9-4BED-3078-CF07-9141BA07C9F3' - ] - }); - test({ - validator: 'isUUID' - , args: [ 5 ] - , valid: [ - '987FBC97-4BED-5078-AF07-9141BA07C9F3' - , '987FBC97-4BED-5078-BF07-9141BA07C9F3' - , '987FBC97-4BED-5078-8F07-9141BA07C9F3' - , '987FBC97-4BED-5078-9F07-9141BA07C9F3' - ] - , invalid: [ - '' - , 'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3' - , '934859' - , 'AAAAAAAA-1111-1111-AAAG-111111111111' - , '9c858901-8a57-4791-81fe-4c455b099bc9' - , 'A987FBC9-4BED-3078-CF07-9141BA07C9F3' - ] - }); - }); - - it('should validate a string that is in another string or array', function () { - test({ validator: 'isIn', args: ['foobar'], valid: ['foo', 'bar', 'foobar', ''], + it('should validate strings by byte length', function () { + test({ + validator: 'isByteLength', + args: [{ min: 2 }], + valid: ['abc', 'de', 'abcd', 'gmail'], + invalid: ['', 'a'], + }); + test({ + validator: 'isByteLength', + args: [{ min: 2, max: 3 }], + valid: ['abc', 'de', 'g'], + invalid: ['', 'a', 'abcd', 'gm'], + }); + test({ + validator: 'isByteLength', + args: [{ max: 3 }], + valid: ['abc', 'de', 'g', 'a', ''], + invalid: ['abcd', 'gm'], + }); + test({ + validator: 'isByteLength', + args: [{ max: 0 }], + valid: [''], + invalid: ['g', 'a'], + }); + }); + + it('should validate UUIDs', function () { + test({ + validator: 'isUUID', + valid: [ + 'A987FBC9-4BED-3078-CF07-9141BA07C9F3', + 'A987FBC9-4BED-4078-8F07-9141BA07C9F3', + 'A987FBC9-4BED-5078-AF07-9141BA07C9F3', + ], + invalid: [ + '', + 'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3', + 'A987FBC9-4BED-3078-CF07-9141BA07C9F3xxx', + 'A987FBC94BED3078CF079141BA07C9F3', + '934859', + '987FBC9-4BED-3078-CF07A-9141BA07C9F3', + 'AAAAAAAA-1111-1111-AAAG-111111111111', + ], + }); + test({ + validator: 'isUUID', + args: [3], + valid: [ + 'A987FBC9-4BED-3078-CF07-9141BA07C9F3', + ], + invalid: [ + '', + 'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3', + '934859', + 'AAAAAAAA-1111-1111-AAAG-111111111111', + 'A987FBC9-4BED-4078-8F07-9141BA07C9F3', + 'A987FBC9-4BED-5078-AF07-9141BA07C9F3', + ], + }); + test({ + validator: 'isUUID', + args: [4], + valid: [ + '713ae7e3-cb32-45f9-adcb-7c4fa86b90c1', + '625e63f3-58f5-40b7-83a1-a72ad31acffb', + '57b73598-8764-4ad0-a76a-679bb6640eb1', + '9c858901-8a57-4791-81fe-4c455b099bc9', + ], + invalid: [ + '', + 'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3', + '934859', + 'AAAAAAAA-1111-1111-AAAG-111111111111', + 'A987FBC9-4BED-5078-AF07-9141BA07C9F3', + 'A987FBC9-4BED-3078-CF07-9141BA07C9F3', + ], + }); + test({ + validator: 'isUUID', + args: [5], + valid: [ + '987FBC97-4BED-5078-AF07-9141BA07C9F3', + '987FBC97-4BED-5078-BF07-9141BA07C9F3', + '987FBC97-4BED-5078-8F07-9141BA07C9F3', + '987FBC97-4BED-5078-9F07-9141BA07C9F3', + ], + invalid: [ + '', + 'xxxA987FBC9-4BED-3078-CF07-9141BA07C9F3', + '934859', + 'AAAAAAAA-1111-1111-AAAG-111111111111', + '9c858901-8a57-4791-81fe-4c455b099bc9', + 'A987FBC9-4BED-3078-CF07-9141BA07C9F3', + ], + }); + }); + + it('should validate a string that is in another string or array', function () { + test({ validator: 'isIn', args: ['foobar'], valid: ['foo', 'bar', 'foobar', ''], invalid: ['foobarbaz', 'barfoo'] }); - test({ validator: 'isIn', args: [['foo', 'bar']], valid: ['foo', 'bar'], + test({ validator: 'isIn', args: [['foo', 'bar']], valid: ['foo', 'bar'], invalid: ['foobar', 'barfoo', ''] }); - test({ validator: 'isIn', args: [['1', '2', '3']], valid: ['1', '2', '3'], + test({ validator: 'isIn', args: [['1', '2', '3']], valid: ['1', '2', '3'], invalid: ['4', ''] }); - test({ validator: 'isIn', invalid: ['foo', ''] }); + test({ validator: 'isIn', invalid: ['foo', ''] }); + }); + + it('should validate a string that is in another object', function () { + test({ + validator: 'isIn', + args: [{ 'foo': 1, 'bar': 2, 'foobar': 3 }], + valid: ['foo', 'bar', 'foobar'], + invalid: ['foobarbaz', 'barfoo', ''], }); + test({ + validator: 'isIn', + args: [{ 1: 3, 2: 0, 3: 1 }], + valid: ['1', '2', '3'], + invalid: ['4', ''], + }); + }); - it('should validate a string that is in another object', function () { - test({ validator: 'isIn', args: [{'foo':1, 'bar':2, 'foobar':3}], valid: ['foo', 'bar', 'foobar'], - invalid: ['foobarbaz', 'barfoo', ''] }); - test({ validator: 'isIn', args: [{1:3, 2:0, 3:1}], valid: ['1', '2', '3'], - invalid: ['4', ''] }); + it('should validate dates', function () { + test({ + validator: 'isDate', + valid: [ + '2011-08-04', + '2011-09-30', + '04. 08. 2011.', + '08/04/2011', + '08/31/2011', + '2011.08.04', + '2/29/24', + '2-29-24', + '4. 8. 2011. GMT', + '2. 28. 2011. GMT', + '2. 29. 2008. GMT', + '2011-08-04 12:00', + '2/22/23', + '2-23-22', + '12', + '11/2/23 12:24', + new Date().toString(), + 'Mon Aug 17 2015 00:24:56 GMT-0500 (CDT)', + '2/22/23 23:24:26', + // valid ISO 8601 dates below + '2009-12T12:34', + '2009', + '2009-05-19', + '2009-05-19', + '2009-05', + '2009-001', + '2009-05-19', + '2009-05-19 00:00', + '2009-05-19 14:31', + '2009-05-19 14:39:22', + '2009-05-19T14:39Z', + '2009-05-19 14:39:22-06:00', + '2009-05-19 14:39:22+0600', + '2009-05-19 14:39:22-01', + '2015-10-20T00:53:09+08:00', + '2015-10-20T00:53:09+09:00', + '2015-10-20T00:53:09+10:00', + '2015-10-20T00:53:09+11:00', + '2015-10-20T00:53:09+12:00', + '2007-04-06T00:00', + '2010-02-18T16:23:48.5', + '200905', + '2009-', + '2009-05-19 14:', + '200912-01', + // RFC 2882 tests below borrowed from the timerep package in Hackage: + // https://hackage.haskell.org/package/timerep-1.0.3/docs/src/Data-Time-RFC2822.html + 'Fri, 21 Nov 1997 09:55:06 -0600', + 'Tue, 15 Nov 1994 12:45:26 GMT', + 'Tue, 1 Jul 2003 10:52:37 +0200', + 'Thu, 13 Feb 1969 23:32:54 -0330', + 'Mon, 24 Nov 1997 14:22:01 -0800', + 'Mon Sep 28 1964 00:05:49 GMT+1100 (AEDST)', + 'Mon Sep 28 1964 00:05:49 +1100 (AEDST)', + 'Mon Sep 28 1964 00:05:49 +1100', + 'Mon Sep 28 1964 00:05:49 \nGMT\n+1100\n', + 'Mon Sep 28 1964 00:05:49 \nGMT\n+1100\n(AEDST)', + 'Thu, 13\n Feb\n 1969\n 23:32\n -0330', + 'Thu, 13\n Feb\n 1969\n 23:32\n -0330 (Newfoundland Time)', + '24 Nov 1997 14:22:01 -0800', + // slight variations of the above with end-of-month + 'Thu, 29\n Feb\n 1968\n 13:32\n -0330', + 'Fri, 30 Nov 1997 09:55:06 -0600', + // more RFC 2882 tests borrowed from libgit2: + // https://github.com/libgit2/libgit2/blob/master/tests/date/rfc2822.c, + 'Wed, 10 Apr 2014 08:21:03 +0000', + 'Wed, 9 Apr 2014 10:21:03 +0200', + 'Wed, 9 Apr 2014 06:21:03 -0200', + 'Wed, 9 Apr 2014 08:21:03 +0000', + '2016-01-20 07:11', + ], + invalid: [ + 'foo', + '2011-foo-04', + '2011-09-31', + '2. 29. 1987. GMT', + '2. 29. 2011. GMT', + '2/29/25', + '2-29-25', + 'GMT', + // invalid ISO 8601 dates below + '2009367', + '2007-04-05T24:50', + '2009-000', + '2009-M511', + '2009M511', + '2009-05-19T14a39r', + '2009-05-19T14:3924', + '2009-0519', + '2009-05-1914:39', + '2009-05-19r14:39', + '2009-05-19 14a39a22', + '2009-05-19 14:39:22+06a00', + '2009-05-19 146922.500', + '2010-02-18T16.5:23.35:48', + '2010-02-18T16:23.35:48', + '2010-02-18T16:23.35:48.45', + '2009-05-19 14.5.44', + '2010-02-18T16:23.33.600', + '2010-02-18T16,25:23:48,444', + '2009-02-30 14:', + '200912-32', + // hackage RFC2822 variants with invalid end-of-month + 'Thu, 29\n Feb\n 1969\n 13:32\n -0330', + 'Fri, 31 Nov 1997 09:55:06 -0600', + ], + }); + }); + + it('should validate dates against a start date', function () { + test({ validator: 'isAfter', args: ['2011-08-03'], + valid: ['2011-08-04', new Date(2011, 8, 10).toString()], + invalid: ['2010-07-02', '2011-08-03', new Date(0).toString(), 'foo'] }); + test({ validator: 'isAfter', + valid: ['2100-08-04', new Date(Date.now() + 86400000).toString()], + invalid: ['2010-07-02', new Date(0).toString()] }); + test({ validator: 'isAfter', args: ['2011-08-03'], + valid: ['2015-09-17'], + invalid: ['invalid date'] }); + test({ validator: 'isAfter', args: ['invalid date'], + invalid: ['invalid date', '2015-09-17'] }); + }); + + it('should validate dates against an end date', function () { + test({ validator: 'isBefore', args: ['08/04/2011'], + valid: ['2010-07-02', '2010-08-04', new Date(0).toString()], + invalid: ['08/04/2011', new Date(2011, 9, 10).toString()] }); + test({ validator: 'isBefore', args: [new Date(2011, 7, 4).toString()], + valid: ['2010-07-02', '2010-08-04', new Date(0).toString()], + invalid: ['08/04/2011', new Date(2011, 9, 10).toString()] }); + test({ + validator: 'isBefore', + valid: [ + '2000-08-04', + new Date(0).toString(), + new Date(Date.now() - 86400000).toString(), + ], + invalid: ['2100-07-02', new Date(2017, 10, 10).toString()], + }); + test({ validator: 'isBefore', args: ['2011-08-03'], + valid: ['1999-12-31'], + invalid: ['invalid date'] }); + test({ validator: 'isBefore', args: ['invalid date'], + invalid: ['invalid date', '1999-12-31'] }); + }); + + it('should validate that integer strings are divisible by a number', function () { + test({ + validator: 'isDivisibleBy', + args: [2], + valid: ['2', '4', '100', '1000'], + invalid: [ + '1', + '2.5', + '101', + 'foo', + '', + ], + }); + }); + + it('should validate credit cards', function () { + test({ + validator: 'isCreditCard', + valid: [ + '375556917985515', + '36050234196908', + '4716461583322103', + '4716-2210-5188-5662', + '4929 7226 5379 7141', + '5398228707871527', + ], + invalid: [ + 'foo', + 'foo', + '5398228707871528', + ], + }); + }); + + it('should validate ISINs', function () { + test({ + validator: 'isISIN', + valid: [ + 'AU0000XVGZA3', + 'DE000BAY0017', + 'BE0003796134', + 'SG1G55870362', + 'GB0001411924', + 'DE000WCH8881', + 'PLLWBGD00016', + ], + invalid: [ + 'DE000BAY0018', + 'PLLWBGD00019', + 'foo', + '5398228707871528', + ], + }); + }); + + it('should validate ISBNs', function () { + test({ + validator: 'isISBN', + args: [10], + valid: [ + '3836221195', '3-8362-2119-5', '3 8362 2119 5', + '1617290858', '1-61729-085-8', '1 61729 085-8', + '0007269706', '0-00-726970-6', '0 00 726970 6', + '3423214120', '3-423-21412-0', '3 423 21412 0', + '340101319X', '3-401-01319-X', '3 401 01319 X', + ], + invalid: [ + '3423214121', '3-423-21412-1', '3 423 21412 1', + '978-3836221191', '9783836221191', + '123456789a', 'foo', '', + ], + }); + test({ + validator: 'isISBN', + args: [13], + valid: [ + '9783836221191', '978-3-8362-2119-1', '978 3 8362 2119 1', + '9783401013190', '978-3401013190', '978 3401013190', + '9784873113685', '978-4-87311-368-5', '978 4 87311 368 5', + ], + invalid: [ + '9783836221190', '978-3-8362-2119-0', '978 3 8362 2119 0', + '3836221195', '3-8362-2119-5', '3 8362 2119 5', + '01234567890ab', 'foo', '', + ], + }); + test({ + validator: 'isISBN', + valid: [ + '340101319X', + '9784873113685', + ], + invalid: [ + '3423214121', + '9783836221190', + ], + }); + test({ + validator: 'isISBN', + args: ['foo'], + invalid: [ + '340101319X', + '9784873113685', + ], + }); + }); + + it('should validate JSON', function () { + test({ + validator: 'isJSON', + valid: [ + '{ "key": "value" }', + '{}', + ], + invalid: [ + '{ key: "value" }', + '{ \'key\': \'value\' }', + 'null', + '1234', + 'false', + '"nope"', + ], + }); + }); + + it('should validate multibyte strings', function () { + test({ + validator: 'isMultibyte', + valid: [ + 'ひらがな・カタカナ、.漢字', + 'あいうえお foobar', + 'test@example.com', + '1234abcDExyz', + 'カタカナ', + '中文', + ], + invalid: [ + 'abc', + 'abc123', + '<>@" *.', + ], + }); + }); + + it('should validate ascii strings', function () { + test({ + validator: 'isAscii', + valid: [ + 'foobar', + '0987654321', + 'test@example.com', + '1234abcDEF', + ], + invalid: [ + 'foobar', + 'xyz098', + '123456', + 'カタカナ', + ], + }); + }); + + it('should validate full-width strings', function () { + test({ + validator: 'isFullWidth', + valid: [ + 'ひらがな・カタカナ、.漢字', + '3ー0 a@com', + 'Fカタカナ゙ᆲ', + 'Good=Parts', + ], + invalid: [ + 'abc', + 'abc123', + '!"#$%&()<>/+=-_? ~^|.,@`{}[]', + ], }); + }); - it('should validate dates', function () { - test({ - validator: 'isDate' - , valid: [ - '2011-08-04' - , '2011-09-30' - , '04. 08. 2011.' - , '08/04/2011' - , '08/31/2011' - , '2011.08.04' - , '2/29/24' - , '2-29-24' - , '4. 8. 2011. GMT' - , '2. 28. 2011. GMT' - , '2. 29. 2008. GMT' - , '2011-08-04 12:00' - , '2/22/23' - , '2-23-22' - , '12' - , '11/2/23 12:24' - , new Date().toString() - , 'Mon Aug 17 2015 00:24:56 GMT-0500 (CDT)' - , '2/22/23 23:24:26' - // valid ISO 8601 dates below - , '2009-12T12:34' - , '2009' - , '2009-05-19' - , '2009-05-19' - , '2009-05' - , '2009-001' - , '2009-05-19' - , '2009-05-19 00:00' - , '2009-05-19 14:31' - , '2009-05-19 14:39:22' - , '2009-05-19T14:39Z' - , '2009-05-19 14:39:22-06:00' - , '2009-05-19 14:39:22+0600' - , '2009-05-19 14:39:22-01' - , '2015-10-20T00:53:09+08:00' - , '2015-10-20T00:53:09+09:00' - , '2015-10-20T00:53:09+10:00' - , '2015-10-20T00:53:09+11:00' - , '2015-10-20T00:53:09+12:00' - , '2007-04-06T00:00' - , '2010-02-18T16:23:48.5' - , '200905' - , '2009-' - , '2009-05-19 14:' - , '200912-01' - // RFC 2882 tests below borrowed from the timerep package in Hackage: - // https://hackage.haskell.org/package/timerep-1.0.3/docs/src/Data-Time-RFC2822.html - , 'Fri, 21 Nov 1997 09:55:06 -0600' - , 'Tue, 15 Nov 1994 12:45:26 GMT' - , 'Tue, 1 Jul 2003 10:52:37 +0200' - , 'Thu, 13 Feb 1969 23:32:54 -0330' - , 'Mon, 24 Nov 1997 14:22:01 -0800' - , 'Mon Sep 28 1964 00:05:49 GMT+1100 (AEDST)' - , 'Mon Sep 28 1964 00:05:49 +1100 (AEDST)' - , 'Mon Sep 28 1964 00:05:49 +1100' - , 'Mon Sep 28 1964 00:05:49 \nGMT\n+1100\n' - , 'Mon Sep 28 1964 00:05:49 \nGMT\n+1100\n(AEDST)' - , 'Thu, 13\n Feb\n 1969\n 23:32\n -0330' - , 'Thu, 13\n Feb\n 1969\n 23:32\n -0330 (Newfoundland Time)' - ,'24 Nov 1997 14:22:01 -0800' - // slight variations of the above with end-of-month - , 'Thu, 29\n Feb\n 1968\n 13:32\n -0330' - , 'Fri, 30 Nov 1997 09:55:06 -0600' - // more RFC 2882 tests borrowed from libgit2: - // https://github.com/libgit2/libgit2/blob/master/tests/date/rfc2822.c - , 'Wed, 10 Apr 2014 08:21:03 +0000' - , 'Wed, 9 Apr 2014 10:21:03 +0200' - , 'Wed, 9 Apr 2014 06:21:03 -0200' - , 'Wed, 9 Apr 2014 08:21:03 +0000' - , '2016-01-20 07:11' - ] - , invalid: [ - 'foo' - , '2011-foo-04' - , '2011-09-31' - , '2. 29. 1987. GMT' - , '2. 29. 2011. GMT' - , '2/29/25' - , '2-29-25' - , 'GMT' - //invalid ISO 8601 dates below - , '2009367' - , '2007-04-05T24:50' - , '2009-000' - , '2009-M511' - , '2009M511' - , '2009-05-19T14a39r' - , '2009-05-19T14:3924' - , '2009-0519' - , '2009-05-1914:39' - , '2009-05-19r14:39' - , '2009-05-19 14a39a22' - , '2009-05-19 14:39:22+06a00' - , '2009-05-19 146922.500' - , '2010-02-18T16.5:23.35:48' - , '2010-02-18T16:23.35:48' - , '2010-02-18T16:23.35:48.45' - , '2009-05-19 14.5.44' - , '2010-02-18T16:23.33.600' - , '2010-02-18T16,25:23:48,444' - , '2009-02-30 14:' - , '200912-32' - // hackage RFC2822 variants with invalid end-of-month - , 'Thu, 29\n Feb\n 1969\n 13:32\n -0330' - , 'Fri, 31 Nov 1997 09:55:06 -0600' - ] - }); - }); - - it('should validate dates against a start date', function () { - test({ validator: 'isAfter', args: ['2011-08-03'], - valid: [ '2011-08-04', new Date(2011, 8, 10).toString() ], - invalid: [ '2010-07-02', '2011-08-03', new Date(0).toString(), 'foo'] }); - test({ validator: 'isAfter', - valid: [ '2100-08-04', new Date(Date.now() + 86400000).toString() ], - invalid: [ '2010-07-02', new Date(0).toString() ] }); - test({ validator: 'isAfter', args: ['2011-08-03'], - valid: [ '2015-09-17' ], - invalid: [ 'invalid date' ] }); - test({ validator: 'isAfter', args: ['invalid date'], - invalid: [ 'invalid date', '2015-09-17' ] }); - }); - - it('should validate dates against an end date', function () { - test({ validator: 'isBefore', args: ['08/04/2011'], - valid: [ '2010-07-02', '2010-08-04', new Date(0).toString() ], - invalid: [ '08/04/2011', new Date(2011, 9, 10).toString() ] }); - test({ validator: 'isBefore', args: [ new Date(2011, 7, 4).toString() ], - valid: [ '2010-07-02', '2010-08-04', new Date(0).toString() ], - invalid: [ '08/04/2011', new Date(2011, 9, 10).toString() ] }); - test({ validator: 'isBefore', - valid: [ '2000-08-04', new Date(0).toString(), new Date(Date.now() - 86400000).toString() ], - invalid: [ '2100-07-02', new Date(2017, 10, 10).toString() ] }); - test({ validator: 'isBefore', args: ['2011-08-03'], - valid: [ '1999-12-31' ], - invalid: [ 'invalid date' ] }); - test({ validator: 'isBefore', args: ['invalid date'], - invalid: [ 'invalid date', '1999-12-31' ] }); - }); - - it('should validate that integer strings are divisible by a number', function () { - test({ - validator: 'isDivisibleBy' - , args: [ 2 ] - , valid: [ '2', '4', '100', '1000' ] - , invalid: [ - '1' - , '2.5' - , '101' - , 'foo' - , '' - ] - }); - }); - - it('should validate credit cards', function () { - test({ - validator: 'isCreditCard' - , valid: [ - '375556917985515' - , '36050234196908' - , '4716461583322103' - , '4716-2210-5188-5662' - , '4929 7226 5379 7141' - , '5398228707871527' - ] - , invalid: [ - 'foo' - , 'foo' - , '5398228707871528' - ] - }); - }); - - it('should validate ISINs', function () { - test({ - validator: 'isISIN' - , valid: [ - 'AU0000XVGZA3' - , 'DE000BAY0017' - , 'BE0003796134' - , 'SG1G55870362' - , 'GB0001411924' - , 'DE000WCH8881' - , 'PLLWBGD00016' - ] - , invalid: [ - 'DE000BAY0018' - , 'PLLWBGD00019' - , 'foo' - , '5398228707871528' - ] - }); - }); - - it('should validate ISBNs', function () { - test({ - validator: 'isISBN' - , args: [ 10 ] - , valid: [ - '3836221195', '3-8362-2119-5', '3 8362 2119 5' - , '1617290858', '1-61729-085-8', '1 61729 085-8' - , '0007269706', '0-00-726970-6', '0 00 726970 6' - , '3423214120', '3-423-21412-0', '3 423 21412 0' - , '340101319X', '3-401-01319-X', '3 401 01319 X' - ] - , invalid: [ - '3423214121', '3-423-21412-1', '3 423 21412 1' - , '978-3836221191', '9783836221191' - , '123456789a', 'foo', '' - ] - }); - test({ - validator: 'isISBN' - , args: [ 13 ] - , valid: [ - '9783836221191', '978-3-8362-2119-1', '978 3 8362 2119 1' - , '9783401013190', '978-3401013190', '978 3401013190' - , '9784873113685', '978-4-87311-368-5', '978 4 87311 368 5' - ] - , invalid: [ - '9783836221190', '978-3-8362-2119-0', '978 3 8362 2119 0' - , '3836221195', '3-8362-2119-5', '3 8362 2119 5' - , '01234567890ab', 'foo', '' - ] - }); - test({ - validator: 'isISBN' - , valid: [ - '340101319X' - , '9784873113685' - ] - , invalid: [ - '3423214121' - , '9783836221190' - ] - }); - test({ - validator: 'isISBN' - , args: [ 'foo' ] - , invalid: [ - '340101319X' - , '9784873113685' - ] - }); - }); - - it('should validate JSON', function () { - test({ - validator: 'isJSON' - , valid: [ - '{ "key": "value" }' - , '{}' - ] - , invalid: [ - '{ key: "value" }' - , '{ \'key\': \'value\' }' - , 'null' - , '1234' - , 'false' - , '"nope"' - ] - }); - }); - - it('should validate multibyte strings', function () { - test({ - validator: 'isMultibyte' - , valid: [ - 'ひらがな・カタカナ、.漢字' - , 'あいうえお foobar' - , 'test@example.com' - , '1234abcDExyz' - , 'カタカナ' - , '中文' - ] - , invalid: [ - 'abc' - , 'abc123' - , '<>@" *.' - ] - }); - }); - - it('should validate ascii strings', function () { - test({ - validator: 'isAscii' - , valid: [ - 'foobar' - , '0987654321' - , 'test@example.com' - , '1234abcDEF' - ] - , invalid: [ - 'foobar' - , 'xyz098' - , '123456' - , 'カタカナ' - ] - }); - }); - - it('should validate full-width strings', function () { - test({ - validator: 'isFullWidth' - , valid: [ - 'ひらがな・カタカナ、.漢字' - , '3ー0 a@com' - , 'Fカタカナ゙ᆲ' - , 'Good=Parts' - ] - , invalid: [ - 'abc' - , 'abc123' - , '!"#$%&()<>/+=-_? ~^|.,@`{}[]' - ] - }); - }); - - it('should validate half-width strings', function () { - test({ - validator: 'isHalfWidth' - , valid: [ - '!"#$%&()<>/+=-_? ~^|.,@`{}[]' - , 'l-btn_02--active' - , 'abc123い' - , 'カタカナ゙ᆲ←' - ] - , invalid: [ - 'あいうえお' - , '0011' - ] - }); - }); - - it('should validate variable-width strings', function () { - test({ - validator: 'isVariableWidth' - , valid: [ - 'ひらがなカタカナ漢字ABCDE' - , '3ー0123' - , 'Fカタカナ゙ᆲ' - , 'Good=Parts' - ] - , invalid: [ - 'abc' - , 'abc123' - , '!"#$%&()<>/+=-_? ~^|.,@`{}[]' - , 'ひらがな・カタカナ、.漢字' - , '123456' - , 'カタカナ゙ᆲ' - ] - }); - }); - - it('should validate surrogate pair strings', function () { - test({ - validator: 'isSurrogatePair' - , valid: [ - '𠮷野𠮷' - , '𩸽' - , 'ABC千𥧄1-2-3' - ] - , invalid: [ - '吉野竈' - , '鮪' - , 'ABC1-2-3' - ] - }); - }); - - it('should validate base64 strings', function () { - test({ - validator: 'isBase64' - , valid: [ - 'TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=' - , 'Vml2YW11cyBmZXJtZW50dW0gc2VtcGVyIHBvcnRhLg==' - , 'U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==' - , 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuMPNS1Ufof9EW/M98FNw'+ - 'UAKrwflsqVxaxQjBQnHQmiI7Vac40t8x7pIb8gLGV6wL7sBTJiPovJ0V7y7oc0Ye'+ - 'rhKh0Rm4skP2z/jHwwZICgGzBvA0rH8xlhUiTvcwDCJ0kc+fh35hNt8srZQM4619'+ - 'FTgB66Xmp4EtVyhpQV+t02g6NzK72oZI0vnAvqhpkxLeLiMCyrI416wHm5Tkukhx'+ - 'QmcL2a6hNOyu0ixX/x2kSFXApEnVrJ+/IxGyfyw8kf4N2IZpW5nEP847lpfj0SZZ'+ - 'Fwrd1mnfnDbYohX2zRptLy2ZUn06Qo9pkG5ntvFEPo9bfZeULtjYzIl6K8gJ2uGZ'+ - 'HQIDAQAB' - ] - , invalid: [ - '12345' - , '' - , 'Vml2YW11cyBmZXJtZtesting123' - ] - }); - for (var i = 0, str = '', encoded; i < 1000; i++) { - str += String.fromCharCode(Math.random() * 26 | 97); - encoded = new Buffer(str).toString('base64'); - if (!validator.isBase64(encoded)) { - var msg = format('validator.isBase64() failed with "%s"', encoded); - throw new Error(msg); - } - } - }); - - it('should validate hex-encoded MongoDB ObjectId', function () { - test({ - validator: 'isMongoId' - , valid: [ - '507f1f77bcf86cd799439011' - ] - , invalid: [ - '507f1f77bcf86cd7994390' - , '507f1f77bcf86cd79943901z' - , '' - , '507f1f77bcf86cd799439011 ' - ] - }); - }); - - it('should define the module using an AMD-compatible loader', function () { - var window = { - validator: null - , define: function (module) { - window.validator = module(); - } - }; - window.define.amd = true; - - var sandbox = vm.createContext(window); - vm.runInContext(validator_js, sandbox); - assert.equal(window.validator.trim(' foobar '), 'foobar'); - }); - - it('should bind validator to the window if no module loaders are available', function () { - var window = {}; - var sandbox = vm.createContext(window); - vm.runInContext(validator_js, sandbox); - assert.equal(window.validator.trim(' foobar '), 'foobar'); - }); - - it('should validate mobile phone number', function () { - test({ - validator: 'isMobilePhone' - , valid: [ - '0944549710' - , '+963944549710' - , '956654379' - , '0944549710' - , '0962655597' - ] - , invalid: [ - '12345' - , '' - , '+9639626626262' - , '+963332210972' - , '0114152198' - ], - args: ['ar-SY'] - }); - - test({ - validator: 'isMobilePhone' - , valid: [ - '+49 (0) 123 456 789' - , '+49 (0) 123 456789' - , '0123/4567890' - , '+49 01234567890' - , '01234567890' - ] - , invalid: [ - '' - , 'Vml2YW11cyBmZXJtZtesting123' - ], - args: ['de-DE'] - }); - - test({ - validator: 'isMobilePhone' - , valid: [ - '55-17-3332-2155' - , '55-15-25661234' - , '551223456789' - , '01523456987' - , '022995678947' - , '+55-12-996551215' - ] - , invalid: [ - '+017-123456789' - , '5501599623874' - , '+55012962308' - , '+55-015-1234-3214' - ], - args: ['pt-BR'] - }); - - test({ - validator: 'isMobilePhone' - , valid: [ - '15323456787' - , '13523333233' - , '13898728332' - , '+086-13238234822' - , '08613487234567' - , '8617823492338' - , '86-17823492338' - ] - , invalid: [ - '12345' - , '' - , 'Vml2YW11cyBmZXJtZtesting123' - , '010-38238383' - ], - args: ['zh-CN'] - }); - - test({ - validator: 'isMobilePhone' - , valid: [ - '0987123456' - , '+886987123456' - , '886987123456' - , '+886-987123456' - , '886-987123456' - ] - , invalid: [ - '12345' - , '' - , 'Vml2YW11cyBmZXJtZtesting123' - , '0-987123456' - ], - args: ['zh-TW'] - }); - - test({ - validator: 'isMobilePhone' - , invalid: [ - '15323456787' - , '13523333233' - , '13898728332' - , '+086-13238234822' - , '08613487234567' - , '8617823492338' - , '86-17823492338' - ], - args: ['en'] - }); - - test({ - validator: 'isMobilePhone' - , valid: [ - '0821231234' - , '+27821231234' - , '27821231234' - ] - , invalid: [ - '082123' - , '08212312345' - , '21821231234' - , '+21821231234' - , '+0821231234' - ], - args: ['en-ZA'] - }); - - test({ - validator: 'isMobilePhone' - , valid: [ - '61404111222' - , '+61411222333' - , '0417123456' - ] - , invalid: [ - '082123' - , '08212312345' - , '21821231234' - , '+21821231234' - , '+0821231234' - , '04123456789' - ], - args: ['en-AU'] - }); - - test({ - validator: 'isMobilePhone' - , valid: [ - '91234567' - , '9123-4567' - , '61234567' - , '51234567' - , '+85291234567' - , '+852-91234567' - , '+852-9123-4567' - , '852-91234567' - ] - , invalid: [ - '999' - , '+852-912345678' - , '123456789' - , '+852-1234-56789' - ], - args: ['en-HK'] - }); - - test({ - validator: 'isMobilePhone' - , valid: [ - '0612457898' - , '+33612457898' - , '33612457898' - , '0712457898' - , '+33712457898' - , '33712457898' - ] - , invalid: [ - '061245789' - , '06124578980' - , '0112457898' - , '0212457898' - , '0312457898' - , '0412457898' - , '0512457898' - , '0812457898' - , '0912457898' - , '+34612457898' - , '+336124578980' - , '+3361245789' - ] - , args: ['fr-FR'] - }); - - test({ - validator: 'isMobilePhone' - , valid: [ - '+306944848966' - , '6944848966' - , '306944848966' - ] - , invalid: [ - '2102323234' - , '+302646041461' - , '120000000' - , '20000000000' - , '68129485729' - , '6589394827' - , '298RI89572' - ] - , args: ['el-GR'] - }); - - test({ - validator: 'isMobilePhone' - , valid: [ - '447789345856' - , '+447861235675' - , '07888814488' - ] - , invalid: [ - '67699567' - , '0773894868' - , '077389f8688' - , '+07888814488' - , '0152456999' - , '442073456754' - , '+443003434751' - , '05073456754' - , '08001123123' - ] - , args: ['en-GB'] - }); - - test({ - validator: 'isMobilePhone' - , valid: [ - '19876543210' - , '8005552222' - , '+15673628910' - ] - , invalid: [ - '564785' - , '0123456789' - , '1437439210' - , '8009112340' - , '+10345672645' - , '11435213543' - , '2436119753' - , '16532116190' - ] - , args: ['en-US'] - }); - - test({ - validator: 'isMobilePhone' - , valid: [ - '0956684590' - , '0966684590' - , '0976684590' - , '+260956684590' - , '+260966684590' - , '+260976684590' - , '260976684590' - ] - , invalid: [ - '12345' - , '' - , 'Vml2YW11cyBmZXJtZtesting123' - , '010-38238383' - , '966684590' - ], - args: ['en-ZM'] - }); - - test({ - validator: 'isMobilePhone' - , valid: [ - '+79676338855' - , '79676338855' - , '89676338855' - , '9676338855' - ] - , invalid: [ - '12345' - , '' - , 'Vml2YW11cyBmZXJtZtesting123' - , '010-38238383' - , '+9676338855' - , '19676338855' - , '6676338855' - , '+99676338855' - ], - args: ['ru-RU'] - }); - - test({ - validator: 'isMobilePhone' - , valid: [ - '+6427987035' - , '642240512347' - , '0293981646' - , '029968425' - ] - , invalid: [ - '12345' - , '' - , 'Vml2YW11cyBmZXJtZtesting123' - , '+642956696123566' - , '+02119620856' - , '+9676338855' - , '19676338855' - , '6676338855' - , '+99676338855' - ], - args: ['en-NZ'] - }); - - var norwegian = { - valid: [ - '+4796338855' - , '+4746338855' - , '4796338855' - , '4746338855' - , '46338855' - , '96338855' - ] - , invalid: [ - '12345' - , '' - , 'Vml2YW11cyBmZXJtZtesting123' - , '+4676338855' - , '19676338855' - , '+4726338855' - , '4736338855' - , '66338855' - ]}; - test({ - validator: 'isMobilePhone' - , valid: norwegian.valid - , invalid: norwegian.invalid, - args: ['nb-NO'] - }); - test({ - validator: 'isMobilePhone' - , valid: norwegian.valid - , invalid: norwegian.invalid, - args: ['nn-NO'] - }); - - test({ - validator: 'isMobilePhone' - , valid: [ - '01636012403' - , '+841636012403' - , '1636012403' - , '841636012403' - , '+84999999999' - , '84999999999' - , '0999999999' - , '999999999' - ] - , invalid: [ - '12345' - , '' - , 'Vml2YW11cyBmZXJtZtesting123' - , '010-38238383' - , '260976684590' - ], - args: ['vi-VN'] - }); - - test({ - validator: 'isMobilePhone' - , valid: [ - '+34654789321' - , '654789321' - , '+34714789321' - , '714789321' - , '+34744789321' - , '744789321' - ] - , invalid: [ - '12345' - , '' - , 'Vml2YW11cyBmZXJtZtesting123' - , '+3465478932' - , '65478932' - , '+346547893210' - , '6547893210' - , '+34704789321' - , '704789321' - , '+34754789321' - , '754789321' - ], - args: ['es-ES'] - }); - }); - - test({ - validator: 'isMobilePhone' - , valid: [ - '+358505557171' - , '0455571' - , '0505557171' - , '358505557171' - , '04412345' - , '0457 123 45 67' - , '+358457 123 45 67' - , '+358 50 555 7171' - ] - , invalid: [ - '12345' - , '' - , '045557' - , '045555717112312332423423421' - , 'Vml2YW11cyBmZXJtZtesting123' - , '010-38238383' - , '+3-585-0555-7171' - , '+9676338855' - , '19676338855' - , '6676338855' - , '+99676338855' - , '044123' - , '019123456789012345678901' - ], - args: ['fi-FI'] - }); - - it('should validate currency', function() { - test({ - validator: 'isCurrency' - , args: [ - {} - , '-$##,###.## (en-US, en-CA, en-AU, en-NZ, en-HK)' - ] - , valid: [ - '-$10,123.45' - , '$10,123.45' - , '$10123.45' - , '10,123.45' - , '10123.45' - , '10,123' - , '1,123,456' - , '1123456' - , '1.39' - , '.03' - , '0.10' - , '$0.10' - , '-$0.01' - , '-$.99' - , '$100,234,567.89' - , '$10,123' - , '10,123' - , '-10123' - ] - , invalid: [ - '1.234' - , '$1.1' - , '$ 32.50' - , '500$' - , '.0001' - , '$.001' - , '$0.001' - , '12,34.56' - , '123456,123,123456' - , '123,4' - , ',123' - , '$-,123' - , '$' - , '.' - , ',' - , '00' - , '$-' - , '$-,.' - , '-' - , '-$' - , '' - , '- $' - ] - }); - - test({ - validator: 'isCurrency' - , args: [ - { - require_symbol: true - } - , '-$##,###.## with $ required (en-US, en-CA, en-AU, en-NZ, en-HK)' - ] - , valid: [ - '-$10,123.45' - , '$10,123.45' - , '$10123.45' - , '$10,123.45' - , '$10,123' - , '$1,123,456' - , '$1123456' - , '$1.39' - , '$.03' - , '$0.10' - , '$0.10' - , '-$0.01' - , '-$.99' - , '$100,234,567.89' - , '$10,123' - , '-$10123' - ] - , invalid: [ - '1.234' - , '$1.234' - , '1.1' - , '$1.1' - , '$ 32.50' - , ' 32.50' - , '500' - , '10,123,456' - , '.0001' - , '$.001' - , '$0.001' - , '1,234.56' - , '123456,123,123456' - , '$123456,123,123456' - , '123.4' - , '$123.4' - , ',123' - , '$,123' - , '$-,123' - , '$' - , '.' - , '$.' - , ',' - , '$,' - , '00' - , '$00' - , '$-' - , '$-,.' - , '-' - , '-$' - , '' - , '$ ' - , '- $' - ] - }); - - test({ - validator: 'isCurrency' - , args: [ - { - symbol:'¥' - , negative_sign_before_digits:true - } - , '¥-##,###.## (zh-CN)' - ] - , valid: [ - '123,456.78' - , '-123,456.78' - , '¥6,954,231' - , '¥-6,954,231' - , '¥10.03' - , '¥-10.03' - , '10.03' - , '1.39' - , '.03' - , '0.10' - , '¥-10567.01' - , '¥0.01' - , '¥1,234,567.89' - , '¥10,123' - , '¥-10,123' - , '¥-10,123.45' - , '10,123' - , '10123' - , '¥-100' - ] - , invalid: [ - '1.234' - , '¥1.1' - , '5,00' - , '.0001' - , '¥.001' - , '¥0.001' - , '12,34.56' - , '123456,123,123456' - , '123 456' - , ',123' - , '¥-,123' - , '' - , ' ' - , '¥' - , '¥-' - , '¥-,.' - , '-' - , '- ¥' - , '-¥' - ] - }); - - test({ - validator: 'isCurrency' - , args: [ - { - symbol:'¥' - , allow_negatives: false - } - , '¥##,###.## with no negatives (zh-CN)' - ] - , valid: [ - '123,456.78' - , '¥6,954,231' - , '¥10.03' - , '10.03' - , '1.39' - , '.03' - , '0.10' - , '¥0.01' - , '¥1,234,567.89' - , '¥10,123' - , '10,123' - , '10123' - , '¥100' - ] - , invalid: [ - '1.234' - , '-123,456.78' - , '¥-6,954,231' - , '¥-10.03' - , '¥-10567.01' - , '¥1.1' - , '¥-10,123' - , '¥-10,123.45' - , '5,00' - , '¥-100' - , '.0001' - , '¥.001' - , '¥-.001' - , '¥0.001' - , '12,34.56' - , '123456,123,123456' - , '123 456' - , ',123' - , '¥-,123' - , '' - , ' ' - , '¥' - , '¥-' - , '¥-,.' - , '-' - , '- ¥' - , '-¥' - ] - }); - - test({ - validator: 'isCurrency' - , args: [ - { - symbol: 'R' - , negative_sign_before_digits: true - , thousands_separator: ' ' - , decimal_separator: ',' - , allow_negative_sign_placeholder: true - } - , 'R ## ###,## and R-10 123,25 (el-ZA)' - ] - , valid: [ - '123 456,78' - , '-10 123' - , 'R-10 123' - , 'R 6 954 231' - , 'R10,03' - , '10,03' - , '1,39' - , ',03' - , '0,10' - , 'R10567,01' - , 'R0,01' - , 'R1 234 567,89' - , 'R10 123' - , 'R 10 123' - , 'R 10123' - , 'R-10123' - , '10 123' - , '10123' - ] - , invalid: [ - '1,234' - , 'R -10123' - , 'R- 10123' - , 'R,1' - , ',0001' - , 'R,001' - , 'R0,001' - , '12 34,56' - , '123456 123 123456' - , ' 123' - , '- 123' - , '123 ' - , '' - , ' ' - , 'R' - , 'R- .1' - , 'R-' - , '-' - , '-R 10123' - , 'R00' - , 'R -' - , '-R' - ] - }); - - test({ - validator: 'isCurrency' - , args: [ - { - symbol: '€' - , thousands_separator: '.' - , decimal_separator: ',' - , allow_space_after_symbol: true - } - , '-€ ##.###,## (it-IT)' - ] - , valid: [ - '123.456,78' - , '-123.456,78' - , '€6.954.231' - , '-€6.954.231' - , '€ 896.954.231' - , '-€ 896.954.231' - , '16.954.231' - , '-16.954.231' - , '€10,03' - , '-€10,03' - , '10,03' - , '-10,03' - , '-1,39' - , ',03' - , '0,10' - , '-€10567,01' - , '-€ 10567,01' - , '€ 0,01' - , '€1.234.567,89' - , '€10.123' - , '10.123' - , '-€10.123' - , '€ 10.123' - , '€10.123' - , '€ 10123' - , '10.123' - , '-10123' - ] - , invalid: [ - '1,234' - , '€ 1,1' - , '50#,50' - , '123,@€ ' - , '€€500' - , ',0001' - , '€ ,001' - , '€0,001' - , '12.34,56' - , '123456.123.123456' - , '€123€' - , '' - , ' ' - , '€' - , ' €' - , '€ ' - , '€€' - , ' 123' - , '- 123' - , '.123' - , '-€.123' - , '123 ' - , '€-' - , '- €' - , '€ - ' - , '-' - , '- ' - , '-€' - ] - }); - - test({ - validator: 'isCurrency' - , args: [ - { - symbol: '€' - , thousands_separator: '.' - , symbol_after_digits: true - , decimal_separator: ',' - , allow_space_after_digits: true - } - , '-##.###,## € (el-GR)' - ] - , valid: [ - '123.456,78' - , '-123.456,78' - , '6.954.231 €' - , '-6.954.231 €' - , '896.954.231' - , '-896.954.231' - , '16.954.231' - , '-16.954.231' - , '10,03€' - , '-10,03€' - , '10,03' - , '-10,03' - , '1,39' - , ',03' - , '-,03' - , '-,03 €' - , '-,03€' - , '0,10' - , '10567,01€' - , '0,01 €' - , '1.234.567,89€' - , '10.123€' - , '10.123' - , '10.123€' - , '10.123 €' - , '10123 €' - , '10.123' - , '10123' - ] - , invalid: [ - '1,234' - , '1,1 €' - , ',0001' - , ',001 €' - , '0,001€' - , '12.34,56' - , '123456.123.123456' - , '€123€' - , '' - , ' ' - , '€' - , ' €' - , '€ ' - , ' 123' - , '- 123' - , '.123' - , '-.123€' - , '-.123 €' - , '123 ' - , '-€' - , '- €' - , '-' - , '- ' - ] - }); - - test({ - validator: 'isCurrency' - , args: [ - { - symbol: 'kr.' - , negative_sign_before_digits: true - , thousands_separator: '.' - , decimal_separator: ',' - , allow_space_after_symbol: true - } - , 'kr. -##.###,## (da-DK)' - ] - , valid: [ - '123.456,78' - , '-10.123' - , 'kr. -10.123' - , 'kr.-10.123' - , 'kr. 6.954.231' - , 'kr.10,03' - , 'kr. -10,03' - , '10,03' - , '1,39' - , ',03' - , '0,10' - , 'kr. 10567,01' - , 'kr. 0,01' - , 'kr. 1.234.567,89' - , 'kr. -1.234.567,89' - , '10.123' - , 'kr. 10.123' - , 'kr.10.123' - , '10123' - , '10.123' - , 'kr.-10123' - ] - , invalid: [ - '1,234' - , 'kr. -10123' - , 'kr.,1' - , ',0001' - , 'kr. ,001' - , 'kr.0,001' - , '12.34,56' - , '123456.123.123456' - , '.123' - , 'kr.-.123' - , 'kr. -.123' - , '- 123' - , '123 ' - , '' - , ' ' - , 'kr.' - , ' kr.' - , 'kr. ' - , 'kr.-' - , 'kr. -' - , 'kr. - ' - , ' - ' - , '-' - , '- kr.' - , '-kr.' - ] - }); - - test({ - validator: 'isCurrency' - , args: [ - { - symbol: 'kr.' - , allow_negatives: false - , negative_sign_before_digits: true - , thousands_separator: '.' - , decimal_separator: ',' - , allow_space_after_symbol: true - } - , 'kr. ##.###,## with no negatives (da-DK)' - ] - , valid: [ - '123.456,78' - , '10.123' - , 'kr. 10.123' - , 'kr.10.123' - , 'kr. 6.954.231' - , 'kr.10,03' - , 'kr. 10,03' - , '10,03' - , '1,39' - , ',03' - , '0,10' - , 'kr. 10567,01' - , 'kr. 0,01' - , 'kr. 1.234.567,89' - , 'kr.1.234.567,89' - , '10.123' - , 'kr. 10.123' - , 'kr.10.123' - , '10123' - , '10.123' - , 'kr.10123' - ] - , invalid: [ - '1,234' - , '-10.123' - , 'kr. -10.123' - , 'kr. -1.234.567,89' - , 'kr.-10123' - , 'kr. -10123' - , 'kr.-10.123' - , 'kr. -10,03' - , 'kr.,1' - , ',0001' - , 'kr. ,001' - , 'kr.0,001' - , '12.34,56' - , '123456.123.123456' - , '.123' - , 'kr.-.123' - , 'kr. -.123' - , '- 123' - , '123 ' - , '' - , ' ' - , 'kr.' - , ' kr.' - , 'kr. ' - , 'kr.-' - , 'kr. -' - , 'kr. - ' - , ' - ' - , '-' - , '- kr.' - , '-kr.' - ] - }); - - test({ - validator: 'isCurrency' - , args: [ - { - parens_for_negatives: true - } - , '($##,###.##) (en-US, en-HK)' - ] - , valid: [ - '1,234' - , '(1,234)' - , '($6,954,231)' - , '$10.03' - , '(10.03)' - , '($10.03)' - , '1.39' - , '.03' - , '(.03)' - , '($.03)' - , '0.10' - , '$10567.01' - , '($0.01)' - , '$1,234,567.89' - , '$10,123' - , '(10,123)' - , '10123' - ] - , invalid: [ - '1.234' - , '($1.1)' - , '-$1.10' - , '$ 32.50' - , '500$' - , '.0001' - , '$.001' - , '($0.001)' - , '12,34.56' - , '123456,123,123456' - , '( 123)' - , ',123' - , '$-,123' - , '' - , ' ' - , ' ' - , ' ' - , '$' - , '$ ' - , ' $' - , ' 123' - , '(123) ' - , '.' - , ',' - , '00' - , '$-' - , '$ - ' - , '$- ' - , ' - ' - , '-' - , '- $' - , '-$' - , '()' - , '( )' - , '( -)' - , '( - )' - , '( - )' - , '(-)' - , '(-$)' - ] - }); - - test({ - validator: 'isCurrency' - , args: [ - {allow_negatives: false} - , '$##,###.## with no negatives (en-US, en-CA, en-AU, en-HK)' - ] - , valid: [ - '$10,123.45' - , '$10123.45' - , '10,123.45' - , '10123.45' - , '10,123' - , '1,123,456' - , '1123456' - , '1.39' - , '.03' - , '0.10' - , '$0.10' - , '$100,234,567.89' - , '$10,123' - , '10,123' - ] - , invalid: [ - '1.234' - , '-1.234' - , '-10123' - , '-$0.01' - , '-$.99' - , '$1.1' - , '-$1.1' - , '$ 32.50' - , '500$' - , '.0001' - , '$.001' - , '$0.001' - , '12,34.56' - , '123456,123,123456' - , '-123456,123,123456' - , '123,4' - , ',123' - , '$-,123' - , '$' - , '.' - , ',' - , '00' - , '$-' - , '$-,.' - , '-' - , '-$' - , '' - , '- $' - , '-$10,123.45' - ] - }); - - test({ - validator: 'isBoolean' - , valid: [ - 'true' - , 'false' - , '0' - , '1' - ] - , invalid: [ - '1.0' - , '0.0' - , 'true ' - , 'False' - , 'True' - , 'yes' - ] - }); - }); - - it('should validate ISO 8601 dates', function () { + it('should validate half-width strings', function () { + test({ + validator: 'isHalfWidth', + valid: [ + '!"#$%&()<>/+=-_? ~^|.,@`{}[]', + 'l-btn_02--active', + 'abc123い', + 'カタカナ゙ᆲ←', + ], + invalid: [ + 'あいうえお', + '0011', + ], + }); + }); + + it('should validate variable-width strings', function () { + test({ + validator: 'isVariableWidth', + valid: [ + 'ひらがなカタカナ漢字ABCDE', + '3ー0123', + 'Fカタカナ゙ᆲ', + 'Good=Parts', + ], + invalid: [ + 'abc', + 'abc123', + '!"#$%&()<>/+=-_? ~^|.,@`{}[]', + 'ひらがな・カタカナ、.漢字', + '123456', + 'カタカナ゙ᆲ', + ], + }); + }); + + it('should validate surrogate pair strings', function () { + test({ + validator: 'isSurrogatePair', + valid: [ + '𠮷野𠮷', + '𩸽', + 'ABC千𥧄1-2-3', + ], + invalid: [ + '吉野竈', + '鮪', + 'ABC1-2-3', + ], + }); + }); + + it('should validate base64 strings', function () { + test({ + validator: 'isBase64', + valid: [ + 'TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4=', + 'Vml2YW11cyBmZXJtZW50dW0gc2VtcGVyIHBvcnRhLg==', + 'U3VzcGVuZGlzc2UgbGVjdHVzIGxlbw==', + 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuMPNS1Ufof9EW/M98FNw' + + 'UAKrwflsqVxaxQjBQnHQmiI7Vac40t8x7pIb8gLGV6wL7sBTJiPovJ0V7y7oc0Ye' + + 'rhKh0Rm4skP2z/jHwwZICgGzBvA0rH8xlhUiTvcwDCJ0kc+fh35hNt8srZQM4619' + + 'FTgB66Xmp4EtVyhpQV+t02g6NzK72oZI0vnAvqhpkxLeLiMCyrI416wHm5Tkukhx' + + 'QmcL2a6hNOyu0ixX/x2kSFXApEnVrJ+/IxGyfyw8kf4N2IZpW5nEP847lpfj0SZZ' + + 'Fwrd1mnfnDbYohX2zRptLy2ZUn06Qo9pkG5ntvFEPo9bfZeULtjYzIl6K8gJ2uGZ' + + 'HQIDAQAB', + ], + invalid: [ + '12345', + '', + 'Vml2YW11cyBmZXJtZtesting123', + ], + }); + for (var i = 0, str = '', encoded; i < 1000; i++) { + str += String.fromCharCode(Math.random() * 26 | 97); + encoded = new Buffer(str).toString('base64'); + if (!validator.isBase64(encoded)) { + var msg = format('validator.isBase64() failed with "%s"', encoded); + throw new Error(msg); + } + } + }); + + it('should validate hex-encoded MongoDB ObjectId', function () { + test({ + validator: 'isMongoId', + valid: [ + '507f1f77bcf86cd799439011', + ], + invalid: [ + '507f1f77bcf86cd7994390', + '507f1f77bcf86cd79943901z', + '', + '507f1f77bcf86cd799439011 ', + ], + }); + }); + + it('should define the module using an AMD-compatible loader', function () { + var window = { + validator: null, + define: function (module) { + window.validator = module(); + }, + }; + window.define.amd = true; + + var sandbox = vm.createContext(window); + vm.runInContext(validator_js, sandbox); + assert.equal(window.validator.trim(' foobar '), 'foobar'); + }); + + it('should bind validator to the window if no module loaders are available', function () { + var window = {}; + var sandbox = vm.createContext(window); + vm.runInContext(validator_js, sandbox); + assert.equal(window.validator.trim(' foobar '), 'foobar'); + }); + + it('should validate mobile phone number', function () { + test({ + validator: 'isMobilePhone', + valid: [ + '0944549710', + '+963944549710', + '956654379', + '0944549710', + '0962655597', + ], + invalid: [ + '12345', + '', + '+9639626626262', + '+963332210972', + '0114152198', + ], + args: ['ar-SY'], + }); + + test({ + validator: 'isMobilePhone', + valid: [ + '+49 (0) 123 456 789', + '+49 (0) 123 456789', + '0123/4567890', + '+49 01234567890', + '01234567890', + ], + invalid: [ + '', + 'Vml2YW11cyBmZXJtZtesting123', + ], + args: ['de-DE'], + }); + + test({ + validator: 'isMobilePhone', + valid: [ + '55-17-3332-2155', + '55-15-25661234', + '551223456789', + '01523456987', + '022995678947', + '+55-12-996551215', + ], + invalid: [ + '+017-123456789', + '5501599623874', + '+55012962308', + '+55-015-1234-3214', + ], + args: ['pt-BR'], + }); + + test({ + validator: 'isMobilePhone', + valid: [ + '15323456787', + '13523333233', + '13898728332', + '+086-13238234822', + '08613487234567', + '8617823492338', + '86-17823492338', + ], + invalid: [ + '12345', + '', + 'Vml2YW11cyBmZXJtZtesting123', + '010-38238383', + ], + args: ['zh-CN'], + }); + + test({ + validator: 'isMobilePhone', + valid: [ + '0987123456', + '+886987123456', + '886987123456', + '+886-987123456', + '886-987123456', + ], + invalid: [ + '12345', + '', + 'Vml2YW11cyBmZXJtZtesting123', + '0-987123456', + ], + args: ['zh-TW'], + }); + + test({ + validator: 'isMobilePhone', + invalid: [ + '15323456787', + '13523333233', + '13898728332', + '+086-13238234822', + '08613487234567', + '8617823492338', + '86-17823492338', + ], + args: ['en'], + }); + + test({ + validator: 'isMobilePhone', + valid: [ + '0821231234', + '+27821231234', + '27821231234', + ], + invalid: [ + '082123', + '08212312345', + '21821231234', + '+21821231234', + '+0821231234', + ], + args: ['en-ZA'], + }); + + test({ + validator: 'isMobilePhone', + valid: [ + '61404111222', + '+61411222333', + '0417123456', + ], + invalid: [ + '082123', + '08212312345', + '21821231234', + '+21821231234', + '+0821231234', + '04123456789', + ], + args: ['en-AU'], + }); + + test({ + validator: 'isMobilePhone', + valid: [ + '91234567', + '9123-4567', + '61234567', + '51234567', + '+85291234567', + '+852-91234567', + '+852-9123-4567', + '852-91234567', + ], + invalid: [ + '999', + '+852-912345678', + '123456789', + '+852-1234-56789', + ], + args: ['en-HK'], + }); + + test({ + validator: 'isMobilePhone', + valid: [ + '0612457898', + '+33612457898', + '33612457898', + '0712457898', + '+33712457898', + '33712457898', + ], + invalid: [ + '061245789', + '06124578980', + '0112457898', + '0212457898', + '0312457898', + '0412457898', + '0512457898', + '0812457898', + '0912457898', + '+34612457898', + '+336124578980', + '+3361245789', + ], + args: ['fr-FR'], + }); + + test({ + validator: 'isMobilePhone', + valid: [ + '+306944848966', + '6944848966', + '306944848966', + ], + invalid: [ + '2102323234', + '+302646041461', + '120000000', + '20000000000', + '68129485729', + '6589394827', + '298RI89572', + ], + args: ['el-GR'], + }); + + test({ + validator: 'isMobilePhone', + valid: [ + '447789345856', + '+447861235675', + '07888814488', + ], + invalid: [ + '67699567', + '0773894868', + '077389f8688', + '+07888814488', + '0152456999', + '442073456754', + '+443003434751', + '05073456754', + '08001123123', + ], + args: ['en-GB'], + }); + + test({ + validator: 'isMobilePhone', + valid: [ + '19876543210', + '8005552222', + '+15673628910', + ], + invalid: [ + '564785', + '0123456789', + '1437439210', + '8009112340', + '+10345672645', + '11435213543', + '2436119753', + '16532116190', + ], + args: ['en-US'], + }); + + test({ + validator: 'isMobilePhone', + valid: [ + '0956684590', + '0966684590', + '0976684590', + '+260956684590', + '+260966684590', + '+260976684590', + '260976684590', + ], + invalid: [ + '12345', + '', + 'Vml2YW11cyBmZXJtZtesting123', + '010-38238383', + '966684590', + ], + args: ['en-ZM'], + }); + + test({ + validator: 'isMobilePhone', + valid: [ + '+79676338855', + '79676338855', + '89676338855', + '9676338855', + ], + invalid: [ + '12345', + '', + 'Vml2YW11cyBmZXJtZtesting123', + '010-38238383', + '+9676338855', + '19676338855', + '6676338855', + '+99676338855', + ], + args: ['ru-RU'], + }); + + test({ + validator: 'isMobilePhone', + valid: [ + '+6427987035', + '642240512347', + '0293981646', + '029968425', + ], + invalid: [ + '12345', + '', + 'Vml2YW11cyBmZXJtZtesting123', + '+642956696123566', + '+02119620856', + '+9676338855', + '19676338855', + '6676338855', + '+99676338855', + ], + args: ['en-NZ'], + }); + + var norwegian = { + valid: [ + '+4796338855', + '+4746338855', + '4796338855', + '4746338855', + '46338855', + '96338855', + ], + invalid: [ + '12345', + '', + 'Vml2YW11cyBmZXJtZtesting123', + '+4676338855', + '19676338855', + '+4726338855', + '4736338855', + '66338855', + ], + }; + test({ + validator: 'isMobilePhone', + valid: norwegian.valid, + invalid: norwegian.invalid, + args: ['nb-NO'], + }); + test({ + validator: 'isMobilePhone', + valid: norwegian.valid, + invalid: norwegian.invalid, + args: ['nn-NO'], + }); + + test({ + validator: 'isMobilePhone', + valid: [ + '01636012403', + '+841636012403', + '1636012403', + '841636012403', + '+84999999999', + '84999999999', + '0999999999', + '999999999', + ], + invalid: [ + '12345', + '', + 'Vml2YW11cyBmZXJtZtesting123', + '010-38238383', + '260976684590', + ], + args: ['vi-VN'], + }); + + test({ + validator: 'isMobilePhone', + valid: [ + '+34654789321', + '654789321', + '+34714789321', + '714789321', + '+34744789321', + '744789321', + ], + invalid: [ + '12345', + '', + 'Vml2YW11cyBmZXJtZtesting123', + '+3465478932', + '65478932', + '+346547893210', + '6547893210', + '+34704789321', + '704789321', + '+34754789321', + '754789321', + ], + args: ['es-ES'], + }); + }); + + test({ + validator: 'isMobilePhone', + valid: [ + '+358505557171', + '0455571', + '0505557171', + '358505557171', + '04412345', + '0457 123 45 67', + '+358457 123 45 67', + '+358 50 555 7171', + ], + invalid: [ + '12345', + '', + '045557', + '045555717112312332423423421', + 'Vml2YW11cyBmZXJtZtesting123', + '010-38238383', + '+3-585-0555-7171', + '+9676338855', + '19676338855', + '6676338855', + '+99676338855', + '044123', + '019123456789012345678901', + ], + args: ['fi-FI'], + }); + + it('should validate currency', function () { + test({ + validator: 'isCurrency', + args: [ + { }, + '-$##,###.## (en-US, en-CA, en-AU, en-NZ, en-HK)', + ], + valid: [ + '-$10,123.45', + '$10,123.45', + '$10123.45', + '10,123.45', + '10123.45', + '10,123', + '1,123,456', + '1123456', + '1.39', + '.03', + '0.10', + '$0.10', + '-$0.01', + '-$.99', + '$100,234,567.89', + '$10,123', + '10,123', + '-10123', + ], + invalid: [ + '1.234', + '$1.1', + '$ 32.50', + '500$', + '.0001', + '$.001', + '$0.001', + '12,34.56', + '123456,123,123456', + '123,4', + ',123', + '$-,123', + '$', + '.', + ',', + '00', + '$-', + '$-,.', + '-', + '-$', + '', + '- $', + ], + }); + + test({ + validator: 'isCurrency', + args: [ + { + require_symbol: true, + }, + '-$##,###.## with $ required (en-US, en-CA, en-AU, en-NZ, en-HK)', + ], + valid: [ + '-$10,123.45', + '$10,123.45', + '$10123.45', + '$10,123.45', + '$10,123', + '$1,123,456', + '$1123456', + '$1.39', + '$.03', + '$0.10', + '$0.10', + '-$0.01', + '-$.99', + '$100,234,567.89', + '$10,123', + '-$10123', + ], + invalid: [ + '1.234', + '$1.234', + '1.1', + '$1.1', + '$ 32.50', + ' 32.50', + '500', + '10,123,456', + '.0001', + '$.001', + '$0.001', + '1,234.56', + '123456,123,123456', + '$123456,123,123456', + '123.4', + '$123.4', + ',123', + '$,123', + '$-,123', + '$', + '.', + '$.', + ',', + '$,', + '00', + '$00', + '$-', + '$-,.', + '-', + '-$', + '', + '$ ', + '- $', + ], + }); + + test({ + validator: 'isCurrency', + args: [ + { + symbol: '¥', + negative_sign_before_digits: true, + }, + '¥-##,###.## (zh-CN)', + ], + valid: [ + '123,456.78', + '-123,456.78', + '¥6,954,231', + '¥-6,954,231', + '¥10.03', + '¥-10.03', + '10.03', + '1.39', + '.03', + '0.10', + '¥-10567.01', + '¥0.01', + '¥1,234,567.89', + '¥10,123', + '¥-10,123', + '¥-10,123.45', + '10,123', + '10123', + '¥-100', + ], + invalid: [ + '1.234', + '¥1.1', + '5,00', + '.0001', + '¥.001', + '¥0.001', + '12,34.56', + '123456,123,123456', + '123 456', + ',123', + '¥-,123', + '', + ' ', + '¥', + '¥-', + '¥-,.', + '-', + '- ¥', + '-¥', + ], + }); + + test({ + validator: 'isCurrency', + args: [ + { + symbol: '¥', + allow_negatives: false, + }, + '¥##,###.## with no negatives (zh-CN)', + ], + valid: [ + '123,456.78', + '¥6,954,231', + '¥10.03', + '10.03', + '1.39', + '.03', + '0.10', + '¥0.01', + '¥1,234,567.89', + '¥10,123', + '10,123', + '10123', + '¥100', + ], + invalid: [ + '1.234', + '-123,456.78', + '¥-6,954,231', + '¥-10.03', + '¥-10567.01', + '¥1.1', + '¥-10,123', + '¥-10,123.45', + '5,00', + '¥-100', + '.0001', + '¥.001', + '¥-.001', + '¥0.001', + '12,34.56', + '123456,123,123456', + '123 456', + ',123', + '¥-,123', + '', + ' ', + '¥', + '¥-', + '¥-,.', + '-', + '- ¥', + '-¥', + ], + }); + + test({ + validator: 'isCurrency', + args: [ + { + symbol: 'R', + negative_sign_before_digits: true, + thousands_separator: ' ', + decimal_separator: ',', + allow_negative_sign_placeholder: true, + }, + 'R ## ###,## and R-10 123,25 (el-ZA)', + ], + valid: [ + '123 456,78', + '-10 123', + 'R-10 123', + 'R 6 954 231', + 'R10,03', + '10,03', + '1,39', + ',03', + '0,10', + 'R10567,01', + 'R0,01', + 'R1 234 567,89', + 'R10 123', + 'R 10 123', + 'R 10123', + 'R-10123', + '10 123', + '10123', + ], + invalid: [ + '1,234', + 'R -10123', + 'R- 10123', + 'R,1', + ',0001', + 'R,001', + 'R0,001', + '12 34,56', + '123456 123 123456', + ' 123', + '- 123', + '123 ', + '', + ' ', + 'R', + 'R- .1', + 'R-', + '-', + '-R 10123', + 'R00', + 'R -', + '-R', + ], + }); + + test({ + validator: 'isCurrency', + args: [ + { + symbol: '€', + thousands_separator: '.', + decimal_separator: ',', + allow_space_after_symbol: true, + }, + '-€ ##.###,## (it-IT)', + ], + valid: [ + '123.456,78', + '-123.456,78', + '€6.954.231', + '-€6.954.231', + '€ 896.954.231', + '-€ 896.954.231', + '16.954.231', + '-16.954.231', + '€10,03', + '-€10,03', + '10,03', + '-10,03', + '-1,39', + ',03', + '0,10', + '-€10567,01', + '-€ 10567,01', + '€ 0,01', + '€1.234.567,89', + '€10.123', + '10.123', + '-€10.123', + '€ 10.123', + '€10.123', + '€ 10123', + '10.123', + '-10123', + ], + invalid: [ + '1,234', + '€ 1,1', + '50#,50', + '123,@€ ', + '€€500', + ',0001', + '€ ,001', + '€0,001', + '12.34,56', + '123456.123.123456', + '€123€', + '', + ' ', + '€', + ' €', + '€ ', + '€€', + ' 123', + '- 123', + '.123', + '-€.123', + '123 ', + '€-', + '- €', + '€ - ', + '-', + '- ', + '-€', + ], + }); + + test({ + validator: 'isCurrency', + args: [ + { + symbol: '€', + thousands_separator: '.', + symbol_after_digits: true, + decimal_separator: ',', + allow_space_after_digits: true, + }, + '-##.###,## € (el-GR)', + ], + valid: [ + '123.456,78', + '-123.456,78', + '6.954.231 €', + '-6.954.231 €', + '896.954.231', + '-896.954.231', + '16.954.231', + '-16.954.231', + '10,03€', + '-10,03€', + '10,03', + '-10,03', + '1,39', + ',03', + '-,03', + '-,03 €', + '-,03€', + '0,10', + '10567,01€', + '0,01 €', + '1.234.567,89€', + '10.123€', + '10.123', + '10.123€', + '10.123 €', + '10123 €', + '10.123', + '10123', + ], + invalid: [ + '1,234', + '1,1 €', + ',0001', + ',001 €', + '0,001€', + '12.34,56', + '123456.123.123456', + '€123€', + '', + ' ', + '€', + ' €', + '€ ', + ' 123', + '- 123', + '.123', + '-.123€', + '-.123 €', + '123 ', + '-€', + '- €', + '-', + '- ', + ], + }); + + test({ + validator: 'isCurrency', + args: [ + { + symbol: 'kr.', + negative_sign_before_digits: true, + thousands_separator: '.', + decimal_separator: ',', + allow_space_after_symbol: true, + }, + 'kr. -##.###,## (da-DK)', + ], + valid: [ + '123.456,78', + '-10.123', + 'kr. -10.123', + 'kr.-10.123', + 'kr. 6.954.231', + 'kr.10,03', + 'kr. -10,03', + '10,03', + '1,39', + ',03', + '0,10', + 'kr. 10567,01', + 'kr. 0,01', + 'kr. 1.234.567,89', + 'kr. -1.234.567,89', + '10.123', + 'kr. 10.123', + 'kr.10.123', + '10123', + '10.123', + 'kr.-10123', + ], + invalid: [ + '1,234', + 'kr. -10123', + 'kr.,1', + ',0001', + 'kr. ,001', + 'kr.0,001', + '12.34,56', + '123456.123.123456', + '.123', + 'kr.-.123', + 'kr. -.123', + '- 123', + '123 ', + '', + ' ', + 'kr.', + ' kr.', + 'kr. ', + 'kr.-', + 'kr. -', + 'kr. - ', + ' - ', + '-', + '- kr.', + '-kr.', + ], + }); + + test({ + validator: 'isCurrency', + args: [ + { + symbol: 'kr.', + allow_negatives: false, + negative_sign_before_digits: true, + thousands_separator: '.', + decimal_separator: ',', + allow_space_after_symbol: true, + }, + 'kr. ##.###,## with no negatives (da-DK)', + ], + valid: [ + '123.456,78', + '10.123', + 'kr. 10.123', + 'kr.10.123', + 'kr. 6.954.231', + 'kr.10,03', + 'kr. 10,03', + '10,03', + '1,39', + ',03', + '0,10', + 'kr. 10567,01', + 'kr. 0,01', + 'kr. 1.234.567,89', + 'kr.1.234.567,89', + '10.123', + 'kr. 10.123', + 'kr.10.123', + '10123', + '10.123', + 'kr.10123', + ], + invalid: [ + '1,234', + '-10.123', + 'kr. -10.123', + 'kr. -1.234.567,89', + 'kr.-10123', + 'kr. -10123', + 'kr.-10.123', + 'kr. -10,03', + 'kr.,1', + ',0001', + 'kr. ,001', + 'kr.0,001', + '12.34,56', + '123456.123.123456', + '.123', + 'kr.-.123', + 'kr. -.123', + '- 123', + '123 ', + '', + ' ', + 'kr.', + ' kr.', + 'kr. ', + 'kr.-', + 'kr. -', + 'kr. - ', + ' - ', + '-', + '- kr.', + '-kr.', + ], + }); + + test({ + validator: 'isCurrency', + args: [ + { + parens_for_negatives: true, + }, + '($##,###.##) (en-US, en-HK)', + ], + valid: [ + '1,234', + '(1,234)', + '($6,954,231)', + '$10.03', + '(10.03)', + '($10.03)', + '1.39', + '.03', + '(.03)', + '($.03)', + '0.10', + '$10567.01', + '($0.01)', + '$1,234,567.89', + '$10,123', + '(10,123)', + '10123', + ], + invalid: [ + '1.234', + '($1.1)', + '-$1.10', + '$ 32.50', + '500$', + '.0001', + '$.001', + '($0.001)', + '12,34.56', + '123456,123,123456', + '( 123)', + ',123', + '$-,123', + '', + ' ', + ' ', + ' ', + '$', + '$ ', + ' $', + ' 123', + '(123) ', + '.', + ',', + '00', + '$-', + '$ - ', + '$- ', + ' - ', + '-', + '- $', + '-$', + '()', + '( )', + '( -)', + '( - )', + '( - )', + '(-)', + '(-$)', + ], + }); + + test({ + validator: 'isCurrency', + args: [ + { allow_negatives: false }, + '$##,###.## with no negatives (en-US, en-CA, en-AU, en-HK)', + ], + valid: [ + '$10,123.45', + '$10123.45', + '10,123.45', + '10123.45', + '10,123', + '1,123,456', + '1123456', + '1.39', + '.03', + '0.10', + '$0.10', + '$100,234,567.89', + '$10,123', + '10,123', + ], + invalid: [ + '1.234', + '-1.234', + '-10123', + '-$0.01', + '-$.99', + '$1.1', + '-$1.1', + '$ 32.50', + '500$', + '.0001', + '$.001', + '$0.001', + '12,34.56', + '123456,123,123456', + '-123456,123,123456', + '123,4', + ',123', + '$-,123', + '$', + '.', + ',', + '00', + '$-', + '$-,.', + '-', + '-$', + '', + '- $', + '-$10,123.45', + ], + }); + + test({ + validator: 'isBoolean', + valid: [ + 'true', + 'false', + '0', + '1', + ], + invalid: [ + '1.0', + '0.0', + 'true ', + 'False', + 'True', + 'yes', + ], + }); + }); + + it('should validate ISO 8601 dates', function () { // from http://www.pelagodesign.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/ - test({ - validator: 'isISO8601' - , valid: [ - '2009-12T12:34' - , '2009' - , '2009-05-19' - , '2009-05-19' - , '20090519' - , '2009123' - , '2009-05' - , '2009-123' - , '2009-222' - , '2009-001' - , '2009-W01-1' - , '2009-W51-1' - , '2009-W511' - , '2009-W33' - , '2009W511' - , '2009-05-19' - , '2009-05-19 00:00' - , '2009-05-19 14' - , '2009-05-19 14:31' - , '2009-05-19 14:39:22' - , '2009-05-19T14:39Z' - , '2009-W21-2' - , '2009-W21-2T01:22' - , '2009-139' - , '2009-05-19 14:39:22-06:00' - , '2009-05-19 14:39:22+0600' - , '2009-05-19 14:39:22-01' - , '20090621T0545Z' - , '2007-04-06T00:00' - , '2007-04-05T24:00' - , '2010-02-18T16:23:48.5' - , '2010-02-18T16:23:48,444' - , '2010-02-18T16:23:48,3-06:00' - , '2010-02-18T16:23.4' - , '2010-02-18T16:23,25' - , '2010-02-18T16:23.33+0600' - , '2010-02-18T16.23334444' - , '2010-02-18T16,2283' - , '2009-05-19 143922.500' - , '2009-05-19 1439,55' - ] - , invalid: [ - '200905' - , '2009367' - , '2009-' - , '2007-04-05T24:50' - , '2009-000' - , '2009-M511' - , '2009M511' - , '2009-05-19T14a39r' - , '2009-05-19T14:3924' - , '2009-0519' - , '2009-05-1914:39' - , '2009-05-19 14:' - , '2009-05-19r14:39' - , '2009-05-19 14a39a22' - , '200912-01' - , '2009-05-19 14:39:22+06a00' - , '2009-05-19 146922.500' - , '2010-02-18T16.5:23.35:48' - , '2010-02-18T16:23.35:48' - , '2010-02-18T16:23.35:48.45' - , '2009-05-19 14.5.44' - , '2010-02-18T16:23.33.600' - , '2010-02-18T16,25:23:48,444' - ] - }); - }); - - it('should validate whitelisted characters', function () { - test({ validator: 'isWhitelisted', args: ['abcdefghijklmnopqrstuvwxyz-'], valid: ['foo', 'foobar', 'baz-foo'], - invalid: ['foo bar', 'fo.bar', 'türkçe'] }); - }); - - it('should error on non-string input', function () { - var empty = [undefined, null, [], NaN]; - empty.forEach(function (item) { - assert.throws(validator.isNull.bind(null, item)); - }); + test({ + validator: 'isISO8601', + valid: [ + '2009-12T12:34', + '2009', + '2009-05-19', + '2009-05-19', + '20090519', + '2009123', + '2009-05', + '2009-123', + '2009-222', + '2009-001', + '2009-W01-1', + '2009-W51-1', + '2009-W511', + '2009-W33', + '2009W511', + '2009-05-19', + '2009-05-19 00:00', + '2009-05-19 14', + '2009-05-19 14:31', + '2009-05-19 14:39:22', + '2009-05-19T14:39Z', + '2009-W21-2', + '2009-W21-2T01:22', + '2009-139', + '2009-05-19 14:39:22-06:00', + '2009-05-19 14:39:22+0600', + '2009-05-19 14:39:22-01', + '20090621T0545Z', + '2007-04-06T00:00', + '2007-04-05T24:00', + '2010-02-18T16:23:48.5', + '2010-02-18T16:23:48,444', + '2010-02-18T16:23:48,3-06:00', + '2010-02-18T16:23.4', + '2010-02-18T16:23,25', + '2010-02-18T16:23.33+0600', + '2010-02-18T16.23334444', + '2010-02-18T16,2283', + '2009-05-19 143922.500', + '2009-05-19 1439,55', + ], + invalid: [ + '200905', + '2009367', + '2009-', + '2007-04-05T24:50', + '2009-000', + '2009-M511', + '2009M511', + '2009-05-19T14a39r', + '2009-05-19T14:3924', + '2009-0519', + '2009-05-1914:39', + '2009-05-19 14:', + '2009-05-19r14:39', + '2009-05-19 14a39a22', + '200912-01', + '2009-05-19 14:39:22+06a00', + '2009-05-19 146922.500', + '2010-02-18T16.5:23.35:48', + '2010-02-18T16:23.35:48', + '2010-02-18T16:23.35:48.45', + '2009-05-19 14.5.44', + '2010-02-18T16:23.33.600', + '2010-02-18T16,25:23:48,444', + ], }); + }); + it('should validate whitelisted characters', function () { + test({ + validator: 'isWhitelisted', + args: ['abcdefghijklmnopqrstuvwxyz-'], + valid: ['foo', 'foobar', 'baz-foo'], + invalid: ['foo bar', 'fo.bar', 'türkçe'], + }); + }); + + it('should error on non-string input', function () { + var empty = [undefined, null, [], NaN]; + empty.forEach(function (item) { + assert.throws(validator.isNull.bind(null, item)); + }); + }); });