refactor(rtts_assert): Ts'ify rtts_assert
Translate rtts_assert to TypeScript.
This commit is contained in:
parent
d53c898499
commit
9e8108ee14
|
@ -1 +0,0 @@
|
||||||
export * from './src/rtts_assert';
|
|
|
@ -0,0 +1 @@
|
||||||
|
export * from './src/rtts_assert';
|
|
@ -16,9 +16,9 @@ function argPositionName(i) {
|
||||||
var primitives;
|
var primitives;
|
||||||
var genericType;
|
var genericType;
|
||||||
|
|
||||||
if (typeof $traceurRuntime === 'object') {
|
if (typeof _global['$traceurRuntime'] === 'object') {
|
||||||
primitives = $traceurRuntime.type;
|
primitives = _global['$traceurRuntime'].type;
|
||||||
genericType = $traceurRuntime.genericType;
|
genericType = _global['$traceurRuntime'].genericType;
|
||||||
} else {
|
} else {
|
||||||
// Allow to work without traceur runtime as well!
|
// Allow to work without traceur runtime as well!
|
||||||
primitives = {
|
primitives = {
|
||||||
|
@ -26,21 +26,15 @@ if (typeof $traceurRuntime === 'object') {
|
||||||
boolean: {name: 'boolean'},
|
boolean: {name: 'boolean'},
|
||||||
number: {name: 'number'},
|
number: {name: 'number'},
|
||||||
string: {name: 'string'},
|
string: {name: 'string'},
|
||||||
symbol: {name: 'symbol'},
|
symbol: {name: 'symbol'}, void: {name: 'void'}
|
||||||
void: {name: 'void'}
|
|
||||||
};
|
};
|
||||||
genericType = function(type, args) {
|
genericType = function(type, args) {
|
||||||
return {
|
return { type: type, args: args }
|
||||||
type: type,
|
|
||||||
args: args
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Object.keys(primitives).forEach(function(name) {
|
Object.keys(primitives).forEach(function(name) { primitives[name].__assertName = name; });
|
||||||
primitives[name].__assertName = name;
|
|
||||||
});
|
|
||||||
|
|
||||||
export function proxy(){
|
export function proxy() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function assertArgumentTypes(...params) {
|
function assertArgumentTypes(...params) {
|
||||||
|
@ -59,10 +53,10 @@ function assertArgumentTypes(...params) {
|
||||||
//
|
//
|
||||||
|
|
||||||
if (!isType(actual, type, currentArgErrors)) {
|
if (!isType(actual, type, currentArgErrors)) {
|
||||||
|
|
||||||
// console.log(JSON.stringify(errors, null, ' '));
|
// console.log(JSON.stringify(errors, null, ' '));
|
||||||
// TODO(vojta): print "an instance of" only if T starts with uppercase.
|
// TODO(vojta): print "an instance of" only if T starts with uppercase.
|
||||||
errors.push(argPositionName(i) + ' argument has to be an instance of ' + prettyPrint(type) + ', got ' + prettyPrint(actual));
|
errors.push(argPositionName(i) + ' argument has to be an instance of ' + prettyPrint(type) +
|
||||||
|
', got ' + prettyPrint(actual));
|
||||||
if (currentArgErrors.length) {
|
if (currentArgErrors.length) {
|
||||||
errors.push(currentArgErrors);
|
errors.push(currentArgErrors);
|
||||||
}
|
}
|
||||||
|
@ -74,7 +68,7 @@ function assertArgumentTypes(...params) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function prettyPrint(value, depth) {
|
function prettyPrint(value, depth?) {
|
||||||
if (typeof(depth) === 'undefined') {
|
if (typeof(depth) === 'undefined') {
|
||||||
depth = 0;
|
depth = 0;
|
||||||
}
|
}
|
||||||
|
@ -159,7 +153,7 @@ function isType(value, T, errors) {
|
||||||
var isValid;
|
var isValid;
|
||||||
currentStack = errors;
|
currentStack = errors;
|
||||||
try {
|
try {
|
||||||
isValid = T.assert(value) ;
|
isValid = T.assert(value);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
fail(e.message);
|
fail(e.message);
|
||||||
isValid = false;
|
isValid = false;
|
||||||
|
@ -201,30 +195,33 @@ function _isProxy(obj) {
|
||||||
|
|
||||||
function formatErrors(errors, indent = ' ') {
|
function formatErrors(errors, indent = ' ') {
|
||||||
return errors.map((e) => {
|
return errors.map((e) => {
|
||||||
if (typeof e === 'string') return indent + '- ' + e;
|
if (typeof e === 'string') return indent + '- ' + e;
|
||||||
return formatErrors(e, indent + ' ');
|
return formatErrors(e, indent + ' ');
|
||||||
}).join('\n');
|
})
|
||||||
|
.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// assert a type of given value and throw if does not pass
|
// assert a type of given value and throw if does not pass
|
||||||
function type(actual, T) {
|
var type: any =
|
||||||
var errors = [];
|
function(actual, T) {
|
||||||
// currentStack = [];
|
var errors = [];
|
||||||
|
// currentStack = [];
|
||||||
|
|
||||||
if (!isType(actual, T, errors)) {
|
if (!isType(actual, T, errors)) {
|
||||||
// console.log(JSON.stringify(errors, null, ' '));
|
// console.log(JSON.stringify(errors, null, ' '));
|
||||||
// TODO(vojta): print "an instance of" only if T starts with uppercase.
|
// TODO(vojta): print "an instance of" only if T starts with uppercase.
|
||||||
var msg = 'Expected an instance of ' + prettyPrint(T) + ', got ' + prettyPrint(actual) + '!';
|
var msg =
|
||||||
if (errors.length) {
|
'Expected an instance of ' + prettyPrint(T) + ', got ' + prettyPrint(actual) + '!';
|
||||||
msg += '\n' + formatErrors(errors);
|
if (errors.length) {
|
||||||
|
msg += '\n' + formatErrors(errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(msg);
|
||||||
|
}
|
||||||
|
return actual;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(msg);
|
|
||||||
}
|
|
||||||
return actual;
|
|
||||||
}
|
|
||||||
|
|
||||||
function returnType(actual, T) {
|
function returnType(actual, T) {
|
||||||
var errors = [];
|
var errors = [];
|
||||||
// currentStack = [];
|
// currentStack = [];
|
||||||
|
@ -232,7 +229,8 @@ function returnType(actual, T) {
|
||||||
if (!isType(actual, T, errors)) {
|
if (!isType(actual, T, errors)) {
|
||||||
// console.log(JSON.stringify(errors, null, ' '));
|
// console.log(JSON.stringify(errors, null, ' '));
|
||||||
// TODO(vojta): print "an instance of" only if T starts with uppercase.
|
// TODO(vojta): print "an instance of" only if T starts with uppercase.
|
||||||
var msg = 'Expected to return an instance of ' + prettyPrint(T) + ', got ' + prettyPrint(actual) + '!';
|
var msg = 'Expected to return an instance of ' + prettyPrint(T) + ', got ' +
|
||||||
|
prettyPrint(actual) + '!';
|
||||||
if (errors.length) {
|
if (errors.length) {
|
||||||
msg += '\n' + formatErrors(errors);
|
msg += '\n' + formatErrors(errors);
|
||||||
}
|
}
|
||||||
|
@ -244,17 +242,12 @@ function returnType(actual, T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(vojta): define these with DSL?
|
// TODO(vojta): define these with DSL?
|
||||||
var string = type.string = define('string', function(value) {
|
var string = type.string = define('string', function(value) { return typeof value === 'string'; });
|
||||||
return typeof value === 'string';
|
|
||||||
});
|
|
||||||
|
|
||||||
var boolean = type.boolean = define('boolean', function(value) {
|
var boolean = type.boolean =
|
||||||
return typeof value === 'boolean';
|
define('boolean', function(value) { return typeof value === 'boolean'; });
|
||||||
});
|
|
||||||
|
|
||||||
var number = type.number = define('number', function(value) {
|
var number = type.number = define('number', function(value) { return typeof value === 'number'; });
|
||||||
return typeof value === 'number';
|
|
||||||
});
|
|
||||||
|
|
||||||
function arrayOf(...types) {
|
function arrayOf(...types) {
|
||||||
return assert.define('array of ' + types.map(prettyPrint).join('/'), function(value) {
|
return assert.define('array of ' + types.map(prettyPrint).join('/'), function(value) {
|
||||||
|
@ -311,46 +304,46 @@ function define(classOrName, check) {
|
||||||
return cls;
|
return cls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var assert: any =
|
||||||
|
function(value) {
|
||||||
|
return {
|
||||||
|
is: function is(...types) {
|
||||||
|
// var errors = []
|
||||||
|
var allErrors = [];
|
||||||
|
var errors;
|
||||||
|
for (var i = 0; i < types.length; i++) {
|
||||||
|
var type = types[i];
|
||||||
|
errors = [];
|
||||||
|
|
||||||
|
if (isType(value, type, errors)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
function assert(value) {
|
// if no errors, merge multiple "is not instance of " into x/y/z ?
|
||||||
return {
|
allErrors.push(prettyPrint(value) + ' is not instance of ' + prettyPrint(type));
|
||||||
is: function is(...types) {
|
if (errors.length) {
|
||||||
// var errors = []
|
allErrors.push(errors);
|
||||||
var allErrors = [];
|
}
|
||||||
var errors;
|
}
|
||||||
for (var i = 0; i < types.length; i++) {
|
|
||||||
var type = types[i];
|
|
||||||
errors = [];
|
|
||||||
|
|
||||||
if (isType(value, type, errors)) {
|
// if (types.length > 1) {
|
||||||
return true;
|
// currentStack.push(['has to be ' + types.map(prettyPrint).join(' or '),
|
||||||
|
// ...allErrors]);
|
||||||
|
// } else {
|
||||||
|
currentStack.push(...allErrors);
|
||||||
|
// }
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
// if no errors, merge multiple "is not instance of " into x/y/z ?
|
|
||||||
allErrors.push(prettyPrint(value) + ' is not instance of ' + prettyPrint(type))
|
|
||||||
if (errors.length) {
|
|
||||||
allErrors.push(errors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (types.length > 1) {
|
|
||||||
// currentStack.push(['has to be ' + types.map(prettyPrint).join(' or '), ...allErrors]);
|
|
||||||
// } else {
|
|
||||||
currentStack.push(...allErrors);
|
|
||||||
// }
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// PUBLIC API
|
// PUBLIC API
|
||||||
|
|
||||||
// asserting API
|
// asserting API
|
||||||
|
|
||||||
// throw if no type provided
|
// throw if no type provided
|
||||||
assert.type = type;
|
assert.type = type;
|
||||||
for (var prop in primitives) {
|
for (var prop in primitives) {
|
||||||
assert.type[prop] = primitives[prop];
|
assert.type[prop] = primitives[prop];
|
||||||
}
|
}
|
|
@ -1,413 +0,0 @@
|
||||||
// # Assert.js
|
|
||||||
// A run-time type assertion library for JavaScript. Designed to be used with [Traceur](https://github.com/google/traceur-compiler).
|
|
||||||
|
|
||||||
|
|
||||||
// - [Basic Type Check](#basic-type-check)
|
|
||||||
// - [Custom Check](#custom-check)
|
|
||||||
// - [Primitive Values](#primitive-values)
|
|
||||||
// - [Describing more complex types](#describing-more-complex-types)
|
|
||||||
// - [assert.arrayOf](#assert-arrayof)
|
|
||||||
// - [assert.structure](#assert-structure)
|
|
||||||
// - [Integrating with Traceur](#integrating-with-traceur)
|
|
||||||
|
|
||||||
// Note: `assert` gets automatically included by traceur!
|
|
||||||
|
|
||||||
export function main() {
|
|
||||||
return;
|
|
||||||
|
|
||||||
describe('prettyPrint', () => {
|
|
||||||
class Type {};
|
|
||||||
|
|
||||||
it('should limit the number of printed properties', () => {
|
|
||||||
var o = {};
|
|
||||||
for (var i = 0; i < 100; i++) {
|
|
||||||
o['p_' + i] = i;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
assert.type(o, Type);
|
|
||||||
throw 'fail!';
|
|
||||||
} catch (e) {
|
|
||||||
expect(e.message.indexOf('p_0')).toBeGreaterThan(-1);
|
|
||||||
expect(e.message.indexOf('...')).toBeGreaterThan(-1);
|
|
||||||
expect(e.message.indexOf('p_20')).toBe(-1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should limit the depth of printed properties', () => {
|
|
||||||
var o = {l1: {l2: {l3: {l4: {l5: {l6: 'deep'}}}}}};
|
|
||||||
|
|
||||||
expect(() => {
|
|
||||||
assert.type(o, Type);
|
|
||||||
}).toThrowError('Expected an instance of Type, got {l1: {l2: {l3: {l4: [...]}}}}!');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// ## Basic Type Check
|
|
||||||
// By default, `instanceof` is used to check the type.
|
|
||||||
//
|
|
||||||
// Note that you can use `assert.type()` in unit tests or anywhere in your code.
|
|
||||||
// Most of the time, you will use it with Traceur.
|
|
||||||
// Jump to the [Traceur section](#integrating-with-traceur) to see an example of that.
|
|
||||||
describe('basic type check', function() {
|
|
||||||
|
|
||||||
class Type {}
|
|
||||||
|
|
||||||
it('should pass', function() {
|
|
||||||
assert.type(new Type(), Type);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should fail', function() {
|
|
||||||
expect(() => assert.type(123, Type))
|
|
||||||
.toThrowError('Expected an instance of Type, got 123!');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should allow null', function() {
|
|
||||||
assert.type(null, Type);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ## Custom Check
|
|
||||||
// Often, `instanceof` is not flexible enough.
|
|
||||||
// In that case, your type can define its own `assert` method which will be used instead.
|
|
||||||
//
|
|
||||||
// See [Describing More Complex Types](#describing-more-complex-types) for examples how to
|
|
||||||
// define custom checks using `assert.define()`.
|
|
||||||
describe('custom check', function() {
|
|
||||||
|
|
||||||
class Type {}
|
|
||||||
|
|
||||||
// the basic check can just return true/false, without specifying any reason
|
|
||||||
it('should pass when returns true', function() {
|
|
||||||
Type.assert = function(value) {
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
assert.type({}, Type);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should fail when returns false', function() {
|
|
||||||
Type.assert = function(value) {
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(() => assert.type({}, Type))
|
|
||||||
.toThrowError('Expected an instance of Type, got {}!');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// Using `assert.fail()` allows to report even multiple errors.
|
|
||||||
it('should fail when calls assert.fail()', function() {
|
|
||||||
Type.assert = function(value) {
|
|
||||||
assert.fail('not smart enough');
|
|
||||||
assert.fail('not blue enough');
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(() => assert.type({}, Type))
|
|
||||||
.toThrowError('Expected an instance of Type, got {}!\n' +
|
|
||||||
' - not smart enough\n' +
|
|
||||||
' - not blue enough');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should fail when throws an exception', function() {
|
|
||||||
Type.assert = function(value) {
|
|
||||||
throw new Error('not long enough');
|
|
||||||
};
|
|
||||||
|
|
||||||
expect(function() {
|
|
||||||
assert.type(12345, Type);
|
|
||||||
}).toThrowError('Expected an instance of Type, got 12345!\n' +
|
|
||||||
' - not long enough');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ## Primitive Values
|
|
||||||
// You don't want to check primitive values (such as strings, numbers, or booleans) using `typeof` rather than
|
|
||||||
// `instanceof`.
|
|
||||||
//
|
|
||||||
// Again, you probably won't write this code and rather use Traceur to do it for you, simply based on type annotations.
|
|
||||||
describe('primitive value check', function() {
|
|
||||||
var primitive = $traceurRuntime.type;
|
|
||||||
|
|
||||||
describe('string', function() {
|
|
||||||
|
|
||||||
it('should pass', function() {
|
|
||||||
assert.type('xxx', primitive.string);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should fail', function() {
|
|
||||||
expect(() => assert.type(12345, primitive.string))
|
|
||||||
.toThrowError('Expected an instance of string, got 12345!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow null', function() {
|
|
||||||
assert.type(null, primitive.string);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('number', function() {
|
|
||||||
|
|
||||||
it('should pass', function() {
|
|
||||||
assert.type(123, primitive.number);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should fail', function() {
|
|
||||||
expect(() => assert.type(false, primitive.number))
|
|
||||||
.toThrowError('Expected an instance of number, got false!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow null', function() {
|
|
||||||
assert.type(null, primitive.number);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('boolean', function() {
|
|
||||||
|
|
||||||
it('should pass', function() {
|
|
||||||
expect(assert.type(true, primitive.boolean)).toBe(true);
|
|
||||||
expect(assert.type(false, primitive.boolean)).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should fail', function() {
|
|
||||||
expect(() => assert.type(123, primitive.boolean))
|
|
||||||
.toThrowError('Expected an instance of boolean, got 123!');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should allow null', function() {
|
|
||||||
assert.type(null, primitive.boolean);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// ## Describing more complex types
|
|
||||||
//
|
|
||||||
// Often, a simple type check using `instanceof` or `typeof` is not enough.
|
|
||||||
// That's why you can define custom checks using this DSL.
|
|
||||||
// The goal was to make them easy to compose and as descriptive as possible.
|
|
||||||
// Of course you can write your own DSL on the top of this.
|
|
||||||
describe('define', function() {
|
|
||||||
|
|
||||||
// If the first argument to `assert.define()` is a type (function), it will define `assert` method on that function.
|
|
||||||
//
|
|
||||||
// In this example, being a type of Type means being a either a function or object.
|
|
||||||
it('should define assert for an existing type', function() {
|
|
||||||
class Type {}
|
|
||||||
|
|
||||||
assert.define(Type, function(value) {
|
|
||||||
assert(value).is(Function, Object);
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.type({}, Type);
|
|
||||||
assert.type(function() {}, Type);
|
|
||||||
expect(() => assert.type('str', Type))
|
|
||||||
.toThrowError('Expected an instance of Type, got "str"!\n' +
|
|
||||||
' - "str" is not instance of Function\n' +
|
|
||||||
' - "str" is not instance of Object');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// If the first argument to `assert.define()` is a string,
|
|
||||||
// it will create an interface - basically an empty class with `assert` method.
|
|
||||||
it('should define an interface', function() {
|
|
||||||
var User = assert.define('MyUser', function(user) {
|
|
||||||
assert(user).is(Object);
|
|
||||||
});
|
|
||||||
|
|
||||||
assert.type({}, User);
|
|
||||||
expect(() => assert.type(12345, User))
|
|
||||||
.toThrowError('Expected an instance of MyUser, got 12345!\n' +
|
|
||||||
' - 12345 is not instance of Object');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// Here are a couple of more APIs to describe your custom types...
|
|
||||||
//
|
|
||||||
// ### assert.arrayOf
|
|
||||||
// Checks if the value is an array and if so, it checks whether all the items are one the given types.
|
|
||||||
// These types can be composed types, not just simple ones.
|
|
||||||
describe('arrayOf', function() {
|
|
||||||
|
|
||||||
var Titles = assert.define('ListOfTitles', function(value) {
|
|
||||||
assert(value).is(assert.arrayOf(assert.string, assert.number));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should pass', function () {
|
|
||||||
assert.type(['one', 55, 'two'], Titles);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should fail when non-array given', function () {
|
|
||||||
expect(() => assert.type('foo', Titles))
|
|
||||||
.toThrowError('Expected an instance of ListOfTitles, got "foo"!\n' +
|
|
||||||
' - "foo" is not instance of array of string/number\n' +
|
|
||||||
' - "foo" is not instance of Array');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should fail when an invalid item in the array', function () {
|
|
||||||
expect(() => assert.type(['aaa', true], Titles))
|
|
||||||
.toThrowError('Expected an instance of ListOfTitles, got ["aaa", true]!\n' +
|
|
||||||
' - ["aaa", true] is not instance of array of string/number\n' +
|
|
||||||
' - true is not instance of string\n' +
|
|
||||||
' - true is not instance of number');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// ### assert.structure
|
|
||||||
// Similar to `assert.arrayOf` which checks a content of an array,
|
|
||||||
// `assert.structure` checks if the value is an object with specific properties.
|
|
||||||
describe('structure', function() {
|
|
||||||
|
|
||||||
var User = assert.define('MyUser', function(value) {
|
|
||||||
assert(value).is(assert.structure({
|
|
||||||
name: assert.string,
|
|
||||||
age: assert.number
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should pass', function () {
|
|
||||||
assert.type({name: 'Vojta', age: 28}, User);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should fail when non-object given', function () {
|
|
||||||
expect(() => assert.type(123, User))
|
|
||||||
.toThrowError('Expected an instance of MyUser, got 123!\n' +
|
|
||||||
' - 123 is not instance of object with properties name, age\n' +
|
|
||||||
' - 123 is not instance of Object');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should fail when an invalid property', function () {
|
|
||||||
expect(() => assert.type({name: 'Vojta', age: true}, User))
|
|
||||||
.toThrowError('Expected an instance of MyUser, got {name: "Vojta", age: true}!\n' +
|
|
||||||
' - {name: "Vojta", age: true} is not instance of object with properties name, age\n' +
|
|
||||||
' - true is not instance of number');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ## Integrating with Traceur
|
|
||||||
//
|
|
||||||
// Manually calling `assert.type()` in your code is cumbersome. Most of the time, you'll want to
|
|
||||||
// have Traceur add the calls to `assert.type()` to your code based on type annotations.
|
|
||||||
//
|
|
||||||
// This has several advantages:
|
|
||||||
// - it's shorter and nicer,
|
|
||||||
// - you can easily ignore it when generating production code.
|
|
||||||
//
|
|
||||||
// You'll need to run Traceur with `--types=true --type-assertions=true --type-assertion-module="path/to/assert"`.
|
|
||||||
describe('Traceur', function() {
|
|
||||||
|
|
||||||
describe('arguments', function() {
|
|
||||||
|
|
||||||
function reverse(str: string) {
|
|
||||||
return str ? reverse(str.substring(1)) + str[0] : ''
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should pass', function() {
|
|
||||||
expect(reverse('angular')).toBe('ralugna');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should fail', function() {
|
|
||||||
expect(() => reverse(123))
|
|
||||||
.toThrowError('Invalid arguments given!\n' +
|
|
||||||
' - 1st argument has to be an instance of string, got 123');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('return value', function() {
|
|
||||||
|
|
||||||
function foo(bar): number {
|
|
||||||
return bar;
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should pass', function() {
|
|
||||||
expect(foo(123)).toBe(123);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should fail', function() {
|
|
||||||
expect(() => foo('bar'))
|
|
||||||
.toThrowError('Expected to return an instance of number, got "bar"!');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('variables', function() {
|
|
||||||
|
|
||||||
it('should pass', function() {
|
|
||||||
var count:number = 1;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should fail', function() {
|
|
||||||
expect(() => {
|
|
||||||
var count: number = true;
|
|
||||||
}).toThrowError('Expected an instance of number, got true!');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('void', function() {
|
|
||||||
function foo(bar): void {
|
|
||||||
return bar;
|
|
||||||
}
|
|
||||||
|
|
||||||
it('should pass when not defined', function() {
|
|
||||||
function nonReturn(): void {}
|
|
||||||
function returnNothing(): void { return; }
|
|
||||||
function returnUndefined(): void { return undefined; }
|
|
||||||
|
|
||||||
foo();
|
|
||||||
foo(undefined);
|
|
||||||
nonReturn();
|
|
||||||
returnNothing();
|
|
||||||
returnUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should fail when a value returned', function() {
|
|
||||||
expect(() => foo('bar'))
|
|
||||||
.toThrowError('Expected to return an instance of void, got "bar"!');
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should fail when null returned', function() {
|
|
||||||
expect(() => foo(null))
|
|
||||||
.toThrowError('Expected to return an instance of void, got null!');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe('generics', function() {
|
|
||||||
|
|
||||||
it('should pass', function() {
|
|
||||||
var list:Array<string> = [];
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO(tbosch): add assertions based on generics to rtts_assert
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,368 @@
|
||||||
|
// # Assert.js
|
||||||
|
// A run-time type assertion library for JavaScript. Designed to be used with
|
||||||
|
// [Traceur](https://github.com/google/traceur-compiler).
|
||||||
|
import {} from '../../angular2/src/test_lib/e2e_util';
|
||||||
|
import {assert} from '../rtts_assert';
|
||||||
|
|
||||||
|
// - [Basic Type Check](#basic-type-check)
|
||||||
|
// - [Custom Check](#custom-check)
|
||||||
|
// - [Primitive Values](#primitive-values)
|
||||||
|
// - [Describing more complex types](#describing-more-complex-types)
|
||||||
|
// - [assert.arrayOf](#assert-arrayof)
|
||||||
|
// - [assert.structure](#assert-structure)
|
||||||
|
// - [Integrating with Traceur](#integrating-with-traceur)
|
||||||
|
|
||||||
|
// Note: `assert` gets automatically included by traceur!
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
return;
|
||||||
|
|
||||||
|
describe('prettyPrint', () => {
|
||||||
|
function Type() {}
|
||||||
|
|
||||||
|
it('should limit the number of printed properties', () => {
|
||||||
|
var o = {};
|
||||||
|
for (var i = 0; i < 100; i++) {
|
||||||
|
o['p_' + i] = i;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
assert.type(o, Type);
|
||||||
|
throw 'fail!';
|
||||||
|
} catch (e) {
|
||||||
|
expect(e.message.indexOf('p_0')).toBeGreaterThan(-1);
|
||||||
|
expect(e.message.indexOf('...')).toBeGreaterThan(-1);
|
||||||
|
expect(e.message.indexOf('p_20')).toEqual(-1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should limit the depth of printed properties', () => {
|
||||||
|
var o = {l1: {l2: {l3: {l4: {l5: {l6: 'deep'}}}}}};
|
||||||
|
|
||||||
|
expect(() => { assert.type(o, Type); })
|
||||||
|
.toThrowError('Expected an instance of Type, got {l1: {l2: {l3: {l4: [...]}}}}!');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ## Basic Type Check
|
||||||
|
// By default, `instanceof` is used to check the type.
|
||||||
|
//
|
||||||
|
// Note that you can use `assert.type()` in unit tests or anywhere in your code.
|
||||||
|
// Most of the time, you will use it with Traceur.
|
||||||
|
// Jump to the [Traceur section](#integrating-with-traceur) to see an example of that.
|
||||||
|
describe('basic type check', function() {
|
||||||
|
|
||||||
|
function Type() {}
|
||||||
|
|
||||||
|
it('should pass', function() { assert.type(new Type(), Type); });
|
||||||
|
|
||||||
|
|
||||||
|
it('should fail', function() {
|
||||||
|
expect(() => assert.type(123, Type)).toThrowError('Expected an instance of Type, got 123!');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should allow null', function() { assert.type(null, Type); });
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ## Custom Check
|
||||||
|
// Often, `instanceof` is not flexible enough.
|
||||||
|
// In that case, your type can define its own `assert` method which will be used instead.
|
||||||
|
//
|
||||||
|
// See [Describing More Complex Types](#describing-more-complex-types) for examples how to
|
||||||
|
// define custom checks using `assert.define()`.
|
||||||
|
describe('custom check', function() {
|
||||||
|
|
||||||
|
function Type() {}
|
||||||
|
|
||||||
|
// the basic check can just return true/false, without specifying any reason
|
||||||
|
it('should pass when returns true', function() {
|
||||||
|
(<any>Type).assert = function(value) { return true; };
|
||||||
|
|
||||||
|
assert.type({}, Type);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should fail when returns false', function() {
|
||||||
|
(<any>Type).assert = function(value) { return false; };
|
||||||
|
|
||||||
|
expect(() => assert.type({}, Type)).toThrowError('Expected an instance of Type, got {}!');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Using `assert.fail()` allows to report even multiple errors.
|
||||||
|
it('should fail when calls assert.fail()', function() {
|
||||||
|
(<any>Type).assert = function(value) {
|
||||||
|
assert.fail('not smart enough');
|
||||||
|
assert.fail('not blue enough');
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(() => assert.type({}, Type))
|
||||||
|
.toThrowError('Expected an instance of Type, got {}!\n' +
|
||||||
|
' - not smart enough\n' +
|
||||||
|
' - not blue enough');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should fail when throws an exception', function() {
|
||||||
|
(<any>Type).assert = function(value) { throw new Error('not long enough'); };
|
||||||
|
|
||||||
|
expect(function() { assert.type(12345, Type); })
|
||||||
|
.toThrowError('Expected an instance of Type, got 12345!\n' +
|
||||||
|
' - not long enough');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ## Primitive Values
|
||||||
|
// You don't want to check primitive values (such as strings, numbers, or booleans) using `typeof`
|
||||||
|
// rather than
|
||||||
|
// `instanceof`.
|
||||||
|
//
|
||||||
|
// Again, you probably won't write this code and rather use Traceur to do it for you, simply based
|
||||||
|
// on type annotations.
|
||||||
|
describe('primitive value check', function() {
|
||||||
|
var primitive = global['$traceurRuntime'].type;
|
||||||
|
|
||||||
|
describe('string', function() {
|
||||||
|
|
||||||
|
it('should pass', function() { assert.type('xxx', primitive.string); });
|
||||||
|
|
||||||
|
|
||||||
|
it('should fail', function() {
|
||||||
|
expect(() => assert.type(12345, primitive.string))
|
||||||
|
.toThrowError('Expected an instance of string, got 12345!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow null', function() { assert.type(null, primitive.string); });
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('number', function() {
|
||||||
|
|
||||||
|
it('should pass', function() { assert.type(123, primitive.number); });
|
||||||
|
|
||||||
|
|
||||||
|
it('should fail', function() {
|
||||||
|
expect(() => assert.type(false, primitive.number))
|
||||||
|
.toThrowError('Expected an instance of number, got false!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow null', function() { assert.type(null, primitive.number); });
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('boolean', function() {
|
||||||
|
|
||||||
|
it('should pass', function() {
|
||||||
|
expect(assert.type(true, primitive.boolean)).toEqual(true);
|
||||||
|
expect(assert.type(false, primitive.boolean)).toEqual(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should fail', function() {
|
||||||
|
expect(() => assert.type(123, primitive.boolean))
|
||||||
|
.toThrowError('Expected an instance of boolean, got 123!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should allow null', function() { assert.type(null, primitive.boolean); });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// ## Describing more complex types
|
||||||
|
//
|
||||||
|
// Often, a simple type check using `instanceof` or `typeof` is not enough.
|
||||||
|
// That's why you can define custom checks using this DSL.
|
||||||
|
// The goal was to make them easy to compose and as descriptive as possible.
|
||||||
|
// Of course you can write your own DSL on the top of this.
|
||||||
|
describe('define', function() {
|
||||||
|
|
||||||
|
// If the first argument to `assert.define()` is a type (function), it will define `assert`
|
||||||
|
// method on that function.
|
||||||
|
//
|
||||||
|
// In this example, being a type of Type means being a either a function or object.
|
||||||
|
it('should define assert for an existing type', function() {
|
||||||
|
function Type() {}
|
||||||
|
|
||||||
|
assert.define(Type, function(value) { assert(value).is(Function, Object); });
|
||||||
|
|
||||||
|
assert.type({}, Type);
|
||||||
|
assert.type(function() {}, Type);
|
||||||
|
expect(() => assert.type('str', Type))
|
||||||
|
.toThrowError('Expected an instance of Type, got "str"!\n' +
|
||||||
|
' - "str" is not instance of Function\n' +
|
||||||
|
' - "str" is not instance of Object');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// If the first argument to `assert.define()` is a string,
|
||||||
|
// it will create an interface - basically an empty class with `assert` method.
|
||||||
|
it('should define an interface', function() {
|
||||||
|
var User = assert.define('MyUser', function(user) { assert(user).is(Object); });
|
||||||
|
|
||||||
|
assert.type({}, User);
|
||||||
|
expect(() => assert.type(12345, User))
|
||||||
|
.toThrowError('Expected an instance of MyUser, got 12345!\n' +
|
||||||
|
' - 12345 is not instance of Object');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Here are a couple of more APIs to describe your custom types...
|
||||||
|
//
|
||||||
|
// ### assert.arrayOf
|
||||||
|
// Checks if the value is an array and if so, it checks whether all the items are one the given
|
||||||
|
// types.
|
||||||
|
// These types can be composed types, not just simple ones.
|
||||||
|
describe('arrayOf', function() {
|
||||||
|
|
||||||
|
var Titles = assert.define('ListOfTitles', function(value) {
|
||||||
|
assert(value).is(assert.arrayOf(assert.string, assert.number));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass', function() { assert.type(['one', 55, 'two'], Titles); });
|
||||||
|
|
||||||
|
|
||||||
|
it('should fail when non-array given', function() {
|
||||||
|
expect(() => assert.type('foo', Titles))
|
||||||
|
.toThrowError('Expected an instance of ListOfTitles, got "foo"!\n' +
|
||||||
|
' - "foo" is not instance of array of string/number\n' +
|
||||||
|
' - "foo" is not instance of Array');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should fail when an invalid item in the array', function() {
|
||||||
|
expect(() => assert.type(['aaa', true], Titles))
|
||||||
|
.toThrowError('Expected an instance of ListOfTitles, got ["aaa", true]!\n' +
|
||||||
|
' - ["aaa", true] is not instance of array of string/number\n' +
|
||||||
|
' - true is not instance of string\n' +
|
||||||
|
' - true is not instance of number');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// ### assert.structure
|
||||||
|
// Similar to `assert.arrayOf` which checks a content of an array,
|
||||||
|
// `assert.structure` checks if the value is an object with specific properties.
|
||||||
|
describe('structure', function() {
|
||||||
|
|
||||||
|
var User = assert.define('MyUser', function(value) {
|
||||||
|
assert(value).is(assert.structure({name: assert.string, age: assert.number}));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should pass', function() { assert.type({name: 'Vojta', age: 28}, User); });
|
||||||
|
|
||||||
|
|
||||||
|
it('should fail when non-object given', function() {
|
||||||
|
expect(() => assert.type(123, User))
|
||||||
|
.toThrowError('Expected an instance of MyUser, got 123!\n' +
|
||||||
|
' - 123 is not instance of object with properties name, age\n' +
|
||||||
|
' - 123 is not instance of Object');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should fail when an invalid property', function() {
|
||||||
|
expect(() => assert.type({name: 'Vojta', age: true}, User))
|
||||||
|
.toThrowError(
|
||||||
|
'Expected an instance of MyUser, got {name: "Vojta", age: true}!\n' +
|
||||||
|
' - {name: "Vojta", age: true} is not instance of object with properties name, age\n' +
|
||||||
|
' - true is not instance of number');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ## Integrating with Traceur
|
||||||
|
//
|
||||||
|
// Manually calling `assert.type()` in your code is cumbersome. Most of the time, you'll want to
|
||||||
|
// have Traceur add the calls to `assert.type()` to your code based on type annotations.
|
||||||
|
//
|
||||||
|
// This has several advantages:
|
||||||
|
// - it's shorter and nicer,
|
||||||
|
// - you can easily ignore it when generating production code.
|
||||||
|
//
|
||||||
|
// You'll need to run Traceur with `--types=true --type-assertions=true
|
||||||
|
// --type-assertion-module="path/to/assert"`.
|
||||||
|
describe('Traceur', function() {
|
||||||
|
|
||||||
|
describe('arguments', function() {
|
||||||
|
|
||||||
|
function reverse(str: string) { return str ? reverse(str.substring(1)) + str[0] : '' }
|
||||||
|
|
||||||
|
it('should pass', function() { expect(reverse('angular')).toEqual('ralugna'); });
|
||||||
|
|
||||||
|
|
||||||
|
it('should fail', function() {
|
||||||
|
expect(() => reverse(<any>123))
|
||||||
|
.toThrowError('Invalid arguments given!\n' +
|
||||||
|
' - 1st argument has to be an instance of string, got 123');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('return value', function() {
|
||||||
|
|
||||||
|
function foo(bar): number { return bar; }
|
||||||
|
|
||||||
|
it('should pass', function() { expect(foo(123)).toEqual(123); });
|
||||||
|
|
||||||
|
|
||||||
|
it('should fail', function() {
|
||||||
|
expect(() => foo('bar'))
|
||||||
|
.toThrowError('Expected to return an instance of number, got "bar"!');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('variables', function() {
|
||||||
|
|
||||||
|
it('should pass', function() { var count: number = 1; });
|
||||||
|
|
||||||
|
|
||||||
|
it('should fail', function() {
|
||||||
|
expect(() => { var count: number = <any>true; })
|
||||||
|
.toThrowError('Expected an instance of number, got true!');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('void', function() {
|
||||||
|
function foo(bar?): void { return bar; }
|
||||||
|
|
||||||
|
it('should pass when not defined', function() {
|
||||||
|
function nonReturn(): void {}
|
||||||
|
function returnNothing(): void { return; }
|
||||||
|
function returnUndefined(): void { return undefined; }
|
||||||
|
|
||||||
|
foo();
|
||||||
|
foo(undefined);
|
||||||
|
nonReturn();
|
||||||
|
returnNothing();
|
||||||
|
returnUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should fail when a value returned', function() {
|
||||||
|
expect(() => foo('bar')).toThrowError('Expected to return an instance of void, got "bar"!');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should fail when null returned', function() {
|
||||||
|
expect(() => foo(null)).toThrowError('Expected to return an instance of void, got null!');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('generics', function() {
|
||||||
|
|
||||||
|
it('should pass', function() { var list: Array<string> = []; });
|
||||||
|
|
||||||
|
// TODO(tbosch): add assertions based on generics to rtts_assert
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue