Last active
October 3, 2016 16:53
-
-
Save jmakeig/9c7f8580d5fa9ac57b1d98bb68616466 to your computer and use it in GitHub Desktop.
Minimal Tape implementation for MarkLogic 8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| var harness = { | |
| items: [], | |
| register: function(test) { | |
| this.items.push(test); | |
| return this; | |
| }, | |
| run: function() { | |
| return new TestOutcomes( | |
| this.items.map(function(test) { | |
| //return test.call(null, 'Hi!'); | |
| return { | |
| 'test': test.name, | |
| 'outcomes': test.run() | |
| } | |
| }) | |
| ); | |
| } | |
| }; | |
| function TestOutcomes(outcomes) { | |
| this.value = outcomes; | |
| } | |
| TestOutcomes.prototype = { | |
| toJSON: function(indent) { | |
| return JSON.stringify(this.value, null, indent); | |
| }, | |
| toTAP: function() { | |
| function byType(type) { | |
| return function(outcome) { | |
| return type === outcome.outcome; | |
| } | |
| } | |
| return this.value.map(function(test) { | |
| return test.test | |
| + ' ' | |
| + test.outcomes.filter(byType('pass')).length | |
| + ', ' + | |
| + test.outcomes.filter(byType('fail')).length | |
| ; | |
| }) | |
| .join('\n'); | |
| } | |
| } | |
| /** | |
| * Registers zero or more tests and returns the harness itself. | |
| * | |
| * @param {Iterable<Test>} tests | |
| * @returns harness Singleton instance of the global harness | |
| */ | |
| function runner(/* ...tests */) { | |
| for(var i = 0; i < arguments.length; i++) { | |
| harness.register(arguments[i]); | |
| } | |
| return harness; | |
| } | |
| module.exports = runner; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function Test(name, impl) { | |
| this.name = name || 'Test'; | |
| this.impl = impl; | |
| this.planned = undefined; | |
| this.tally = 0; | |
| this.isEnded = false; | |
| this.outcomes = []; | |
| } | |
| Test.prototype = { | |
| /** | |
| * Internal assertion. | |
| * | |
| * @param {string} operator | |
| * @param {boolean} ok | |
| * @param {any} actual | |
| * @param {any} expected | |
| * @param {string} [msg] | |
| * @returns {void} | |
| */ | |
| assert: function(operator, ok, actual, expected, msg) { | |
| var result; | |
| if(this.isEnded) { | |
| // result = { | |
| // operator: 'end', | |
| // outcome: 'fail', | |
| // msg: 'Tried to assert ' + operator + ' after end() has been called' | |
| // } | |
| throw new Error('Tried to assert ' + operator + ' after end() has been called'); | |
| } else { | |
| result = { | |
| operator: operator, | |
| outcome: true === ok ? 'pass' : 'fail', | |
| expected: expected, | |
| actual: actual, | |
| message: msg | |
| } | |
| } | |
| this.outcomes.push(result); | |
| if(this.tally++ === this.planned) { | |
| this.end(); | |
| } | |
| }, | |
| /** | |
| * @param {number} num | |
| * @returns {void} | |
| * @throws {TypeError} | |
| */ | |
| plan: function(num) { | |
| if('number' !== typeof num || num < 1) { | |
| throw new TypeError(num); | |
| } | |
| this.planned = num; | |
| }, | |
| /** | |
| * @returns {void} | |
| */ | |
| end: function() { | |
| this.isEnded = true; | |
| }, | |
| /** | |
| * Runs the actual test, including clean-up to make sure `plan()`/`end()` have | |
| * been called. | |
| * | |
| * @returns {Array<object>} | |
| * @see assert | |
| */ | |
| run: function() { | |
| this.impl.call(this, this); | |
| if(this.planned) { | |
| if(this.planned !== this.tally) { | |
| var msg = 'Planned for ' + String(this.planned) + ' assertions, but got ' + String(this.tally); | |
| this.assert('plan', false, this.tally, this.planned, msg); | |
| } else { | |
| this.end(); | |
| } | |
| } else { | |
| if(!this.isEnded) { | |
| // TODO: Exception instead? | |
| this.assert('end', this.isEnded, false, 'Never called end()'); | |
| } | |
| } | |
| return this.outcomes; | |
| }, | |
| /********** Assertions ***************/ | |
| /** | |
| * Whether the `value` is strictly (`===`) `true`. | |
| * | |
| * @param {any} value | |
| * @param {string} [msg] | |
| * @returns {void} | |
| */ | |
| true: function(value, msg) { | |
| msg = msg || String(value) + ' is true?'; | |
| this.assert('true', true === value, true, value, msg); | |
| }, | |
| /** | |
| * Whether `actual` and `expected` are strictly (`===`) equal. | |
| * | |
| * @param {any} actual | |
| * @param {any} expected | |
| * @param {string} [msg] | |
| * @returns {void} | |
| */ | |
| equal: function(actual, expected, msg) { | |
| msg = msg || String(actual) + ' equals ' + String(expected); | |
| this.assert('equal', expected === actual, actual, expected, msg); | |
| }, | |
| /** | |
| * @param {any} actual | |
| * @param {any} expected | |
| * @param {string} [msg] | |
| * @returns {void} | |
| */ | |
| deepEqual: function(actual, expected, msg) { | |
| msg = msg || 'deepEqual'; | |
| throw new Error('deepEqual() is not yet implemented'); | |
| }, | |
| /** | |
| * @param {function} fct | |
| * @param {Error|string} error | |
| * @param {string} [msg] | |
| * @returns {void} | |
| */ | |
| 'throws': function(fct, error, msg) { | |
| msg = msg || 'throws'; | |
| throw new Error('throws() is not yet implemented'); | |
| }, | |
| /** | |
| * @param {string} [msg] | |
| * @returns {void} | |
| */ | |
| skip: function(msg) {} | |
| } | |
| var runner = require('./runner'); | |
| /** | |
| * Creates a new test and registers it with the harness. | |
| * | |
| * @example | |
| * var test = require('/mltap/test'); | |
| * test('Uno', function(assert) { assert.plan(2); assert.true(true); assert.true(!!true); }); | |
| * test('Dos', function(assert) { assert.true(true); assert.end(); }) | |
| * .run().value; | |
| * | |
| * @param {string} name A short name describing the nature of the test | |
| * @param {function(Test)} impl The implementation of the test | |
| * @returns harness | |
| */ | |
| function test(name, impl) { | |
| return runner( | |
| new Test(name, impl) | |
| ); | |
| } | |
| module.exports = test; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment