Commit 0f98c333 authored by Stefan Cameron's avatar Stefan Cameron

Working on tests... isMap and isSet remain

parent aa8e13ed
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
////// RtvError Class
import {isTypeset} from './validation';
import {isTypeset} from './validation/validation';
import {validator as isString} from './validation/isString';
// @type {function} The super class.
......
......@@ -5,7 +5,7 @@ import {validator as isBoolean} from './validation/isBoolean';
import {validator as isArray} from './validation/isArray';
import {validator as isFunction} from './validation/isFunction';
import {validator as isObject} from './validation/isObject';
import {isTypeset} from './validation';
import {isTypeset} from './validation/validation';
import {DEFAULT_OBJECT_TYPE, default as types} from './types';
import {DEFAULT_QUALIFIER, default as qualifiers} from './qualifiers';
import {print} from './util';
......
......@@ -94,7 +94,7 @@ import Enumeration from './Enumeration';
* iterated.
*
* @typedef {Object} rtvref.types.collection_args
* @property {number} [length] The number of elements required in
* @property {number} [length] The exact number of elements required in
* the collection. A negative value allows for any number of entries. Zero
* requires an empty collection. Ignored if not a
* {@link rtvref.types.FINITE FINITE} number.
......
......@@ -20,22 +20,20 @@ import qualifiers from '../qualifiers';
export const validator = function isArray(v, q = qualifiers.REQUIRED, args) {
let valid = _isArray(v);
if (valid) {
if (valid && args) { // then check args
if (isFinite(args.length) && args.length >= 0) {
valid = (v.length === args.length);
} else {
let min;
if (valid && isFinite(args.min) && args.min >= 0) {
min = args.min;
valid = (v.length >= args.min);
}
if (valid && isFinite(args.max) && args.max >= 0) {
if (min === undefined || args.max >= min) {
valid = (v.length <= args.max);
} // else, ignore
}
if (valid && args) { // then check args
if (isFinite(args.length) && args.length >= 0) {
valid = (v.length === args.length);
} else {
let min;
if (valid && isFinite(args.min) && args.min >= 0) {
min = args.min;
valid = (v.length >= min);
}
if (valid && isFinite(args.max) && args.max >= 0) {
if (min === undefined || args.max >= min) {
valid = (v.length <= args.max);
} // else, ignore
}
}
}
......
......@@ -23,22 +23,20 @@ import qualifiers from '../qualifiers';
export const validator = function isFinite(v, q = qualifiers.REQUIRED, args) {
let valid = _isFinite(v); // eliminates NaN, +/-Infinity
if (valid) {
if (valid && args) { // then check args
if (_isFinite(args.exact)) { // ignore if NaN, +/-Infinity
valid = (v === args.exact);
} else {
let min;
if (valid && _isFinite(args.min)) { // ignore if NaN, +/-Infinity
min = args.min;
valid = (v >= args.min);
}
if (valid && args) { // then check args
if (_isFinite(args.exact)) { // ignore if NaN, +/-Infinity
valid = (v === args.exact);
} else {
let min;
if (valid && _isFinite(args.min)) { // ignore if NaN, +/-Infinity
min = args.min;
valid = (v >= min);
}
if (valid && _isFinite(args.max)) { // ignore if NaN, +/-Infinity
if (min === undefined || args.max >= min) {
valid = (v <= args.max);
} // else, ignore
}
if (valid && _isFinite(args.max)) { // ignore if NaN, +/-Infinity
if (min === undefined || args.max >= min) {
valid = (v <= args.max);
} // else, ignore
}
}
}
......
......@@ -36,48 +36,46 @@ const isStringTypeset = function(ts) {
export const validator = function isMap(v, q = qualifiers.REQUIRED, args) {
let valid = _isMap(v);
if (valid) {
if (valid && args) { // then check args
// start with the easiest/most efficient test: length
if (valid && isFinite(args.length) && args.length >= 0) {
valid = (v.size >= args.length);
}
if (valid && args) { // then check args
// start with the easiest/most efficient test: length
if (valid && isFinite(args.length) && args.length >= 0) {
valid = (v.size === args.length);
}
// remaining args, if specified, require iterating potentially the entire map
if (valid) {
// get the typeset for keys
const tsKeys = isTypeset(args.keys) ? args.keys : undefined;
// get the key expression only if the keys are expected to be strings
const tsKeysIsString = isStringTypeset(tsKeys);
const keyExp = (tsKeysIsString && isString(args.keyExp)) ?
args.keyExp : undefined;
// get the key expression flags only if we have a key expression
const keyFlagSpec = (keyExp && isString(args.keyFlagSpec)) ?
args.keyFlagSpec : undefined;
// get the typeset for values
const tsValues = isTypeset(args.values) ? args.values : undefined;
// remaining args, if specified, require iterating potentially the entire map
if (valid) {
// get the typeset for keys
const tsKeys = isTypeset(args.keys) ? args.keys : undefined;
// get the key expression only if the keys are expected to be strings
const tsKeysIsString = !!(tsKeys && isStringTypeset(tsKeys));
const keyExp = (tsKeysIsString && isString(args.keyExp)) ?
args.keyExp : undefined;
// get the key expression flags only if we have a key expression
const keyFlagSpec = (keyExp && isString(args.keyFlagSpec)) ?
args.keyFlagSpec : undefined;
// get the typeset for values
const tsValues = isTypeset(args.values) ? args.values : undefined;
if (tsKeys || tsValues) {
const reKeys = keyExp ? new RegExp(keyExp, keyFlagSpec) : undefined;
const it = v.entries(); // iterator
if (tsKeys || tsValues) {
const reKeys = keyExp ? new RegExp(keyExp, keyFlagSpec) : undefined;
const it = v.entries(); // iterator
for (let elem of it) {
const [key, value] = elem.value;
for (let elem of it) {
const [key, value] = elem.value;
if (tsKeys) {
valid = impl.check(key, tsKeys); // check key against typeset
if (valid && tsKeysIsString && reKeys) {
valid = reKeys.test(key); // check key against regex since it's a string
}
if (tsKeys) {
valid = impl.check(key, tsKeys); // check key against typeset
if (valid && tsKeysIsString && reKeys) {
valid = reKeys.test(key); // check key against regex since it's a string
}
}
if (valid && tsValues) {
valid = impl.check(value, tsValues); // check value against typeset
}
if (valid && tsValues) {
valid = impl.check(value, tsValues); // check value against typeset
}
if (!valid) {
break;
}
if (!valid) {
break;
}
}
}
......
......@@ -37,7 +37,7 @@ export const validator = function isNumber(v, q = qualifiers.REQUIRED, args) {
let min;
if (valid && _isNumber(args.min) && !_isNaN(args.min)) {
min = args.min;
valid = (v >= args.min);
valid = (v >= min);
}
if (valid && _isNumber(args.max) && !_isNaN(args.max)) {
......
......@@ -2,10 +2,12 @@
import {default as _isObjectLike} from 'lodash/isObjectLike';
// avoid circular dependency with isMap and isSet validators by using lodash
import {default as _isMap} from 'lodash/isMap';
import {default as _isSet} from 'lodash/isSet';
import {validator as isArray} from './isArray';
import {validator as isMap} from './isMap';
import {validator as isWeakMap} from './isWeakMap';
import {validator as isSet} from './isSet';
import {validator as isWeakSet} from './isWeakSet';
import {validator as isRegExp} from './isRegExp';
......@@ -25,8 +27,8 @@ import types from '../types';
export const validator = function isObject(v) { // no qualifier rules, no args
return _isObjectLike(v) && // excludes primitives and functions
!isArray(v) && // excludes arrays which are otherwise object-like (typeof [] === 'object')
!isMap(v) && !isWeakMap(v) && // excludes weak/maps
!isSet(v) && !isWeakSet(v) && // excludes weak/sets
!_isMap(v) && !isWeakMap(v) && // excludes weak/maps
!_isSet(v) && !isWeakSet(v) && // excludes weak/sets
!isRegExp(v); // excludes regex
};
......
......@@ -11,18 +11,6 @@ import qualifiers from '../qualifiers';
import {isTypeset} from './validation';
import * as impl from '../impl';
/**
* Determines if a typeset represents a string, and only a string.
* @param {rtvref.types.typeset} ts Typeset to check.
* @return {boolean} `true` if so; `false` otherwise.
*/
const isStringTypeset = function(ts) {
const fqts = impl.fullyQualify(ts);
// must be `[qualifier, STRING]`, otherwise no
return (fqts.length === 2 && fqts[1] === types.STRING);
};
/**
* {@link rtvref.validation.validator Validator} function for the
* {@link rtvref.types.SET SET} type.
......@@ -36,27 +24,25 @@ const isStringTypeset = function(ts) {
export const validator = function isSet(v, q = qualifiers.REQUIRED, args) {
let valid = _isSet(v);
if (valid) {
if (valid && args) { // then check args
// start with the easiest/most efficient test: length
if (valid && isFinite(args.length) && args.length >= 0) {
valid = (v.size >= args.length);
}
if (valid && args) { // then check args
// start with the easiest/most efficient test: length
if (valid && isFinite(args.length) && args.length >= 0) {
valid = (v.size >= args.length);
}
// remaining args, if specified, require iterating potentially the entire set
if (valid) {
// get the typeset for values
const tsValues = isTypeset(args.values) ? args.values : undefined;
// remaining args, if specified, require iterating potentially the entire set
if (valid) {
// get the typeset for values
const tsValues = isTypeset(args.values) ? args.values : undefined;
if (tsValues) {
const it = v.entries(); // iterator
if (tsValues) {
const it = v.entries(); // iterator
for (let elem of it) {
const value = elem.value[1];
valid = impl.check(value, tsValues); // check value against typeset
if (!valid) {
break;
}
for (let elem of it) {
const value = elem.value[1];
valid = impl.check(value, tsValues); // check value against typeset
if (!valid) {
break;
}
}
}
......
......@@ -35,7 +35,7 @@ export const validator = function isString(v, q = qualifiers.REQUIRED, args) {
let min;
if (valid && isFinite(args.min) && args.min >= 0) {
min = args.min;
valid = (v.length >= args.min);
valid = (v.length >= min);
}
if (valid && isFinite(args.max) && args.max >= 0) {
......
......@@ -114,8 +114,8 @@ export const isPrimitive = function(v) {
* @see {@link rtvref.types.typeset}
*/
export const isTypeset = function(v, {deep = false, fullyQualified = false} = {}) {
let valid = !!(isObject(v) || (isString(v) && types.check(v)) || isFunction(v) ||
(isArray(v) && v.length > 0));
let valid = !!(v && (isObject(v) || (isString(v) && types.check(v)) || isFunction(v) ||
(isArray(v) && v.length > 0)));
// FIRST: check if needs to be fully-qualified, and check deep within if requested
if (valid && fullyQualified) {
......
......@@ -14,7 +14,10 @@ describe('module: lib/validation/isAnyObject', function() {
it('should validate any object', function() {
const validValues = vtu.getValidValues(); // @type {Object}
const validTypes = Object.keys(validValues); // @type {Array}
_.pull(validTypes, types.ANY, types.STRING, types.BOOLEAN, types.NUMBER, types.SYMBOL); // remove primitives
// remove primitives
_.pull(validTypes, types.ANY, types.STRING, types.BOOLEAN, types.NUMBER,
types.FINITE, types.INT, types.FLOAT, types.SYMBOL);
let values = [];
_.forEach(validTypes, function(type) {
......
......@@ -3,6 +3,7 @@ import _ from 'lodash';
import * as vtu from './validationTestUtil';
import types from '../../../src/lib/types';
import qualifiers from '../../../src/lib/qualifiers';
import * as val from '../../../src/lib/validation/isArray';
describe('module: lib/validation/isArray', function() {
......@@ -33,12 +34,12 @@ describe('module: lib/validation/isArray', function() {
const arr = [7];
expect(val.validator([], undefined, {length: 0})).to.be.true;
expect(val.validator([], undefined, {length: -0})).to.be.true;
expect(val.validator(arr, undefined, {length: 1})).to.be.true;
expect(val.validator(arr, undefined, {length: 2})).to.be.false;
expect(val.validator(arr, undefined, {length: 1.1})).to.be.false;
expect(val.validator(arr, undefined, {length: '1'})).to.be.true; // ignored
expect(val.validator(arr, undefined, {length: -0})).to.be.true; // ignored
expect(val.validator(arr, undefined, {length: -1})).to.be.true; // ignored
expect(val.validator(arr, undefined, {length: NaN})).to.be.true; // ignored
expect(val.validator(arr, undefined, {length: Infinity})).to.be.true; // ignored
......
......@@ -3,6 +3,7 @@ import _ from 'lodash';
import * as vtu from './validationTestUtil';
import types from '../../../src/lib/types';
import qualifiers from '../../../src/lib/types';
import * as val from '../../../src/lib/validation/isFinite';
describe('module: lib/validation/isFinite', function() {
......@@ -52,7 +53,7 @@ describe('module: lib/validation/isFinite', function() {
expect(val.validator(7, undefined, {exact: 8})).to.be.false;
expect(val.validator(7.7, undefined, {exact: 7.6 + Number.EPSILON})).to.be.false;
expect(val.validator(7, undefined, {exact: '7'})).to.be.false; // ignored
expect(val.validator(7, undefined, {exact: '6'})).to.be.true; // ignored
expect(val.validator(NaN, undefined, {exact: NaN})).to.be.false; // ignored
expect(val.validator(NaN, qualifiers.EXPECTED, {exact: NaN})).to.be.false; // ignored
expect(val.validator(Infinity, undefined, {exact: Infinity})).to.be.false; // ignored
......@@ -73,7 +74,7 @@ describe('module: lib/validation/isFinite', function() {
expect(val.validator(7, undefined, {min: '7'})).to.be.true; // ignored
expect(val.validator(7, undefined, {min: NaN})).to.be.true; // ignored
expect(val.validator(-8, undefined, {min: -7})).to.be.false;
expect(val.validator(7, undefined, {min: 6})).to.be.false;
expect(val.validator(7, undefined, {min: 8})).to.be.false;
expect(val.validator(7, undefined, {min: Infinity})).to.be.true; // ignored
expect(val.validator(7, undefined, {min: -Infinity})).to.be.true; // ignored
expect(val.validator(7, undefined, {min: Number.POSITIVE_INFINITY})).to.be.true; // ignored
......@@ -94,7 +95,7 @@ describe('module: lib/validation/isFinite', function() {
});
it('max ignored if less than min', function() {
expect(val.validator(7, undefined, {min: 8, max: 6})).to.be.true;
expect(val.validator(7, undefined, {min: 7, max: 6})).to.be.true;
});
});
});
......@@ -4,7 +4,7 @@ import * as vtu from './validationTestUtil';
import types from '../../../src/lib/types';
import * as val from '../../../src/lib/validation/isMap';
describe('module: lib/validation/isMap', function() {
describe.only('module: lib/validation/isMap', function() { // DEBUG remove 'only'
describe('validator', function() {
it('type', function() {
expect(val.type).to.equal(types.MAP);
......@@ -27,9 +27,9 @@ describe('module: lib/validation/isMap', function() {
expect(val.validator(map, undefined, {length: 3})).to.be.true;
expect(val.validator(map, undefined, {length: 2})).to.be.false;
expect(val.validator(map, undefined, {length: 1.1})).to.be.false;
expect(val.validator(map, undefined, {length: -0})).to.be.false;
expect(val.validator(map, undefined, {length: '1'})).to.be.true; // ignored
expect(val.validator(map, undefined, {length: -0})).to.be.true; // ignored
expect(val.validator(map, undefined, {length: -1})).to.be.true; // ignored
expect(val.validator(map, undefined, {length: NaN})).to.be.true; // ignored
expect(val.validator(map, undefined, {length: Infinity})).to.be.true; // ignored
......@@ -54,7 +54,7 @@ describe('module: lib/validation/isMap', function() {
});
it('checks for strings keys that match a pattern', function() {
let map = new Map([1, 'one'], [2, 'two']);
let map = new Map([[1, 'one'], [2, 'two']]);
expect(val.validator(map, undefined, {
keys: types.FINITE,
......@@ -120,9 +120,9 @@ describe('module: lib/validation/isMap', function() {
it('checks for keys and values with specified typeset', function() {
const map = new Map([
[1, new Map(['1', true])],
[2, new Map(['2', false])],
[3, new Map(['3', true])]
[1, new Map([['1', true]])],
[2, new Map([['2', false]])],
[3, new Map([['3', true]])]
]);
expect(val.validator(map, undefined, {
......
......@@ -3,6 +3,7 @@ import _ from 'lodash';
import * as vtu from './validationTestUtil';
import types from '../../../src/lib/types';
import qualifiers from '../../../src/lib/qualifiers';
import * as val from '../../../src/lib/validation/isNumber';
describe('module: lib/validation/isNumber', function() {
......@@ -22,8 +23,8 @@ describe('module: lib/validation/isNumber', function() {
// remove subset types
_.pull(invalidTypes, types.NUMBER, types.FINITE, types.INT, types.FLOAT);
// build a list of all remaining invalid values
let invalidValues = [];
// build a list of all remaining invalid values, along with NaN
let invalidValues = [NaN];
_.forEach(invalidTypes, function(type) {
invalidValues = invalidValues.concat(validValues[type]);
});
......@@ -54,7 +55,7 @@ describe('module: lib/validation/isNumber', function() {
expect(val.validator(NaN, undefined, {exact: NaN})).to.be.false; // qualifier takes precedence
expect(val.validator(NaN, qualifiers.EXPECTED, {exact: NaN})).to.be.true;
expect(val.validator(7, undefined, {exact: '7'})).to.be.false; // ignored
expect(val.validator(7, undefined, {exact: '6'})).to.be.true; // ignored
expect(val.validator(Infinity, undefined, {exact: Infinity})).to.be.true; // ignored
expect(val.validator(-Infinity, undefined, {exact: -Infinity})).to.be.true; // ignored
expect(val.validator(Number.POSITIVE_INFINITY, undefined, {exact: Number.POSITIVE_INFINITY})).to.be.true; // ignored
......@@ -70,10 +71,10 @@ describe('module: lib/validation/isNumber', function() {
it('checks for a minimum number', function() {
expect(val.validator(7, undefined, {min: 7})).to.be.true;
expect(val.validator(7, undefined, {min: 0})).to.be.true;
expect(val.validator(7, undefined, {min: '7'})).to.be.true; // ignored
expect(val.validator(7, undefined, {min: '8'})).to.be.true; // ignored
expect(val.validator(7, undefined, {min: NaN})).to.be.true; // ignored
expect(val.validator(-8, undefined, {min: -7})).to.be.false;
expect(val.validator(7, undefined, {min: 6})).to.be.false;
expect(val.validator(7, undefined, {min: 6})).to.be.true;
expect(val.validator(7, undefined, {min: Infinity})).to.be.false;
expect(val.validator(7, undefined, {min: -Infinity})).to.be.true;
expect(val.validator(7, undefined, {min: Number.POSITIVE_INFINITY})).to.be.false;
......@@ -94,7 +95,7 @@ describe('module: lib/validation/isNumber', function() {
});
it('max ignored if less than min', function() {
expect(val.validator(7, undefined, {min: 8, max: 6})).to.be.true;
expect(val.validator(7, undefined, {min: 7, max: 6})).to.be.true;
});
});
});
......@@ -6,7 +6,7 @@ import types from '../../../src/lib/types';
import qualifiers from '../../../src/lib/qualifiers';
import * as val from '../../../src/lib/validation/isString';
describe.only('module: lib/validation/isString', function() {
describe('module: lib/validation/isString', function() {
describe('validator', function() {
it('type', function() {
expect(val.type).to.equal(types.STRING);
......@@ -46,7 +46,7 @@ describe.only('module: lib/validation/isString', function() {
it('checks for min length if "exact" is not specified', function() {
expect(val.validator('minimum', undefined, {min: 7})).to.be.true;
expect(val.validator('minimum', undefined, {min: 6})).to.be.false;
expect(val.validator('minimum', undefined, {min: 8})).to.be.false;
expect(val.validator('minimum', undefined, {min: -100})).to.be.true;
expect(val.validator('minimum', undefined, {min: '100'})).to.be.true; // ignored: not finite
expect(val.validator('minimum', undefined, {min: NaN})).to.be.true; // ignored: not finite
......@@ -58,7 +58,7 @@ describe.only('module: lib/validation/isString', function() {
it('min takes precedence over partial', function() {
expect(val.validator('minimum', undefined, {min: 7, partial: 'nim'})).to.be.true;
expect(val.validator('minimum', undefined, {min: 6, partial: 'nim'})).to.be.false;
expect(val.validator('minimum', undefined, {min: 8, partial: 'nim'})).to.be.false;
expect(val.validator('minimum', undefined, {min: -100, partial: 'foo'})).to.be.false;
expect(val.validator('minimum', undefined, {min: -1, partial: 'nim'})).to.be.true;
expect(val.validator('', undefined, {min: 0, partial: ''})).to.be.false; // default qualifier requires non-empty
......
......@@ -5,7 +5,7 @@ import * as vtu from './validationTestUtil';
import types, {DEFAULT_OBJECT_TYPE} from '../../../src/lib/types';
import qualifiers, {DEFAULT_QUALIFIER} from '../../../src/lib/qualifiers';
import * as util from '../../../src/lib/util';
import * as val from '../../../src/lib/validation';
import * as val from '../../../src/lib/validation/validation';
describe('module: lib/validation/validation', function() {
let validValues;
......@@ -108,10 +108,10 @@ describe('module: lib/validation/validation', function() {
});
it('should validate shallow typesets', function() {
let results = vtu.vtu.testValues('isTypeset', val.isTypeset, goodValues);
let results = vtu.testValues('isTypeset', val.isTypeset, goodValues);
expect(results.failures).to.eql([]);
results = vtu.vtu.testValues('isTypeset', val.isTypeset, badValues);
results = vtu.testValues('isTypeset', val.isTypeset, badValues);
expect(results.passes).to.eql([]);
});
......
......@@ -27,7 +27,7 @@ export const getValidValues = function(type) {
[types.NUMBER]: [-1, -0, 0, 1, Number.MIN_VALUE, Number.MIN_SAFE_INTEGER,
Number.MAX_VALUE, Number.MAX_SAFE_INTEGER, Number.EPSILON,
7.7, -7.7, NaN, Infinity, -Infinity, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY],
7.7, -7.7, Infinity, -Infinity, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY],
[types.FINITE]: [-1, -0, 0, 1, Number.MIN_VALUE, Number.MIN_SAFE_INTEGER,
Number.MAX_VALUE, Number.MAX_SAFE_INTEGER, Number.EPSILON, 7.7, -7.7],
[types.INT]: [-1, -0, 0, 1, Number.MIN_VALUE, Number.MIN_SAFE_INTEGER,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment