diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/Changes b/Changes deleted file mode 100644 index 5df0821..0000000 --- a/Changes +++ /dev/null @@ -1,200 +0,0 @@ -Tue Oct 21 16:34:03 CDT 2008 jeremy@marzhillstudios.com - * fixed dirty global scope problems in run_it - -Tue Oct 21 16:27:00 CDT 2008 jeremy@marzhillstudios.com - * Test.TAP needs to know the global scope sometimes so we store it here - -Mon Oct 20 21:51:02 CDT 2008 jeremy@marzhillstudios.com - * added description to the html test harness - -Mon Oct 20 21:49:29 CDT 2008 jeremy@marzhillstudios.com - * using pound properly again - -Mon Oct 20 21:47:43 CDT 2008 jeremy@marzhillstudios.com - * added a license agreement to Class.js - -Mon Oct 20 21:47:28 CDT 2008 jeremy@marzhillstudios.com - * added a new helper script - -Mon Oct 20 18:57:30 CDT 2008 jeremy@marzhillstudios.com - * mkdist shell script - -Mon Oct 20 18:13:07 CDT 2008 jeremy@marzhillstudios.com - * fixed mysterious *pound* bug - -Sun Oct 19 20:20:16 CDT 2008 jeremy@marzhillstudios.com - * use pount instead of ? for test specification - -Sun Oct 19 20:15:09 CDT 2008 jeremy@marzhillstudios.com - * additional harness features - -Sat Oct 18 02:01:14 CDT 2008 jeremy@marzhillstudios.com - * bugfix wrong directory to write to - -Sat Oct 18 01:56:25 CDT 2008 jeremy@marzhillstudios.com - * helper script - -Sat Oct 18 01:31:14 CDT 2008 jeremy@marzhillstudios.com - * added todo and skipped - -Fri Oct 17 22:37:33 CDT 2008 jeremy@marzhillstudios.com - * templates for harness setup - -Thu Oct 16 21:28:00 CDT 2008 jeremy@marzhillstudios.com - * do things in the right order - -Thu Oct 16 21:24:55 CDT 2008 jeremy@marzhillstudios.com - * count needs to be incremented so the onfinished handler gets run correctly - -Thu Oct 16 21:19:50 CDT 2008 jeremy@marzhillstudios.com - * refactored the Test Class library to be more friendly to multi method tests - -Thu Oct 16 21:19:09 CDT 2008 jeremy@marzhillstudios.com - * refactored tests to one testclass and changed harnesses accordingly - -Thu Oct 16 00:06:57 CDT 2008 jeremy@marzhillstudios.com - * a rhino harness for the test suite - -Wed Oct 15 23:55:35 CDT 2008 jeremy@marzhillstudios.com - * whole new test files yay!! - -Wed Oct 15 23:53:15 CDT 2008 jeremy@marzhillstudios.com - * refactored a whole lotta tests - -Wed Oct 15 23:18:51 CDT 2008 jeremy@marzhillstudios.com - * changed the size of the test divs for less scrolling - -Wed Oct 15 23:11:28 CDT 2008 jeremy@marzhillstudios.com - * asynchronous harness and accompanying tests - -Wed Oct 15 22:54:50 CDT 2008 jeremy@marzhillstudios.com - * made the asynchronous stuff safe for non-browser tests - -Wed Oct 15 22:42:20 CDT 2008 jeremy@marzhillstudios.com - * imported Malte Ubl's asynchronous testing feature - -Wed Oct 15 22:21:42 CDT 2008 jeremy@marzhillstudios.com - * changes to constructor arguments and improvements to class plan setting - -Wed Oct 15 21:52:32 CDT 2008 jeremy@marzhillstudios.com - * setup and teardown for Test.TAP.Class - -Tue Oct 14 22:56:14 CDT 2008 jeremy@marzhillstudios.com - * a whole lot of refactore goin on (uhhuh) - -Tue Oct 14 22:48:19 CDT 2008 jeremy@marzhillstudios.com - * refactored the harness location - -Tue Oct 14 22:47:18 CDT 2008 jeremy@marzhillstudios.com - * html harness enhancements - -Tue Oct 14 22:07:58 CDT 2008 jeremy@marzhillstudios.com - * Test.TAP.Class is added - -Tue Oct 14 20:45:59 CDT 2008 jeremy@marzhillstudios.com - * Runner uses the refactored Test Class functionality - -Tue Oct 14 20:43:08 CDT 2008 jeremy@marzhillstudios.com - * added a new Test Class to replace Runner - -Tue Oct 14 20:42:31 CDT 2008 jeremy@marzhillstudios.com - * refactored some of Test.TAP for easier reuse of code - -Tue Oct 14 20:27:22 CDT 2008 jeremy@marzhillstudios.com - * pass in your own output function for to override output method - -Sun Sep 28 23:24:34 CDT 2008 jeremy@marzhillstudios.com - * better summaries from the runner - -Sun Sep 28 22:51:37 CDT 2008 jeremy@marzhillstudios.com - * fixed excess newlines in print for commandline systems - -Sat Jun 28 17:29:37 CDT 2008 jeremy@marzhillstudios.com - * updated TODO - -Sat Jun 28 17:28:11 CDT 2008 jeremy@marzhillstudios.com - * fixed descriptions for throws ok - -Sat Jun 28 17:13:41 CDT 2008 jeremy@marzhillstudios.com - * if a test suite dies it doesn't kill the runner now - -Sat Jun 28 14:31:31 CDT 2008 jeremy@marzhillstudios.com - * TODO file added - -Fri Jun 6 20:58:05 CDT 2008 jeremy@marzhillstudios.com - * changed teh Tap.j TAP.js - -Fri Jun 6 20:51:19 CDT 2008 jeremy@marzhillstudios.com - * html versions of the tests have been added - -Thu Feb 28 10:20:41 CST 2008 jeremy@marzhillstudios.com - tagged V0.12 - -Thu Feb 28 10:20:23 CST 2008 jeremy@marzhillstudios.com - * up the version number - -Thu Feb 28 10:18:18 CST 2008 jeremy@marzhillstudios.com - * added dies_ok and lives_ok tests - -Fri Feb 1 21:02:16 CST 2008 jeremy@marzhillstudios.com - * make can_ok work for prototype methods also. - - currently only supports one level of inheritance. this will be fixed later - - -Fri Sep 14 17:08:58 CDT 2007 jeremy@marzhillstudios.com - * documentation for Test.TAP.Runner - -Tue Sep 11 19:50:22 CDT 2007 jeremy@marzhillstudios.com - * POD Documentation for Test.TAP - -Mon Sep 10 14:12:34 CDT 2007 jeremy@marzhillstudios.com - * fixed version number - -Mon Sep 10 14:10:30 CDT 2007 jeremy@marzhillstudios.com - * added changelog - -Mon Sep 10 14:09:01 CDT 2007 jeremy@marzhillstudios.com - tagged first release - -Mon Sep 10 14:05:21 CDT 2007 jeremy@marzhillstudios.com - * additional debugging output - -Mon Sep 10 14:03:42 CDT 2007 jeremy@marzhillstudios.com - * Runner bugfix and the tests that revealed the bug; - -Sat Sep 8 14:00:38 CDT 2007 jeremy@marzhillstudios.com - * fixed mut[_^H_]l[_^H_][_^H_][_^H_] - -Fri Sep 7 20:59:27 CDT 2007 jeremy@marzhillstudios.com - * readded the running tests tests message - -Fri Sep 7 20:46:40 CDT 2007 jeremy@marzhillstudios.com - * added a new message about the name of the test running - -Fri Sep 7 20:45:33 CDT 2007 jeremy@marzhillstudios.com - * whitespace cleanup of a mock testobj definition - -Fri Sep 7 20:44:17 CDT 2007 jeremy@marzhillstudios.com - * removed test for the running test message - -Fri Sep 7 20:35:54 CDT 2007 jeremy@marzhillstudios.com - * added Test.TAP.Runner Library - -Fri Sep 7 20:35:13 CDT 2007 jeremy@marzhillstudios.com - * added TAP Directory - -Fri Sep 7 20:34:48 CDT 2007 jeremy@marzhillstudios.com - * added tests for Test.TAP.Runner - -Fri Sep 7 19:17:50 CDT 2007 jeremy@marzhillstudios.com - * additional META for the library - -Fri Sep 7 19:16:54 CDT 2007 jeremy@marzhillstudios.com - * minor changes to the counter and bugfix for throws_ok - -Fri Sep 7 19:16:00 CDT 2007 jeremy@marzhillstudios.com - * More tests for Test.TAP test functions [can_ok throws_ok plan] - -Wed Sep 5 19:08:11 CDT 2007 jeremy@marzhillstudios.com - * initial start of repository diff --git a/META.yml b/META.yml deleted file mode 100644 index b78a9b7..0000000 --- a/META.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- #YAML:1.0 -name: Test.TAP -version: 0.12 -author: - - Jeremy Wall -abstract: A zero dependency TAP compliant test library. Useable from commandline with no mocking -license: perl -generated_by: Jeremy Wall diff --git a/Makefile b/Makefile index 80db69f..42b07a7 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,2 @@ test: - rhino harness/rhino_harness.js + node tests/01_tap.t.js diff --git a/README b/README deleted file mode 100644 index e69de29..0000000 diff --git a/README.md b/README.md new file mode 100644 index 0000000..383639d --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# Test-Tap a 0 dependency single file Test Anything Protocol suite. + +# Install + +copy `src/Tap.mjs` into your source tree. + +Eventually I'll see about publishing it to npm but for now this is good enough. + +# Use + +See the `tests/01_tap.t.js` and `TapHarness.html` for node cli and browser based examples. diff --git a/TODO b/TODO deleted file mode 100644 index 797d285..0000000 --- a/TODO +++ /dev/null @@ -1,2 +0,0 @@ -[] skip and todo tests need to handle exceptions better -[] diff --git a/harness/prove_rhino.t b/harness/prove_rhino.t deleted file mode 100644 index cf881a7..0000000 --- a/harness/prove_rhino.t +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -rhino harness/rhino_harness.js diff --git a/harness/rhino_harness.js b/harness/rhino_harness.js deleted file mode 100755 index c23d6e0..0000000 --- a/harness/rhino_harness.js +++ /dev/null @@ -1,24 +0,0 @@ -var path = 'lib'; -var testpath = 'tests'; - -var libs = [ - 'Test/TAP.js', - 'Test/TAP/Class.js', - 'Test/TAP/Runner.js' - ]; - -var tests = [ - '01_tap.t.js', - ]; - -for (i in libs) { - var lib = libs[i]; - load(path+'/'+lib); -} - -for (i in tests) { - var test = tests[i]; - var script = readFile(testpath+'/'+test); - t = eval(script); - t.run_tests(); -} diff --git a/lib/Test/TAP.js b/lib/Test/TAP.js deleted file mode 100644 index cdaf8c3..0000000 --- a/lib/Test/TAP.js +++ /dev/null @@ -1,356 +0,0 @@ -//grab the global scope -var testtop = this; - -Test = function() {}; - -Test.prototype.top = function() { - return testtop; -} - -Test.prototype.out = function(text) { - this.print(text); -}; - -Test.prototype.diag = function(msg){ - if (!msg) { - msg = " "; - } - this.out('# ' + msg); -}; - -Test.prototype.mk_tap = function(ok, description){ - if(!this.planned){ - this.out("You tried to run tests without a plan. Gotta have a plan."); - throw new Error("You tried to run tests without a plan. Gotta have a plan."); - } - this.counter++; - this.out(ok + ' ' + this.counter + ' - ' + description); -}; - -/* - -=head1 NAME - - Test.TAP - a 0 dependency TAP compliant test library useable from the commandline - -=head1 Synopsis - - var t = new Test.TAP; - t.plan(3); - - t.ok(true, 'True is True'); # test will pass - t.is(1, 2, 'one is two'); # test will fail - - var obj = {}; - obj.method1 = function() { return true; }; - - t.can_ok(obj, 'method1'); # test will pass - -=head1 DESCRIPTION - -Test.TAP is a javascript testing library that meets the needs of TDD for a commandline environment. - -=head1 METHODS - -=cut - -*/ - - -Test.TAP = function(out) { - this.planned = 0; - this.counter = 0; - this.passed = 0; - this.failed = 0; - this.print = out || function(text) { - if(typeof document == 'undefined') { - document = {}; - } - if(typeof document.write == 'undefined') { - document.write = print; - } - if (typeof print == 'undefined' - || document.write != print) { - text += '\n'; - } - document.write(text); - }; -}; - -Test.TAP.prototype = new Test; - -Test.TAP.prototype.pass = function(description) { - this.mk_tap('ok', description); -}; - -Test.TAP.prototype.fail = function(description) { - this.mk_tap('not ok', description); -}; - -Test.TAP.prototype.todo = function(func) { - var self = this; - var tapper = self.mk_tap; - self.mk_tap = function(ok, desc) { - tapper.apply(self, [ok, "# TODO: "+desc]); - } - func(); - self.mk_tap = tapper; -} - -Test.TAP.prototype.skip = function(crit, reason, count, func) { - var self = this; - if (crit) { - var tapper = self.mk_tap; - self.mk_tap = function(ok, desc) { - tapper.apply(self, [ok, desc]); - } - for(var i = 0; i < count; i++) { - self.fail("# SKIP "+reason) - } - self.mk_tap = tapper; - } else { - func(); - } -} - -/* - -=head2 plan() - - t.plan(3); - -Sets the test plan. Once set this can not be reset again. An attempt to change the plan once already set will throw an exception. - -=cut - -*/ - -Test.TAP.prototype.plan = function(tests) { - if (tests == 'no_plan') { - this.planned = tests; - } else { - if(this.planned > 0 || this.planned == 'no_plan'){ - throw new Error("you tried to set the plan twice!"); - } - this.planned = tests; - this.out('1..' + tests); - } -}; - -Test.TAP.prototype._pass_if = function(func, desc){ - var result = func(); - if(result){ this.pass(desc) } - else { this.fail(desc) } -} - - -/* - -=head2 diag() - - t.diag('a diagnostic message'); - -prints out a TAP compliant diagnostic message. - -=cut - -*/ - - -/* - -=head2 is() - - t.is(got, expected, 'test description'); - -tests that what we got matches what we expected. An equality test. - -=cut - -*/ - -Test.TAP.prototype.is = function(got, expected, desc) { - this._pass_if(function(){ return got == expected; }, desc); -}; - - -/* - -=head2 ok() - - t.ok(expression, 'test description'); - -Test that expression evaluates to true value - -=cut - -*/ - -Test.TAP.prototype.ok = function(got, desc) { - this._pass_if(function(){ return !!got; }, desc); -}; - - -/* - -=head2 like() - - t.like('string', /regex/, 'test description'); - -Tests that a string matches the regex. - -=cut - -*/ - -Test.TAP.prototype.like = function(string, regex, desc) { - this._pass_if(function(){ - if(regex instanceof RegExp) { - return string.match(regex) - } else { - return string.indexOf(regex) != -1 - } - }, desc) -} - -/* - -=head2 unlike() - - t.unlike('string', /regex/, 'test description'); - -The opposite of like. tests that the string doesn't match the regex - -=cut - -*/ - -Test.TAP.prototype.unlike = function(string, regex, desc) { - this._pass_if(function(){ - return !string.match(regex); - }, desc) -} - -/* - -=head2 can_ok() - - t.can_ok(obj, 'method1', method2'); - -tests that the object has the list of methods. outputs diagnostics about which ones are missing if the test fails. - -=cut - -*/ - - -Test.TAP.prototype.can_ok = function(obj) { - var desc = 'object can ['; - var pass = true; - for (i=1; i -L - -=head1 AUTHOR - -Jeremy Wall L<< jeremy@marzhillstudios.com >> - -=head1 COPYRIGHT AND LICENSE - -Copyright (C) 2007 Jeremy Wall - -This library is free software; you can redistribute it and/or modify -it under the same terms as Perl itself, either Perl version 5.8.4 or, -at your option, any later version of Perl 5 you may have available. - -=cut - -*/ - diff --git a/lib/Test/TAP/Class.js b/lib/Test/TAP/Class.js deleted file mode 100644 index c539a24..0000000 --- a/lib/Test/TAP/Class.js +++ /dev/null @@ -1,212 +0,0 @@ -if (typeof Test == 'undefined') { - Test = {}; -} -if (typeof Test.TAP == 'undefined') { - if (typeof JSAN != 'undefined') { - JSAN.use('Test.TAP'); - } else { - throw new ReferenceError('Test.TAP.Runner is dependent on Test.TAP'); - } -} - -/* - -=head1 NAME - - Test.TAP.Runner - A Simple Test Harness for Test.TAP - -=head1 Synopsis - - var r = new Test.TAP.Runner(). - - var testobj = {}; - testobj.runtests = function() { - var t = new Test.TAP(); - t.plan(2); - t.ok(true, 'true is true'); - t.is(1, 1, 'one is one'); - return t; - } - r.run_tests(obj); -=cut - -*/ - -Test.TAP.Class = function() { - var self = this; - // call our superclasses constructor as well - Test.TAP.apply(self, arguments); -}; - -/* - -=head1 Methods - -=head2 out() - -internal method inherited from L see L for useage - -=cut - -=head2 diag() - -internal method inherited from L see L for useage - -=cut - -=head2 run_it() - -runs the tests in a test object and reports on the results - -=cut - -*/ - -Test.TAP.Class.prototype = new Test.TAP(); - -Test.TAP.Class.prototype.run_it = function(method) { - var self = this; - var fun = self[method]; - self.diag("trying to run "+method+" tests"); - - // remember the globals that existed before the test execution - var originalGlobal = {}; - var top = self.top(); - for(var name in top ) { - originalGlobal[name] = true; - } - - try { - if (typeof this.setup == 'function') { - self.setup(); - } - fun.call(self); - if (typeof this.teardown == 'function') { - self.teardown(); - } - } - catch(err) { - this.diag("Test Suite Crashed!!! (" + err + ")"); - } - finally { - // Delete globals which were created during test execution - // THis avoid conflicts between tests when running multiple tests in a row - for(var name in top) { - if(!originalGlobal[name]) { - try { - delete top[name] - } catch (e) { - // Delete threw an error, so just assign undefined - top[name] = undefined - } - } - } - } -}; - -/* - -=head2 run_tests() - - r.run_tests(obj1, obj2); - -runs the tests in a list of test objects and reports on the results - -=cut - -*/ - -Test.TAP.Class.prototype.run_tests = function() { - var self = this; - var counter = 0; - - var methods = []; - for (m in self) { - if (m.match(/^test.+/)) { - methods.push(m) - } - } - - this.finished = true; - - var onFinish = function () { - if (self.planned > self.counter) { - self.diag('looks like you planned ' + self.planned + ' tests but only ran ' - + self.counter + ' tests'); - } else if (self.planned < self.counter) { - self.diag('looks like you planned ' + self.planned + ' tests but ran ' - + (self.counter - self.planned) + ' tests extra'); - } - self.diag('ran ' + self.counter + ' tests out of ' + self.planned); - self.diag('passed ' + self.passed + ' tests out of ' + self.planned) - self.diag('failed ' + self.failed + ' tests out of ' + self.planned) - } - - var count = 0; - var testRunInterval - if (typeof setInterval == 'undefined') { - setInterval = function() { - }; - } - if (typeof clearInterval == 'undefined') { - clearInterval = function() { - } - } - var run = function () { - if(self.finished) { - if(count > 0) { - if(self.on_finished) { - onFinish() - self.on_finished() - } - } - if(methods.length == 0) { - clearInterval(testRunInterval) - if(self.on_finished_all) { - self.on_finished_all() - } - } else { - self.finished = false; - } - } else { - if(self.planned == "no_plan" - || self.planned == 0 - || self.counter >= self.planned) { - self.finished = true - } - } - }; - testRunInterval = setInterval(run, 50) - run(); - var methodname; - while (methodname = methods.shift()) { - self.run_it(methodname); - count++ - } - run(); - - return self; -}; - -/* - -=head1 SEE ALSO - -L -L - -=head1 AUTHOR - -Jeremy Wall L<< jeremy@marzhillstudios.com >> - -=head1 COPYRIGHT AND LICENSE - -Copyright (C) 2007 Jeremy Wall - -This library is free software; you can redistribute it and/or modify -it under the same terms as Perl itself, either Perl version 5.8.4 or, -at your option, any later version of Perl 5 you may have available. - -=cut - -*/ diff --git a/lib/Test/TAP/Runner.js b/lib/Test/TAP/Runner.js deleted file mode 100644 index 5a1aa28..0000000 --- a/lib/Test/TAP/Runner.js +++ /dev/null @@ -1,104 +0,0 @@ -if (typeof Test == 'undefined') { - Test = {}; -} -if (typeof Test.TAP == 'undefined') { - if (typeof JSAN != 'undefined') { - JSAN.use('Test.TAP'); - } else { - throw new Error('Test.TAP.Runner is dependent on Test.TAP'); - } -} -/* - -=head1 NAME - - Test.TAP.Runner - A Simple Test Harness for Test.TAP - -=head1 Synopsis - - var r = new Test.TAP.Runner(). - - var testobj = {}; - testobj.runtests = function() { - var t = new Test.TAP(); - t.plan(2); - t.ok(true, 'true is true'); - t.is(1, 1, 'one is one'); - return t; - } - r.run_tests(obj); -=cut - -*/ - -Test.TAP.Runner = function() {}; - -Test.TAP.Runner.prototype = new Test(); - -/* - -=head1 Methods - -=head2 out() - -internal method inherited from L see L for useage - -=cut - -=head2 diag() - -internal method inherited from L see L for useage - -=cut - -=head2 run_it() - -runs the tests in a test object and reports on the results - -=cut - -*/ - -Test.TAP.Runner.prototype.run_it = function(obj) { - this.diag('running ' + obj.name + ' tests'); - var tester; - try { - tester = obj.runtests(); - if (tester.planned > tester.counter) { - tester.diag('looks like you planned ' + tester.planned + ' tests but only ran ' - + tester.counter + ' tests'); - } else if (tester.planned < tester.counter) { - tester.diag('looks like you planned ' + tester.planned + ' tests but ran ' - + (tester.counter - tester.planned) + ' tests extra'); - } - this.diag('ran ' + tester.counter + ' tests out of ' + tester.planned); - this.diag('passed ' + tester.passed + ' tests out of ' + tester.planned) - this.diag('failed ' + tester.failed + ' tests out of ' + tester.planned) - } - catch(err) { - this.diag("Test Suite Crashed!!! (" + err + ")"); - } - - return tester; -}; - -/* - -=head2 run_tests() - - r.run_tests(obj1, obj2); - -runs the tests in a list of test objects and reports on the results - -=cut - -*/ - -Test.TAP.Runner.prototype.run_tests = function() { - var all = []; - for (i=0; i(run in a single window)...'); - var req = new XMLHttpRequest(); - req.open("GET", path, false); - req.send(null); - if (req.readyState == 4) { - var testobj = eval(req.responseText); - return testobj; - } -} - -function createScriptTag(library) { - var path = library.replace(/\./g, '/')+'.js'; - var script = document.createElement("script"); - script.src = lib+'/'+path; - return script; -} - -function loadlib(library) { - document.body.appendChild(createScriptTag(library)); -} - -function loadTest(test) { - var path = testlib+'/'+test; - return load(path); -} - -function loadComponents() { - for (c in toLoad) { - var comp = toLoad[c]; - loadlib(comp); - } -} - -function runtest(t) { - var outtxt = ""; - var div = document.createElement("div"); - - var onclick = function () { - var c = div.className; - if (c.match(/big/)) { - c = c.replace(/big/, "small"); - } else if (c.match(/small/)) { - c = c.replace(/small/, "big"); - } - div.className = c; - }; - div.addEventListener('click', onclick, true); - - div.className = 'test small'; - document.body.appendChild(div); - - var outfunc = function(text) { - if (text) { - outtxt += text; - if (text.match(/(not ok|Test Suite Crashed)/g) ) { - div.innerHTML = "
" + div.innerHTML + "\n" + text + "
" - } else { - div.innerHTML = "
" + div.innerHTML + "\n" + text + "
" - } - - } - } - - // set globally for synchronous run - Test.TAP.prototype.out = outfunc; - var testobj = loadTest(t); - if (!testobj) { - alert ("Test Object: "+t+" did not load"); - throw new ReferenceError("Test Object did now load"); - } - // also set to instance for asynchronous output - testobj.out = outfunc - - testobj.on_finished = function () { - if (outtxt.match(/(not ok|Test Suite Crashed)/g) ) { - div.className += ' failsuite'; - div.className.replace(/small/, 'big'); - - } - results.push(div); - } - - setTimeout(function () { - testobj.run_tests() - }, 0) -} - -var test = loc.match(/.+[#?](.*)\??.*/); - -loadComponents(); - -window.onload = function() { - var testlist = []; - if (test) { - runtest(test[1]); - } else { - for (t in tests) { - runtest(tests[t]); - } - } -} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..34f78df --- /dev/null +++ b/package-lock.json @@ -0,0 +1,24 @@ +{ + "name": "test-tap", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "test-tap", + "version": "0.0.1", + "license": "Artistic-2.0", + "dependencies": { + "esm": "^3.2.25" + } + }, + "node_modules/esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "engines": { + "node": ">=6" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..ec59658 --- /dev/null +++ b/package.json @@ -0,0 +1,34 @@ +{ + "name": "test-tap", + "version": "0.0.1", + "description": "Test-Tap a 0 dependency single file Test Anything Protocol library", + "type": "module", + "directories": { + "test": "tests", + "lib": "src" + }, + "files": [ + "src/*.mjs", + "src/*.js" + ], + "scripts": { + "test": "node tests/01_tap.t.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/zaphar/test-tap.git" + }, + "keywords": [ + "testing", + "tap" + ], + "author": "Jeremy Wall (jeremy@marzhillstudios.com)", + "license": "Artistic-2.0", + "bugs": { + "url": "https://github.com/zaphar/test-tap/issues" + }, + "homepage": "https://github.com/zaphar/test-tap#readme", + "dependencies": { + "esm": "^3.2.25" + } +} diff --git a/scripts/addtoproject.sh b/scripts/addtoproject.sh deleted file mode 100755 index 6d9c675..0000000 --- a/scripts/addtoproject.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/bin/bash - -usage() -{ - cat << HELPMSG -Usage: - add this library to a javascript project for you - $0 -d - - print this help - $0 -h -HELPMSG -} - -while getopts "d:h" OPTION -do - case $OPTION in - d) - DIRNAME=$OPTARG - ;; - h) - usage - exit 0 - ;; - ?) - usage - exit 1 - esac -done - -MYDIR=$(dirname $0) - -if [[ -z $DIRNAME ]] -then - echo "No -d option was present. You must provide a Project path."; - usage - exit 1 -fi - -echo "Setting up in project: ${DIRNAME}" - -#set up the directory structure -if [[ ! -d $DIRNAME/ext ]] -then - echo Making ${DIRNAME}/ext - mkdir $DIRNAME/ext -fi - -if [[ ! -d $DIRNAME/harness ]] -then - echo Making ${DIRNAME}/harness - mkdir $DIRNAME/harness -fi - -if [[ ! -d $DIRNAME/t || -d $DIRNAME/tests ]] -then - echo Making ${DIRNAME}/t - mkdir $DIRNAME/t -fi - -echo copy the files we need for initial setup -cp -r -f $MYDIR/../lib/Test $DIRNAME/ext/ -if [[ -d $DIRNAME/t ]] -then - echo copying TapHarness.html to $DIRNAME/t/ - cp -r -f $MYDIR/../tmpl/TapHarness.html $DIRNAME/t/ -elif [[ -d tests ]] -then - echo copying TapHarness.html to $DIRNAME/tests/ - cp -r -f $MYDIR/../tmpl/TapHarness.html $DIRNAME/tests/ -fi - -echo copying rhino harnesses to $DIRNAME/harness/ -cp -r -f $MYDIR/../tmpl/*rhino* $DIRNAME/harness/ - diff --git a/scripts/mkdist.sh b/scripts/mkdist.sh deleted file mode 100755 index 15fe0b5..0000000 --- a/scripts/mkdist.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!bash - -usage() -{ - cat << HELPMSG -Usage: - create a distribution directory with the specified version - $0 -d -v - - print this help - $0 -h -HELPMSG -} - -while getopts ":d:v:h" OPTION -do - case $OPTION in - d) - DIRNAME=$OPTARG - ;; - v) - VERSION=$OPTARG - ;; - h) - usage - exit 1 - ;; - ?) - usage - exit 1 - ;; - esac -done - -if [[ -z $DIRNAME ]] -then - usage - exit 1 -fi - -if [[ -z $VERSION ]] -then - usage - exit 1 -fi - -DIST="$DIRNAME-$VERSION" -ROOT="$(dirname $0)/.." -LIB="${ROOT}/lib"; -TLIB="${ROOT}/tests"; -SCRIPTS="Test/TAP.js Test/TAP/Class.js Test/TAP/Runner.js"; - -if [[ ! -d $DIST ]] -then - mkdir $DIST -else - rm -rf $DIST - mkdir $DIST -fi - -for s in $SCRIPTS -do - cat - $LIB/$s >> $DIST/test_tap.js < - - print this help - $0 -h -HELPMSG -} - -while getopts ":d:h" OPTION -do - case $OPTION in - d) - DIRNAME=$OPTARG - ;; - h) - usage - exit 1 - ;; - ?) - usage - exit 1 - ;; - esac -done - -shift $(($OPTIND - 1)) - -if [[ -z $DIRNAME ]] -then - echo 'Must provide a test directory' - usage - exit 1 -fi - -if [[ -z $1 ]] -then - echo 'Must provide a test name' - usage - exit 1 -fi - -TESTNAME=`echo $1 | tr '[:upper:]' '[:lower:]'`.t.js - -cat > $DIRNAME/$TESTNAME << TEST -(function() { - var t = new Test.TAP.Class(); - t.plan('no_plan'); - - t.setUp = function() { - }; - - t.testSomething = function() { - }; - - t.tearDown = function() { - }; - - return t; -})(); -TEST diff --git a/scripts/updateproject.sh b/scripts/updateproject.sh deleted file mode 100755 index da15057..0000000 --- a/scripts/updateproject.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash - -usage() -{ - cat << HELPMSG -Usage: - update this library in a javascript project for you - $0 -d - - print this help - $0 -h -HELPMSG -} - -while getopts "d:h" OPTION -do - case $OPTION in - d) - DIRNAME=$OPTARG - ;; - h) - usage - exit 0 - ;; - ?) - usage - exit 1 - esac -done - -MYDIR=$(dirname $0) - -if [[ -z $DIRNAME ]] -then - echo "No -d option was present. You must provide a Project path."; - usage - exit 1 -fi - -echo "Setting up in project: ${DIRNAME}" - -#set up the directory structure -if [[ ! -d $DIRNAME/ext ]] -then - mkdir $DIRNAME/ext -fi - -echo copying the javascript test libraries -cp -r -f $MYDIR/../lib/Test $DIRNAME/ext/ - -#now go back to where we started -cd $WORKING diff --git a/src/TAP.mjs b/src/TAP.mjs new file mode 100644 index 0000000..f59442d --- /dev/null +++ b/src/TAP.mjs @@ -0,0 +1,448 @@ +/** +* Tap - a 0 dependency TAP compliant test library useable from the commandline +* +* ```js +* import { Tap } from './src/TAP.mjs'; +* var t = new Tap; +* t.plan(3); +* +* t.ok(true, 'True is True'); # test will pass +* t.is(1, 2, 'one is two'); # test will fail +* +* var obj = {}; +* obj.method1 = function() { return true; }; +* +* t.can_ok(obj, 'method1'); # test will pass +* ``` +* +* @module TAP +* @license Artistic-2.0 +*/ + +/** @implements TapRenderer */ +class NodeRenderer { + /** @type {Array} */ + #thunks = []; + + out(text) { + this.#thunks.push( + // Because this is a ECMAScript module we have to do dynamic module loads + // of the node ecosystem when running in Node.js. + import('node:process').then(loaded => { + loaded.stdout.write(text + "\n"); + })); + } + + comment(lines) { + for (var line of lines) { + this.out('# ' + line); + } + } + + // This gives us a way to block on output. It's ghetto but async is a harsh task master. + async renderAll() { + for (var thunk of this.#thunks) { + await thunk; + } + + } +} + +/** @implements TapRenderer */ +class BrowserRenderer { + #target = document.body; + + /** @param {HtmlElement=} target */ + constructor(target) { + if (target) { + this.#target = target; + } + } + + /** @returns TextNode */ + #createText(text) { + return document.createTextNode(text); + } + + /** + * @param {Node} nodes + * @returns HTMLDivElement + */ + #createDiv(nodes) { + const div = document.createElement("div"); + div.append(...nodes); + return div; + } + + out(text) { + const textNode = this.#createText(text); + this.#target.appendChild(this.#createDiv([textNode])); + } + + comment(lines) { + // TODO(jeremy): + var elems = []; + for (var line of lines) { + elems.push(this.#createText(line), document.createElement("br")); + } + var commentDiv = this.#createDiv(elems); + commentDiv.setAttribute("class", "tap-comment"); + this.#target.appendChild(commentDiv); + } +} + +/** + * The Tap Test Class helper. + */ +class Tap { + /** @type Number? */ + planned = null; + /** @type Number */ + counter = 0; + /** @type Number */ + passed = 0; + /** @type Number */ + failed = 0; + /** @type TapRenderer */ + renderer + + /** + * Construct a new Tap Suite with a renderLine function. + * @param {TapRenderer} + */ + constructor(renderer) { + this.renderer = renderer; + } + + /** + * @return {{"Renderer": BrowserRenderer, "Tap": Tap}} + */ + static Browser() { + var r = new BrowserRenderer(); + return {"Renderer": r, "Tap": new Tap(r)}; + return new Tap(new BrowserRenderer()); + } + + /** + * @return {{"Renderer": NodeRenderer, "Tap": Tap}} + */ + static Node() { + var r = new NodeRenderer(); + return {"Renderer": r, "Tap": new Tap(r)}; + } + + isPass() { + return this.passed != 0; + } + + /** Renders output for the test results */ + out(text) { + this.renderer.out(text); + }; + + /** + * Construct a Tap output message. + * + * @param {boolean} ok + * @param {string=} description + */ + mk_tap(ok, description) { + if (!this.planned) { + this.out("You tried to run tests without a plan. Gotta have a plan."); + throw new Error("You tried to run tests without a plan. Gotta have a plan."); + } + this.counter++; + this.out(ok + ' ' + this.counter + ' - ' + (description || "")); + }; + + + comment(msg) { + if (!msg) { + msg = " "; + } + var lines = msg.split("\n"); + this.renderer.comment(lines); + }; + + /** Render a pass TAP output message. + * @param {string} description + */ + pass(description) { + this.passed++; + this.mk_tap('ok', description); + }; + + /** Render a fail TAP output message. + * @param {string} description + */ + fail(description) { + this.failed++; + this.mk_tap('not ok', description); + }; + + /** Run a function as a TODO test. + * + * @param {function(this:Tap, boolean, description)} func + */ + todo(func) { + var self = this; + var tapper = self.mk_tap; + self.mk_tap = function(ok, desc) { + tapper.apply(self, [ok, "# TODO: " + desc]); + } + func(); + self.mk_tap = tapper; + } + + /** Run a function as a skip Test. + * + * @param {boolean} criteria + * @param {string} reason + * @param {number} count - The number of tests to skip + * @param {function(this:Tap, boolean, description)} func + */ + skip(criteria, reason, count, func) { + var self = this; + if (criteria) { + var tapper = self.mk_tap; + self.mk_tap = function(ok, desc) { + tapper.apply(self, [ok, desc]); + } + for (var i = 0; i < count; i++) { + self.fail("# SKIP " + reason) + } + self.mk_tap = tapper; + } else { + func(); + } + } + + /** Sets the test plan. + * Once set this can not be reset again. Any attempt to change the plan once already + * set will throw an exception. + * + * Call with no arguments if you don't want to specify the number of tests to run. + * + * @param {Number=} testCount + */ + plan(testCount) { + if (this.planned) { + throw new Error("you tried to set the plan twice!"); + } + if (!testCount) { + this.planned = 'no_plan'; + } else { + this.planned = testCount; + this.out('1..' + testCount); + } + }; + + #pass_if(func, desc) { + var result = func(); + if (result) { this.pass(desc) } + else { this.fail(desc) } + } + + // exception tests + + /** + * Tests that a function throws with a given error message. + * + * @param {function()} func + * @param {RegExp} msg + */ + throws_ok(func, msg) { + var errormsg = ' '; + if (typeof func != 'function') + this.comment('throws_ok needs a function to run'); + + try { + func(); + } + catch (err) { + errormsg = err + ''; + } + this.like(errormsg, msg, 'code threw [' + errormsg + '] expected: [' + msg + ']'); + } + + /** + * Tests that a function throws. + * + * @param {function()} func + */ + dies_ok(func) { + var errormsg = ' '; + var msg = false; + if (typeof func != 'function') + this.comment('throws_ok needs a function to run'); + + try { + func(); + } + catch (err) { + errormsg = err + ''; + msg = true; + } + this.ok(msg, 'code died with [' + errormsg + ']'); + } + + /** + * Tests that a function does not throw an exception. + * + * @param {function()} func + */ + lives_ok(func, msg) { + var errormsg = true; + if (typeof func != 'function') + this.comment('throws_ok needs a function to run'); + + try { + func(); + } + catch (err) { + errormsg = false; + } + this.ok(errormsg, msg); + } + + /** + * Tests that an object has a given method or function. + * + * @param {*} obj + */ + can_ok(obj) { + var desc = 'object can ['; + var pass = true; + for (var i = 1; i < arguments.length; i++) { + if (typeof (obj[arguments[i]]) != 'function') { + if (typeof (obj.prototype) != 'undefined') { + var result = typeof eval('obj.prototype.' + arguments[i]); + if (result == 'undefined') { + pass = false; + this.comment('Missing ' + arguments[i] + ' method'); + } + } else { + pass = false; + this.comment('Missing ' + arguments[i] + ' method'); + } + } + desc += ' ' + arguments[i]; + } + desc += ' ]'; + this.#pass_if(function() { + return pass; + }, desc); + + } + + /** + * Tests that two given objects are equal. + * + * @param {*} got + * @param {*} expected + * @param {string} desc + */ + is(got, expected, desc) { + this.#pass_if(function() { return got == expected; }, desc); + }; + + + /** + * Test that expression evaluates to true value + * + * @param {*} got + * @param {string} desc + */ + ok(got, desc) { + this.#pass_if(function() { return !!got; }, desc); + }; + + + /** + * Tests that a string matches the regex. + * + * @param {string} string + * @param {RegExp} regex + * @param {string} desc + */ + like(string, regex, desc) { + this.#pass_if(function() { + if (regex instanceof RegExp) { + return string.match(regex) + } else { + return string.indexOf(regex) != -1 + } + }, desc) + } + + /** + * The opposite of like. tests that the string doesn't match the regex. + * + * @param {string} string + * @param {RegExp} regex + * @param {string} desc + */ + unlike(string, regex, desc) { + this.#pass_if(function() { + return !string.match(regex); + }, desc) + } + +} + +/** + * Run a test and render a summarization. + * + * @param {Tap} t + * @param {string} testName + * @param {function(Tap)} test + */ +function runTest(t, testName, test) { + t.comment('running ' + testName + ' tests'); + try { + test(t); + summarize(t); + } + catch (err) { + t.comment("Test Suite Crashed!!! (" + err + ")"); + } + + return t; +} + +/** + * Output a summary of the tests as comments. + * + * @param {Tap} t + */ +function summarize(t) { + if (t.planned > t.counter) { + t.comment('looks like you planned ' + t.planned + ' tests but only ran ' + + t.counter + ' tests'); + } else if (t.planned < t.counter) { + t.comment('looks like you planned ' + t.planned + ' tests but ran ' + + (t.counter - t.planned) + ' tests extra'); + } + t.comment('ran ' + t.counter + ' tests out of ' + t.planned); + t.comment('passed ' + t.passed + ' tests out of ' + t.planned); + t.comment('failed ' + t.failed + ' tests out of ' + t.planned); +} + +/** + * @param {Tap} t + * @param {Array<{'plan': Number, name: string, 'test': function(Tap)}} suite + */ +function runSuite(t, suite) { + const plan = suite.reduce((acc, item) => { + return acc + item.plan + }, 0); + t.plan(plan); + for (var item of suite) { + t.comment('running ' + item.name + ' tests'); + item.test(t); + } + summarize(t); +} + +export { Tap, runTest, runSuite, summarize, BrowserRenderer, NodeRenderer }; + diff --git a/src/Tap.d.js b/src/Tap.d.js new file mode 100644 index 0000000..aae8a36 --- /dev/null +++ b/src/Tap.d.js @@ -0,0 +1,16 @@ +/** @interface */ +class TapRenderer { + /** Renders output for the test results + * @param {string} text + */ + out(text) { + } + + /** Diagnostic formatter for TAP Output. + * + * @param {Array} lines + */ + comment(lines) { + } +} + diff --git a/tests/01_tap.t.js b/tests/01_tap.t.js index 39a222a..ce42ba8 100644 --- a/tests/01_tap.t.js +++ b/tests/01_tap.t.js @@ -1,175 +1,8 @@ -(function() { -var out = "nothing yet"; -var diag = ""; -var t = new Test.TAP.Class(); // the real TAP -t.plan(27); +import { Tap, runTest } from '../src/Tap.mjs'; +import { tapSuite } from './suite.mjs'; -t.testCan = function () { - var self = this; - // setup fake test object - var f = new Test.TAP(); // the TAP thats failing - f.out = function(newout) { out = newout }; - f.diag = function(newdiag) { diag += newdiag }; - f.plan(4); - - //mock a fake object to run test against - var obj = new Object; - obj.run = function() {}; - var method = 'run'; - - // begin real tests! - f.can_ok(obj, 'not_there'); - t.like(out, /not ok 1 - object can \[ not_there \]/, 'can_ok failed'); - f.can_ok(obj, method); - diag = ''; - self.like(out, /ok 2 - object can \[ run \]/, 'can_ok passed'); - - //Now we need to test the whole prototype method assignment thing - - function MockObj() { - this.attr = 1; - } - - MockObj.prototype.fakeme = function () {}; - - f.can_ok(MockObj, 'fakeme'); - diag = ''; - self.like(out, /^ok .* \[ fakeme \]/, - 'can_ok recognized prototype methods'); - f.can_ok(MockObj, 'fakeme2'); - diag = ''; - self.like(out, /^not ok .* \[ fakeme2 \]/, - 'can_ok prototype recognization doesnt break methods'); -} - -t.testClassTests = function() { - var self = this; - self.ok(Test.TAP.Class, 'Test.TAP.Class namespace exists'); - - var rout = ''; - var fun = function (value) { - rout += value; - } - - var testclass = new Test.TAP.Class(fun); - testclass.plan('no_plan'); - testclass.out = fun; - self.is(testclass.print, fun, 'testclass has our own printer'); - self.is(testclass.planned, 'no_plan', 'testclass has no plan'); - - testclass.testMyTest = function() { - testclass.ok(1 === 1, 'it worked'); - } - testclass.run_tests(); - //self.diag("here is rout"); - //self.diag(rout); - self.like(rout, /ok 1 - it worked/, 'we printed the correct output'); -} - -t.testDescApears = function() { - var self = this; - // setup fake test object - var f = new Test.TAP(); // the TAP that's failing - f.out = function(newout) { out = newout }; - f.plan(1); - self.id = "t"; - f.id = "f"; - - // begin real tests! - f.like("hello", /hello/, "hello matches hello"); - self.like(out, /ok 1 - hello matches hello/, 'got description in TAP output'); -} - -t.testDiag = function() { - // setup fake test object - var f = new Test.TAP(); // the TAP that's failing - f.out = function(newout) { out = newout }; - f.plan(10); - // begin real tests! - f.diag("hello"); - t.like(out, /# hello/, 'got hello'); -} - -t.testException = function() { - // setup fake test object - var f = new Test.TAP(); // the TAP that's failing - f.out = function(newout) { out = newout }; - f.plan(2); - - // begin real tests! - f.throws_ok(function() {throw new Error('I made a boo boo')}, 'I made a boo boo'); - //t.diag(out); - this.like(out, /ok 1 - code threw \[Error: I made a boo boo\]/, 'uncaught exception'); - f.throws_ok(function() {}, 'I made a boo boo'); - //t.diag(out); - this.like(out, /not ok 2 - code threw \[ \]/, 'false failed'); -} - -t.testFails = function() { - // setup fake test object - var f = new Test.TAP(); // the TAP that's failing - f.out = function(newout) { out = newout }; - f.plan(3); - - // begin real tests! - f.ok(false, 'false fails'); - t.like(out, /not ok 1 - false fails/, 'false failed'); - - f.ok(0, 'zero fails'); - t.like(out, /not ok 2 - zero fails/, '0 failed'); - - f.is(0, 1, 'zero is one'); - t.like(out, /not ok 3 - zero is one/, '0 != 1'); -} - -t.testPass = function() { - this.ok(true, 'true is true'); - this.is(1,1, '1 is 1'); - this.pass('pass passes'); - this.like("hello world", /hel+o/, 'regexen work'); - this.unlike("hello there", /world/, 'no world'); -} - -t.testPlan = function() { - var self = this; - // setup fake test object - var f = new Test.TAP(); // the TAP that's failing - f.out = function(newout) { out = newout }; - f.plan(2); - - // begin real tests! - f.ok(false, 'false fails'); - self.is(f.counter, 1, 'counter increments by one'); - self.is(f.planned, 2, 'planned = 2'); -} - -t.testTodoSkip = function() { - var self = this; - var out; - self.can_ok(Test.TAP, 'todo', 'skip'); - var f = new Test.TAP(); // the TAP that's failing - f.out = function(newout) { out = newout }; - f.plan(4); - - f.todo(function() { - f.ok(true, 'true is true'); - }); - self.like(out, /ok 1 - # TODO: true is true/g, - 'the non todo output is suitably formatted'); - f.ok(!false, 'not false is true'); - self.like(out, /ok 2 -/g, 'the regular output is suitably formatted'); - - f.skip(true, 'because I said so', 1, - function() { - f.is(1, 2, 'one is two'); - } - ); - self.like(out, /^not ok 3 - # SKIP because I said so$/, - 'the skipped output is suitably formatted'); - f.is(1, 1, 'one is one'); - self.like(out, /ok 4 - one is one/, - 'the non skipped output is suitable formatted'); -}; - -return t; -})() +const pair = Tap.Node(); +runTest(pair.Tap, "Tap dogfood test suite", tapSuite); +// Note output requires some async machinery because it uses some dynamic inputs. +await pair.Renderer.renderAll(); +process.exit(pair.Tap.isPass() ? 0 : 1); diff --git a/tests/TapHarness.html b/tests/TapHarness.html index 9c9785b..6bfbf89 100644 --- a/tests/TapHarness.html +++ b/tests/TapHarness.html @@ -1,11 +1,6 @@ - - + - - - - -This is the Test.TAP.Class and company test harness for the browser. - - diff --git a/tests/suite.mjs b/tests/suite.mjs new file mode 100644 index 0000000..4773a1e --- /dev/null +++ b/tests/suite.mjs @@ -0,0 +1,162 @@ +/** @implements TapRenderer */ +import { Tap } from '../src/Tap.mjs'; + +class FakeRenderer { + output = "nothing yet"; + commentOutput = ""; + + out(text) { + this.output = text; + } + + comment(lines) { + for (var line of lines) { + this.commentOutput += line; + } + } +} + +function tapSuite(t) { + t.plan(23); + + var renderer = new FakeRenderer(); + var testCan = function() { + // setup fake test object + var f = new Tap(renderer); // the TAP thats failing + f.plan(4); + + //mock a fake object to run test against + var obj = new Object; + obj.run = function() { }; + var method = 'run'; + + // begin real tests! + f.can_ok(obj, 'not_there'); + t.like(renderer.output, /not ok 1 - object can \[ not_there \]/, 'can_ok failed'); + f.can_ok(obj, method); + t.like(renderer.output, /ok 2 - object can \[ run \]/, 'can_ok passed'); + + //Now we need to test the whole prototype method assignment thing + + function MockObj() { + this.attr = 1; + } + + MockObj.prototype.fakeme = function() { }; + + f.can_ok(MockObj, 'fakeme'); + renderer.commentOutput = ''; + t.like(renderer.output, /^ok .* \[ fakeme \]/, + 'can_ok recognized prototype methods'); + f.can_ok(MockObj, 'fakeme2'); + renderer.commentOutput = ''; + t.like(renderer.output, /^not ok .* \[ fakeme2 \]/, + 'can_ok prototype recognization doesnt break methods'); + }; + testCan(); + + var testLike = function() { + // setup fake test object + var f = new Tap(renderer); // the TAP that's failing + f.plan(1); + + // begin real tests! + f.like("hello", /hello/, "hello matches hello"); + t.like(renderer.output, /ok 1 - hello matches hello/, 'got description in TAP output'); + }; + testLike() + + var testDiag = function() { + // setup fake test object + var f = new Tap(renderer); // the TAP that's failing + f.plan(10); + // begin real tests! + f.comment("hello"); + t.comment(renderer.commentOutput); + t.like(renderer.commentOutput, /hello/, 'got hello'); + }; + testDiag(); + + var testException = function() { + // setup fake test object + var f = new Tap(renderer); // the TAP that's failing + f.plan(2); + + // begin real tests! + f.throws_ok(function() { throw new Error('I made a boo boo') }, 'I made a boo boo'); + //t.comment(renderer.output); + t.like(renderer.output, /ok 1 - code threw \[Error: I made a boo boo\]/, 'uncaught exception'); + f.throws_ok(function() { }, 'I made a boo boo'); + //t.comment(renderer.output); + t.like(renderer.output, /not ok 2 - code threw \[ \]/, 'false failed'); + }; + testException(); + + var testFails = function() { + // setup fake test object + var f = new Tap(renderer); // the TAP that's failing + f.plan(3); + + // begin real tests! + f.ok(false, 'false fails'); + t.like(renderer.output, /not ok 1 - false fails/, 'false failed'); + + f.ok(0, 'zero fails'); + t.like(renderer.output, /not ok 2 - zero fails/, '0 failed'); + + f.is(0, 1, 'zero is one'); + t.like(renderer.output, /not ok 3 - zero is one/, '0 != 1'); + }; + testFails(); + + var testPass = function() { + t.ok(true, 'true is true'); + t.is(1, 1, '1 is 1'); + t.pass('pass passes'); + t.like("hello world", /hel+o/, 'regexen work'); + t.unlike("hello there", /world/, 'no world'); + }; + testPass(); + + var testPlan = function() { + // setup fake test object + var f = new Tap(renderer); // the TAP that's failing + f.plan(2); + + // begin real tests! + f.ok(false, 'false fails'); + t.is(f.counter, 1, 'counter increments by one'); + t.is(f.planned, 2, 'planned = 2'); + }; + testPlan(); + + var testTodoSkip = function() { + t.can_ok(Tap, 'todo', 'skip'); + var f = new Tap(renderer); // the TAP that's failing + f.plan(4); + + f.todo(function() { + f.ok(true, 'true is true'); + }); + t.like(renderer.output, /ok 1 - # TODO: true is true/g, + 'the non todo output is suitably formatted'); + f.ok(!false, 'not false is true'); + t.like(renderer.output, /ok 2 -/g, 'the regular output is suitably formatted'); + + f.skip(true, 'because I said so', 1, + function() { + f.is(1, 2, 'one is two'); + } + ); + t.like(renderer.output, /^not ok 3 - # SKIP because I said so$/, + 'the skipped output is suitably formatted'); + f.is(1, 1, 'one is one'); + t.like(renderer.output, /ok 4 - one is one/, + 'the non skipped output is suitable formatted'); + }; + testTodoSkip(); + + return t; +} + +export { tapSuite }; diff --git a/tmpl/TapHarness.html b/tmpl/TapHarness.html deleted file mode 100644 index 26f9cff..0000000 --- a/tmpl/TapHarness.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/tmpl/prove_rhino.t b/tmpl/prove_rhino.t deleted file mode 100644 index cf881a7..0000000 --- a/tmpl/prove_rhino.t +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -rhino harness/rhino_harness.js diff --git a/tmpl/rhino_harness.js b/tmpl/rhino_harness.js deleted file mode 100755 index 1c9468f..0000000 --- a/tmpl/rhino_harness.js +++ /dev/null @@ -1,35 +0,0 @@ -var libpath = 'lib'; -var extpath = 'ext'; -var testpath = 't'; - -var extlibs = [ - 'Test/TAP.js', - 'Test/TAP/Class.js', - 'Test/TAP/Runner.js', - 'joose.js' - ]; - -var libs = [ - '' - ]; - -var tests = [ - '', - ]; - -for (i in extlibs) { - var lib = extlibs[i]; - load(extpath+'/'+lib); -} - -for (i in libs) { - var lib = libs[i]; - load(libpath+'/'+lib); -} - -for (i in tests) { - var test = tests[i]; - var script = readFile(testpath+'/'+test); - t = eval(script); - t.run_tests(); -}