typ
Version:
Type predicates and assertions for Node
228 lines (199 loc) • 7.13 kB
JavaScript
// Copyright 2012 The Obvious Corporation.
/*
* Tests for the typ module
*/
/*
* Modules used
*/
;
var assert = require("assert");
var events = require("events");
var util = require("util");
var typ = require("../");
/*
* Module variables
*/
/**
* List of all predicate and assertion functions. Each element maps
* `assert` to the assertion and `predicate` to the predicate.
*/
var PREDICATES = [
{ assert: typ.assertArray, predicate: typ.isArray },
{ assert: typ.assertBoolean, predicate: typ.isBoolean },
{ assert: typ.assertBuffer, predicate: typ.isBuffer },
{ assert: typ.assertDate, predicate: typ.isDate },
{ assert: typ.assertDefined, predicate: typ.isDefined },
{ assert: typ.assertError, predicate: typ.isError },
{ assert: typ.assertFunction, predicate: typ.isFunction },
{ assert: typ.assertInt, predicate: typ.isInt },
{ assert: typ.assertMap, predicate: typ.isMap },
{ assert: typ.assertNull, predicate: typ.isNull },
{ assert: typ.assertNullish, predicate: typ.isNullish },
{ assert: typ.assertNumber, predicate: typ.isNumber },
{ assert: typ.assertObject, predicate: typ.isObject },
{ assert: typ.assertRegExp, predicate: typ.isRegExp },
{ assert: typ.assertString, predicate: typ.isString },
{ assert: typ.assertUInt, predicate: typ.isUInt },
{ assert: typ.assertUndefined, predicate: typ.isUndefined },
];
/**
* List of value / predicate correspondences for use as test cases. On
* each element `v` maps to an arbitrary value, and `p` maps to a list
* of predicates which should be true for the value. All unlisted predicates
* for a value are expected to be false for that value.
*/
var PREDICATE_CASES = [
// arrays
{ v: [], p: [typ.isArray, typ.isObject, typ.isDefined] },
{ v: [1, 2, 3], p: [typ.isArray, typ.isObject, typ.isDefined] },
// booleans
{ v: false, p: [typ.isBoolean, typ.isDefined] },
{ v: true, p: [typ.isBoolean, typ.isDefined] },
// buffers
{ v: new Buffer(100), p: [typ.isBuffer, typ.isObject, typ.isDefined] },
// dates
{ v: new Date(1234567), p: [typ.isDate, typ.isObject, typ.isDefined] },
// errors
{ v: new Error("oy"), p: [typ.isError, typ.isObject, typ.isDefined] },
// functions
{ v: function () { return 0; },
p: [typ.isFunction, typ.isObject, typ.isDefined] },
{ v: new Function("return 5"),
p: [typ.isFunction, typ.isObject, typ.isDefined] },
// maps
{ v: {}, p: [typ.isMap, typ.isObject, typ.isDefined] },
{ v: { a: 10, b: 20 }, p: [typ.isMap, typ.isObject, typ.isDefined] },
// non-map objects
{ v: new events.EventEmitter(), p: [typ.isObject, typ.isDefined] },
{ v: { get a() { return 5; } }, p: [typ.isObject, typ.isDefined] },
{ v: { set b(n) { } }, p: [typ.isObject, typ.isDefined] },
// numbers
{ v: 0, p: [typ.isInt, typ.isUInt, typ.isNumber, typ.isDefined] },
{ v: 10, p: [typ.isInt, typ.isUInt, typ.isNumber, typ.isDefined] },
{ v: 1e200, p: [typ.isInt, typ.isUInt, typ.isNumber, typ.isDefined] },
{ v: -1, p: [typ.isInt, typ.isNumber, typ.isDefined] },
{ v: -12345, p: [typ.isInt, typ.isNumber, typ.isDefined] },
{ v: -12e55, p: [typ.isInt, typ.isNumber, typ.isDefined] },
{ v: 123.4, p: [typ.isNumber, typ.isDefined] },
{ v: Infinity, p: [typ.isNumber, typ.isDefined] },
{ v: -Infinity, p: [typ.isNumber, typ.isDefined] },
{ v: NaN, p: [typ.isNumber, typ.isDefined] }, // somewhat ironic
{ v: -1e-1000, p: [typ.isNumber, typ.isDefined] }, // !isInt()
// regexps
{ v: /frobozz/, p: [typ.isRegExp, typ.isObject, typ.isDefined] },
{ v: new RegExp("fizmo"), p: [typ.isRegExp, typ.isObject, typ.isDefined] },
// strings
{ v: "", p: [typ.isString, typ.isDefined] },
{ v: "blort", p: [typ.isString, typ.isDefined] },
// notable edge cases
{ v: new Number(5), p: [typ.isObject, typ.isDefined] }, // !isNumber()
{ v: new String("fuzz"), p: [typ.isObject, typ.isDefined] }, // !isString()
{ v: new Boolean(true), p: [typ.isObject, typ.isDefined] }, // !isBoolean()
// other
{ v: null, p: [typ.isNull, typ.isNullish, typ.isDefined] },
{ v: undefined, p: [typ.isNullish, typ.isUndefined] }
];
/*
* Helper functions
*/
/**
* Gets whether the given value is in the given array.
*/
function contains(array, value) {
for (var i = 0; i < array.length; i++) {
if (array[i] === value) {
return true;
}
}
return false;
}
/*
* Tests
*/
/**
* Test all the predicate cases. For each value, run each of the
* predicates and assertions, checking to make sure they are all
* as expected.
*/
function testAllPredicates() {
for (var i = 0; i < PREDICATE_CASES.length; i++) {
var one = PREDICATE_CASES[i];
testOneValue(one.v, one.p);
}
function testOneValue(value, predicates) {
for (var i = 0; i < PREDICATES.length; i++) {
var one = PREDICATES[i];
var assertFunc = one.assert;
var predicate = one.predicate;
var expectTrue = contains(predicates, predicate);
var passedPredicate;
try {
passedPredicate = predicate(value);
} catch (ex) {
console.log("Unexpected exception", ex.stack);
var msg = predicate.name + "(" + util.inspect(value) + ")";
assert.fail("no exception", ex, msg);
}
if (predicate(value) !== expectTrue) {
var msg = predicate.name + "(" + util.inspect(value) + ")";
assert.fail(!expectTrue, expectTrue, msg);
}
var passedAssert;
try {
assertFunc(value);
passedAssert = true;
} catch (ex) {
passedAssert = false;
}
if (passedAssert !== expectTrue) {
var msg = assertFunc.name + "(" + util.inspect(value) + ")";
assert.fail(!expectTrue, expectTrue, msg);
}
if (!passedAssert) {
var message = "sample message " + i + " // " + value;
try {
assertFunc(value, message);
var msg = assertFunc.name + "(" + util.inspect(value) + ", message)";
assert.fail(true, false, msg);
} catch (ex) {
assert.equal(ex.message, message);
}
}
}
}
}
/**
* Test `%` handling in failure messages.
*/
function testFailureFormat() {
try {
typ.assertString(123, "Well %% howdy %%% [%s]");
assert.fail(true, false, "Failed to throw.");
} catch (ex) {
assert.equal(ex.message,
"Well % howdy %% [Expected string; got uint (123).]");
}
// We assume that all the substitution code is shared, and so we
// don't bother testing all possible types.
}
/**
* Test `hasDefaultPrototype()`.
*/
function testHasDefaultPrototype() {
assert.ok(typ.hasDefaultPrototype({}));
assert.ok(!typ.hasDefaultPrototype(Object.create({})));
assert.ok(!typ.hasDefaultPrototype(new events.EventEmitter()));
}
/**
* Test `hasOwnProperty()`.
*/
function testHasOwnProperty() {
assert.ok(typ.hasOwnProperty({a: 10}, "a"));
assert.ok(!typ.hasOwnProperty({}, "hasOwnProperty"));
assert.ok(typ.hasOwnProperty({hasOwnProperty: "yay"}, "hasOwnProperty"));
}
testAllPredicates();
testFailureFormat();
testHasDefaultPrototype();
testHasOwnProperty();
console.log("All tests pass.");