From 9fe35146cc0bc9d1ecf8d2c03216d82eb964a2ee Mon Sep 17 00:00:00 2001 From: julien Date: Thu, 8 Jan 2015 13:31:27 +0100 Subject: [PATCH 1/4] added option to validate unexpected properties are not present --- src/errorTypes.js | 9 +++++++++ src/validateModel.js | 13 ++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/errorTypes.js b/src/errorTypes.js index 860767f..9362e25 100644 --- a/src/errorTypes.js +++ b/src/errorTypes.js @@ -129,6 +129,15 @@ MissingValueError.prototype = Object.create(DataTypeValidationError.prototype); MissingValueError.prototype.constructor = MissingValueError; exports.MissingValueError = MissingValueError; +function UnexpectedValueError(){ + this.name = 'UnexpectedValueError'; + + this.message = 'This value is unexpected'; +} +UnexpectedValueError.prototype = Object.create(DataTypeValidationError.prototype); +UnexpectedValueError.prototype.constructor = UnexpectedValueError; +exports.UnexpectedValueError = UnexpectedValueError; + function ValidationError(specName, spec, error){ this.name = 'ValidationError'; this.specName = specName; diff --git a/src/validateModel.js b/src/validateModel.js index 22c16de..c165d56 100644 --- a/src/validateModel.js +++ b/src/validateModel.js @@ -4,6 +4,7 @@ var errorTypes = require('./errorTypes'), ValidationError = errorTypes.ValidationError, ValidationErrors = errorTypes.ValidationErrors, MissingValueError = errorTypes.MissingValueError, + UnexpectedValueError = errorTypes.UnexpectedValueError, validate = require('./index'); // http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-an-object @@ -43,12 +44,13 @@ function addInhertiedProperties(model, modelId, models){ addInhertiedProperties(model, parent.id, models); } -function validateModel(candidate, model, models){ +function validateModel(candidate, model, models, options){ if(candidate === null || typeof candidate !== 'object'){ return new ValidationErrors(candidate, model); } models = models || {}; + options = options || {}; model = clone(model); if(!model.required) model.required = []; @@ -67,7 +69,12 @@ function validateModel(candidate, model, models){ Object.keys(candidate).forEach(function(propertyName){ var property = model.properties[propertyName]; - if(property === undefined) return; + if(property === undefined) { + if( options.validateUnexpectedValues ) { + errors.push(new ValidationError(propertyName, propertyName, new UnexpectedValueError())); + } + return; + } var error = validate.dataType(candidate[propertyName], property, models); if(error){ @@ -79,4 +86,4 @@ function validateModel(candidate, model, models){ return new ValidationErrors(candidate, model.id, model, errors); } } -module.exports = validateModel; \ No newline at end of file +module.exports = validateModel; From 87be8ddaee8c15e41b1c7d0620449457e45820eb Mon Sep 17 00:00:00 2001 From: julien Date: Fri, 9 Jan 2015 08:58:49 +0100 Subject: [PATCH 2/4] added format & pattern validation --- src/errorTypes.js | 23 ++++++++++++++ src/validateDataType.js | 10 +++++-- src/validateModel.js | 2 +- src/validatePrimitiveTypes.js | 56 +++++++++++++++++++++++++++++++---- 4 files changed, 81 insertions(+), 10 deletions(-) diff --git a/src/errorTypes.js b/src/errorTypes.js index 9362e25..fc606c3 100644 --- a/src/errorTypes.js +++ b/src/errorTypes.js @@ -111,6 +111,29 @@ StringNotInEnumError.prototype.constructor = StringNotInEnumError; exports.StringNotInEnumError = StringNotInEnumError; +function StringFormatNotValidError(value, pattern){ + this.name = 'StringFormatNotValidError'; + this.message = '"' + value + '" is not an acceptable value: "' + pattern + '"'; + + this.value = value; +} +StringFormatNotValidError.prototype = Object.create(DataTypeValidationError.prototype); +StringFormatNotValidError.prototype.constructor = StringFormatNotValidError; +exports.StringFormatNotValidError = StringFormatNotValidError; + + +function NotADateValueError(value, actualType){ + this.name = 'NotADateValueError'; + this.message = '"' + value + '" is not a date value'; + if(actualType) this.message += ' (got a ' + actualType + ' instead)'; + + this.value = value; +} +NotADateValueError.prototype = Object.create(DataTypeValidationError.prototype); +NotADateValueError.prototype.constructor = NotADateValueError; +exports.NotADateValueError = NotADateValueError; + + function ErrorsInArrayElementsError(errors){ this.name = 'ErrorsInArrayElementsError'; this.message = 'Errors in array elements:\n\t' + errors.join(',\n\t'); diff --git a/src/validateDataType.js b/src/validateDataType.js index c0129af..fdedf41 100644 --- a/src/validateDataType.js +++ b/src/validateDataType.js @@ -6,14 +6,16 @@ function validateDataType(candidate, dataType, models){ models = models || {}; var type = dataType.type || dataType.dataType || dataType.$ref; + var format = dataType.format; + var pattern = dataType.pattern; switch(type){ case 'integer': - return validate.primitive.integer(candidate, dataType); + return validate.primitive.integer(candidate, dataType, format); case 'number': - return validate.primitive.number(candidate, dataType); + return validate.primitive.number(candidate, dataType, format); case 'string': - return validate.primitive.string(candidate, dataType); + return validate.primitive.string(candidate, dataType, format, pattern); case 'boolean': return validate.primitive.boolean(candidate); case 'array': @@ -22,6 +24,8 @@ function validateDataType(candidate, dataType, models){ return validate.primitive.void(candidate); case 'File': return validate.primitive.file(); + case 'date-time': + return validate.primitive.dateTime(); default: // Assumed to be complex model var model = models[type]; diff --git a/src/validateModel.js b/src/validateModel.js index c165d56..7f22480 100644 --- a/src/validateModel.js +++ b/src/validateModel.js @@ -70,7 +70,7 @@ function validateModel(candidate, model, models, options){ var property = model.properties[propertyName]; if(property === undefined) { - if( options.validateUnexpectedValues ) { + if( options.checkUnexpectedValues ) { errors.push(new ValidationError(propertyName, propertyName, new UnexpectedValueError())); } return; diff --git a/src/validatePrimitiveTypes.js b/src/validatePrimitiveTypes.js index 6e4ef6d..e2a826c 100644 --- a/src/validatePrimitiveTypes.js +++ b/src/validatePrimitiveTypes.js @@ -2,9 +2,28 @@ var errorTypes = require('./errorTypes'); -function validateInteger(candidate, dataType){ - var error = validateNumber(candidate, dataType); - if(error) return error; +function validateInteger(candidate, dataType, format){ + var error; + if( !format ) { + error = validateNumber(candidate, dataType); + } + else if(format === 'int32') { + var int32Max = Math.pow(2, 31) - 1; + var value = parseInt(property); + if(isNaN(value) || !isFinite(property) || value < -(int32Max + 1) || value > int32Max) { + error = new errorTypes.NotANumberError(candidate, typeof candidate); + } + } + else if(format === 'int64') { + var value = parseInt(property); + if(isNaN(value) || !isFinite(property)) { + error = new errorTypes.NotANumberError(candidate, typeof candidate); + } + } + + if(error) { + return error; + } if(candidate % 1){ return new errorTypes.NotAnIntegerError(candidate); @@ -12,7 +31,7 @@ function validateInteger(candidate, dataType){ } exports.validateInteger = validateInteger; -function validateNumber(candidate, dataType){ +function validateNumber(candidate, dataType, format){ if(!(typeof candidate === 'number' || candidate instanceof Number) || isNaN(candidate)){ return new errorTypes.NotANumberError(candidate, typeof candidate); } @@ -47,7 +66,7 @@ function validateFile(){ } exports.validateFile = validateFile; -function validateString(candidate, dataType){ +function validateString(candidate, dataType, format, pattern){ if(typeof candidate !== 'string' && !(candidate instanceof String)){ return new errorTypes.NotAStringError(candidate, typeof candidate); } @@ -57,5 +76,30 @@ function validateString(candidate, dataType){ return new errorTypes.StringNotInEnumError(candidate, dataType.enum); } } + + if( format === 'date-time' || format === 'date' ) { + var date = new Date(candidate); + if(date !== "Invalid Date" && !isNaN(date) && isNaN(candidate)) { + if(format === 'date' && property.length !== 10) { + return new errorTypes.NotADateValueError(candidate, typeof candidate); + } + } + else { + return new errorTypes.NotADateValueError(candidate, typeof candidate); + } + } + + if( pattern ) { + var regExp = new RegExp(pattern); + if( !regExp.test(candidate) ) { + return new errorTypes.StringFormatNotValidError(candidate, pattern); + } + } +} +exports.validateString = validateString; + + +function validateDateTime(candidate, dataType){ + return ( (new Date(candidate) !== "Invalid Date" && !isNaN(new Date(candidate)) )); } -exports.validateString = validateString; \ No newline at end of file +exports.validateDateTime = validateDateTime; From 44b8799d1d883af50a9a7d4f30bf3725b96d2a0e Mon Sep 17 00:00:00 2001 From: julien Date: Fri, 9 Jan 2015 09:08:43 +0100 Subject: [PATCH 3/4] fix errors --- src/validatePrimitiveTypes.js | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/validatePrimitiveTypes.js b/src/validatePrimitiveTypes.js index e2a826c..6e956e4 100644 --- a/src/validatePrimitiveTypes.js +++ b/src/validatePrimitiveTypes.js @@ -9,14 +9,14 @@ function validateInteger(candidate, dataType, format){ } else if(format === 'int32') { var int32Max = Math.pow(2, 31) - 1; - var value = parseInt(property); - if(isNaN(value) || !isFinite(property) || value < -(int32Max + 1) || value > int32Max) { + var int32Value = parseInt(candidate); + if(isNaN(int32Value) || !isFinite(candidate) || int32Value < -(int32Max + 1) || int32Value > int32Max) { error = new errorTypes.NotANumberError(candidate, typeof candidate); } } else if(format === 'int64') { - var value = parseInt(property); - if(isNaN(value) || !isFinite(property)) { + var int64Value = parseInt(candidate); + if(isNaN(int64Value) || !isFinite(candidate)) { error = new errorTypes.NotANumberError(candidate, typeof candidate); } } @@ -79,8 +79,8 @@ function validateString(candidate, dataType, format, pattern){ if( format === 'date-time' || format === 'date' ) { var date = new Date(candidate); - if(date !== "Invalid Date" && !isNaN(date) && isNaN(candidate)) { - if(format === 'date' && property.length !== 10) { + if(date !== 'Invalid Date' && !isNaN(date) && isNaN(candidate)) { + if(format === 'date' && candidate.length !== 10) { return new errorTypes.NotADateValueError(candidate, typeof candidate); } } @@ -97,9 +97,3 @@ function validateString(candidate, dataType, format, pattern){ } } exports.validateString = validateString; - - -function validateDateTime(candidate, dataType){ - return ( (new Date(candidate) !== "Invalid Date" && !isNaN(new Date(candidate)) )); -} -exports.validateDateTime = validateDateTime; From 1f22e30e96b31a90da4519c9abcc28aa6b1c3f6c Mon Sep 17 00:00:00 2001 From: julien Date: Fri, 9 Jan 2015 09:14:39 +0100 Subject: [PATCH 4/4] fix errors #2 --- src/validatePrimitiveTypes.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/validatePrimitiveTypes.js b/src/validatePrimitiveTypes.js index 6e956e4..a4b9bc6 100644 --- a/src/validatePrimitiveTypes.js +++ b/src/validatePrimitiveTypes.js @@ -31,7 +31,7 @@ function validateInteger(candidate, dataType, format){ } exports.validateInteger = validateInteger; -function validateNumber(candidate, dataType, format){ +function validateNumber(candidate, dataType){ if(!(typeof candidate === 'number' || candidate instanceof Number) || isNaN(candidate)){ return new errorTypes.NotANumberError(candidate, typeof candidate); }