Permalink
Browse files

convert old code into the json validator

  • Loading branch information...
1 parent ec2d87d commit 27bcb5d4543425a555e9c74475342e3bf98a5677 @bronson committed Sep 20, 2011
Showing with 194 additions and 336 deletions.
  1. +1 −1 console.js
  2. +17 −0 lib/valid.js
  3. +99 −0 lib/validjson.js
  4. +1 −1 package.json
  5. +0 −109 test-validator.js
  6. 0 test/{test-valid.js → valid.test.js}
  7. +76 −0 test/validjson.test.js
  8. +0 −225 validator.js
View
@@ -1,5 +1,5 @@
#!/usr/bin/env node
// fires up a console with Valid loaded
-Valid = require('./lib/valid');
+Valid = require('./lib/validjson');
require('repl').start();
View
@@ -7,6 +7,23 @@ var Valid = require('./valid-engine');
module.exports = Valid;
+// results
+
+Valid.test = function test(value) {
+ var self = this.GetChain();
+ return self.GetChain().ValidateQueue(self._queue, value);
+};
+
+Valid.check = function check(value) {
+ return !this.test(value);
+};
+
+Valid.verify = function assert(value) {
+ var message = this.test(value);
+ if(message) throw value + " " + message;
+};
+
+
// core tests
Valid.nop = Valid.SimpleTest(function Nop(val) { });
View
@@ -0,0 +1,99 @@
+// Returns a full Valid environment that includes json comparison
+
+var Valid = require('./valid');
+module.exports = Valid;
+
+
+Valid.JsonError = function(path, value, message) {
+ var pathItem = function(i) {
+ return Valid.integer().check(path[i]) ? '['+path[i]+']' : "." + path[i];
+ };
+
+ var str = (path[0] === undefined ? "." : pathItem(0));
+ for(var i=1; i<path.length; i++) {
+ str += pathItem(i);
+ }
+
+ if(this._errors[str]) return; // ignore duplicate errors
+ this._errors[str] = {value: value, message: message};
+ this._errorCount += 1;
+};
+
+
+Valid.JsonObject = function(path, value, schema) {
+ var key;
+
+ for(key in value) {
+ if(!value.hasOwnProperty(key)) continue;
+ if(schema[key]) {
+ this.JsonField(path.concat(key), value[key], schema[key]);
+ } else {
+ this.JsonError(path, value, "has " + key + " but schema does not");
+ if(this._errorCount > this._maxErrors) break;
+ }
+ }
+
+ for(key in schema) {
+ if(!value.hasOwnProperty(key)) continue;
+ if(value[key] === undefined) this.JsonError(path, value, "is missing " + key);
+ if(this._errorCount > this._maxErrors) break;
+ }
+};
+
+
+Valid.JsonField = function(path, value, schema) {
+ switch(typeof schema) {
+ case 'string':
+ case 'number':
+ case 'boolean':
+ case 'undefined':
+ if(value !== schema) this.JsonError(path, value, "does not equal " + Valid.Escape(schema));
+ break;
+
+ case 'function':
+ if(schema instanceof RegExp) {
+ if(typeof value === 'string') {
+ if(!value.match(schema)) this.JsonError(path, value, "does not match " + schema);
+ } else {
+ this.error("is not a string so can't match " + schema);
+ }
+ } else {
+ schema.call(this, value);
+ }
+ break;
+
+ case 'null':
+ case 'object':
+ if(schema === null) {
+ if(value !== null) this.error("is not null");
+ } else if(schema instanceof Array) {
+ if(value instanceof Array) {
+ if(value.length !== schema.length) this.error(" has " + value.length + " items, not " + schema.length);
+ for(var i=0; i < Math.min(schema.length, value.length); i++) {
+ this.JsonField(path.concat(i), value[i], schema[i]);
+ if(this._errorCount > this._maxErrors) break;
+ }
+ } else {
+ this.error("is not an Array");
+ }
+ } else {
+ this.JsonObject(value, schema);
+ }
+ break;
+
+ default:
+ this.error(path, value, "Error in template: what is " + (typeof schema) + "?");
+ }
+};
+
+
+Valid.json = function json(schema) {
+ return this.AddTest(function Json(value, maxErrors) {
+ this._errors = {};
+ this._errorCount = 0;
+ this._maxErrors = maxErrors || 20;
+ this.JsonField([], value, schema, {});
+ if(this._errorCount > 0) return this._errors;
+ }, schema);
+};
+
View
@@ -10,5 +10,5 @@
, "bugs" : { "web" : "https://github.com/bronson/valid/issues" }
, "directories" : { "lib" : "./lib" }
, "main" : "./lib"
-, "scripts" : { "test" : "node test/test-valid.js" }
+, "scripts" : { "test" : "node test/valid.test.js && node test/validjson.test.js" }
}
View
@@ -1,109 +0,0 @@
-var Validator = require('./validator');
-
-
-// todo: make invalid last so tests are more readable
-
-
-// Modifies the Validator to ensure expected errors are caught
-var Checker = function(template, error) {
- Validator.call(this, template, error);
- this.error_strings = [];
-}
-Checker.prototype.constructor = Checker; // is this necessary?
-Checker.prototype = new Validator();
-
-Checker.prototype.error = function(msg) {
- this.error_strings.push(this.error_str(msg));
-}
-
-Checker.prototype.result = function(expected) {
- if(expected === undefined) expected = [];
- if(typeof expected == 'string') expected = [expected];
- var actual = this.error_strings;
-
- if(expected.length == 0 && actual.length > 0) {
- throw "expected no error but got [" + actual + "]";
- } else if(expected.length > 0 && actual.length == 0) {
- throw "expected [" + expected + "] but got nothing.";
- } else if(expected.length != actual.length) {
- throw "expected " + expected.length + " [" + expected +
- "] but got " + actual.length + " [" + actual + "]";
- } else {
- for(var i=0; i<expected.length; i++) {
- if(expected[i] !== actual[i]) {
- throw "expected [" + expected + "] but got [" + actual[i] + "] (they differ at " + i + ")";
- }
- }
- // expected and actual are identical
- }
-}
-
-
-Checker.create = function(template) {
- return new this(template);
-};
-
-
-function schema(tmpl) { return Checker.create(tmpl); }
-
-// constants
-schema( null ).validate( null ).result(); // same as Validator.create(null).validate(null)
-schema( null ).validate( 1 ).result("1 is not null");
-schema( null ).validate( undefined ).result("undefined is not null");
-
-schema( undefined ).validate( undefined ).result();
-schema( undefined ).validate( 1 ).result("1 is not undefined");
-schema( undefined ).validate( null ).result("null is not undefined");
-
-schema( true ).validate( true ).result();
-schema( false ).validate( false ).result();
-schema( true ).validate( false ).result("false is not true");
-schema( false ).validate( true ).result("true is not false");
-schema( false ).validate(undefined).result("undefined is not false");
-
-schema( 'abc' ).validate( 'abc' ).result();
-schema( 'abc' ).validate( 'abc ' ).result("'abc ' does not equal 'abc'");
-schema( 123 ).validate( 123 ).result();
-schema( 123 ).validate( 123.1 ).result("123.1 does not equal 123");
-schema( /^abc$/ ).validate( 'abc' ).result();
-schema( /^abc$/ ).validate( 'abcd' ).result("'abcd' doesn't match /^abc$/");
-
-schema( {abc: 123} ).validate( {abc: 123} ).result();
-schema( {abc: 123, def: 456} ).validate( {abc: 123} ).result("[object Object] is missing def");
-schema( {abc: 123} ).validate( {abc: 123, def: 456} ).result("[object Object] has def but template doesn't");
-
-schema( {a: {b: {c: 1}}} ).validate( {a: {b: {c: 2}}} ).result("a,b,c: 2 does not equal 1 for [object Object]"); // TODO: improve error message
-
-schema( function (val) { if(val != 123) this.error("nope!"); } ).validate(123).result();
-schema( function (val) { if(val == 123) this.error("is equal"); } ).validate(123).result("123 is equal");
-
-// compare functions
-schema( Validator.IsAnything ).validate(123).result();
-schema( Validator.IsAnything ).validate(undefined).result();
-schema( Validator.IsDefined ).validate(123).result();
-schema( Validator.IsDefined ).validate(null).result("null is not defined");
-schema( Validator.IsDefined ).validate(undefined).result("undefined is not defined");
-schema( Validator.IsNumber ).validate(123).result();
-schema( Validator.IsInteger ).validate(123.0).result();
-schema( Validator.IsInteger ).validate(123.1).result("123.1 is not an integer");
-schema( Validator.IsNotBlank ).validate('0').result();
-schema( Validator.IsNotBlank ).validate(' a').result("' a' has leading whitespace");
-schema( Validator.IsNotBlank ).validate('').result("'' can't be blank");
-
-schema( Validator.IsOptional(Validator.IsInteger) ).validate(undefined).result();
-schema( Validator.IsOptional(Validator.IsInteger) ).validate(12).result();
-
-// arrays
-schema( [12, 13] ).validate( [12, 13] ).result();
-schema( [12, 13] ).validate( [12, 14] ).result("1: 14 does not equal 13 for 12,14"); // TODO improve error message
-schema( [12, 13] ).validate( 12 ).result("12 is not an Array");
-schema( [12, 13] ).validate( undefined ).result("undefined is not an Array");
-schema( [12, Validator.IsInteger] ).validate( [12, 13] ).result();
-
-var _ = Validator;
-schema( _.IsArray(_.IsInteger) ).validate([12, 13, 14]).result();
-schema( _.IsArray(_.IsInteger, {min: 1, max: 3}) ).validate([12, 13]).result();
-schema( _.IsArray(_.IsString, {min: 1, max: 3}) ).validate([12, 13]).result(["0: 12 is number, not string for 12,13", "1: 13 is number, not string for 12,13"]); // TODO: improve error message
-schema( _.IsArray(_.IsInteger, {min: 3, max: 4}) ).validate([12, 13]).result("12,13 has fewer than 3 elements");
-schema( _.IsArray(_.IsInteger, {min: 1, max: 0}) ).validate([12, 13]).result("12,13 has more than 0 elements");
-
File renamed without changes.
@@ -0,0 +1,76 @@
+var Valid = require('../lib/validjson');
+
+// Like check() but throws if the result doesn't match the expectation
+Valid.assert = function assert(value, expected) {
+ // can't use JSON.stringify for comparison because of key order problems
+ var JsonCompare = function(path,a,b) {
+ if(typeof a !== typeof b) return path + ": " + (typeof a) + " vs " + (typeof b);
+ switch(typeof a) {
+ case 'string': case 'number': case 'boolean': case 'undefined':
+ if(a !== b) return path + ": " + a + " != " + b;
+ break;
+
+ case 'null': case 'function': case 'object':
+ if(a === null && b === null) return;
+ if(a instanceof Array || b instanceof Array)
+ return path + ": we don't do arrays yet";
+ for(var i in a) {
+ if(!a.hasOwnProperty(i)) continue;
+ if(!(i in b)) return path + ": " + i + " is missing";
+ var result = JsonCompare(path+"."+i, a[i], b[i]);
+ if(result) return result;
+ }
+ for(i in b) {
+ if(!b.hasOwnProperty(i)) continue;
+ if(!(i in a)) return path + ": " + i + " shouldn't exist";
+ }
+ break;
+
+ default: throw "what is a " + (typeof a) + "?";
+ }
+ };
+
+ var actual = this.test(value);
+ var diffstr = JsonCompare("", expected, actual);
+ if(diffstr) {
+ var exstr = (expected === undefined ? "success" : JSON.stringify(expected));
+ var acstr = (actual === undefined ? "success" : JSON.stringify(actual));
+ throw value + ":\n expected " + exstr + "\n but got " + acstr + "\n (" + diffstr + ")";
+ }
+};
+
+
+Valid.json(true ).assert(true);
+Valid.json(false).assert(false);
+Valid.json(true ).assert(false, {'.': {message: "does not equal true", value: false}});
+Valid.json(false).assert(true, {'.': {message: "does not equal false", value: true}});
+Valid.json(false).assert(undefined, {'.': {message: "does not equal false", value: undefined}});
+
+Valid.json('abc' ).assert('abc');
+Valid.json('abc' ).assert('abc ', {'.': {message: "does not equal 'abc'", value: "abc "}});
+Valid.json(123 ).assert(123);
+Valid.json(123 ).assert(123.1, {'.': {message: "does not equal 123", value: 123.1}});
+Valid.json(/^abc$/).assert('abc');
+Valid.json(/^abc$/).assert('abcd', {'.': {message: "does not match /^abc$/", value: 'abcd'}});
+
+/*
+schema( {abc: 123} ).validate( {abc: 123} ).result();
+schema( {abc: 123, def: 456} ).validate( {abc: 123} ).result("[object Object] is missing def");
+schema( {abc: 123} ).validate( {abc: 123, def: 456} ).result("[object Object] has def but template does not");
+
+schema( {a: {b: {c: 1}}} ).validate( {a: {b: {c: 2}}} ).result("a,b,c: 2 does not equal 1 for [object Object]"); // TODO: improve error message
+
+// arrays
+schema( [12, 13] ).validate( [12, 13] ).result();
+schema( [12, 13] ).validate( [12, 14] ).result("1: 14 does not equal 13 for 12,14"); // TODO improve error message
+schema( [12, 13] ).validate( 12 ).result("12 is not an Array");
+schema( [12, 13] ).validate( undefined ).result("undefined is not an Array");
+schema( [12, Validator.IsInteger] ).validate( [12, 13] ).result();
+
+var _ = Validator;
+schema( _.IsArray(_.IsInteger) ).validate([12, 13, 14]).result();
+schema( _.IsArray(_.IsInteger, {min: 1, max: 3}) ).validate([12, 13]).result();
+schema( _.IsArray(_.IsString, {min: 1, max: 3}) ).validate([12, 13]).result(["0: 12 is number, not string for 12,13", "1: 13 is number, not string for 12,13"]); // TODO: improve error message
+schema( _.IsArray(_.IsInteger, {min: 3, max: 4}) ).validate([12, 13]).result("12,13 has fewer than 3 elements");
+schema( _.IsArray(_.IsInteger, {min: 1, max: 0}) ).validate([12, 13]).result("12,13 has more than 0 elements");
+*/
Oops, something went wrong.

0 comments on commit 27bcb5d

Please sign in to comment.