npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

doormen

v0.15.5

Published

Validate, sanitize and assert: the silver bullet of data!

Downloads

326

Readme

Doormen

Validate, sanitize and assert: the silver bullet of data!

Beta version.

/!\ This documentation is still a Work In Progress /!\

Basic validation

  • sanitize Array of string the sanitizer's name to apply before any type checking
  • optional boolean the data can be null or undefined, if so the data validate immediately
  • default (anything) the data can be null or undefined, if so it is overwritten by the default value and it validates immediately
  • type string the name of the type checker
  • instanceOf
  • min
  • max
  • length
  • minLength
  • maxLength
  • match
  • in
  • notIn
  • when
  • properties object of schema, it iterates through each properties and checks that they all match their own schema
  • elements Array same than properties but for arrays
  • only boolean used in conjunction with properties or elements, it checks that no properties other than those listed are present
  • of object contains one schema that will check each elements of an array or each properties

Type Checkers

Javascript primitive types:

  • undefined: the data should be undefined
  • null: the data should be null
  • boolean: the data should be a boolean, i.e. true or false
  • number: the data should be a number. NOTE that Infinity and NaN are ok, so you may consider using real instead of number in almost all cases
  • string: the data should be a string
  • object: the data should be an Object
  • function: the data should be a Function

Javascript/Node.js built-in types:

  • array: the data should be an Array
  • error: the data should be an instance of Error
  • date: the data should be an instance of Date
  • buffer: the data should be a Node.js Buffer

Common meta types:

  • real: a number that is not NaN nor +/- Infinity
  • integer: a number that is not NaN nor +/- Infinity, and that do not have decimal part

Sanitizers

  • toNumber: try to convert a string to a number
  • trim: trim a string, removing whitespace at the beginning and the end

TOC

Assertion utilities

doormen.shouldThrow() should throw if the callback has not throw, and catch if it has throw.

var thrown ;
thrown = false ;
try {
	doormen.shouldThrow( () => {} ) ;
}
catch ( error ) {
	thrown = true ;
}
if ( ! thrown ) { throw new Error( 'It should throw!' ) ; }
thrown = false ;
try {
	doormen.shouldThrow( () => { throw new Error( 'Fatal error' ) ; } ) ;
}
catch ( error ) {
	thrown = true ;
}
if ( thrown ) { throw new Error( 'It should *NOT* throw' ) ; }

doormen.not() should throw if the data validate, and catch if it has throw.

var thrown ;
thrown = false ;
try {
	doormen.not( { type: 'string' } , 'text' ) ;
}
catch ( error ) {
	thrown = true ;
}
if ( ! thrown ) { throw new Error( 'It should throw' ) ; }
thrown = false ;
try {
	doormen.not( { type: 'string' } , 1 ) ;
}
catch ( error ) {
	thrown = true ;
}
if ( thrown ) { throw new Error( 'It should *NOT* throw' ) ; }

Equality checker

Equality of simple type.

doormen.equals( undefined , undefined ) ;
doormen.equals( null , null ) ;
doormen.equals( true , true ) ;
doormen.equals( false , false ) ;
doormen.not.equals( undefined , null ) ;
doormen.not.equals( true , false ) ;
doormen.not.equals( null , false ) ;
doormen.not.equals( undefined , false ) ;
doormen.equals( NaN , NaN ) ;
doormen.not.equals( NaN , null ) ;
doormen.not.equals( NaN , undefined ) ;
doormen.equals( Infinity , Infinity ) ;
doormen.equals( -Infinity , -Infinity ) ;
doormen.not.equals( Infinity , -Infinity ) ;
doormen.equals( 0 , 0 ) ;
doormen.equals( 123 , 123 ) ;
doormen.equals( 0.123 , 0.123 ) ;
doormen.equals( "" , "" ) ;
doormen.equals( "abc" , "abc" ) ;
doormen.equals( "   abc" , "   abc" ) ;
doormen.equals( "abc  " , "abc  " ) ;
doormen.equals( "     abc  " , "     abc  " ) ;
doormen.not.equals( 0 , "" ) ;
doormen.not.equals( false , "" ) ;

Equality of objects.

var o = {} ;
doormen.equals( {} , {} ) ;
doormen.equals( o , o ) ;
doormen.equals( { a: 2 , b: 5 } , { a: 2 , b: 5 } ) ;
doormen.not.equals( { a: 2 , b: 6 } , { a: 2 , b: 5 } ) ;
doormen.equals( { b: 5 , a: 2 } , { a: 2 , b: 5 } ) ;
doormen.not.equals( { a: 2 , b: 5 , c: null } , { a: 2 , b: 5 } ) ;
doormen.not.equals( { a: 2 , b: 5 } , { a: 2 , b: 5 , c: null } ) ;
doormen.not.equals( { a: 2 , b: 5 , c: {} } , { a: 2 , b: 5 } ) ;
doormen.equals( { a: 2 , b: 5 , c: {} } , { a: 2 , b: 5 , c: {} } ) ;
doormen.equals( { a: 2 , b: 5 , c: { d: 'titi' } } , { a: 2 , b: 5 , c: { d: 'titi' } } ) ;
doormen.not.equals( { a: 2 , b: 5 , c: { d: 'titi' } } , { a: 2 , b: 5 , c: { d: 'toto' } } ) ;
doormen.equals(
	{ a: 2 , b: 5 , c: { d: 'titi' , e: { f: 'f' , g: 7 } } } ,
	{ a: 2 , b: 5 , c: { d: 'titi' , e: { f: 'f' , g: 7 } } }
) ;

when a property is undefined in the left-side and non-existant in the right-side, they should be equals.

doormen.equals( { a: 2 , b: 5 , c: undefined } , { a: 2 , b: 5 } ) ;
doormen.equals( { a: 2 , b: 5 } , { a: 2 , b: 5 , c: undefined } ) ;
doormen.equals( { a: 2 , b: 5 , c: undefined } , { a: 2 , b: 5 , c: undefined } ) ;
doormen.equals( { a: 2 , b: 5 , c: undefined } , { a: 2 , b: 5 , d: undefined } ) ;
doormen.equals( { a: 2 , b: 5 , c: { d: 'titi' } } , { a: 2 , b: 5 , c: { d: 'titi' , e: undefined } } ) ;

Equality of functions.

var o = {} ;
var fn = function() {} ;
var fn2 = function() {} ;
doormen.equals( fn , fn ) ;
doormen.not.equals( fn , fn2 ) ;
doormen.equals( { a: fn } , { a: fn } ) ;
doormen.equals( { b: 2 , a: fn } , { a: fn , b: 2 } ) ;
doormen.equals( [ fn ] , [ fn ] ) ;
doormen.equals( [ 1 , 2 , fn ] , [ 1 , 2 , fn ] ) ;
doormen.not.equals( [ 1 , 2 , fn ] , [ 1 , 2 ] ) ;

Equality of arrays.

var o = [] ;
doormen.equals( [] , [] ) ;
doormen.equals( o , o ) ;
doormen.equals( [ 1 ] , [ 1 ] ) ;
doormen.not.equals( [ 1 , undefined ] , [ 1 ] ) ;
doormen.not.equals( [ 1 ] , [ 1 , undefined ] ) ;
doormen.not.equals( [ 1 ] , [ 2 ] ) ;
doormen.equals( [ 1 , 2 , 3 ] , [ 1 , 2 , 3 ] ) ;
doormen.equals( [ 1 , [] , 3 ] , [ 1 , [] , 3 ] ) ;
doormen.equals( [ 1 , [ 2 ] , 3 ] , [ 1 , [ 2 ] , 3 ] ) ;
doormen.equals( [ 1 , [ 2 , 'a' ] , 3 ] , [ 1 , [ 2 , 'a' ] , 3 ] ) ;
doormen.not.equals( [ 1 , [ 2 , 'a' ] , 3 ] , [ 1 , [ 2 , 'b' ] , 3 ] ) ;
doormen.equals( [ 1 , [ 2 , [ null ] , 'a' ] , 3 ] , [ 1 , [ 2 , [ null ] , 'a' ] , 3 ] ) ;
doormen.not.equals( [ 1 , [ 2 , [ undefined ] , 'a' ] , 3 ] , [ 1 , [ 2 , [ null ] , 'a' ] , 3 ] ) ;

doormen.equals( [ [ 'one' ] , [ 'two' ] ] , [ [ 'one' ] , [ 'two' ] ] ) ;
doormen.not.equals( [ [ 'one' ] , [ 'two' ] ] , [ [ 'one' ] , [ 'twoa' ] ] ) ;

Equality of nested and mixed objects and arrays.

doormen.not.equals( {} , [] ) ;
doormen.equals(
	{ a: 2 , b: 5 , c: [ 'titi' , { f: 'f' , g: 7 } ] } ,
	{ a: 2 , b: 5 , c: [ 'titi' , { f: 'f' , g: 7 } ] }
) ;
doormen.equals(
	[ 'a' , 'b' , { c: 'titi' , d: [ 'f' , 7 ] } ] ,
	[ 'a' , 'b' , { c: 'titi' , d: [ 'f' , 7 ] } ]
) ;

Circular references: stop searching when both part have reached circular references.

var a , b ;
a = { a: 1 , b: 2 } ;
a.c = a ;
b = { a: 1 , b: 2 } ;
b.c = b ;
doormen.equals( a , b ) ;
a = { a: 1 , b: 2 , c: { a: 1 , b: 2 } } ;
a.c.c = a ;
b = { a: 1 , b: 2 } ;
b.c = b ;
doormen.equals( a , b ) ;

Date.

var date1 = new Date( '2019-06-18' ) ,
	date2 = new Date( '2019-08-21' ) ,
	date3 = new Date( '2019-08-21' ) ;

doormen.not.equals( date1 , date2 ) ;
doormen.equals( date2 , date3 ) ;

Buffers.

var buf , buf2 , i ;
buf = Buffer.allocUnsafe( 80 ) ;
buf2 = Buffer.allocUnsafe( 80 ) ;
for ( i = 0 ; i < 80 ; i ++ ) { buf[ i ] = i ; }
buf.copy( buf2 ) ;
doormen.equals( buf , buf2 ) ;
buf2[ 4 ] = 117 ;
doormen.not.equals( buf , buf2 ) ;

Basic types

should validate undefined accordingly.

doormen( { type: 'undefined' } , undefined ) ;
doormen.not( { type: 'undefined' } , null ) ;
doormen.not( { type: 'undefined' } , false ) ;
doormen.not( { type: 'undefined' } , true ) ;
doormen.not( { type: 'undefined' } , 0 ) ;
doormen.not( { type: 'undefined' } , 1 ) ;
doormen.not( { type: 'undefined' } , '' ) ;
doormen.not( { type: 'undefined' } , 'text' ) ;
doormen.not( { type: 'undefined' } , {} ) ;
doormen.not( { type: 'undefined' } , [] ) ;

should validate null accordingly.

doormen.not( { type: 'null' } , undefined ) ;
doormen( { type: 'null' } , null ) ;
doormen.not( { type: 'null' } , false ) ;
doormen.not( { type: 'null' } , true ) ;
doormen.not( { type: 'null' } , 0 ) ;
doormen.not( { type: 'null' } , 1 ) ;
doormen.not( { type: 'null' } , '' ) ;
doormen.not( { type: 'null' } , 'text' ) ;
doormen.not( { type: 'null' } , {} ) ;
doormen.not( { type: 'null' } , [] ) ;

should validate boolean accordingly.

doormen.not( { type: 'boolean' } , undefined ) ;
doormen.not( { type: 'boolean' } , null ) ;
doormen( { type: 'boolean' } , false ) ;
doormen( { type: 'boolean' } , true ) ;
doormen.not( { type: 'boolean' } , 0 ) ;
doormen.not( { type: 'boolean' } , 1 ) ;
doormen.not( { type: 'boolean' } , '' ) ;
doormen.not( { type: 'boolean' } , 'text' ) ;
doormen.not( { type: 'boolean' } , {} ) ;
doormen.not( { type: 'boolean' } , [] ) ;

should validate number accordingly.

doormen.not( { type: 'number' } , undefined ) ;
doormen.not( { type: 'number' } , null ) ;
doormen.not( { type: 'number' } , false ) ;
doormen.not( { type: 'number' } , true ) ;
doormen( { type: 'number' } , 0 ) ;
doormen( { type: 'number' } , 1 ) ;
doormen( { type: 'number' } , Infinity ) ;
doormen( { type: 'number' } , NaN ) ;
doormen.not( { type: 'number' } , '' ) ;
doormen.not( { type: 'number' } , 'text' ) ;
doormen.not( { type: 'number' } , {} ) ;
doormen.not( { type: 'number' } , [] ) ;

should validate string accordingly.

doormen.not( { type: 'string' } , undefined ) ;
doormen.not( { type: 'string' } , null ) ;
doormen.not( { type: 'string' } , false ) ;
doormen.not( { type: 'string' } , true ) ;
doormen.not( { type: 'string' } , 0 ) ;
doormen.not( { type: 'string' } , 1 ) ;
doormen( { type: 'string' } , '' ) ;
doormen( { type: 'string' } , 'text' ) ;
doormen.not( { type: 'string' } , {} ) ;
doormen.not( { type: 'string' } , [] ) ;

should validate object accordingly.

doormen.not( { type: 'object' } , undefined ) ;
doormen.not( { type: 'object' } , null ) ;
doormen.not( { type: 'object' } , false ) ;
doormen.not( { type: 'object' } , true ) ;
doormen.not( { type: 'object' } , 0 ) ;
doormen.not( { type: 'object' } , 1 ) ;
doormen.not( { type: 'object' } , '' ) ;
doormen.not( { type: 'object' } , 'text' ) ;
doormen( { type: 'object' } , {} ) ;
doormen( { type: 'object' } , { a: 1 , b: 2 } ) ;
doormen( { type: 'object' } , [] ) ;
doormen( { type: 'object' } , [ 1 , 2 , 3 ] ) ;
doormen( { type: 'object' } , new Date() ) ;
doormen.not( { type: 'object' } , () => {} ) ;

should validate function accordingly.

doormen.not( { type: 'function' } , undefined ) ;
doormen.not( { type: 'function' } , null ) ;
doormen.not( { type: 'function' } , false ) ;
doormen.not( { type: 'function' } , true ) ;
doormen.not( { type: 'function' } , 0 ) ;
doormen.not( { type: 'function' } , 1 ) ;
doormen.not( { type: 'function' } , '' ) ;
doormen.not( { type: 'function' } , 'text' ) ;
doormen.not( { type: 'function' } , {} ) ;
doormen.not( { type: 'function' } , [] ) ;
doormen( { type: 'function' } , () => {} ) ;

Optional, default and forced data

when a data is null, undefined or unexistant, and the optional flag is set the schema, it should validate.

doormen.not( { type: 'string' } , null ) ;
doormen( { optional: true , type: 'string' } , null ) ;
doormen.not( { type: 'string' } , undefined ) ;
doormen( { optional: true , type: 'string' } , undefined ) ;
doormen( { type: 'string' } , 'text' ) ;
doormen( { optional: true , type: 'string' } , 'text' ) ;
doormen.not( { type: 'string' } , 1 ) ;
doormen.not( { optional: true , type: 'string' } , 1 ) ;
doormen.not( { properties: { a: { type: 'string' } } } , {} ) ;
doormen( { properties: { a: { optional: true , type: 'string' } } } , {} ) ;
doormen( { properties: { a: { optional: true , type: 'string' } } } , { a: null } ) ;
doormen( { properties: { a: { optional: true , type: 'string' } } } , { a: undefined } ) ;

if 'nullIsValue' and 'optional' flags are set, null values should validate instead being considerate a non-value.

doormen.not( { nullIsValue: true , type: 'string' } , null ) ;
doormen.not( { nullIsValue: true , optional: true , type: 'string' } , null ) ;
doormen.not( { nullIsValue: true , type: 'string' } , undefined ) ;
doormen( { nullIsValue: true , optional: true , type: 'string' } , undefined ) ;
doormen.not( { properties: { a: { nullIsValue: true , type: 'string' } } } , {} ) ;
doormen( { properties: { a: { nullIsValue: true , optional: true , type: 'string' } } } , {} ) ;
doormen.not( { properties: { a: { nullIsValue: true , optional: true , type: 'string' } } } , { a: null } ) ;
doormen( { properties: { a: { nullIsValue: true , optional: true , type: 'string' } } } , { a: undefined } ) ;

if 'nullIsUndefined' is set null values are turned to 'undefined' before applying anything else.

doormen.equals( doormen( { nullIsUndefined: false } , null ) , null ) ;
doormen.equals( doormen( { nullIsUndefined: true } , null ) , undefined ) ;

doormen.not( { nullIsUndefined: true , type: 'string' } , null ) ;
doormen( { nullIsUndefined: true , optional: true , type: 'string' } , null ) ;
doormen.not( { nullIsUndefined: true , type: 'string' } , undefined ) ;
doormen( { nullIsUndefined: true , optional: true , type: 'string' } , undefined ) ;
doormen.equals( doormen( { properties: { a: { nullIsUndefined: true , optional: true , type: 'string' } } } , { a: null } ) , { a: undefined } ) ;
doormen.equals( doormen( { properties: { a: { nullIsUndefined: true , optional: true , type: 'string' } } } , { a: null } ) , {} ) ;

missing optional properties should not be created (i.e. with undefined)..

var result ;
result = doormen( { properties: { a: { optional: true , type: 'string' } } } , {} ) ;
// {a:undefined} is equals to {} for doormen.equals() (this is the correct behaviour), but here we want to know for sure
// that a key is not defined, so we have to check it explicitly
doormen.equals( 'a' in result , false ) ;
result = doormen(
	{
		properties: {
			a: { optional: true , type: 'string' } ,
			b: { optional: true , type: 'string' } ,
			c: {
				optional: true ,
				properties: {
					d: { optional: true , type: 'string' }
				}
			}
		}
	} ,
	{}
) ;
doormen.equals( 'a' in result , false ) ;
doormen.equals( 'b' in result , false ) ;
doormen.equals( 'c' in result , false ) ;
result = doormen(
	{
		properties: {
			a: { optional: true , type: 'string' } ,
			b: { optional: true , type: 'string' } ,
			c: {
				optional: true ,
				properties: {
					d: { optional: true , type: 'string' }
				}
			}
		}
	} ,
	{ c: undefined }
) ;
doormen.equals( 'a' in result , false ) ;
doormen.equals( 'b' in result , false ) ;
doormen.equals( 'c' in result , true ) ;
doormen.equals( result.c , undefined ) ;
result = doormen(
	{
		properties: {
			a: { optional: true , type: 'string' } ,
			b: { optional: true , type: 'string' } ,
			c: {
				optional: true ,
				properties: {
					d: { optional: true , type: 'string' }
				}
			}
		}
	} ,
	{ c: null }
) ;
doormen.equals( 'a' in result , false ) ;
doormen.equals( 'b' in result , false ) ;
doormen.equals( 'c' in result , true ) ;
doormen.equals( result.c , null ) ;
result = doormen(
	{
		properties: {
			a: { optional: true , type: 'string' } ,
			b: { optional: true , type: 'string' } ,
			c: {
				optional: true ,
				properties: {
					d: { optional: true , type: 'string' }
				}
			}
		}
	} ,
	{ c: {} }
) ;
doormen.equals( 'a' in result , false ) ;
doormen.equals( 'b' in result , false ) ;
doormen.equals( 'c' in result , true ) ;
doormen.equals( 'd' in result.c , false ) ;

when a data is null, undefined or unexistant, and a default value is specified in the schema, that default value should overwrite the original one.

doormen.equals( doormen( { type: 'string' , "default": 'default!' } , null ) , 'default!' ) ;
doormen.equals(
	doormen(
		{ properties: { a: { type: 'string' , "default": 'default!' } } } ,
		{ a: null } ) ,
	{ a: 'default!' }
) ;
doormen.equals(
	doormen(
		{ properties: { a: { type: 'string' , "default": 'default!' } , b: { type: 'object' , "default": { c: 5 } } } } ,
		{ a: null , b: undefined } ) ,
	{ a: 'default!' , b: { c: 5 } }
) ;
doormen.equals(
	doormen(
		{ properties: { a: { type: 'string' , "default": 'default!' } , b: { type: 'object' , "default": { c: 5 } } } } ,
		{} ) ,
	{ a: 'default!' , b: { c: 5 } }
) ;

// verify that default value can be a function (regression of v0.10.9)
var fn = () => null ;
doormen.equals(
	doormen(
		{ properties: { a: { type: 'string' , "default": fn } } } ,
		{ a: null } ) ,
	{ a: fn }
) ;

when the 'defaultFn' is specified in the schema and is a string, that builtin default function is executed and its return-value is used as the default.

//doormen.equals( doormen( { type: 'date' , defaultFn: 'now' } , null ) , new Date() ) ;
doormen.equals(
	doormen(
		{ properties: { a: { type: 'date' , defaultFn: 'now' } } } ,
		{ a: null } ) ,
	{ a: new Date() }
) ;

when the 'defaultFn' is specified in the schema and is a function, that function is executed and its return-value is used as the default.

var date , count = 0 ;
doormen.equals( doormen( { type: 'date' , defaultFn: () => date = new Date() } , null ) , date ) ;
doormen.equals(
	doormen(
		{ properties: { a: { type: 'date' , defaultFn: () => date = new Date() } } } ,
		{ a: null } ) ,
	{ a: date }
) ;
doormen.equals( doormen( { type: 'integer' , defaultFn: () => ++ count } , null ) , 1 ) ;
doormen.equals(
	doormen(
		{ properties: {
			a: { type: 'integer' , defaultFn: () => ++ count } ,
			b: { type: 'integer' , defaultFn: () => ++ count }
		} } ,
		{ a: null } ) ,
	{ a: 2 , b: 3 }
) ;

if 'nullIsValue' is set and a 'default' value is set, null values are not replaced by the default value.

doormen.not( { type: 'string' , nullIsValue: true , "default": 'default!' } , null ) ;
doormen.equals( doormen( { nullIsValue: true , "default": 'default!' } , null ) , null ) ;
doormen.equals( doormen( { nullIsValue: true , "default": 'default!' } , undefined ) , 'default!' ) ;

doormen.not(
	{ properties: { a: { type: 'string' , nullIsValue: true , "default": 'default!' } } } ,
	{ a: null } ) ,
{ a: null }
doormen.equals(
	doormen(
		{ properties: { a: { nullIsValue: true , "default": 'default!' } } } ,
		{ a: null } ) ,
	{ a: null }
) ;
doormen.equals(
	doormen(
		{ properties: { a: { nullIsValue: true , "default": 'default!' } } } ,
		{ a: undefined } ) ,
	{ a: 'default!' }
) ;
doormen.equals(
	doormen(
		{ properties: { a: { nullIsValue: true , "default": 'default!' } , b: { type: 'object' , nullIsValue: true , "default": { c: 5 } } } } ,
		{ a: null , b: undefined } ) ,
	{ a: null , b: { c: 5 } }
) ;

when the schema has a forced value, it should validate the data and set it to that value.

var schema ;

schema = { value: 'forced!' } ;
doormen.equals( doormen( schema , null ) , 'forced!' ) ;
doormen.equals( doormen( schema , undefined ) , 'forced!' ) ;
doormen.equals( doormen( schema , 'bob' ) , 'forced!' ) ;
doormen.equals( doormen( schema , {} ) , 'forced!' ) ;

schema = { properties: { a: { value: 'forced!' } } } ;
doormen.equals( doormen( schema , {} ) , { a: 'forced!' } ) ;
doormen.equals( doormen( schema , { a: undefined } ) , { a: 'forced!' } ) ;
doormen.equals( doormen( schema , { a: null } ) , { a: 'forced!' } ) ;
doormen.equals( doormen( schema , { a: 'bob' } ) , { a: 'forced!' } ) ;
doormen.equals( doormen( schema , { a: { jack: 'bob' } } ) , { a: 'forced!' } ) ;

schema = { properties: { a: { value: 'forced!' } , b: { value: { c: 5 } } } } ;
doormen.equals( doormen( schema , { a: null , b: undefined } ) , { a: 'forced!' , b: { c: 5 } } ) ;
doormen.equals( doormen( schema , {} ) , { a: 'forced!' , b: { c: 5 } } ) ;

Built-in types

should validate 'unset' accordingly (undefined or null).

doormen( { type: 'unset' } , undefined ) ;
doormen( { type: 'unset' } , null ) ;
doormen.not( { type: 'unset' } , false ) ;
doormen.not( { type: 'unset' } , true ) ;
doormen.not( { type: 'unset' } , 0 ) ;
doormen.not( { type: 'unset' } , 1 ) ;
doormen.not( { type: 'unset' } , '' ) ;
doormen.not( { type: 'unset' } , 'text' ) ;
doormen.not( { type: 'unset' } , {} ) ;
doormen.not( { type: 'unset' } , [] ) ;

should validate array accordingly.

doormen.not( { type: 'array' } , undefined ) ;
doormen.not( { type: 'array' } , null ) ;
doormen.not( { type: 'array' } , false ) ;
doormen.not( { type: 'array' } , true ) ;
doormen.not( { type: 'array' } , 0 ) ;
doormen.not( { type: 'array' } , 1 ) ;
doormen.not( { type: 'array' } , '' ) ;
doormen.not( { type: 'array' } , 'text' ) ;
doormen.not( { type: 'array' } , {} ) ;
doormen.not( { type: 'array' } , { a: 1 , b: 2 } ) ;
doormen( { type: 'array' } , [] ) ;
doormen( { type: 'array' } , [ 1 , 2 , 3 ] ) ;
doormen.not( { type: 'array' } , () => {} ) ;

should validate date accordingly.

doormen( { type: 'date' } , new Date() ) ;
doormen.not( { type: 'date' } , undefined ) ;
doormen.not( { type: 'date' } , null ) ;
doormen.not( { type: 'date' } , false ) ;
doormen.not( { type: 'date' } , true ) ;
doormen.not( { type: 'date' } , 0 ) ;
doormen.not( { type: 'date' } , 1 ) ;
doormen.not( { type: 'date' } , '' ) ;
doormen.not( { type: 'date' } , 'text' ) ;
doormen.not( { type: 'date' } , {} ) ;
doormen.not( { type: 'date' } , { a: 1 , b: 2 } ) ;
doormen.not( { type: 'date' } , [] ) ;
doormen.not( { type: 'date' } , [ 1 , 2 , 3 ] ) ;
doormen.not( { type: 'date' } , () => {} ) ;

should validate error accordingly.

doormen( { type: 'error' } , new Error() ) ;
doormen.not( { type: 'error' } , undefined ) ;
doormen.not( { type: 'error' } , null ) ;
doormen.not( { type: 'error' } , false ) ;
doormen.not( { type: 'error' } , true ) ;
doormen.not( { type: 'error' } , 0 ) ;
doormen.not( { type: 'error' } , 1 ) ;
doormen.not( { type: 'error' } , '' ) ;
doormen.not( { type: 'error' } , 'text' ) ;
doormen.not( { type: 'error' } , {} ) ;
doormen.not( { type: 'error' } , { a: 1 , b: 2 } ) ;
doormen.not( { type: 'error' } , [] ) ;
doormen.not( { type: 'error' } , [ 1 , 2 , 3 ] ) ;
doormen.not( { type: 'error' } , () => {} ) ;

should validate arguments accordingly.

var fn = function() { doormen( { type: 'arguments' } , arguments ) ; } ;	// eslint-disable-line prefer-rest-params
fn() ;
fn( 1 ) ;
fn( 1 , 2 , 3 ) ;
doormen.not( { type: 'arguments' } , undefined ) ;
doormen.not( { type: 'arguments' } , null ) ;
doormen.not( { type: 'arguments' } , false ) ;
doormen.not( { type: 'arguments' } , true ) ;
doormen.not( { type: 'arguments' } , 0 ) ;
doormen.not( { type: 'arguments' } , 1 ) ;
doormen.not( { type: 'arguments' } , '' ) ;
doormen.not( { type: 'arguments' } , 'text' ) ;
doormen.not( { type: 'arguments' } , {} ) ;
doormen.not( { type: 'arguments' } , { a: 1 , b: 2 } ) ;
doormen.not( { type: 'arguments' } , [] ) ;
doormen.not( { type: 'arguments' } , [ 1 , 2 , 3 ] ) ;
doormen.not( { type: 'arguments' } , () => {} ) ;

Mixed types

should validate 'strictObject' accordingly, i.e. objects that are NOT arrays.

doormen.not( { type: 'strictObject' } , undefined ) ;
doormen.not( { type: 'strictObject' } , null ) ;
doormen.not( { type: 'strictObject' } , false ) ;
doormen.not( { type: 'strictObject' } , true ) ;
doormen.not( { type: 'strictObject' } , 0 ) ;
doormen.not( { type: 'strictObject' } , 1 ) ;
doormen.not( { type: 'strictObject' } , '' ) ;
doormen.not( { type: 'strictObject' } , 'text' ) ;
doormen( { type: 'strictObject' } , {} ) ;
doormen( { type: 'strictObject' } , { a: 1 , b: 2 } ) ;
doormen.not( { type: 'strictObject' } , [] ) ;
doormen.not( { type: 'strictObject' } , [ 1 , 2 , 3 ] ) ;
doormen.not( { type: 'strictObject' } , () => {} ) ;

should validate 'regexp' accordingly, i.e. RegExp instance or string convertible to RegExp.

doormen( { type: 'regexp' } , /Random/ ) ;
doormen( { type: 'regexp' } , new RegExp( "Random" ) ) ;
doormen( { type: 'regexp' } , "Random" ) ;
doormen.not( { type: 'regexp' } , "(Random" ) ;
doormen.not( { type: 'regexp' } , undefined ) ;
doormen.not( { type: 'regexp' } , null ) ;
doormen.not( { type: 'regexp' } , false ) ;
doormen.not( { type: 'regexp' } , true ) ;
doormen.not( { type: 'regexp' } , 0 ) ;
doormen.not( { type: 'regexp' } , 1 ) ;
doormen( { type: 'regexp' } , '' ) ;
doormen( { type: 'regexp' } , 'text' ) ;
doormen.not( { type: 'regexp' } , {} ) ;
doormen.not( { type: 'regexp' } , { a: 1 , b: 2 } ) ;
doormen.not( { type: 'regexp' } , [] ) ;
doormen.not( { type: 'regexp' } , [ 1 , 2 , 3 ] ) ;
doormen.not( { type: 'regexp' } , () => {} ) ;

should validate 'classId' accordingly, i.e. function (constructor) or non-empty string.

doormen.not( { type: 'classId' } , undefined ) ;
doormen.not( { type: 'classId' } , null ) ;
doormen.not( { type: 'classId' } , false ) ;
doormen.not( { type: 'classId' } , true ) ;
doormen.not( { type: 'classId' } , 0 ) ;
doormen.not( { type: 'classId' } , 1 ) ;
doormen.not( { type: 'classId' } , '' ) ;
doormen( { type: 'classId' } , 'text' ) ;
doormen.not( { type: 'classId' } , {} ) ;
doormen.not( { type: 'classId' } , { a: 1 , b: 2 } ) ;
doormen.not( { type: 'classId' } , [] ) ;
doormen.not( { type: 'classId' } , [ 1 , 2 , 3 ] ) ;
doormen( { type: 'classId' } , () => {} ) ;

Top-level filters

'instanceOf' should validate object accordingly.

function MyClass() {}
if ( doormen.isBrowser ) { window[ 'MyClass' ] = MyClass ; }
else { global[ 'MyClass' ] = MyClass ; }
doormen( { instanceOf: Date } , new Date() ) ;
doormen( { instanceOf: Array } , new Array() ) ;
doormen( { instanceOf: MyClass } , new MyClass() ) ;
doormen( { instanceOf: Object } , new MyClass() ) ;
doormen( { instanceOf: 'MyClass' } , new MyClass() ) ;
doormen( { instanceOf: 'Object' } , new MyClass() ) ;
doormen.not( { instanceOf: Date } , new Array() ) ;
doormen.not( { instanceOf: 'Date' } , new Array() ) ;

min filter should validate accordingly, non-number should throw.

doormen( { min: 3 } , 10 ) ;
doormen( { min: 3 } , 3 ) ;
doormen.not( { min: 3 } , 1 ) ;
doormen.not( { min: 3 } , 0 ) ;
doormen.not( { min: 3 } , -10 ) ;
doormen( { min: 3 } , Infinity ) ;
doormen( { min: Infinity } , Infinity ) ;
doormen.not( { min: 3 } , -Infinity ) ;
doormen.not( { min: 3 } , NaN ) ;
doormen.not( { min: 3 } , true ) ;
doormen.not( { min: 3 } , false ) ;
doormen.not( { min: 3 } , undefined ) ;
doormen.not( { min: 0 } , undefined ) ;
doormen.not( { min: -3 } , undefined ) ;
doormen.not( { min: 3 } , '10' ) ;

max filter should validate accordingly, non-number should throw.

doormen.not( { max: 3 } , 10 ) ;
doormen( { max: 3 } , 3 ) ;
doormen( { max: 3 } , 1 ) ;
doormen( { max: 3 } , 0 ) ;
doormen( { max: 3 } , -10 ) ;
doormen.not( { max: 3 } , Infinity ) ;
doormen( { max: 3 } , -Infinity ) ;
doormen( { max: -Infinity } , -Infinity ) ;
doormen.not( { max: 3 } , NaN ) ;
doormen.not( { max: 3 } , true ) ;
doormen.not( { max: 3 } , false ) ;
doormen.not( { max: 3 } , '1' ) ;

min + max filter should validate accordingly, non-number should throw.

doormen.not( { min: 3 , max: 10 } , 15 ) ;
doormen( { min: 3 , max: 10 } , 10 ) ;
doormen( { min: 3 , max: 10 } , 5 ) ;
doormen( { min: 3 , max: 10 } , 3 ) ;
doormen.not( { min: 3 , max: 10 } , 1 ) ;
doormen.not( { min: 3 , max: 10 } , 0 ) ;
doormen.not( { min: 3 , max: 10 } , -10 ) ;
doormen.not( { min: 3 , max: 10 } , Infinity ) ;
doormen.not( { min: 3 , max: 10 } , -Infinity ) ;
doormen.not( { min: 3 , max: 10 } , NaN ) ;
doormen.not( { min: 3 , max: 10 } , true ) ;
doormen.not( { min: 3 , max: 10 } , false ) ;
doormen.not( { min: 3 , max: 10 } , '6' ) ;

'length' filter should validate accordingly, data that do not have a length should throw.

doormen( { length: 3 } , "abc" ) ;
doormen.not( { length: 3 } , "abcde" ) ;
doormen.not( { length: 3 } , "ab" ) ;
doormen.not( { length: 3 } , "" ) ;
doormen.not( { length: 3 } , 1 ) ;
doormen.not( { length: 0 } , 1 ) ;
doormen.not( { length: 3 } , NaN ) ;
doormen.not( { length: 3 } , true ) ;
doormen.not( { length: 3 } , false ) ;

minLength filter should validate accordingly, data that do not have a length should throw.

doormen( { minLength: 3 } , "abc" ) ;
doormen( { minLength: 3 } , "abcde" ) ;
doormen.not( { minLength: 3 } , "ab" ) ;
doormen.not( { minLength: 3 } , "" ) ;

doormen( { minLength: 3 } , [ 1,2,3 ] ) ;
doormen( { minLength: 3 } , [ 1,2,3,4 ] ) ;
doormen.not( { minLength: 3 } , [ 1,2 ] ) ;
doormen.not( { minLength: 3 } , 1 ) ;
doormen.not( { minLength: 0 } , 1 ) ;
doormen.not( { minLength: 3 } , NaN ) ;
doormen.not( { minLength: 3 } , true ) ;
doormen.not( { minLength: 3 } , false ) ;

maxLength filter should validate accordingly, data that do not have a length should throw.

doormen( { maxLength: 3 } , "abc" ) ;
doormen.not( { maxLength: 3 } , "abcde" ) ;
doormen( { maxLength: 3 } , "ab" ) ;
doormen( { maxLength: 3 } , "" ) ;
doormen( { maxLength: 3 } , [ 1,2,3 ] ) ;
doormen.not( { maxLength: 3 } , [ 1,2,3,4 ] ) ;
doormen( { maxLength: 3 } , [ 1,2 ] ) ;
doormen.not( { maxLength: 3 } , 1 ) ;
doormen.not( { maxLength: 0 } , 1 ) ;
doormen.not( { maxLength: 3 } , NaN ) ;
doormen.not( { maxLength: 3 } , true ) ;
doormen.not( { maxLength: 3 } , false ) ;

minLength + maxLength filter should validate accordingly, data that do not have a length should throw.

doormen( { minLength: 3 , maxLength: 5 } , "abc" ) ;
doormen( { minLength: 3 , maxLength: 5 } , "abcd" ) ;
doormen( { minLength: 3 , maxLength: 5 } , "abcde" ) ;
doormen.not( { minLength: 3 , maxLength: 5 } , "abcdef" ) ;
doormen.not( { minLength: 3 , maxLength: 5 } , "ab" ) ;
doormen.not( { minLength: 3 , maxLength: 5 } , "" ) ;
doormen.not( { minLength: 3 , maxLength: 5 } , 1 ) ;
doormen.not( { maxLength: 0 } , 1 ) ;
doormen.not( { minLength: 3 , maxLength: 5 } , NaN ) ;
doormen.not( { minLength: 3 , maxLength: 5 } , true ) ;
doormen.not( { minLength: 3 , maxLength: 5 } , false ) ;

'match' filter should validate accordingly using a RegExp.

doormen( { match: "^[a-f]*$" } , "" ) ;
doormen.not( { match: "^[a-f]+$" } , "" ) ;
doormen( { match: "^[a-f]*$" } , "abc" ) ;
doormen( { match: "^[a-f]*$" } , "abcdef" ) ;
doormen.not( { match: "^[a-f]*$" } , "ghi" ) ;
doormen.not( { match: /^[a-f]*$/ } , "ghi" ) ;
doormen.not( { match: "^[a-f]*$" } , 1 ) ;
doormen.not( { match: "^[a-f]*$" } , NaN ) ;
doormen.not( { match: "^[a-f]*$" } , true ) ;
doormen.not( { match: "^[a-f]*$" } , false ) ;

'in' filter should validate if the value is listed.

doormen.not( { in: [ 1 , 5 , 7 ] } , 10 ) ;
doormen( { in: [ 1 , 5 , 7 ] } , 5 ) ;
doormen( { in: [ 1 , 5 , 7 ] } , 1 ) ;
doormen.not( { in: [ 1 , 5 , 7 ] } , 0 ) ;
doormen.not( { in: [ 1 , 5 , 7 ] } , -10 ) ;
doormen.not( { in: [ 1 , 5 , 7 ] } , Infinity ) ;
doormen( { in: [ 1 , 5 , Infinity , 7 ] } , Infinity ) ;
doormen.not( { in: [ 1 , 5 , 7 ] } , -Infinity ) ;
doormen.not( { in: [ 1 , 5 , 7 ] } , NaN ) ;
doormen( { in: [ 1 , 5 , NaN , 7 ] } , NaN ) ;
doormen( { in: [ 1 , true , 5 , 7 ] } , true ) ;
doormen.not( { in: [ 1 , 5 , 7 ] } , true ) ;
doormen( { in: [ 1 , false , 5 , 7 ] } , false ) ;
doormen.not( { in: [ 1 , 5 , 7 ] } , false ) ;
doormen.not( { in: [ 1 , 5 , 7 ] } , "text" ) ;
doormen( { in: [ 1 , "text" , 5 , 7 ] } , "text" ) ;
doormen( { in: [ "string" , "text" , "bob" ] } , "text" ) ;
doormen.not( { in: [ "string" , "text" , "bob" ] } , "bobby" ) ;
doormen( { in: [ "string" , "text" , "" ] } , "" ) ;
doormen.not( { in: [ "string" , "text" , "bob" ] } , "" ) ;

'notIn' filter should validate if the value is listed.

doormen( { notIn: [ 1 , 5 , 7 ] } , 10 ) ;
doormen.not( { notIn: [ 1 , 5 , 7 ] } , 5 ) ;
doormen.not( { notIn: [ 1 , 5 , 7 ] } , 1 ) ;
doormen( { notIn: [ 1 , 5 , 7 ] } , 0 ) ;
doormen( { notIn: [ 1 , 5 , 7 ] } , -10 ) ;
doormen( { notIn: [ 1 , 5 , 7 ] } , Infinity ) ;
doormen.not( { notIn: [ 1 , 5 , Infinity , 7 ] } , Infinity ) ;
doormen( { notIn: [ 1 , 5 , 7 ] } , -Infinity ) ;
doormen( { notIn: [ 1 , 5 , 7 ] } , NaN ) ;
doormen.not( { notIn: [ 1 , 5 , NaN , 7 ] } , NaN ) ;
doormen.not( { notIn: [ 1 , true , 5 , 7 ] } , true ) ;
doormen( { notIn: [ 1 , 5 , 7 ] } , true ) ;
doormen.not( { notIn: [ 1 , false , 5 , 7 ] } , false ) ;
doormen( { notIn: [ 1 , 5 , 7 ] } , false ) ;
doormen( { notIn: [ 1 , 5 , 7 ] } , "text" ) ;
doormen.not( { notIn: [ 1 , "text" , 5 , 7 ] } , "text" ) ;
doormen.not( { notIn: [ "string" , "text" , "bob" ] } , "text" ) ;
doormen( { notIn: [ "string" , "text" , "bob" ] } , "bobby" ) ;
doormen.not( { notIn: [ "string" , "text" , "" ] } , "" ) ;
doormen( { notIn: [ "string" , "text" , "bob" ] } , "" ) ;

'in' filter containing object and arrays.

doormen( { in: [ 1 , { a: 2 } , 5 , 7 ] } , { a: 2 } ) ;
doormen.not( { in: [ 1 , { a: 2 } , 5 , 7 ] } , { a: 2 , b: 5 } ) ;
doormen.not( { in: [ 1 , { a: 2 } , { b: 5 } , 7 ] } , { a: 2 , b: 5 } ) ;
doormen( { in: [ 1 , { a: 2 } , { a: 2 , b: 5 } , { b: 5 } , 7 ] } , { a: 2 , b: 5 } ) ;
doormen( { in: [ 1 , [ 'a' , 2 ] , 5 , 7 ] } , [ 'a' , 2 ] ) ;
doormen.not( { in: [ 1 , [ 'a' , 2 , 3 ] , 5 , 7 ] } , [ 'a' , 2 ] ) ;

Filters

'greaterThan' and aliases ('gt' and '>') filter should validate accordingly, non-number should throw.

doormen( { filter: { greaterThan: 3 } } , 10 ) ;
doormen( { filter: { greaterThan: 3 } } , 3.00001 ) ;
doormen.not( { filter: { greaterThan: 3 } } , 3 ) ;
doormen.not( { filter: { greaterThan: 3 } } , 1 ) ;
doormen.not( { filter: { greaterThan: 3 } } , 0 ) ;
doormen.not( { filter: { greaterThan: 3 } } , -10 ) ;
doormen( { filter: { greaterThan: 3 } } , Infinity ) ;
doormen.not( { filter: { greaterThan: Infinity } } , Infinity ) ;
doormen.not( { filter: { greaterThan: 3 } } , -Infinity ) ;
doormen.not( { filter: { greaterThan: 3 } } , NaN ) ;
doormen.not( { filter: { greaterThan: 3 } } , true ) ;
doormen.not( { filter: { greaterThan: 3 } } , false ) ;
doormen.not( { filter: { greaterThan: 3 } } , undefined ) ;
doormen.not( { filter: { greaterThan: 0 } } , undefined ) ;
doormen.not( { filter: { greaterThan: -3 } } , undefined ) ;
doormen.not( { filter: { greaterThan: 3 } } , '10' ) ;
doormen( { filter: { gt: 3 } } , 3.00001 ) ;
doormen.not( { filter: { gt: 3 } } , 3 ) ;
doormen( { filter: { '>': 3 } } , 3.00001 ) ;
doormen.not( { filter: { '>': 3 } } , 3 ) ;

'lesserThan' and aliases ('lt' and '<') filter should validate accordingly, non-number should throw.

doormen.not( { filter: { lesserThan: 3 } } , 10 ) ;
doormen( { filter: { lesserThan: 3 } } , 2.999 ) ;
doormen.not( { filter: { lesserThan: 3 } } , 3 ) ;
doormen( { filter: { lesserThan: 3 } } , 1 ) ;
doormen( { filter: { lesserThan: 3 } } , 0 ) ;
doormen( { filter: { lesserThan: 3 } } , -10 ) ;
doormen.not( { filter: { lesserThan: 3 } } , Infinity ) ;
doormen( { filter: { lesserThan: 3 } } , -Infinity ) ;
doormen.not( { filter: { lesserThan: -Infinity } } , -Infinity ) ;
doormen.not( { filter: { lesserThan: 3 } } , NaN ) ;
doormen.not( { filter: { lesserThan: 3 } } , true ) ;
doormen.not( { filter: { lesserThan: 3 } } , false ) ;
doormen.not( { filter: { lesserThan: 3 } } , '1' ) ;
doormen( { filter: { lt: 3 } } , 2.999 ) ;
doormen.not( { filter: { lt: 3 } } , 3 ) ;
doormen( { filter: { '<': 3 } } , 2.999 ) ;
doormen.not( { filter: { '<': 3 } } , 3 ) ;

Children and recursivity

'of' should perform the check recursively for each children, using the same given schema for all of them..

var schema ;
		schema = {
			of: { type: 'string' }
		} ;
		// Object
		doormen( schema , { b: 'text' } ) ;
		doormen.not( schema , { a: 1 } ) ;
		doormen.not( schema , { a: 1 , b: 'text' } ) ;
		doormen.not( schema , { a: 'text' , b: 3 } ) ;
		doormen( schema , { a: 'text' , b: 'string' } ) ;
		doormen.not( schema , { A: 'TEXT' , b: 'text' , c: undefined } ) ;
		// Array
		doormen( schema , [ 'text' ] ) ;
		doormen( schema , [] ) ;
		doormen( schema , [ 'text' , 'string' ] ) ;
		doormen.not( schema , [ 'text' , 'string' , null ] ) ;
		doormen.not( schema , [ 1 , 'text' , 'string' ] ) ;
		doormen.not( schema , [ 'text' , 'string' , null ] ) ;
		doormen.not( schema , [ true ] ) ;

when 'properties' is an array, it should check if the value has all listed properties, no extra properties are allowed.

var schema = {
			properties: [ 'a' , 'b' ]
		} ;
		doormen( schema , { a: 1 , b: 'text' } ) ;
		doormen( schema , { a: 'text' , b: 3 } ) ;
		doormen.not( schema , {
			A: 'TEXT' , a: 1 , b: 'text' , c: 5
		} ) ;
		doormen.not( schema , { b: 'text' } ) ;
		doormen.not( schema , { a: 1 } ) ;

when 'properties' is an array and 'extraProperties' is set, it should allow non-listed extra-properties.

var schema = {
			properties: [ 'a' , 'b' ] ,
			extraProperties: true
		} ;
		doormen( schema , { a: 1 , b: 'text' } ) ;
		doormen( schema , { a: 'text' , b: 3 } ) ;
		doormen( schema , {
			A: 'TEXT' , a: 1 , b: 'text' , c: 5
		} ) ;
		doormen.not( schema , { b: 'text' } ) ;
		doormen.not( schema , { a: 1 } ) ;

when 'properties' is an object, it should perform the check recursively for each listed child, no extra properties are allowed.

var schema = {
			properties: {
				a: { type: 'number' } ,
				b: { type: 'string' }
			}
		} ;
		doormen( schema , { a: 1 , b: 'text' } ) ;
		doormen.not( schema , { a: 'text' , b: 3 } ) ;
		doormen.not( schema , {
			A: 'TEXT' , a: 1 , b: 'text' , c: 5
		} ) ;
		doormen.not( schema , { b: 'text' } ) ;
		doormen.not( schema , { a: 1 } ) ;

when 'properties' is an object and 'extraProperties' is set, it should allow extra-properties.

var schema = {
			properties: {
				a: { type: 'number' } ,
				b: { type: 'string' }
			} ,
			extraProperties: true
		} ;
		doormen( schema , { a: 1 , b: 'text' } ) ;
		doormen.not( schema , { a: 'text' , b: 3 } ) ;
		doormen( schema , {
			A: 'TEXT' , a: 1 , b: 'text' , c: 5
		} ) ;
		doormen.not( schema , { b: 'text' } ) ;
		doormen.not( schema , { a: 1 } ) ;

'elements' should perform the check recursively for each children elements, using a specific schema for each one, extra-element are not allowed.

var schema = {
			elements: [
				{ type: 'string' } ,
				{ type: 'number' } ,
				{ type: 'boolean' }
			]
		} ;
		doormen( schema , [ 'text' , 3 , false ] ) ;
		doormen.not( schema , [ 'text' , 3 , false , 'extra' , true ] ) ;
		doormen.not( schema , [] ) ;
		doormen.not( schema , [ 'text' , 3 ] ) ;
		doormen.not( schema , [ true ] ) ;

when 'elements' is used in conjunction with 'extraElements', extra-elements are allowed.

var schema = {
			elements: [
				{ type: 'string' } ,
				{ type: 'number' } ,
				{ type: 'boolean' }
			] ,
			extraElements: true
		} ;
		doormen( schema , [ 'text' , 3 , false ] ) ;
		doormen( schema , [ 'text' , 3 , false , 'extra' , true ] ) ;
		doormen.not( schema , [] ) ;
		doormen.not( schema , [ 'text' , 3 ] ) ;
		doormen.not( schema , [ true ] ) ;

Mask

should mask data using a tier-level.

var schema = {
	properties: {
		a: {
			type: 'number' ,
			tier: 1
		} ,
		b: {
			type: 'boolean' ,
			tier: 3
		} ,
		c: {
			type: 'string' ,
			tier: 2
		}
	}
} ;
var data = {
	a: 1 ,
	b: true ,
	c: 'blah!'
} ;
doormen.equals(
	doormen.tierMask( schema , data , 0 ) ,
	{}
) ;
doormen.equals(
	doormen.tierMask( schema , data , 1 ) ,
	{ a: 1 }
) ;
doormen.equals(
	doormen.tierMask( schema , data , 2 ) ,
	{ a: 1 , c: 'blah!' }
) ;
doormen.equals(
	doormen.tierMask( schema , data , 3 ) ,
	{ a: 1 , b: true , c: 'blah!' }
) ;
doormen.equals(
	doormen.tierMask( schema , data , 4 ) ,
	{ a: 1 , b: true , c: 'blah!' }
) ;

should mask nested data using a tier-level.

var schema = {
	properties: {
		a: {
			type: 'number' ,
			tier: 1
		} ,
		b: {
			type: 'boolean' ,
			tier: 3
		} ,
		c: {
			type: 'string' ,
			tier: 2
		} ,
		d: {
			type: 'strictObject' ,
			properties: {
				e: {
					type: 'number' ,
					tier: 1
				} ,
				f: {
					type: 'boolean' ,
					tier: 3
				} ,
				g: {
					type: 'string' ,
					tier: 2
				}
			}
		} ,
		d2: {
			type: 'strictObject' ,
			tier: 2 ,
			extraProperties: true ,
			properties: {
				e: {
					type: 'number' ,
					tier: 1
				} ,
				f: {
					type: 'boolean' ,
					tier: 3
				} ,
				g: {
					type: 'string' ,
					tier: 2
				}
			}
		}
	}
} ;
var data = {
	a: 1 ,
	b: true ,
	c: 'blah!' ,
	d: {
		e: 7 ,
		f: false ,
		g: 'bob'
	} ,
	d2: {
		e: 7 ,
		f: false ,
		g: 'bob'
	}
} ;
doormen.equals(
	doormen.tierMask( schema , data , 1 ) ,
	{ a: 1 , d: { e: 7 } }
) ;
doormen.equals(
	doormen.tierMask( schema , data , 2 ) ,
	{
		a: 1 , c: 'blah!' , d: { e: 7 , g: 'bob' } , d2: { e: 7 , g: 'bob' }
	}
) ;
doormen.equals(
	doormen.tierMask( schema , data , 3 ) ,
	{
		a: 1 , b: true , c: 'blah!' , d: { e: 7 , f: false , g: 'bob' } , d2: { e: 7 , f: false , g: 'bob' }
	}
) ;

// Test extra-properties
data.d.extra = 'val' ;
data.d2.extra = 'val' ;
doormen.equals(
	doormen.tierMask( schema , data , 2 ) ,
	{
		a: 1 , c: 'blah!' , d: { e: 7 , g: 'bob' } , d2: { e: 7 , g: 'bob' , extra: 'val' }
	}
) ;

// Test submasking
schema.properties.d2.noSubmasking = true ;
doormen.equals(
	doormen.tierMask( schema , data , 2 ) ,
	{
		a: 1 , c: 'blah!' , d: { e: 7 , g: 'bob' } , d2: { e: 7 , f: false , g: 'bob' , extra: 'val' }
	}
) ;

should mask data using tags.

var schema = {
	properties: {
		_id: { tags: [] } ,
		slug: { tags: [ 'internal' , 'meta' ] } ,
		access: { tags: [ 'internal' ] } ,
		title: { tags: [ 'meta' ] } ,
		post: { tags: [ 'content' ] }
	}
} ;
var data = {
	_id: '1978f09ac3e' ,
	slug: 'ten-things-about-nothing' ,
	access: 'public' ,
	title: '10 things you should know about nothing' ,
	post: 'blah blah blah blah'
} ;
doormen.equals(
	doormen.tagMask( schema , data , [ 'meta' ] ) ,
	{
		_id: '1978f09ac3e' ,
		slug: 'ten-things-about-nothing' ,
		title: '10 things you should know about nothing'
	}
) ;
// Test the non-array syntax
doormen.equals(
	doormen.tagMask( schema , data , 'meta' ) ,
	{
		_id: '1978f09ac3e' ,
		slug: 'ten-things-about-nothing' ,
		title: '10 things you should know about nothing'
	}
) ;
doormen.equals(
	doormen.tagMask( schema , data , [ 'internal' ] ) ,
	{
		_id: '1978f09ac3e' ,
		slug: 'ten-things-about-nothing' ,
		access: 'public'
	}
) ;
doormen.equals(
	doormen.tagMask( schema , data , [ 'internal' , 'content' ] ) ,
	{
		_id: '1978f09ac3e' ,
		slug: 'ten-things-about-nothing' ,
		access: 'public' ,
		post: 'blah blah blah blah'
	}
) ;
doormen.equals(
	doormen.tagMask( schema , data , [ 'internal' , 'meta' , 'content' ] ) ,
	{
		_id: '1978f09ac3e' ,
		slug: 'ten-things-about-nothing' ,
		access: 'public' ,
		title: '10 things you should know about nothing' ,
		post: 'blah blah blah blah'
	}
) ;

should mask nested data using tags.

var schema = {
	properties: {
		_id: {} ,
		slug: { tags: [ 'internal' , 'meta' ] } ,
		accesses: {
			of: {
				properties: {
					userId: {} ,
					accessLevel: { tags: [ 'internal' ] }
				}
			}
		} ,
		title: { tags: [ 'meta' ] } ,
		post: { tags: [ 'content' ] }
	}
} ;
var data = {
	_id: '1978f09ac3e' ,
	slug: 'ten-things-about-nothing' ,
	accesses: [
		{
			userId: 'bob' ,
			accessLevel: 2
		} ,
		{
			userId: 'bill' ,
			accessLevel: 3
		}
	] ,
	title: '10 things you should know about nothing' ,
	post: 'blah blah blah blah'
} ;
doormen.equals(
	doormen.tagMask( schema , data , [ 'meta' ] ) ,
	{
		_id: '1978f09ac3e' ,
		slug: 'ten-things-about-nothing' ,
		accesses: [ { userId: 'bob' } , { userId: 'bill' } ] ,
		title: '10 things you should know about nothing'
	}
) ;
doormen.equals(
	doormen.tagMask( schema , data , [ 'internal' ] ) ,
	{
		_id: '1978f09ac3e' ,
		slug: 'ten-things-about-nothing' ,
		accesses: [
			{ userId: 'bob' , accessLevel: 2 } ,
			{ userId: 'bill' , accessLevel: 3 }
		]
	}
) ;
doormen.equals(
	doormen.tagMask( schema , data , [ 'internal' , 'content' ] ) ,
	{
		_id: '1978f09ac3e' ,
		slug: 'ten-things-about-nothing' ,
		accesses: [
			{ userId: 'bob' , accessLevel: 2 } ,
			{ userId: 'bill' , accessLevel: 3 }
		] ,
		post: 'blah blah blah blah'
	}
) ;
doormen.equals(
	doormen.tagMask( schema , data , [ 'internal' , 'meta' , 'content' ] ) ,
	{
		_id: '1978f09ac3e' ,
		slug: 'ten-things-about-nothing' ,
		accesses: [
			{ userId: 'bob' , accessLevel: 2 } ,
			{ userId: 'bill' , accessLevel: 3 }
		] ,
		title: '10 things you should know about nothing' ,
		post: 'blah blah blah blah'
	}
) ;

tag-masking and 'noSubmasking' behavior.

var schema = {
	properties: {
		_id: {} ,
		slug: { tags: [ 'internal' , 'meta' ] } ,
		accesses: {
			of: {
				properties: {
					userId: {} ,
					accessLevel: { tags: [ 'internal' ] } ,
					details: {
						tags: [ 'internal' ] ,
						properties: {
							k1: { type: 'string' , tags: [ 'nope' ] } ,
							k2: { type: 'string' }
						}
					}
				}
			}
		} ,
		title: { tags: [ 'meta' ] } ,
		post: { tags: [ 'content' ] }
	}
} ;
var data = {
	_id: '1978f09ac3e' ,
	slug: 'ten-things-about-nothing' ,
	accesses: [
		{
			userId: 'bob' ,
			accessLevel: 2 ,
			details: { k1: 'one' , k2: 'two' }
		} ,
		{
			userId: 'bill' ,
			accessLevel: 3 ,
			details: { k1: 'three' , k2: 'four' }
		}
	] ,
	title: '10 things you should know about nothing' ,
	post: 'blah blah blah blah'
} ;
doormen.equals(
	doormen.tagMask( schema , data , [ 'meta' ] ) ,
	{
		_id: '1978f09ac3e' ,
		slug: 'ten-things-about-nothing' ,
		accesses: [ { userId: 'bob' } , { userId: 'bill' } ] ,
		title: '10 things you should know about nothing'
	}
) ;
doormen.equals(
	doormen.tagMask( schema , data , [ 'internal' ] ) ,
	{
		_id: '1978f09ac3e' ,
		slug: 'ten-things-about-nothing' ,
		accesses: [
			{ userId: 'bob' , accessLevel: 2 , details: { k2: 'two' } } ,
			{ userId: 'bill' , accessLevel: 3 , details: { k2: 'four' } }
		]
	}
) ;
schema.properties.accesses.of.properties.details.noSubmasking = true ;
doormen.equals(
	doormen.tagMask( schema , data , [ 'internal' ] ) ,
	{
		_id: '1978f09ac3e' ,
		slug: 'ten-things-about-nothing' ,
		accesses: [
			{ userId: 'bob' , accessLevel: 2 , details: { k1: 'one' , k2: 'two' } } ,
			{ userId: 'bill' , accessLevel: 3 , details: { k1: 'three' , k2: 'four' } }
		]
	}
) ;

depthLimit with mask and nested data.

var schema = {
	properties: {
		title: { tags: [ 'meta' ] } ,
		post: { tags: [ 'meta' ] } ,
		accesses: {
			of: {
				properties: {
					userId: { tags: [ 'meta' ] } ,
					accessLevel: { tags: [ 'internal' ] }
				}
			}
		}
	}
} ;
var data = {
	title: '10 things you should know about nothing' ,
	post: 'blah blah blah blah' ,
	accesses: [
		{
			userId: 'bob' ,
			accessLevel: 2
		} ,
		{
			userId: 'bill' ,
			accessLevel: 3
		}
	]
} ;
doormen.equals(
	doormen.tagMask( schema , data , [ 'meta' ] ) ,
	{
		title: '10 things you should know about nothing' ,
		post: 'blah blah blah blah' ,
		accesses: [ { userId: 'bob' } , { userId: 'bill' } ]
	}
) ;
doormen.equals(
	doormen.tagMask( schema , data , [ 'meta' ] , 1 ) ,
	{
		title: '10 things you should know about nothing' ,
		post: 'blah blah blah blah' ,
		accesses: [ { userId: 'bob' , accessLevel: 2 } , { userId: 'bill' , accessLevel: 3 } ]
	}
) ;
doormen.equals(
	doormen.tagMask( schema , data , [ 'meta' ] , 2 ) ,
	{
		title: '10 things you should know about nothing' ,
		post: 'blah blah blah blah' ,
		accesses: [ { userId: 'bob' , accessLevel: 2 } , { userId: 'bill' , accessLevel: 3 } ]
	}
) ;
doormen.equals(
	doormen.tagMask( schema , data , [ 'meta' ] , 3 ) ,
	{
		title: '10 things you should know about nothing' ,
		post: 'blah blah blah blah' ,
		accesses: [ { userId: 'bob' } , { userId: 'bill' } ]
	}
) ;

.patchTier().

var schema = {
	type: 'strictObject' ,
	properties: {
		a: {
			type: 'number' ,
			tier: 3
		} ,
		b: {
			type: 'string' ,
			tier: 1
		} ,
		c: {
			type: 'string' ,
			tier: 4
		} ,
		embedded: {
			type: 'strictObject' ,
			tier: 3 ,
			extraProperties: true ,
			properties: {
				d: {
					type: 'number' ,
					tier: 2
				} ,
				e: {
					type: 'string' ,
					tier: 4
				}
			}
		}
	}
} ;
doormen.equals(  doormen.patchTier( schema , {} )  ,  1  ) ;
doormen.equals(  doormen.patchTier( schema , { a: 'some' , b: 'useless' , c: 'values' } )  ,  4  ) ;
doormen.equals(  doormen.patchTier( schema , { a: 'some' } )  ,  3  ) ;
doormen.equals(  doormen.patchTier( schema , { b: 'some' } )  ,  1  ) ;
doormen.equals(  doormen.patchTier( schema , { a: 'some' , c: 'values' } )  ,  4  ) ;
doormen.equals(  doormen.patchTier( schema , { a: 'some' , b: 'useless' } )  ,  3  ) ;
doormen.equals(  doormen.patchTier( schema , { embedded: 'useless' } )  ,  3  ) ;
doormen.equals(  doormen.patchTier( schema , { b: 'some' , 'embedded.e': 'useless' } )  ,  4  ) ;
doormen.equals(  doormen.patchTier( schema , { b: 'some' , 'embedded.unexistant': 'useless' } )  ,  3  ) ;
doormen.equals(  doormen.patchTier( schema , { 'embedded.e': 'useless' } )  ,  4  ) ;
doormen.equals(  doormen.patchTier( schema , { 'embedded.d': 'useless' } )  ,  3  ) ;
doormen.equals(  doormen.patchTier( schema , { 'embedded.unexistant': 'useless' } )  ,  3  ) ;

.checkPatchByTags().

var schema = {
	properties: {
		_id: {} ,
		slug: { tags: [ 'internal' , 'meta' ] } ,
		accesses: {
			of: {
				properties: {
					userId: {} ,
					accessLevel: { tags: [ 'internal' ] }
				}
			}
		} ,
		title: { tags: [ 'meta' ] } ,
		post: { tags: [ 'content' ] }
	}
} ;
doormen.checkPatchByTags( schema , { slug: 'bob' } , 'meta' ) ;
doormen.checkPatchByTags( schema , { slug: 'bob' } , 'internal' ) ;
doormen.checkPatchByTags( schema , { slug: 'bob' } , [ 'meta' , 'content' ] ) ;
doormen.shouldThrow( () => doormen.checkPatchByTags( schema , { slug: 'bob' } , 'content' ) ) ;
doormen.shouldThrow( () => doormen.checkPatchByTags( schema , { slug: 'bob' } , [ 'content' , 'unknown' ] ) ) ;

doormen.checkPatchByTags( schema , { title: 'bob' } , 'meta' ) ;
doormen.checkPatchByTags( schema , { title: 'bob' } , [ 'content' , 'meta' ] ) ;
doormen.shouldThrow( () => doormen.checkPatchByTags( schema , { title: 'bob' } , 'content' ) ) ;

doormen.checkPatchByTags( schema , { "accesses.public.accessLevel": 5 } , 'internal' ) ;
doormen.shouldThrow( () => doormen.checkPatchByTags( schema , { "accesses.public.accessLevel": 5 } , 'meta' ) ) ;
doormen.checkPatchByTags( schema , { slug: 'bob' , title: 'bob' } , [ 'meta' , 'unknown' ] ) ;
doormen.checkPatchByTags( schema , { slug: 'bob' , "accesses.public.accessLevel": 5 } , [ 'internal' , 'unknown' ] ) ;

doormen.checkPatchByTags( schema , { post: 'my content' } , [ 'content' , 'unknown' ] ) ;
doormen.shouldThrow( () => doormen.checkPatchByTags( schema , { slug: 'bob' , post: 'my content' } , [ 'content' , 'unknown' ] ) ) ;

should validate a patch with the 'allowedTags' option.

var schema ;
schema = {
	type: 'strictObject' ,
	properties: {
		a: { type: 'string' , sanitize: 'toString' , tags: [ 'meta' ] } ,
		b: { type: 'string' , tags: [ 'meta' , 'internal' ] } ,
		c: { type: 'string' , tags: [ 'content' ] }
	}
} ;
doormen.patch( { allowedTags: [ 'meta' , 'content' ] } , schema , { a: 'one' , b: 'two' , c: 'three' } ) ;
doormen.patch( { allowedTags: 'meta' } , schema , { a: 'one' , b: 'two' } ) ;
doormen.shouldThrow( () => doormen.patch( { allowedTags: 'meta' } , schema , { a: 'one' , b: 'two' , c: 'three' } ) ) ;
doormen.patch( { allowedTags: [ 'meta' , 'content' ] } , schema , { a: 1 , b: 'two' , c: 'three' } ) ;
doormen.equals( doormen.patch( { allowedTags: [ 'meta' , 'content' ] } , schema , { a: 1 , b: 'two' } ) , { a: '1' , b: 'two' } ) ;

Numbers meta types

should validate real accordingly.

doormen( { type: 'real' } , 0 ) ;
doormen( { type: 'real' } , 1 ) ;
doormen( { type: 'real' } , -1 ) ;
doormen( { type: 'real' } , 0.3 ) ;
doormen( { type: 'real' } , 18.36 ) ;
doormen.not( { type: 'real' } , 1 / 0 ) ;
doormen.not( { type: 'real' } , -1 / 0 ) ;
doormen.not( { type: 'real' } , Infinity ) ;
doormen.not( { type: 'real' } , -Infinity ) ;
doormen.not( { type: 'real' } , NaN ) ;
doormen.not( { type: 'real' } , undefined ) ;
doormen.not( { type: 'real' } , null ) ;
doormen.not( { type: 'real' } , false ) ;
doormen.not( { type: 'real' } , true ) ;
doormen.not( { type: 'real' } , '' ) ;
doormen.not( { type: 'real' } , 'text' ) ;
doormen.not( { type: 'real' } , {} ) ;
doormen.not( { type: 'real' } , [] ) ;

should validate integer accordingly.

doormen( { type: 'integer' } , 0 ) ;
doormen( { type: 'integer' } , 1 ) ;
doormen( { type: 'integer' } , 123456789 ) ;
doormen( { type: 'integer' } , -1 ) ;
doormen.not( { type: 'integer' } , 0.00001 ) ;
doormen.not( { type: 'integer' } , -0.00001 ) ;
doormen.not( { type: 'integer' } , 123456.00001 ) ;
doormen.not( { type: 'integer' } , 123456.99999 ) ;
doormen.not( { type: 'integer' } , 0.3 ) ;
doormen.not( { type: 'integer' } , 18.36 ) ;
doormen.not( { type: 'integer' } , 1 / 0 ) ;
doormen.not( { type: 'integer' } , Infinity ) ;
doormen.not( { type: 'integer' } , -Infinity ) ;
doormen.not( { type: 'integer' } , NaN ) ;
doormen.not( { type: 'integer' } , undefined ) ;
doormen.not( { type: 'integer' } , null ) ;
doormen.not( { type: 'integer' } , false ) ;
doormen.not( { type: 'integer' } , true ) ;
doormen.not( { type: 'integer' } , '' ) ;
doormen.not( { type: 'integer' } , 'text' ) ;
doormen.not( { type: 'integer' } , {} ) ;
doormen.not( { type: 'integer' } , [] ) ;

Strings meta types

should validate hex accordingly.

doormen( { type: 'hex' } , '1234' ) ;
doormen( { type: 'hex' } , '12af34' ) ;
doormen( { type: 'hex' } , '12AF34' ) ;
doormen.not( { type: 'hex' } , '12g34' ) ;

should validate ipv4 accordingly.

doormen( { type: 'ipv4' } , '127.0.0.1' ) ;
doormen( { type: 'ipv4' } , '127.000.00.001' ) ;
doormen.not( { type: 'ipv4' } , '127.0000.00.001' ) ;
doormen.not( { type: 'ipv4' } , '0127.000.00.001' ) ;
doormen.not( { type: 'ipv4' } , '127.0.0.0001' ) ;
doormen.not( { type: 'ipv4' } , '127.0.0.' ) ;
doormen.not( { type: 'ipv4' } , '127.0.0.256' ) ;
doormen.not( { type: 'ipv4' } , '127.0.0.1.' ) ;
doormen.not( { type: 'ipv4' } , '.127.0.0.1' ) ;
doormen.not( { type: 'ipv4' } , '.127.0.0.' ) ;

should validate ipv6 accordingly.

doormen( { type: 'ipv6' } , '2001:0db8:0000:0000:0000:ff00:0042:8329' ) ;
doormen.not( { type: 'ipv6' } , ':2001:0db8:0000:0000:0000:ff00:0042:8329' ) ;
doormen.not( { type: 'ipv6' } , 'abcd:2001:0db8:0000:0000:0000:ff00:0042:8329' ) ;
doormen.not( { type: 'ipv6' } , '2001:0db8:0000:0000:0000:ff00:0042:8329:' ) ;
doormen.not( { type: 'ipv6' } , '2001:0000:0000:0000:ff00:0042:8329:' ) ;
doormen.not( { type: 'ipv6' } , ':2001:0000:0000:0000:ff00:0042:8329' ) ;
doormen( { type: 'ipv6' } , '2001:db8:0:0:0:ff00:0042:8329' ) ;
doormen( { type: 'ipv6' } , '2001:db8::ff00:0042:8329' ) ;
doormen.not( { type: 'ipv6' } , '2001:db8:::0042:8329' ) ;
doormen.not( { type: 'ipv6' } , '2001:db8::ff00::0042:8329' ) ;
doormen.not( { type: 'ipv6' } , '2001::ff00::0042:8329' ) ;
doormen( { type: 'ipv6' } , '::1' ) ;
doormen( { type: 'ipv6' } , '1::' ) ;

should validate ip accordingly.

doormen( { type: 'ip' } , '127.0.0.1' ) ;
doormen( { type: 'ip' } , '127.000.00.001' ) ;
doormen.not( { type: 'ip' } , '127.0000.00.001' ) ;
doormen.not( { type: 'ip' } , '0127.000.00.001' ) ;
doormen.not( { type: 'ip' } , '127.0.0.0001' ) ;
doormen.not( { type: 'ip' } , '127.0.0.' ) ;
doormen.not( { type: 'ip' } , '127.0.0.256' ) ;
doormen.not( { type: 'ip' } , '127.0.0.1.' ) ;
doormen.not( { type: 'ip' } , '.127.0.0.1' ) ;
doormen.not( { type: 'ip' } , '.127.0.0.' ) ;
doormen( { type: 'ip' } , '2001:0db8:0000:0000:0000:ff00:0042:8329' ) ;
doormen.not( { type: 'ip' } , ':2001:0db8:0000:0000:0000:ff00:0042:8329' ) ;
doormen.not( { type: 'ip' } , 'abcd:2001:0db8:0000:0000:0000:ff00:0042:8329' ) ;
doormen.not( { type: 'ip' } , '2001:0db8:0000:0000:0000:ff00:0042:8329:' ) ;
doormen.not( { type: 'ip' } , '2001:0000:0000:0000:ff00:0042:8329:' ) ;
doormen.not( { type: 'ip' } , ':2001:0000:0000:0000:ff00:0042:8329' ) ;
doormen( { type: 'ip' } , '2001:db8:0:0:0:ff00:0042:8329' ) ;
doormen( { type: 'ip' } , '2001:db8::ff00:0042:8329' ) ;
doormen.not( { type: 'ip' } , '2001:db8:::0042:8329' ) ;
doormen.not( { type: 'ip' } , '2001:db8::ff00::0042:8329' ) ;
doormen.not( { type: 'ip' } , '2001::ff00::0042:8329' ) ;
doormen( { type: 'ip' } , '::1' ) ;
doormen( { type: 'ip' } , '1::' ) ;

should validate url accordingly.

doormen( { type: 'url' } , 'http://google.com' ) ;
doormen( { type: 'url' } , 'http://google.com/' ) ;
doormen( { type: 'url' } , 'https://stackoverflow.com/questions/1303872/url-validation-using-javascript' ) ;
doormen( { type: 'url' } , 'http://regexlib.com/DisplayPatterns.aspx?cattabindex=1&categoryId=2' ) ;
doormen( { type: 'url' } , 'https://uk.reuters.com/article/2013/02/25/rosneft-tender-idUKL6N0BPJZC20130225' ) ;
doormen( { type: 'url' } , 'http://grooveshark.com/#!/massive_attack' ) ;
doormen( { type: 'url' } , 'http://::1/#!/massive_attack' ) ;
doormen( { type: 'url' } , 'http://127.0.0.1/' ) ;
doormen( { type: 'url' } , 'http://localhost/' ) ;
doormen( { type: 'url' } , 'http://localhost:8080/' ) ;
doormen( { type: 'url' } , 'http://bob@localhost/' ) ;
doormen( { type: 'url' } , 'http://bob:pw@localhost/' ) ;
doormen.not( { type: 'url' } , 'http://127.0.0.1/spaces not allowed' ) ;
doormen.not( { type: 'url' } , 'http://127.0.0/' ) ;
doormen.not( { type: 'url' } , 'http://192.168.0.256/' ) ;
doormen.not( { type: 'url' } , 'http://19.16.33.25.6/' ) ;
doormen( { type: 'url' } , 'file:///home/toto/TODO.txt' ) ;
doormen.not( { type: 'url' } , 'http:///google.com/' ) ;
doormen.not( { type: 'url' } , 'google.com' ) ;

should validate web url accordingly.

doormen( { type: 'weburl' } , 'http://google.com' ) ;
doormen( { type: 'weburl' } , 'https://stackoverflow.com/questions/1303872/url-validation-using-javascript' ) ;
doormen( { type: 'weburl' } , 'http://regexlib.com/DisplayPatterns.aspx?cattabindex=1&categoryId=2' ) ;
doormen( { type: 'weburl' } , 'https://uk.reuters.com/article/2013/02/25/rosneft-tender-idUKL6N0BPJZC20130225' ) ;
doormen( { type: 'weburl' } , 'http://grooveshark.com/#!/massive_attack' ) ;
doormen( { type: 'weburl' } , 'http://127.0.0.1/#!/massive_attack' ) ;
doormen( { type: 'weburl' } , 'http://::1/#!/massive_attack' ) ;
doormen( { type: 'weburl' } , 'http://127.0.0.1/' ) ;
doormen.not( { type: 'weburl' } , 'http://127.0.0.1/spaces not allowed' ) ;
doormen.not( { type: 'weburl' } , 'http://127.0.0/' ) ;
doormen.not( { type: 'weburl' } , 'http://192.168.0.256/' ) ;
doormen.not( { type: 'weburl' } , 'http://19.16.33.25.6/' ) ;
doormen.not( { type: 'weburl' } , 'file:///home/toto/TODO.txt' ) ;
doormen.not( { type: 'weburl' } , 'google.com' ) ;

should validate email accordingly.

doormen( { type: 'email' } , '[email protected]' ) ;
doormen( { type: 'email' } , '[email protected]' ) ;
doormen( { type: 'email' } , 'cé[email protected]' ) ;
doormen( { type: 'email' } , 'Cé[email protected]' ) ;
doormen( { type: 'email' } , 'söm3-2än.dOm+ç[email protected]' ) ;
doormen.not( { type: 'email' } , 'bobgmail.com' ) ;
doormen.not( { type: 'email' } , '[email protected]' ) ;
doormen.not( { type: 'email' } , '[email protected]' ) ;
doormen.not( { type: 'email' } , '[email protected]' ) ;
doormen( { type: 'email' } , '[email protected]' ) ;
doormen.not( { type: 'email' } , 'bob @gmail.com' ) ;
doormen.not( { type: 'email' } , ' [email protected]' ) ;
doormen.not( { type: 'email' } , 'b [email protected]' ) ;

Sanitize

should sanitize to 'toBoolean' accordingly.

doormen.equals( doormen( { sanitize: 'toBoolean' } , 0 ) , false ) ;
doormen.equals( doormen( { sanitize: 'toBoolean' } , '0' ) , false ) ;
doormen.equals( doormen( { sanitize: 'toBoolean' } , 1 ) , true ) ;
doormen.equals( doormen( { sanitize: 'toBoolean' } , '1' ) , true ) ;
doormen.equals( doormen( { sanitize: 'toBoolean' } , 123 ) , true ) ;
doormen.equals( doormen( { sanitize: 'toBoolean' } , "on" ) , true ) ;
doormen.equals( doormen( { sanitize: 'toBoolean' } , "On" ) , true ) ;
doormen.equals( doormen( { sanitize: 'toBoolean' } , "ON" ) , true ) ;
doormen.equals( doormen( { sanitize: 'toBoolean' } , "off" ) , false ) ;
doormen.equals( doormen( { sanitize: 'toBoolean' } , "Off" ) , false ) ;
doormen.equals( doormen( { sanitize: 'toBoolean' } , "OFF" ) , false ) ;
doormen.equals( doormen( { sanitize: 'toBoolean' } , "true" ) , true ) ;
doormen.equals( doormen( { sanitize: 'toBoolean' } , "false" ) , false ) ;
doormen.equals( doormen( { sanitize: 'toBoolean' } , "yes" ) , true ) ;
doormen.equals( doormen( { sanitize: 'toBoolean' } , "no" ) , false ) ;
doormen.equals( doormen( { sanitize: 'toBoolean' } , '123' ) , true ) ;

should sanitize to 'toNumber' accordingly.

doormen.equals( doormen( { sanitize: 'toNumber' } , 0 ) , 0 ) ;
doormen.equals( doormen( { sanitize: 'toNumber' } , '0' ) , 0 ) ;
doormen.equals( doormen( { sanitize: 'toNumber' } , 1 ) , 1 ) ;
doormen.equals( doormen( { sanitize: 'toNumber' } , '1' ) , 1 ) ;
doormen.equals( doormen( { sanitize: 'toNumber' } , 123 ) , 123 ) ;
doormen.equals( doormen( { sanitize: 'toNumber' } , '123' ) , 123 ) ;
doormen.equals( doormen( { sanitize: 'toNumber' } , 123.456 ) , 123.456 ) ;
doormen.equals( doormen( { sanitize: 'toNumber' } , '123.456' ) , 123.456 ) ;

should sanitize to 'toInteger' accordingly.

doormen.equals( doormen( { sanitize: 'toInteger' } , 0 ) , 0 ) ;
doormen.equals( doormen( { sanitize: 'toInteger' } , '0' ) , 0 ) ;
doormen.equals( doormen( { sanitize: 'toInteger' } , 1 ) , 1 ) ;
doormen.equals( doormen( { sanitize: 'toInteger' } , '1' ) , 1 ) ;
doormen.equals( doormen( { sanitize: 'toInteger' } , 123 ) , 123 ) ;
doormen.equals( doormen( { sanitize: 'toInteger' } , '123' ) , 123 ) ;
doormen.equals( doormen( { sanitize: 'toInteger' } , 123.456 ) , 123 ) ;
doormen.equals( doormen( { sanitize: 'toInteger' } , '123.456' ) , 123 ) ;
doormen.equals( doormen( { sanitize: 'toInteger' } , 123.789 ) , 124 ) ;
doormen.equals( doormen( { sanitize: 'toInteger' } , '123.789' ) , 124 ) ;

should sanitize to 'toArray' accordingly.

// <- function() because we use 'arguments' in the test
	doormen.equals( doormen( { sanitize: 'toArray' } , [] ) , [] ) ;
	doormen.equals( doormen( { sanitize: 'toArray' } , [ 1 , 2 , 3 ] ) , [ 1 , 2 , 3 ] ) ;
	doormen.equals( doormen( { sanitize: 'toArray' } , { a: 'Ah!' , b: 'bee' } ) , [ { a: 'Ah!' , b: 'bee' } ] ) ;
	doormen.equals( doormen( { sanitize: 'toArray' } , 0 ) , [ 0 ] ) ;
	doormen.equals( doormen( { sanitize: 'toArray' } , 'a' ) , [ 'a' ] ) ;
	var fn = function() { return doormen( { sanitize: 'toArray' } , arguments ) ; } ;	// eslint-disable-line prefer-rest-params
	doormen.equals( fn() , [] ) ;
	doormen.equals( fn( 1 , 2 , 3 ) , [ 1 , 2 , 3 ] ) ;
	doormen.equals( fn( { yeepee: 'yaa' } , 'yeah' , true ) , [ { yeepee: 'yaa' } , 'yeah' , true ] ) ;
	doormen.equals( Array.isArray( fn( 1 , 2 , 3 ) ) , true ) ;
	doormen.equals( Array.isArray( arguments ) , false ) ;	// eslint-disable-line prefer-rest-params

should sanitize to 'toDate' accordingly.

var date = new Date() ;
var timestamp = date.getTime() ;
var dateString = date.toISOString() ;	// .toString() doesn't work: it strips millisecond
doormen.equals( doormen( { sanitize: 'toDate' } , date ) , date ) ;
doormen.equals( doormen( { sanitize: 'toDate' } , timestamp ) , date ) ;
doormen.equals( doormen( { sanitize: 'toDate' } , dat