diff --git a/tests/arithmetics/counters.js b/tests/arithmetics/counters.js new file mode 100644 index 0000000..9bcbd63 --- /dev/null +++ b/tests/arithmetics/counters.js @@ -0,0 +1,10 @@ +return new UnitTest('counters') + .add('postfix increment', function () { var i = 10; i++ === 10; }) + .add('postfix decrement', function () { var i = 10; i-- === 10; }) + .add('prefix decrement', function () { var i = 10; --i === 9; }) + .add('prefix increment', function () { var i = 10; ++i === 11; }) + .add('ostfix increment of non-number', function () { var i = 'hi mom'; isNaN(i++); }) + .add('ostfix decrement of non-number', function () { var i = 'hi mom'; isNaN(i--); }) + .add('prefix increment of non-number', function () { var i = 'hi mom'; isNaN(++i); }) + .add('prefix decrement of non-number', function () { var i = 'hi mom'; isNaN(--i); }) + .add('postfix increment of convertible to number', function () { var i = '10'; i++; i === 11; }) \ No newline at end of file diff --git a/tests/arithmetics/index.js b/tests/arithmetics/index.js new file mode 100644 index 0000000..a1cb82c --- /dev/null +++ b/tests/arithmetics/index.js @@ -0,0 +1,2 @@ +return new UnitTest('Arithmetics') + .add(include('counters.js')) \ No newline at end of file diff --git a/tests/array/concat.js b/tests/array/concat.js new file mode 100644 index 0000000..bab004f --- /dev/null +++ b/tests/array/concat.js @@ -0,0 +1,4 @@ +return new UnitTest('concat', function() { return typeof Array.prototype.concat === 'function'; }) + .add('two arrays', function() { return match([1, 2, 3], [1].concat([2], [3])) }) + .add('simple spread', function() { return match([1, 2, 3, 4, 5], [1].concat([2], 3, [4, 5])) }) + .add('sparse concat', function() { return match([1,, 2,,, 3,,, 4, 5], [1,,2].concat([,,3,,,4], 5)) }) \ No newline at end of file diff --git a/tests/array/index.js b/tests/array/index.js new file mode 100644 index 0000000..ee18fa2 --- /dev/null +++ b/tests/array/index.js @@ -0,0 +1,22 @@ +function runIterator(arr, method, func, n) { + var res = []; + var j = 1; + var args = [ function() { + var pushed = []; + for (var i = 0; i < n; i++) pushed[i] = arguments[i]; + res[j++] = pushed; + return func.apply(this, arguments); + } ]; + + for (var i = 4; i < arguments.length; i++) args[i - 3] = arguments[i]; + + res[0] = method.apply(arr, args); + + return res; +} + +return new UnitTest('Array', function() { []; }) + .add(include('length.js')) + .add(include('reduce.js')) + .add(include('sparse.js')) + .add(include('concat.js')) diff --git a/tests/array/length.js b/tests/array/length.js new file mode 100644 index 0000000..9bee0e1 --- /dev/null +++ b/tests/array/length.js @@ -0,0 +1,26 @@ +return new UnitTest('length & capacity', function() { return 'length' in Array.prototype; }) + .add('empty literal', function() { return [].length === 0 }) + .add('filled literal', function() { return [1, 2, 3].length === 3 }) + .add('set length', function() { + var a = []; + a.length = 10; + return a.length === 10; + }) + .add('length after set', function() { + var a = []; + a [5]= 5; + return a.length === 6; + }) + .add('length after set (big', function() { + var a = [1, 2]; + a [5000]= 5; + return a.length === 5001; + }) + .add('expand test', function() { + var a = []; + for (var i = 0; i < 1000; i++) { + a[i] = i * 50; + if (a[i] !== i * 50) return false; + } + return a.length === 1000; + }) \ No newline at end of file diff --git a/tests/array/reduce.js b/tests/array/reduce.js new file mode 100644 index 0000000..c1c2892 --- /dev/null +++ b/tests/array/reduce.js @@ -0,0 +1,44 @@ +var res = []; + +return new UnitTest('reduceRight', function () { return typeof Array.prototype.reduceRight === 'function' }) + .add('empty function', function () {match( + [ undefined, [4, 3, 2], [undefined, 2, 1], [undefined, 1, 0], ], + runIterator([1, 2, 3, 4], Array.prototype.reduceRight, function() { }, 3), 1 + )}) + .add('adder', function () {match( + [ 10, [4, 3, 2], [7, 2, 1], [9, 1, 0], ], + runIterator([1, 2, 3, 4], Array.prototype.reduceRight, function(a, b) { return a + b; }, 3), 1 + )}) + .add('sparse array', function () {match( + [ 10, [4, 3, 11], [7, 2, 7], [9, 1, 3], ], + runIterator([,,,1,,,, 2,,,, 3,,,, 4,,,,], Array.prototype.reduceRight, function(a, b) { return a + b }, 3), 1 + )}) + .add('sparse array with one element', function () {match( + [ 1 ], + runIterator([,,,1,,,,], Array.prototype.reduceRight, function(v) { return v; }, 3), 1 + )}) + .add('sparse array with no elements', function () {match( + [ undefined ], + runIterator([,,,,,,,], Array.prototype.reduceRight, function(v) { return v; }, 3), 1 + )}) + + .add('initial value and empty function', function () {match( + [ undefined, [0, 4, 3], [undefined, 3, 2], [undefined, 2, 1], [undefined, 1, 0] ], + runIterator([1, 2, 3, 4], Array.prototype.reduceRight, function() { }, 3, 0), 1 + )}) + .add('initial value and adder', function () {match( + [ 15, [5, 4, 3], [9, 3, 2], [12, 2, 1], [14, 1, 0] ], + runIterator([1, 2, 3, 4], Array.prototype.reduceRight, function(a, b) { return a + b; }, 3, 5), 1 + )}) + .add('initial value, sparce array and adder', function () {match( + [ 15, [5, 4, 15], [9, 3, 11], [12, 2, 7], [14, 1, 3] ], + runIterator([,,,1,,,, 2,,,, 3,,,, 4,,,,], Array.prototype.reduceRight, function(a, b) { return a + b; }, 3, 5), 1 + )}) + .add('initial value and sparse array with one element', function () {match( + [ 6, [5, 1, 3] ], + runIterator([,,,1,,,,], Array.prototype.reduceRight, function(a, b) { return a + b; }, 3, 5), 1 + )}) + .add('initial value and sparse array with no elements', function () {match( + [ 5 ], + runIterator([,,,,,,,], Array.prototype.reduceRight, function(v) { return v; }, 3, 5), 1 + )}); \ No newline at end of file diff --git a/tests/array/sort.js b/tests/array/sort.js new file mode 100644 index 0000000..bab004f --- /dev/null +++ b/tests/array/sort.js @@ -0,0 +1,4 @@ +return new UnitTest('concat', function() { return typeof Array.prototype.concat === 'function'; }) + .add('two arrays', function() { return match([1, 2, 3], [1].concat([2], [3])) }) + .add('simple spread', function() { return match([1, 2, 3, 4, 5], [1].concat([2], 3, [4, 5])) }) + .add('sparse concat', function() { return match([1,, 2,,, 3,,, 4, 5], [1,,2].concat([,,3,,,4], 5)) }) \ No newline at end of file diff --git a/tests/array/sparse.js b/tests/array/sparse.js new file mode 100644 index 0000000..ecd0e26 --- /dev/null +++ b/tests/array/sparse.js @@ -0,0 +1,5 @@ +return new UnitTest('sparse', function() { return !(0 in [,,]) }) + .add('empty in start', function() { var a = [,1]; return !(0 in a) && (1 in a); }) + .add('empty in middle', function() { var a = [1,,2]; return !(1 in a) && (2 in a) && (0 in a); }) + .add('empty in end', function() { var a = [1,,]; return !(1 in a) && (0 in a); }) + .add('trailing comma', function() { var a = [1,]; return a.length === 1; }) \ No newline at end of file diff --git a/tests/index.js b/tests/index.js new file mode 100644 index 0000000..6290b85 --- /dev/null +++ b/tests/index.js @@ -0,0 +1,70 @@ +function assert(cond, msg, locDepth) { + if (locDepth < 0 || locDepth === undefined) locDepth = 0; + if (!cond) { + log('Assert failed', (typeof locDepth === 'string' ? locDepth : Error().stack[locDepth + 1]) + ': ', msg); + } +} +function assertMatch(expected, actual, depth, msg) { + if (!match(expected, actual, depth)) { + log('Assert failed', Error().stack[1] + ': ', msg); + log('Expected:', expected); + log('Actual:', actual); + } +} +function match(expected, actual, depth) { + if (!Array.isArray(expected) || !Array.isArray(actual)) return expected === actual; + else if (expected.length !== actual.length) return false; + else if (depth === undefined || depth < 0) depth = 0; + + for (var i = 0; i < expected.length; i++) { + if (!(i in expected) || !(i in actual)) return !(i in expected) && !(i in actual); + + if ( + expected[i] === actual[i] || + depth > 0 && + Array.isArray(expected) && + Array.isArray(actual) && + match(expected[i], actual[i], depth - 1) + ) continue; + + return false; + } + + return true; +} + +/** @class */ function UnitTest(msg, exec) { + this.name = msg; + this.exec = exec; + this.subtests = []; +} + +UnitTest.prototype.run = function(path) { + if (path === undefined) path = []; + + path.push(this.name); + + if (typeof this.exec === 'function') { + var res = true, err = 'exec() returned false.'; + try { + if (this.exec() === false) res = false; + } + catch (e) { res = false; err = e; } + assert(res, path.join('/') + ': ' + err, this.exec.location()); + } + for (var i = 0; i < this.subtests.length; i++) { + this.subtests[i].run(path); + } + + path.pop(); +} +UnitTest.prototype.add = function(test, exec) { + if (test instanceof UnitTest) this.subtests.push(test); + else this.subtests.push(new UnitTest(test, exec)); + return this; +} + +include('arithmetics/index.js').run(); +include('array/index.js').run(); + +log('Tests complete.'); \ No newline at end of file