diff --git a/lib/helpers.js b/lib/helpers.js index 9e983df..031a982 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -2,7 +2,7 @@ var uri = require('url'); -var ValidationError = exports.ValidationError = function ValidationError (message, instance, schema, propertyPath) { +var ValidationError = exports.ValidationError = function ValidationError(message, instance, schema, propertyPath) { if (propertyPath) { this.property = propertyPath; } @@ -48,37 +48,47 @@ ValidatorResult.prototype.importErrors = function importErrors(res) { this.addError(res); } else if (res && res.errors) { var errs = this.errors; - res.errors.forEach(function (v) { + res.errors.forEach(function(v) { errs.push(v) }); } }; ValidatorResult.prototype.toString = function toString(res) { - return this.errors.map(function(v,i){ return i+': '+v.toString()+'\n'; }).join(''); + return this.errors.map(function(v, i) { + return i + ': ' + v.toString() + '\n'; + }).join(''); }; -Object.defineProperty(ValidatorResult.prototype, "valid", { get: function() { - return !this.errors.length; -} }); +Object.defineProperty(ValidatorResult.prototype, "valid", { + get: function() { + return !this.errors.length; + } +}); /** * Describes a problem with a Schema which prevents validation of an instance * @name SchemaError * @constructor */ -var SchemaError = exports.SchemaError = function SchemaError (msg, schema) { +var SchemaError = exports.SchemaError = function SchemaError(msg, schema) { this.message = msg; this.schema = schema; Error.call(this, msg); Error.captureStackTrace(this, SchemaError); }; -SchemaError.prototype = Object.create(Error.prototype, - { constructor: {value: SchemaError, enumerable: false} - , name: {value: 'SchemaError', enumerable: false} - }); +SchemaError.prototype = Object.create(Error.prototype, { + constructor: { + value: SchemaError, + enumerable: false + }, + name: { + value: 'SchemaError', + enumerable: false + } +}); -var SchemaContext = exports.SchemaContext = function SchemaContext (schema, options, propertyPath, base, schemas) { +var SchemaContext = exports.SchemaContext = function SchemaContext(schema, options, propertyPath, base, schemas) { this.schema = schema; this.options = options; this.propertyPath = propertyPath; @@ -86,22 +96,22 @@ var SchemaContext = exports.SchemaContext = function SchemaContext (schema, opti this.schemas = schemas; }; -SchemaContext.prototype.resolve = function resolve (target) { +SchemaContext.prototype.resolve = function resolve(target) { return uri.resolve(this.base, target); }; -SchemaContext.prototype.makeChild = function makeChild(schema, propertyName){ - var propertyPath = (propertyName===undefined) ? this.propertyPath : this.propertyPath+makeSuffix(propertyName); - var base = uri.resolve(this.base, schema.id||''); +SchemaContext.prototype.makeChild = function makeChild(schema, propertyName) { + var propertyPath = (propertyName === undefined) ? this.propertyPath : this.propertyPath + makeSuffix(propertyName); + var base = uri.resolve(this.base, schema.id || ''); var ctx = new SchemaContext(schema, this.options, propertyPath, base, Object.create(this.schemas)); - if(schema.id && !ctx.schemas[base]){ + if (schema.id && !ctx.schemas[base]) { ctx.schemas[base] = schema; } return ctx; } var FORMAT_REGEXPS = exports.FORMAT_REGEXPS = { - 'date-time': /^\d{4}-(?:0[0-9]{1}|1[0-2]{1})-[0-9]{2}[tT ]\d{2}:\d{2}:\d{2}(\.\d+)?([zZ]|[+-]\d{2}:\d{2})$/, + 'date-time': /^\d{4}-[0-1]{1}[0-9]{1}-[0-3]{1}[0-9]{1}[Tt]{0,1}[ ]{0,1}\d{2}:\d{2}:\d{2}((\.*\d{0,7}[Zz]{0,1}$)|(\.*\d{0,7}[\+\-]\d{0,2}:\d{0,2}$)|(\.*\d{0,7}$)|$|[Zz]{0,1}$)/, 'date': /^\d{4}-(?:0[0-9]{1}|1[0-2]{1})-[0-9]{2}$/, 'time': /^\d{2}:\d{2}:\d{2}$/, @@ -116,10 +126,10 @@ var FORMAT_REGEXPS = exports.FORMAT_REGEXPS = { 'alpha': /^[a-zA-Z]+$/, 'alphanumeric': /^[a-zA-Z0-9]+$/, - 'utc-millisec': function (input) { + 'utc-millisec': function(input) { return (typeof input === 'string') && parseFloat(input) === parseInt(input, 10) && !isNaN(input); }, - 'regex': function (input) { + 'regex': function(input) { var result = true; try { new RegExp(input); @@ -136,7 +146,7 @@ FORMAT_REGEXPS.regexp = FORMAT_REGEXPS.regex; FORMAT_REGEXPS.pattern = FORMAT_REGEXPS.regex; FORMAT_REGEXPS.ipv4 = FORMAT_REGEXPS['ip-address']; -exports.isFormat = function isFormat (input, format) { +exports.isFormat = function isFormat(input, format) { if (FORMAT_REGEXPS[format] !== undefined) { if (FORMAT_REGEXPS[format] instanceof RegExp) { return FORMAT_REGEXPS[format].test(input); @@ -148,7 +158,7 @@ exports.isFormat = function isFormat (input, format) { return false; }; -var makeSuffix = exports.makeSuffix = function makeSuffix (key) { +var makeSuffix = exports.makeSuffix = function makeSuffix(key) { key = key.toString(); // This function could be capable of outputting valid a ECMAScript string, but the // resulting code for testing which form to use would be tens of thousands of characters long @@ -162,7 +172,7 @@ var makeSuffix = exports.makeSuffix = function makeSuffix (key) { return '[' + JSON.stringify(key) + ']'; }; -exports.deepCompareStrict = function deepCompareStrict (a, b) { +exports.deepCompareStrict = function deepCompareStrict(a, b) { if (typeof a !== typeof b) { return false; } @@ -173,7 +183,7 @@ exports.deepCompareStrict = function deepCompareStrict (a, b) { if (a.length !== b.length) { return false; } - return a.every(function (v, i) { + return a.every(function(v, i) { return deepCompareStrict(a[i], b[i]); }); } @@ -186,21 +196,21 @@ exports.deepCompareStrict = function deepCompareStrict (a, b) { if (aKeys.length !== bKeys.length) { return false; } - return aKeys.every(function (v) { + return aKeys.every(function(v) { return deepCompareStrict(a[v], b[v]); }); } return a === b; }; -module.exports.deepMerge = function deepMerge (target, src) { +module.exports.deepMerge = function deepMerge(target, src) { var array = Array.isArray(src); var dst = array && [] || {}; if (array) { target = target || []; dst = dst.concat(target); - src.forEach(function (e, i) { + src.forEach(function(e, i) { if (typeof e === 'object') { dst[i] = deepMerge(target[i], e) } else { @@ -211,15 +221,14 @@ module.exports.deepMerge = function deepMerge (target, src) { }); } else { if (target && typeof target === 'object') { - Object.keys(target).forEach(function (key) { + Object.keys(target).forEach(function(key) { dst[key] = target[key]; }); } - Object.keys(src).forEach(function (key) { + Object.keys(src).forEach(function(key) { if (typeof src[key] !== 'object' || !src[key]) { dst[key] = src[key]; - } - else { + } else { if (!target[key]) { dst[key] = src[key]; } else { @@ -242,8 +251,8 @@ module.exports.deepMerge = function deepMerge (target, src) { exports.objectGetPath = function objectGetPath(o, s) { var parts = s.split('/').slice(1); var k; - while (typeof (k=parts.shift()) == 'string') { - var n = decodeURIComponent(k.replace(/~0/,'~').replace(/~1/g,'/')); + while (typeof(k = parts.shift()) == 'string') { + var n = decodeURIComponent(k.replace(/~0/, '~').replace(/~1/g, '/')); if (!(n in o)) return; o = o[n]; } @@ -255,8 +264,10 @@ exports.objectGetPath = function objectGetPath(o, s) { * @param Array a * @return {String} */ -exports.encodePath = function encodePointer(a){ - // ~ must be encoded explicitly because hacks - // the slash is encoded by encodeURIComponent - return a.map(function(v){ return '/'+encodeURIComponent(v).replace(/~/g,'%7E'); }).join(''); -} +exports.encodePath = function encodePointer(a) { + // ~ must be encoded explicitly because hacks + // the slash is encoded by encodeURIComponent + return a.map(function(v) { + return '/' + encodeURIComponent(v).replace(/~/g, '%7E'); + }).join(''); +} \ No newline at end of file diff --git a/lib/validator.js b/lib/validator.js index 7d25a4d..0207e3d 100644 --- a/lib/validator.js +++ b/lib/validator.js @@ -13,7 +13,7 @@ var SchemaContext = helpers.SchemaContext; * @name Validator * @constructor */ -var Validator = function Validator () { +var Validator = function Validator() { this.schemas = {}; this.unresolvedRefs = []; @@ -34,7 +34,7 @@ Validator.prototype.unresolvedRefs = null; * @param urn * @return {Object} */ -Validator.prototype.addSchema = function addSchema (schema, uri) { +Validator.prototype.addSchema = function addSchema(schema, uri) { if (!schema) { return null; } @@ -47,9 +47,9 @@ Validator.prototype.addSchema = function addSchema (schema, uri) { }; Validator.prototype.addSubSchema = function addSubSchema(baseuri, schema) { - if(!schema || typeof schema!='object') return; + if (!schema || typeof schema != 'object') return; // Mark all referenced schemas so we can tell later which schemas are referred to, but never defined - if(schema.$ref){ + if (schema.$ref) { var resolvedUri = urilib.resolve(baseuri, schema.$ref); // Only mark unknown schemas as unresolved if (this.schemas[resolvedUri] === undefined) { @@ -61,9 +61,9 @@ Validator.prototype.addSubSchema = function addSubSchema(baseuri, schema) { var ourUri = schema.id && urilib.resolve(baseuri, schema.id); var ourBase = ourUri || baseuri; if (ourUri) { - if(this.schemas[ourUri]){ - if(!helpers.deepCompareStrict(this.schemas[ourUri], schema)){ - throw new Error('Schema <'+schema+'> already exists with different definition'); + if (this.schemas[ourUri]) { + if (!helpers.deepCompareStrict(this.schemas[ourUri], schema)) { + throw new Error('Schema <' + schema + '> already exists with different definition'); } return this.schemas[ourUri]; } @@ -71,7 +71,7 @@ Validator.prototype.addSubSchema = function addSubSchema(baseuri, schema) { var documentUri = ourUri.replace(/^([^#]*)#$/, '$1'); this.schemas[documentUri] = schema; } - this.addSubSchemaArray(ourBase, ((schema.items instanceof Array)?schema.items:[schema.items])); + this.addSubSchemaArray(ourBase, ((schema.items instanceof Array) ? schema.items : [schema.items])); this.addSubSchema(ourBase, schema.additionalItems); this.addSubSchemaObject(ourBase, schema.properties); this.addSubSchema(ourBase, schema.additionalProperties); @@ -87,15 +87,15 @@ Validator.prototype.addSubSchema = function addSubSchema(baseuri, schema) { }; Validator.prototype.addSubSchemaArray = function addSubSchemaArray(baseuri, schemas) { - if(!(schemas instanceof Array)) return; - for(var i=0; i", schema); } var subschema = helpers.objectGetPath(ctx.schemas[document], fragment.substr(1)); - if(subschema===undefined){ + if (subschema === undefined) { throw new SchemaError("no such schema " + fragment + " located in <" + document + ">", schema); } - return {subschema: subschema, switchSchema: switchSchema}; + return { + subschema: subschema, + switchSchema: switchSchema + }; } /** * Tests whether the instance if of a certain type. @@ -266,9 +272,15 @@ Validator.prototype.resolve = function resolve (schema, switchSchema, ctx) { * @param type * @return {boolean} */ -Validator.prototype.testType = function validateType (instance, schema, options, ctx, type) { +Validator.prototype.testType = function validateType(instance, schema, options, ctx, type) { + //allow non-required fields to hold null values if (typeof this.types[type] == 'function') { - return this.types[type].call(this, instance); + var is_valid = this.types[type].call(this, instance); + + if (!schema.required) + return is_valid || this.types.null(instance); + else + return is_valid; } if (type && typeof type == 'object') { var res = this.validateSchema(instance, type, options, ctx); @@ -279,36 +291,33 @@ Validator.prototype.testType = function validateType (instance, schema, options, }; var types = Validator.prototype.types = {}; -types.string = function testString (instance) { +types.string = function testString(instance) { return typeof instance == 'string'; }; -types.number = function testNumber (instance) { +types.number = function testNumber(instance) { return typeof instance == 'number'; }; -types.integer = function testInteger (instance) { +types.integer = function testInteger(instance) { return (typeof instance == 'number') && instance % 1 === 0; }; -types.boolean = function testBoolean (instance) { +types.boolean = function testBoolean(instance) { return typeof instance == 'boolean'; }; -types.number = function testNumber (instance) { - return typeof instance == 'number'; -}; -types.array = function testArray (instance) { +types.array = function testArray(instance) { return instance instanceof Array; }; -types.null = function testNull (instance) { +types.null = function testNull(instance) { return instance === null; }; -types.date = function testDate (instance) { +types.date = function testDate(instance) { return instance instanceof Date; }; -types.any = function testAny (instance) { +types.any = function testAny(instance) { return true; }; -types.object = function testObject (instance) { +types.object = function testObject(instance) { // TODO: fix this - see #15 return instance && (typeof instance) === 'object' && !(instance instanceof Array) && !(instance instanceof Date); }; -module.exports = Validator; +module.exports = Validator; \ No newline at end of file diff --git a/package.json b/package.json index dcdf20e..9a23358 100644 --- a/package.json +++ b/package.json @@ -2,17 +2,13 @@ "author": "Tom de Grunt ", "name": "jsonschema", "version": "1.0.0", - "dependencies": { - }, + "dependencies": {}, "main": "./lib", "devDependencies": { "mocha": "~1.8.2", "chai": "~1.5.0" }, "optionalDependencies": {}, - "engines": { - "node": "*" - }, "keywords": [ "json", "schema", @@ -28,4 +24,4 @@ "scripts": { "test": "./node_modules/.bin/mocha -R spec" } -} +} \ No newline at end of file diff --git a/test/attributes.js b/test/attributes.js index 0befd1a..a8f4e48 100644 --- a/test/attributes.js +++ b/test/attributes.js @@ -6,323 +6,528 @@ var Validator = require('../lib/validator'); var should = require('chai').should(); -describe('Attributes', function () { - describe('type', function () { - beforeEach(function () { +describe('Attributes', function() { + describe('type', function() { + beforeEach(function() { this.validator = new Validator(); }); - describe('number', function () { - it('should validate a valid number', function () { - this.validator.validate(0, {'type': 'number'}).valid.should.be.true; + describe('number', function() { + it('should validate a valid number', function() { + this.validator.validate(0, { + 'type': 'number' + }).valid.should.be.true; }); - it('should not validate an invalid number', function () { - return this.validator.validate('0', {'type': 'number'}).valid.should.be.false; + it('should validate a non-required null number', function() { + return this.validator.validate(null, { + 'type': 'number', + 'required': false + }).valid.should.be.true; + }); + + it('should not validate a required null number', function() { + return this.validator.validate(null, { + 'type': 'number', + 'required': true + }).valid.should.be.false; + }); + + it('should not validate a non-required non-null non-number', function() { + return this.validator.validate('0', { + 'type': 'number', + 'required': false + }).valid.should.be.false; }); }); - describe('required', function () { - it('should not validate an undefined instance', function () { - this.validator.validate(undefined, {'type': 'number', 'required': true}).valid.should.be.false; + describe('required', function() { + it('should not validate an undefined instance', function() { + this.validator.validate(undefined, { + 'type': 'number', + 'required': true + }).valid.should.be.false; }); }); - describe('null', function () { + describe('null', function() { - it('should validate null', function () { - return this.validator.validate(null, {'type': 'null'}).valid.should.be.true; + it('should validate null', function() { + return this.validator.validate(null, { + 'type': 'null' + }).valid.should.be.true; }); - it('should not validate no-null', function () { - return this.validator.validate('0', {'type': 'null'}).valid.should.be.false; + it('should not validate no-null', function() { + return this.validator.validate('0', { + 'type': 'null' + }).valid.should.be.false; }); // I don't know - strictly undefined should not be a valid null - it('should not validate an undefined instance', function () { - this.validator.validate(undefined, {'type': 'date', 'required': true}).valid.should.be.false; + it('should not validate an undefined instance', function() { + this.validator.validate(undefined, { + 'type': 'date', + 'required': true + }).valid.should.be.false; }); }); - describe('date', function () { + describe('date', function() { - it('should validate date', function () { - return this.validator.validate(new Date(), {'type': 'date'}).valid.should.be.true; + it('should validate date', function() { + return this.validator.validate(new Date(), { + 'type': 'date' + }).valid.should.be.true; }); - it('should not validate no-null', function () { - return this.validator.validate('0', {'type': 'date'}).valid.should.be.false; + it('should not validate no-null', function() { + return this.validator.validate('0', { + 'type': 'date' + }).valid.should.be.false; }); - it('should not validate an undefined instance', function () { - this.validator.validate(undefined, {'type': 'date', 'required': true}).valid.should.be.false; + it('should not validate an undefined instance', function() { + this.validator.validate(undefined, { + 'type': 'date', + 'required': true + }).valid.should.be.false; }); }); - describe('integer', function () { + describe('integer', function() { - it('should validate integer', function () { - return this.validator.validate(12, {'type': 'integer'}).valid.should.be.true; + it('should validate integer', function() { + return this.validator.validate(12, { + 'type': 'integer' + }).valid.should.be.true; }); - it('should not validate non integer', function () { - return this.validator.validate(0.25, {'type': 'integer'}).valid.should.be.false; + it('should not validate non integer', function() { + return this.validator.validate(0.25, { + 'type': 'integer' + }).valid.should.be.false; }); - it('should not validate an undefined instance', function () { - this.validator.validate(undefined, {'type': 'integer', 'required': true}).valid.should.be.false; + it('should not validate an undefined instance', function() { + this.validator.validate(undefined, { + 'type': 'integer', + 'required': true + }).valid.should.be.false; }); }); - describe('boolean', function () { + describe('boolean', function() { - it('should validate true', function () { - return this.validator.validate(true, {'type': 'boolean'}).valid.should.be.true; + it('should validate true', function() { + return this.validator.validate(true, { + 'type': 'boolean' + }).valid.should.be.true; }); - it('should validate false', function () { - return this.validator.validate(false, {'type': 'boolean'}).valid.should.be.true; + it('should validate false', function() { + return this.validator.validate(false, { + 'type': 'boolean' + }).valid.should.be.true; }); - it('should not validate non boolean', function () { - return this.validator.validate('true', {'type': 'boolean'}).valid.should.be.false; + it('should not validate non boolean', function() { + return this.validator.validate('true', { + 'type': 'boolean' + }).valid.should.be.false; }); - it('should not validate an undefined instance', function () { - this.validator.validate(undefined, {'type': 'boolean', 'required': true}).valid.should.be.false; + it('should not validate an undefined instance', function() { + this.validator.validate(undefined, { + 'type': 'boolean', + 'required': true + }).valid.should.be.false; }); }); - describe('any', function () { + describe('any', function() { - it('should validate true as any', function () { - return this.validator.validate(true, {'type': 'any'}).valid.should.be.true; + it('should validate true as any', function() { + return this.validator.validate(true, { + 'type': 'any' + }).valid.should.be.true; }); - it('should validate "true" as any', function () { - return this.validator.validate('true', {'type': 'any'}).valid.should.be.true; + it('should validate "true" as any', function() { + return this.validator.validate('true', { + 'type': 'any' + }).valid.should.be.true; }); - it('should validate 0 as any', function () { - return this.validator.validate(0, {'type': 'any'}).valid.should.be.true; + it('should validate 0 as any', function() { + return this.validator.validate(0, { + 'type': 'any' + }).valid.should.be.true; }); - it('should validate Date as any', function () { - return this.validator.validate(new Date(), {'type': 'any'}).valid.should.be.true; + it('should validate Date as any', function() { + return this.validator.validate(new Date(), { + 'type': 'any' + }).valid.should.be.true; }); - it('should not validate an undefined instance', function () { - this.validator.validate(undefined, {'type': 'any', 'required': true}).valid.should.be.false; + it('should not validate an undefined instance', function() { + this.validator.validate(undefined, { + 'type': 'any', + 'required': true + }).valid.should.be.false; }); }); }); - describe('minimum', function () { - beforeEach(function () { + describe('minimum', function() { + beforeEach(function() { this.validator = new Validator(); }); - it('should validate if number meets minimum', function () { - return this.validator.validate(1, {'type': 'number', 'minimum': '1'}).valid.should.be.true; + it('should validate if number meets minimum', function() { + return this.validator.validate(1, { + 'type': 'number', + 'minimum': '1' + }).valid.should.be.true; }); - it('should not validate if number is below minimum', function () { - return this.validator.validate(0, {'type': 'number', 'minimum': '1'}).valid.should.be.false; + it('should not validate if number is below minimum', function() { + return this.validator.validate(0, { + 'type': 'number', + 'minimum': '1' + }).valid.should.be.false; }); - it('should validate if number is above minimum, using exclusiveMinimum', function () { - return this.validator.validate(2, {'type': 'number', 'minimum': '1', 'exclusiveMinimum': true}).valid.should.be.true; + it('should validate if number is above minimum, using exclusiveMinimum', function() { + return this.validator.validate(2, { + 'type': 'number', + 'minimum': '1', + 'exclusiveMinimum': true + }).valid.should.be.true; }); - it('should not validate if number is the minimum, using exclusiveMinimum', function () { - return this.validator.validate(1, {'type': 'number', 'minimum': '1', 'exclusiveMinimum': true}).valid.should.be.false; + it('should not validate if number is the minimum, using exclusiveMinimum', function() { + return this.validator.validate(1, { + 'type': 'number', + 'minimum': '1', + 'exclusiveMinimum': true + }).valid.should.be.false; }); }); - describe('maximum', function () { - beforeEach(function () { + describe('maximum', function() { + beforeEach(function() { this.validator = new Validator(); }); - it('should validate if number is below the maximum', function () { - return this.validator.validate(1, {'type': 'number', 'maximum': '2'}).valid.should.be.true; + it('should validate if number is below the maximum', function() { + return this.validator.validate(1, { + 'type': 'number', + 'maximum': '2' + }).valid.should.be.true; }); - it('should not validate if number is above maximum', function () { - return this.validator.validate(3, {'type': 'number', 'maximum': '2'}).valid.should.be.false; + it('should not validate if number is above maximum', function() { + return this.validator.validate(3, { + 'type': 'number', + 'maximum': '2' + }).valid.should.be.false; }); - it('should validate if number is below maximum, using exclusiveMinimum', function () { - return this.validator.validate(1, {'type': 'number', 'maximum': '2', 'exclusiveMaximum': true}).valid.should.be.true; + it('should validate if number is below maximum, using exclusiveMinimum', function() { + return this.validator.validate(1, { + 'type': 'number', + 'maximum': '2', + 'exclusiveMaximum': true + }).valid.should.be.true; }); - it('should not validate if number is the maximum, using exclusiveMinimum', function () { - return this.validator.validate(2, {'type': 'number', 'maximum': '2', 'exclusiveMaximum': true}).valid.should.be.false; + it('should not validate if number is the maximum, using exclusiveMinimum', function() { + return this.validator.validate(2, { + 'type': 'number', + 'maximum': '2', + 'exclusiveMaximum': true + }).valid.should.be.false; }); }); - describe('combined minimum and maximum', function () { - beforeEach(function () { + describe('combined minimum and maximum', function() { + beforeEach(function() { this.validator = new Validator(); }); - it('should validate if number is below the maximum', function () { - return this.validator.validate(1, {'type': 'number', 'minimum': '1', 'maximum': '2'}).valid.should.be.true; + it('should validate if number is below the maximum', function() { + return this.validator.validate(1, { + 'type': 'number', + 'minimum': '1', + 'maximum': '2' + }).valid.should.be.true; }); - it('should not validate if number is above minumum', function () { - this.validator.validate(3, {'type': 'number', 'minimum': '1', 'maximum': '2'}).valid.should.be.false; + it('should not validate if number is above minumum', function() { + this.validator.validate(3, { + 'type': 'number', + 'minimum': '1', + 'maximum': '2' + }).valid.should.be.false; }); }); - describe('dividibleBy', function () { - beforeEach(function () { + describe('dividibleBy', function() { + beforeEach(function() { this.validator = new Validator(); }); - it('should validate if 0 is even', function () { - return this.validator.validate(2, {'type': 'number', 'divisibleBy': 2}).valid.should.be.true; + it('should validate if 0 is even', function() { + return this.validator.validate(2, { + 'type': 'number', + 'divisibleBy': 2 + }).valid.should.be.true; }); - it('should validate if -2 is even', function () { - return this.validator.validate(-2, {'type': 'number', 'divisibleBy': 2}).valid.should.be.true; + it('should validate if -2 is even', function() { + return this.validator.validate(-2, { + 'type': 'number', + 'divisibleBy': 2 + }).valid.should.be.true; }); - it('should not validate 1 is even', function () { - return this.validator.validate(1, {'type': 'number', 'divisibleBy': 2}).valid.should.be.false; + it('should not validate 1 is even', function() { + return this.validator.validate(1, { + 'type': 'number', + 'divisibleBy': 2 + }).valid.should.be.false; }); }); - describe('pattern', function () { - beforeEach(function () { + describe('pattern', function() { + beforeEach(function() { this.validator = new Validator(); }); - it('should validate if string matches the string pattern', function () { - return this.validator.validate('abbbc', {'type': 'string', 'pattern': 'ab+c'}).valid.should.be.true; + it('should validate if string matches the string pattern', function() { + return this.validator.validate('abbbc', { + 'type': 'string', + 'pattern': 'ab+c' + }).valid.should.be.true; }); - it('should validate if string matches the regexp pattern', function () { - return this.validator.validate('abbbc', {'type': 'string', 'pattern': /ab+c/}).valid.should.be.true; + it('should validate if string matches the regexp pattern', function() { + return this.validator.validate('abbbc', { + 'type': 'string', + 'pattern': /ab+c/ + }).valid.should.be.true; }); - it('should validate if string does not match the string pattern', function () { - return this.validator.validate('abac', {'type': 'string', 'pattern': 'ab+c'}).valid.should.be.false; + it('should validate if string does not match the string pattern', function() { + return this.validator.validate('abac', { + 'type': 'string', + 'pattern': 'ab+c' + }).valid.should.be.false; }); }); - describe('minLength', function () { - beforeEach(function () { + describe('minLength', function() { + beforeEach(function() { this.validator = new Validator(); }); - it('should validate if string has a length larger than minLength', function () { - return this.validator.validate('abcde', {'type': 'string', 'minLength': 5}).valid.should.be.true; + it('should validate if string has a length larger than minLength', function() { + return this.validator.validate('abcde', { + 'type': 'string', + 'minLength': 5 + }).valid.should.be.true; }); - it('should not validate if string does has a length less than minLength', function () { - return this.validator.validate('abcde', {'type': 'string', 'minLength': 6}).valid.should.be.false; + it('should not validate if string does has a length less than minLength', function() { + return this.validator.validate('abcde', { + 'type': 'string', + 'minLength': 6 + }).valid.should.be.false; }); }); - describe('maxLength', function () { - beforeEach(function () { + describe('maxLength', function() { + beforeEach(function() { this.validator = new Validator(); }); - it('should validate if string has a length equal to maxLength', function () { - return this.validator.validate('abcde', {'type': 'string', 'maxLength': 5}).valid.should.be.true; + it('should validate if string has a length equal to maxLength', function() { + return this.validator.validate('abcde', { + 'type': 'string', + 'maxLength': 5 + }).valid.should.be.true; }); - it('should not validate if string does has a length larger than maxLength', function () { - return this.validator.validate('abcde', {'type': 'string', 'maxLength': 4}).valid.should.be.false; + it('should not validate if string does has a length larger than maxLength', function() { + return this.validator.validate('abcde', { + 'type': 'string', + 'maxLength': 4 + }).valid.should.be.false; }); }); - describe('enum', function () { - beforeEach(function () { + describe('enum', function() { + beforeEach(function() { this.validator = new Validator(); }); - it('should validate if string is one of the enum values', function () { - return this.validator.validate('abcde', {'type': 'string', 'enum': ['abcdf', 'abcde']}).valid.should.be.true; - }); - - it('should not validate if string is not one of the enum values', function () { - return this.validator.validate('abcde', {'type': 'string', 'enum': ['abcdf', 'abcdd']}).valid.should.be.false; - }); - - it('should validate if number is one of the enum values', function () { - return this.validator.validate(1, {'type': 'number', 'enum': [1, 2]}).valid.should.be.true; - }); - - it('should not validate if number is not one of the enum values', function () { - return this.validator.validate(3, {'type': 'string', 'enum': [1, 2]}).valid.should.be.false; - }); - - it('should validate if value is undefined but defaults to one of the enum values', function () { - return this.validator.validate(undefined, {'enum': ['foo', 'bar', 'baz'], 'default': 'baz'}).valid.should.be.true; - }); - - it('should not validate if value is undefined and required, even if a default is given', function () { - return this.validator.validate(undefined, {'enum': ['foo', 'bar', 'baz'], 'required': true, 'default': 'baz'}).valid.should.be.false; - }); - - it('should not validate if a required field is ommited', function () { - return this.validator.validate({}, {'type': 'object', 'properties':{'the_field': {'enum': ['foo', 'bar', 'baz'], 'required': true}}}).valid.should.be.false; - }); - - it('should not validate if a required field is undefined', function () { - return this.validator.validate({'the_field':undefined}, {'type': 'object', 'properties':{'the_field': {'enum': ['foo', 'bar', 'baz'], 'required': true}}}).valid.should.be.false; - }); - - it('should validate if a required field has a value out of enum', function () { - return this.validator.validate({'the_field':'bar'}, {'type': 'object', 'properties':{'the_field': {'enum': ['foo', 'bar', 'baz'], 'required': true}}}).valid.should.be.true; + it('should validate if string is one of the enum values', function() { + return this.validator.validate('abcde', { + 'type': 'string', + 'enum': ['abcdf', 'abcde'] + }).valid.should.be.true; + }); + + it('should not validate if string is not one of the enum values', function() { + return this.validator.validate('abcde', { + 'type': 'string', + 'enum': ['abcdf', 'abcdd'] + }).valid.should.be.false; + }); + + it('should validate if number is one of the enum values', function() { + return this.validator.validate(1, { + 'type': 'number', + 'enum': [1, 2] + }).valid.should.be.true; + }); + + it('should not validate if number is not one of the enum values', function() { + return this.validator.validate(3, { + 'type': 'string', + 'enum': [1, 2] + }).valid.should.be.false; + }); + + it('should validate if value is undefined but defaults to one of the enum values', function() { + return this.validator.validate(undefined, { + 'enum': ['foo', 'bar', 'baz'], + 'default': 'baz' + }).valid.should.be.true; + }); + + it('should not validate if value is undefined and required, even if a default is given', function() { + return this.validator.validate(undefined, { + 'enum': ['foo', 'bar', 'baz'], + 'required': true, + 'default': 'baz' + }).valid.should.be.false; + }); + + it('should not validate if a required field is ommited', function() { + return this.validator.validate({}, { + 'type': 'object', + 'properties': { + 'the_field': { + 'enum': ['foo', 'bar', 'baz'], + 'required': true + } + } + }).valid.should.be.false; + }); + + it('should not validate if a required field is undefined', function() { + return this.validator.validate({ + 'the_field': undefined + }, { + 'type': 'object', + 'properties': { + 'the_field': { + 'enum': ['foo', 'bar', 'baz'], + 'required': true + } + } + }).valid.should.be.false; + }); + + it('should validate if a required field has a value out of enum', function() { + return this.validator.validate({ + 'the_field': 'bar' + }, { + 'type': 'object', + 'properties': { + 'the_field': { + 'enum': ['foo', 'bar', 'baz'], + 'required': true + } + } + }).valid.should.be.true; }); }); - describe('description', function () { - beforeEach(function () { + describe('description', function() { + beforeEach(function() { this.validator = new Validator(); }); - it('should be ignored', function () { - this.validator.validate(1, {'description': 'some text'}).valid.should.be.true; + it('should be ignored', function() { + this.validator.validate(1, { + 'description': 'some text' + }).valid.should.be.true; }); }); - describe('disallow', function () { - beforeEach(function () { + describe('disallow', function() { + beforeEach(function() { this.validator = new Validator(); }); - it('should prohibit specified types', function () { - this.validator.validate(1, {'type': 'any', 'disallow':'array'}).valid.should.be.true; + it('should prohibit specified types', function() { + this.validator.validate(1, { + 'type': 'any', + 'disallow': 'array' + }).valid.should.be.true; }); - it('should not prohibit unprohibited types', function () { - this.validator.validate(1, {'type':'any', 'disallow':'array'}).valid.should.be.true; + it('should not prohibit unprohibited types', function() { + this.validator.validate(1, { + 'type': 'any', + 'disallow': 'array' + }).valid.should.be.true; }); }); - describe('dependencies', function () { - beforeEach(function () { + describe('dependencies', function() { + beforeEach(function() { this.validator = new Validator(); }); - it('should validate with missing non-depended properties', function () { - this.validator.validate({foo: 1}, {'dependencies': {'quux': ['foo', 'bar']}}).valid.should.be.true; - }); - - it('should not validate with missing dependencies', function () { - this.validator.validate({quux: 1, foo: 1}, {'dependencies': {'quux': ['foo', 'bar']}}).valid.should.be.false; - }); - - it('should validate with satisfied dependencies', function () { - this.validator.validate({quux: 1, foo: 1, bar: 1}, {'dependencies': {'quux': ['foo', 'bar']}}).valid.should.be.true; + it('should validate with missing non-depended properties', function() { + this.validator.validate({ + foo: 1 + }, { + 'dependencies': { + 'quux': ['foo', 'bar'] + } + }).valid.should.be.true; + }); + + it('should not validate with missing dependencies', function() { + this.validator.validate({ + quux: 1, + foo: 1 + }, { + 'dependencies': { + 'quux': ['foo', 'bar'] + } + }).valid.should.be.false; + }); + + it('should validate with satisfied dependencies', function() { + this.validator.validate({ + quux: 1, + foo: 1, + bar: 1 + }, { + 'dependencies': { + 'quux': ['foo', 'bar'] + } + }).valid.should.be.true; }); }); -}); +}); \ No newline at end of file diff --git a/test/fixtures/types.json b/test/fixtures/types.json index df36d21..e263ef7 100644 --- a/test/fixtures/types.json +++ b/test/fixtures/types.json @@ -1,16 +1,17 @@ { - "description" : "custom types", - "type":"object", + "description": "custom types", + "type": "object", "amount": { - "description" : "Amount of the payment in cents, must be > 0", - "type" : "integer", + "description": "Amount of the payment in cents, must be > 0", + "type": "integer", "minimum": 1, "exclusiveMinimum": false }, "usage": { - "description" : "text statement for bank statement", - "type" : "string", + "description": "text statement for bank statement", + "type": "string", "minLength": 1, - "maxLength": 255 + "maxLength": 255, + "required": true } } \ No newline at end of file diff --git a/test/formats.js b/test/formats.js index 7b0a6d1..bb97cad 100644 --- a/test/formats.js +++ b/test/formats.js @@ -6,259 +6,455 @@ var Validator = require('../lib/validator'); var should = require('chai').should(); -describe('Formats', function () { - beforeEach(function () { +describe('Formats', function() { + beforeEach(function() { this.validator = new Validator(); }); - describe('date-time', function () { - it('should validate a valid date-time', function () { - this.validator.validate("2012-07-08T16:41:41.532Z", {'type': 'string', 'format': 'date-time'}).valid.should.be.true; + describe('date-time', function() { + it('should validate a valid date-time', function() { + this.validator.validate("2012-07-08T16:41:41.532Z", { + 'type': 'string', + 'format': 'date-time' + }).valid.should.be.true; }); - it('should validate a valid date-time without milliseconds', function () { - this.validator.validate("2012-07-08T16:41:41Z", {'type': 'string', 'format': 'date-time'}).valid.should.be.true; + it('should validate a valid date-time without milliseconds', function() { + this.validator.validate("2012-07-08T16:41:41Z", { + 'type': 'string', + 'format': 'date-time' + }).valid.should.be.true; }); - it('should validate a date-time with a timezone offset instead of Z', function () { - this.validator.validate("2012-07-08T16:41:41.532+00:00", {'type': 'string', 'format': 'date-time'}).valid.should.be.true; - this.validator.validate("2012-07-08T16:41:41.532+05:30", {'type': 'string', 'format': 'date-time'}).valid.should.be.true; - this.validator.validate("2012-07-08T16:41:41.532+04:00", {'type': 'string', 'format': 'date-time'}).valid.should.be.true; + it('should validate a RFC3339 format', function() { + this.validator.validate("1996-12-19T16:39:57-08:00", { + 'type': 'string', + 'format': 'date-time' + }).valid.should.be.true; }); - it('should validate a date-time with a z instead of a Z', function () { - this.validator.validate("2012-07-08T16:41:41.532z", {'type': 'string', 'format': 'date-time'}).valid.should.be.true; + it('should validate a date-time with a timezone offset instead of Z', function() { + this.validator.validate("2012-07-08T16:41:41.532+00:00", { + 'type': 'string', + 'format': 'date-time' + }).valid.should.be.true; + this.validator.validate("2012-07-08T16:41:41.532+05:30", { + 'type': 'string', + 'format': 'date-time' + }).valid.should.be.true; + this.validator.validate("2012-07-08T16:41:41.532+04:00", { + 'type': 'string', + 'format': 'date-time' + }).valid.should.be.true; }); - it('should validate a date-time with a space instead of a T', function () { - this.validator.validate("2012-07-08 16:41:41.532Z", {'type': 'string', 'format': 'date-time'}).valid.should.be.true; + it('should validate a date-time with timezone adjustment and milliseconds', function() { + this.validator.validate("2014-07-17T19:08:05.7126000+00:00", { + 'type': 'string', + 'format': 'date-time' + }).valid.should.be.true; }); - it('should validate a date-time with a t instead of a T', function () { - this.validator.validate("2012-07-08t16:41:41.532Z", {'type': 'string', 'format': 'date-time'}).valid.should.be.true; + it('should validate a date-time with milliseconds', function() { + this.validator.validate("2014-06-27T21:26:26.91", { + 'type': 'string', + 'format': 'date-time' + }).valid.should.be.true; }); - it('should not validate a date-time with the time missing', function () { - this.validator.validate("2012-07-08", {'type': 'string', 'format': 'date-time'}).valid.should.be.false; + it('should validate a date-time with a z instead of a Z', function() { + this.validator.validate("2012-07-08T16:41:41.532z", { + 'type': 'string', + 'format': 'date-time' + }).valid.should.be.true; }); - it('should not validate an invalid date-time', function () { - this.validator.validate("TEST2012-07-08T16:41:41.532Z", {'type': 'string', 'format': 'date-time'}).valid.should.be.false; + it('should validate a date-time with a z instead of a Z', function() { + this.validator.validate("2012-07-08T16:41:41.532z", { + 'type': 'string', + 'format': 'date-time' + }).valid.should.be.true; }); - it('should not validate a date-time with a timezone offset AND a Z', function () { - this.validator.validate("2012-07-08T16:41:41.532+00:00Z", {'type': 'string', 'format': 'date-time'}).valid.should.be.false; - this.validator.validate("2012-07-08T16:41:41.532+Z00:00", {'type': 'string', 'format': 'date-time'}).valid.should.be.false; + it('should validate a date-time with a space instead of a T', function() { + this.validator.validate("2012-07-08 16:41:41.532Z", { + 'type': 'string', + 'format': 'date-time' + }).valid.should.be.true; + }); + + it('should validate a date-time with a t instead of a T', function() { + this.validator.validate("2012-07-08t16:41:41.532Z", { + 'type': 'string', + 'format': 'date-time' + }).valid.should.be.true; + }); + + it('should not validate a date-time with the time missing', function() { + this.validator.validate("2012-07-08", { + 'type': 'string', + 'format': 'date-time' + }).valid.should.be.false; + }); + + it('should not validate an invalid date-time', function() { + this.validator.validate("TEST2012-07-08T16:41:41.532Z", { + 'type': 'string', + 'format': 'date-time' + }).valid.should.be.false; + }); + + it('should not validate a date-time with a timezone offset AND a Z', function() { + this.validator.validate("2012-07-08T16:41:41.532+00:00Z", { + 'type': 'string', + 'format': 'date-time' + }).valid.should.be.false; + this.validator.validate("2012-07-08T16:41:41.532+Z00:00", { + 'type': 'string', + 'format': 'date-time' + }).valid.should.be.false; }); }); - describe('date', function () { - it('should validate a valid date', function () { - this.validator.validate("2012-07-08", {'type': 'string', 'format': 'date'}).valid.should.be.true; + describe('date', function() { + it('should validate a valid date', function() { + this.validator.validate("2012-07-08", { + 'type': 'string', + 'format': 'date' + }).valid.should.be.true; }); - it('should not validate an invalid date', function () { - this.validator.validate("TEST2012-07-08", {'type': 'string', 'format': 'date'}).valid.should.be.false; + it('should not validate an invalid date', function() { + this.validator.validate("TEST2012-07-08", { + 'type': 'string', + 'format': 'date' + }).valid.should.be.false; }); }); - describe('time', function () { - it('should validate a valid time', function () { - this.validator.validate("16:41:41", {'type': 'string', 'format': 'time'}).valid.should.be.true; + describe('time', function() { + it('should validate a valid time', function() { + this.validator.validate("16:41:41", { + 'type': 'string', + 'format': 'time' + }).valid.should.be.true; }); - it('should not validate an invalid time', function () { - this.validator.validate("16:41:41.532Z", {'type': 'string', 'format': 'time'}).valid.should.be.false; + it('should not validate an invalid time', function() { + this.validator.validate("16:41:41.532Z", { + 'type': 'string', + 'format': 'time' + }).valid.should.be.false; }); }); - describe('utc-millisec', function () { - it('should validate a valid utc-millisec', function () { - this.validator.validate("-1234567890", {'type': 'string', 'format': 'utc-millisec'}).valid.should.be.true; + describe('utc-millisec', function() { + it('should validate a valid utc-millisec', function() { + this.validator.validate("-1234567890", { + 'type': 'string', + 'format': 'utc-millisec' + }).valid.should.be.true; }); - it('should not validate an invalid utc-millisec', function () { - this.validator.validate("16:41:41.532Z", {'type': 'string', 'format': 'utc-millisec'}).valid.should.be.false; + it('should not validate an invalid utc-millisec', function() { + this.validator.validate("16:41:41.532Z", { + 'type': 'string', + 'format': 'utc-millisec' + }).valid.should.be.false; }); }); - describe('regex', function () { - it('should validate a valid regex', function () { - this.validator.validate("/a/", {'type': 'string', 'format': 'regex'}).valid.should.be.true; + describe('regex', function() { + it('should validate a valid regex', function() { + this.validator.validate("/a/", { + 'type': 'string', + 'format': 'regex' + }).valid.should.be.true; }); - it('should not validate an invalid regex', function () { - this.validator.validate("/^(abc]/", {'type': 'string', 'format': 'regex'}).valid.should.be.false; + it('should not validate an invalid regex', function() { + this.validator.validate("/^(abc]/", { + 'type': 'string', + 'format': 'regex' + }).valid.should.be.false; }); }); - describe('color', function () { - it('should validate the color red', function () { - this.validator.validate("red", {'type': 'string', 'format': 'color'}).valid.should.be.true; + describe('color', function() { + it('should validate the color red', function() { + this.validator.validate("red", { + 'type': 'string', + 'format': 'color' + }).valid.should.be.true; }); - it('should validate the color #f00', function () { - this.validator.validate("#f00", {'type': 'string', 'format': 'color'}).valid.should.be.true; + it('should validate the color #f00', function() { + this.validator.validate("#f00", { + 'type': 'string', + 'format': 'color' + }).valid.should.be.true; }); - it('should validate the color #ff0000', function () { - this.validator.validate("#ff0000", {'type': 'string', 'format': 'color'}).valid.should.be.true; + it('should validate the color #ff0000', function() { + this.validator.validate("#ff0000", { + 'type': 'string', + 'format': 'color' + }).valid.should.be.true; }); - it('should validate the color rgb(255,0,0)', function () { - this.validator.validate("rgb(255,0,0)", {'type': 'string', 'format': 'color'}).valid.should.be.true; + it('should validate the color rgb(255,0,0)', function() { + this.validator.validate("rgb(255,0,0)", { + 'type': 'string', + 'format': 'color' + }).valid.should.be.true; }); - it('should not validate an invalid color (json)', function () { - this.validator.validate("json", {'type': 'string', 'format': 'color'}).valid.should.be.false; + it('should not validate an invalid color (json)', function() { + this.validator.validate("json", { + 'type': 'string', + 'format': 'color' + }).valid.should.be.false; }); }); - describe('style', function () { - it('should validate a valid style', function () { - this.validator.validate("color: red;", {'type': 'string', 'format': 'style'}).valid.should.be.true; + describe('style', function() { + it('should validate a valid style', function() { + this.validator.validate("color: red;", { + 'type': 'string', + 'format': 'style' + }).valid.should.be.true; }); - it('should validate a valid complex style', function () { - this.validator.validate("color: red; position: absolute; background-color: rgb(204, 204, 204); max-width: 150px;", {'type': 'string', 'format': 'style'}).valid.should.be.true; + it('should validate a valid complex style', function() { + this.validator.validate("color: red; position: absolute; background-color: rgb(204, 204, 204); max-width: 150px;", { + 'type': 'string', + 'format': 'style' + }).valid.should.be.true; }); - it('should validate a valid complex style', function () { - this.validator.validate("color:red;position:absolute; background-color: rgb(204, 204, 204); max-width: 150px;", {'type': 'string', 'format': 'style'}).valid.should.be.true; + it('should validate a valid complex style', function() { + this.validator.validate("color:red;position:absolute; background-color: rgb(204, 204, 204); max-width: 150px;", { + 'type': 'string', + 'format': 'style' + }).valid.should.be.true; }); - it('should not validate an invalid style', function () { - this.validator.validate("0", {'type': 'string', 'format': 'style'}).valid.should.be.false; + it('should not validate an invalid style', function() { + this.validator.validate("0", { + 'type': 'string', + 'format': 'style' + }).valid.should.be.false; }); }); - describe('phone', function () { - it('should validate a valid phone-number', function () { - this.validator.validate("+31 42 123 4567", {'type': 'string', 'format': 'phone'}).valid.should.be.true; + describe('phone', function() { + it('should validate a valid phone-number', function() { + this.validator.validate("+31 42 123 4567", { + 'type': 'string', + 'format': 'phone' + }).valid.should.be.true; }); - it('should not validate an invalid phone-number', function () { - this.validator.validate("31 42 123 4567", {'type': 'string', 'format': 'phone'}).valid.should.be.false; + it('should not validate an invalid phone-number', function() { + this.validator.validate("31 42 123 4567", { + 'type': 'string', + 'format': 'phone' + }).valid.should.be.false; }); }); - describe('uri', function () { - it('should validate http://www.google.com/', function () { - this.validator.validate("http://www.google.com/", {'type': 'string', 'format': 'uri'}).valid.should.be.true; + describe('uri', function() { + it('should validate http://www.google.com/', function() { + this.validator.validate("http://www.google.com/", { + 'type': 'string', + 'format': 'uri' + }).valid.should.be.true; }); - it('should validate http://www.google.com/search', function () { - this.validator.validate("http://www.google.com/search", {'type': 'string', 'format': 'uri'}).valid.should.be.true; + it('should validate http://www.google.com/search', function() { + this.validator.validate("http://www.google.com/search", { + 'type': 'string', + 'format': 'uri' + }).valid.should.be.true; }); - it('should not validate relative URIs', function () { - this.validator.validate("tdegrunt", {'type': 'string', 'format': 'uri'}).valid.should.be.false; + it('should not validate relative URIs', function() { + this.validator.validate("tdegrunt", { + 'type': 'string', + 'format': 'uri' + }).valid.should.be.false; }); - it('should not validate with whitespace', function () { - this.validator.validate("The dog jumped", {'type': 'string', 'format': 'uri'}).valid.should.be.false; + it('should not validate with whitespace', function() { + this.validator.validate("The dog jumped", { + 'type': 'string', + 'format': 'uri' + }).valid.should.be.false; }); }); - describe('email', function () { - it('should validate obama@whitehouse.gov', function () { - this.validator.validate("obama@whitehouse.gov", {'type': 'string', 'format': 'email'}).valid.should.be.true; + describe('email', function() { + it('should validate obama@whitehouse.gov', function() { + this.validator.validate("obama@whitehouse.gov", { + 'type': 'string', + 'format': 'email' + }).valid.should.be.true; }); - it('should validate barack+obama@whitehouse.gov', function () { - this.validator.validate("barack+obama@whitehouse.gov", {'type': 'string', 'format': 'email'}).valid.should.be.true; + it('should validate barack+obama@whitehouse.gov', function() { + this.validator.validate("barack+obama@whitehouse.gov", { + 'type': 'string', + 'format': 'email' + }).valid.should.be.true; }); - it('should not validate obama@', function () { - this.validator.validate("obama@", {'type': 'string', 'format': 'email'}).valid.should.be.false; + it('should not validate obama@', function() { + this.validator.validate("obama@", { + 'type': 'string', + 'format': 'email' + }).valid.should.be.false; }); }); - describe('ip-address', function () { - it('should validate 192.168.0.1', function () { - this.validator.validate("192.168.0.1", {'type': 'string', 'format': 'ip-address'}).valid.should.be.true; + describe('ip-address', function() { + it('should validate 192.168.0.1', function() { + this.validator.validate("192.168.0.1", { + 'type': 'string', + 'format': 'ip-address' + }).valid.should.be.true; }); - it('should validate 127.0.0.1', function () { - this.validator.validate("127.0.0.1", {'type': 'string', 'format': 'ip-address'}).valid.should.be.true; + it('should validate 127.0.0.1', function() { + this.validator.validate("127.0.0.1", { + 'type': 'string', + 'format': 'ip-address' + }).valid.should.be.true; }); - it('should not validate 192.168.0', function () { - this.validator.validate("192.168.0", {'type': 'string', 'format': 'ip-address'}).valid.should.be.false; + it('should not validate 192.168.0', function() { + this.validator.validate("192.168.0", { + 'type': 'string', + 'format': 'ip-address' + }).valid.should.be.false; }); - it('should not validate 256.168.0', function () { - this.validator.validate("256.168.0", {'type': 'string', 'format': 'ip-address'}).valid.should.be.false; + it('should not validate 256.168.0', function() { + this.validator.validate("256.168.0", { + 'type': 'string', + 'format': 'ip-address' + }).valid.should.be.false; }); }); - describe('ipv6', function () { - it('should validate fe80::1%lo0', function () { - this.validator.validate("fe80::1%lo0", {'type': 'string', 'format': 'ipv6'}).valid.should.be.true; + describe('ipv6', function() { + it('should validate fe80::1%lo0', function() { + this.validator.validate("fe80::1%lo0", { + 'type': 'string', + 'format': 'ipv6' + }).valid.should.be.true; }); - it('should validate ::1', function () { - this.validator.validate("::1", {'type': 'string', 'format': 'ipv6'}).valid.should.be.true; + it('should validate ::1', function() { + this.validator.validate("::1", { + 'type': 'string', + 'format': 'ipv6' + }).valid.should.be.true; }); - it('should not validate 127.0.0.1', function () { - this.validator.validate("127.0.0.1", {'type': 'string', 'format': 'ipv6'}).valid.should.be.false; + it('should not validate 127.0.0.1', function() { + this.validator.validate("127.0.0.1", { + 'type': 'string', + 'format': 'ipv6' + }).valid.should.be.false; }); - it('should not validate localhost', function () { - this.validator.validate("localhost", {'type': 'string', 'format': 'ipv6'}).valid.should.be.false; + it('should not validate localhost', function() { + this.validator.validate("localhost", { + 'type': 'string', + 'format': 'ipv6' + }).valid.should.be.false; }); }); - describe('host-name', function () { - it('should validate localhost', function () { - this.validator.validate("localhost", {'type': 'string', 'format': 'host-name'}).valid.should.be.true; + describe('host-name', function() { + it('should validate localhost', function() { + this.validator.validate("localhost", { + 'type': 'string', + 'format': 'host-name' + }).valid.should.be.true; }); - it('should validate www.google.com', function () { - this.validator.validate("www.google.com", {'type': 'string', 'format': 'host-name'}).valid.should.be.true; + it('should validate www.google.com', function() { + this.validator.validate("www.google.com", { + 'type': 'string', + 'format': 'host-name' + }).valid.should.be.true; }); - it('should not validate www.-hi-.com', function () { - this.validator.validate("www.-hi-.com", {'type': 'string', 'format': 'host-name'}).valid.should.be.false; + it('should not validate www.-hi-.com', function() { + this.validator.validate("www.-hi-.com", { + 'type': 'string', + 'format': 'host-name' + }).valid.should.be.false; }); }); - describe('alpha', function () { - it('should validate alpha', function () { - this.validator.validate("alpha", {'type': 'string', 'format': 'alpha'}).valid.should.be.true; + describe('alpha', function() { + it('should validate alpha', function() { + this.validator.validate("alpha", { + 'type': 'string', + 'format': 'alpha' + }).valid.should.be.true; }); - it('should validate abracadabra', function () { - this.validator.validate("abracadabra", {'type': 'string', 'format': 'alpha'}).valid.should.be.true; + it('should validate abracadabra', function() { + this.validator.validate("abracadabra", { + 'type': 'string', + 'format': 'alpha' + }).valid.should.be.true; }); - it('should not validate 1test', function () { - this.validator.validate("www.-hi-.com", {'type': 'string', 'format': 'alpha'}).valid.should.be.false; + it('should not validate 1test', function() { + this.validator.validate("www.-hi-.com", { + 'type': 'string', + 'format': 'alpha' + }).valid.should.be.false; }); }); - describe('alphanumeric', function () { - it('should validate alphanumeric', function () { - this.validator.validate("alpha", {'type': 'string', 'format': 'alphanumeric'}).valid.should.be.true; + describe('alphanumeric', function() { + it('should validate alphanumeric', function() { + this.validator.validate("alpha", { + 'type': 'string', + 'format': 'alphanumeric' + }).valid.should.be.true; }); - it('should validate 123', function () { - this.validator.validate("123", {'type': 'string', 'format': 'alphanumeric'}).valid.should.be.true; + it('should validate 123', function() { + this.validator.validate("123", { + 'type': 'string', + 'format': 'alphanumeric' + }).valid.should.be.true; }); - it('should validate abracadabra123', function () { - this.validator.validate("abracadabra123", {'type': 'string', 'format': 'alphanumeric'}).valid.should.be.true; + it('should validate abracadabra123', function() { + this.validator.validate("abracadabra123", { + 'type': 'string', + 'format': 'alphanumeric' + }).valid.should.be.true; }); - it('should not validate 1test!', function () { - this.validator.validate("1test!", {'type': 'string', 'format': 'alphanumeric'}).valid.should.be.false; + it('should not validate 1test!', function() { + this.validator.validate("1test!", { + 'type': 'string', + 'format': 'alphanumeric' + }).valid.should.be.false; }); }); -}); +}); \ No newline at end of file diff --git a/test/objects.js b/test/objects.js index 5fa592c..62bdc90 100644 --- a/test/objects.js +++ b/test/objects.js @@ -6,81 +6,101 @@ var Validator = require('../lib/validator'); var should = require('chai').should(); -describe('Objects', function () { - beforeEach(function () { +describe('Objects', function() { + beforeEach(function() { this.validator = new Validator(); }); - describe('simple object', function () { - it('should validate a valid object', function () { - this.validator.validate({}, {'type': 'object'}).valid.should.be.true; + describe('simple object', function() { + it('should validate a valid object', function() { + this.validator.validate({}, { + 'type': 'object' + }).valid.should.be.true; }); - it('should validate an undefined object', function () { - this.validator.validate(undefined, {'type': 'object'}).valid.should.be.true; + it('should validate an undefined object', function() { + this.validator.validate(undefined, { + 'type': 'object' + }).valid.should.be.true; }); - it('should not validate a number', function () { - return this.validator.validate(0, {'type': 'object'}).valid.should.be.false; + it('should not validate a number', function() { + return this.validator.validate(0, { + 'type': 'object' + }).valid.should.be.false; }); - it('should not validate an array', function () { - return this.validator.validate([0], {'type': 'object'}).valid.should.be.false; + it('should not validate an array', function() { + return this.validator.validate([0], { + 'type': 'object' + }).valid.should.be.false; }); }); - describe('object with property', function () { - it('should validate a valid object', function () { - this.validator.validate( - {'name': 'test'}, - { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'} + describe('object with property', function() { + it('should validate a valid object', function() { + this.validator.validate({ + 'name': 'test' + }, { + 'type': 'object', + 'properties': { + 'name': { + 'type': 'string' } } - ).valid.should.be.true; + }).valid.should.be.true; }); - it('should not validate an invalid object', function () { - return this.validator.validate(0, {'type': 'object'}).valid.should.be.false; + it('should not validate an invalid object', function() { + return this.validator.validate(0, { + 'type': 'object' + }).valid.should.be.false; }); }); - describe('object with properties', function () { - it('should validate a valid object with multiple properties', function () { - this.validator.validate( - {'name': 'test', 'address': 'someplace'}, - { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'address': {'type': 'string'} + describe('object with properties', function() { + it('should validate a valid object with multiple properties', function() { + this.validator.validate({ + 'name': 'test', + 'address': 'someplace' + }, { + 'type': 'object', + 'properties': { + 'name': { + 'type': 'string' + }, + 'address': { + 'type': 'string' } } - ).valid.should.be.true; + }).valid.should.be.true; }); - it('should validate a valid object with undefined property', function () { - this.validator.validate( - {'name': 'test'}, - { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'address': {'type': 'string'} + it('should validate a valid object with undefined property', function() { + this.validator.validate({ + 'name': 'test' + }, { + 'type': 'object', + 'properties': { + 'name': { + 'type': 'string' + }, + 'address': { + 'type': 'string' } } - ).valid.should.be.true; + }).valid.should.be.true; }); it('should not throw when checking properties on a non-object', function() { this.validator.validate( - null, - { + null, { 'type': 'object', + 'required': 'true', 'properties': { - 'name': {'type': 'string'} + 'name': { + 'type': 'string' + } } } ).valid.should.be.false; @@ -88,111 +108,149 @@ describe('Objects', function () { }); - describe('nested object with property', function () { - it('should NOT validate a valid object', function () { - this.validator.validate( - {'name': 'test', 'nested': 'test2'}, - { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'nested': {'type': 'object'} + describe('nested object with property', function() { + it('should NOT validate a valid object', function() { + this.validator.validate({ + 'name': 'test', + 'nested': 'test2' + }, { + 'type': 'object', + 'properties': { + 'name': { + 'type': 'string' + }, + 'nested': { + 'type': 'object' } } - ).valid.should.be.false; + }).valid.should.be.false; }); - it('should validate a valid object', function () { - this.validator.validate( - {'name': 'test', 'nested': 'test2'}, - { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'nested': {'type': 'string'} + it('should validate a valid object', function() { + this.validator.validate({ + 'name': 'test', + 'nested': 'test2' + }, { + 'type': 'object', + 'properties': { + 'name': { + 'type': 'string' + }, + 'nested': { + 'type': 'string' } } - ).valid.should.be.true; + }).valid.should.be.true; }); }); - describe('undefined but required object', function () { - it('should NOT validate an undefined object', function () { - var ret = this.validator.validate( - {'foo': {'baz': 1}}, - { - 'type': 'object', - 'required': true, - 'properties': { - 'foo': { - 'type': 'object', - 'required': true, - 'properties': { - 'bar': {'type': 'object', 'required': true}, - 'baz': {'type': 'number', 'required': true} + describe('undefined but required object', function() { + it('should NOT validate an undefined object', function() { + var ret = this.validator.validate({ + 'foo': { + 'baz': 1 + } + }, { + 'type': 'object', + 'required': true, + 'properties': { + 'foo': { + 'type': 'object', + 'required': true, + 'properties': { + 'bar': { + 'type': 'object', + 'required': true + }, + 'baz': { + 'type': 'number', + 'required': true } } } } - ).valid.should.be.false; + }).valid.should.be.false; }); }); - describe('additionalProperties', function () { - it('should validate if there are no additionalProperties', function () { - this.validator.validate( - {'name': 'test', 'nested': 'test2'}, - { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'nested': {'type': 'string'} + describe('additionalProperties', function() { + it('should validate if there are no additionalProperties', function() { + this.validator.validate({ + 'name': 'test', + 'nested': 'test2' + }, { + 'type': 'object', + 'properties': { + 'name': { + 'type': 'string' }, - 'additionalProperties': false - } - ).valid.should.be.true; + 'nested': { + 'type': 'string' + } + }, + 'additionalProperties': false + }).valid.should.be.true; }); - it('should not validate if there are additionalProperties', function () { - this.validator.validate( - {'name': 'test', 'nested': 'test2', 'extraProp': 1}, - { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'nested': {'type': 'string'} + it('should not validate if there are additionalProperties', function() { + this.validator.validate({ + 'name': 'test', + 'nested': 'test2', + 'extraProp': 1 + }, { + 'type': 'object', + 'properties': { + 'name': { + 'type': 'string' }, - 'additionalProperties': false - } - ).valid.should.be.false; + 'nested': { + 'type': 'string' + } + }, + 'additionalProperties': false + }).valid.should.be.false; }); - it('should validate if the additionalProperties are compliant with additionalProperties', function () { - this.validator.validate( - {'name': 'test', 'nested': 'test2', 'extraProp': 1}, - { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'nested': {'type': 'string'} + it('should validate if the additionalProperties are compliant with additionalProperties', function() { + this.validator.validate({ + 'name': 'test', + 'nested': 'test2', + 'extraProp': 1 + }, { + 'type': 'object', + 'properties': { + 'name': { + 'type': 'string' }, - 'additionalProperties': {'type': 'number'} + 'nested': { + 'type': 'string' + } + }, + 'additionalProperties': { + 'type': 'number' } - ).valid.should.be.true; + }).valid.should.be.true; }); - it('should not validate if the additionalProperties are not compliant with additionalProperties', function () { - this.validator.validate( - {'name': 'test', 'nested': 'test2', 'extraProp': '1'}, - { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'nested': {'type': 'string'} + it('should not validate if the additionalProperties are not compliant with additionalProperties', function() { + this.validator.validate({ + 'name': 'test', + 'nested': 'test2', + 'extraProp': '1' + }, { + 'type': 'object', + 'properties': { + 'name': { + 'type': 'string' }, - 'additionalProperties': {'type': 'number'} + 'nested': { + 'type': 'string' + } + }, + 'additionalProperties': { + 'type': 'number' } - ).valid.should.be.false; + }).valid.should.be.false; }); }); -}); +}); \ No newline at end of file diff --git a/test/required_with_ref.js b/test/required_with_ref.js index 97e7789..225c233 100644 --- a/test/required_with_ref.js +++ b/test/required_with_ref.js @@ -9,168 +9,171 @@ var assert = require('chai').assert var Validator = require('../lib/validator') /** -* sort of functional test for "extends" and "required" -*/ -describe('required with $ref', function () { - var json, validator, schema, data, payment; + * sort of functional test for "extends" and "required" + */ +describe('required with $ref', function() { + var json, validator, schema, data, payment; - beforeEach(function () { - if(!json) { - json = { - schema :fs.readFileSync('test/fixtures/data_schema.json') - ,types :fs.readFileSync('test/fixtures/types.json') - ,data :fs.readFileSync('test/fixtures/data.json') - } - } - validator = new Validator() - schema = JSON.parse(json.schema) - validator.addSchema(JSON.parse(json.types), '/types.json') - data = JSON.parse(json.data) - payment = data.payment - }) + beforeEach(function() { + if (!json) { + json = { + schema: fs.readFileSync('test/fixtures/data_schema.json'), + types: fs.readFileSync('test/fixtures/types.json'), + data: fs.readFileSync('test/fixtures/data.json') + } + } + validator = new Validator() + schema = JSON.parse(json.schema) + validator.addSchema(JSON.parse(json.types), '/types.json') + data = JSON.parse(json.data) + payment = data.payment + }) - function assertValid(p) { - validate(p, true) - } - function assertNotValid(p) { - validate(p, false) - } - function validate(p, bool) { - var result = validator.validate(p, schema) - //console.log(util.inspect(validator,{depth: 3 })) - assert.strictEqual(result.valid, bool, util.inspect(result.errors, { showHidden: false, depth: 1 })) - } + function assertValid(p) { + validate(p, true) + } - describe('fixture', function () { - it('should validate', function () { - assertValid(data) - }) - it('with wrong root node schould not be valid', function(){ - assertNotValid({wrong_root:payment}) - }) - }) + function assertNotValid(p) { + validate(p, false) + } - describe('required positive integer (amount)', function() { - describe('valid', function() { - it('1', function () { - payment.amount = 1; - assertValid(data) - }) - it('1000000000', function () { - payment.amount = 1000000000; - assertValid(data) - }) - }) - describe('not valid', function() { - it('missing', function () { - delete(payment.amount) - assertNotValid(data) - }) - it('1.2', function () { - payment.amount = 1.2; - assertNotValid(data) - }) - it('0', function () { - payment.amount = 0; - assertNotValid(data) - }) - it('-1', function () { - payment.amount = -1; - assertNotValid(data) - }) - it('-1.2', function () { - payment.amount = -1.2; - assertNotValid(data) - }) - it('foo', function () { - payment.amount = 'foo'; - assertNotValid(data) - }) - }) - }) + function validate(p, bool) { + var result = validator.validate(p, schema) + //console.log(util.inspect(validator,{depth: 3 })) + assert.strictEqual(result.valid, bool, util.inspect(result.errors, { + showHidden: false, + depth: 1 + })) + } + describe('fixture', function() { + it('should validate', function() { + assertValid(data) + }) + it('with wrong root node schould not be valid', function() { + assertNotValid({ + wrong_root: payment + }) + }) + }) - describe('required positive integer via $ref (other_amount)', function() { - describe('valid', function() { - it('1', function () { - payment.other_amount = 1; - assertValid(data) - }) - it('1000000000', function () { - payment.other_amount = 1000000000; - assertValid(data) - }) - }) - describe('not valid', function() { - it('missing', function () { - delete(payment.other_amount) - assertNotValid(data) - }) - it('1.2', function () { - payment.other_amount = 1.2; - assertNotValid(data) - }) - it('0', function () { - payment.other_amount = 0; - assertNotValid(data) - }) - it('-1', function () { - payment.other_amount = -1; - assertNotValid(data) - }) - it('-1.2', function () { - payment.other_amount = -1.2; - assertNotValid(data) - }) - it('foo', function () { - payment.other_amount = 'foo'; - assertNotValid(data) - }) - }) - }) + describe('required positive integer (amount)', function() { + describe('valid', function() { + it('1', function() { + payment.amount = 1; + assertValid(data) + }) + it('1000000000', function() { + payment.amount = 1000000000; + assertValid(data) + }) + }) + describe('not valid', function() { + it('missing', function() { + delete(payment.amount) + assertNotValid(data) + }) + it('1.2', function() { + payment.amount = 1.2; + assertNotValid(data) + }) + it('0', function() { + payment.amount = 0; + assertNotValid(data) + }) + it('-1', function() { + payment.amount = -1; + assertNotValid(data) + }) + it('-1.2', function() { + payment.amount = -1.2; + assertNotValid(data) + }) + it('foo', function() { + payment.amount = 'foo'; + assertNotValid(data) + }) + }) + }) - describe('optional string 1..255 (usage)', function() { - describe('valid', function() { - it('missing', function () { - delete(payment.usage); - assertValid(data) - }) - it('string', function () { - payment.usage = "the usage"; - assertValid(data) - }) - it('"a"', function () { - payment.usage = 'a'; - assertValid(data) - }) - it('255 chars', function () { - payment.usage = - "bbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqq" - +"bbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqq" - +"bbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbzzzzz"; - assertValid(data) - }) - }) - describe('not valid', function() { - it('1234', function () { - payment.usage = 1234; - assertNotValid(data) - }) - it('null', function () { - payment.usage = null; - assertNotValid(data) - }) - it('""', function () { - payment.usage = ''; - assertNotValid(data) - }) - it('256 chars', function () { - payment.usage = - "bbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqq" - +"bbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqq" - +"bbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbzzzzzX"; - assertNotValid(data) - }) - }) - }) + + describe('required positive integer via $ref (other_amount)', function() { + describe('valid', function() { + it('1', function() { + payment.other_amount = 1; + assertValid(data) + }) + it('1000000000', function() { + payment.other_amount = 1000000000; + assertValid(data) + }) + }) + describe('not valid', function() { + it('missing', function() { + delete(payment.other_amount) + assertNotValid(data) + }) + it('1.2', function() { + payment.other_amount = 1.2; + assertNotValid(data) + }) + it('0', function() { + payment.other_amount = 0; + assertNotValid(data) + }) + it('-1', function() { + payment.other_amount = -1; + assertNotValid(data) + }) + it('-1.2', function() { + payment.other_amount = -1.2; + assertNotValid(data) + }) + it('foo', function() { + payment.other_amount = 'foo'; + assertNotValid(data) + }) + }) + }) + + describe('optional string 1..255 (usage)', function() { + describe('valid', function() { + it('missing', function() { + delete(payment.usage); + assertNotValid(data) + }) + it('string', function() { + payment.usage = "the usage"; + assertValid(data) + }) + it('"a"', function() { + payment.usage = 'a'; + assertValid(data) + }) + it('255 chars', function() { + payment.usage = + "bbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqq" + "bbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqq" + "bbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbzzzzz"; + assertValid(data) + }) + }) + describe('not valid', function() { + it('1234', function() { + payment.usage = 1234; + assertNotValid(data) + }) + it('null', function() { + payment.usage = null; + assertNotValid(data) + }) + it('""', function() { + payment.usage = ''; + assertNotValid(data) + }) + it('256 chars', function() { + payment.usage = + "bbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqq" + "bbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqq" + "bbbbbbbbbbqqqqqqqqqqbbbbbbbbbbqqqqqqqqqqbbbbbbbbbbzzzzzX"; + assertNotValid(data) + }) + }) + }) }) \ No newline at end of file