Merge pull request #1 from zaphar/revival

Revive the librarly as an extremely lightweight testing alternative
This commit is contained in:
Jeremy Wall 2024-04-03 17:49:46 -04:00 committed by GitHub
commit d868d25761
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 711 additions and 1562 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules/

200
Changes
View File

@ -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 <name> 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

View File

@ -1,8 +0,0 @@
--- #YAML:1.0
name: Test.TAP
version: 0.12
author:
- Jeremy Wall <Jeremy@marzhillstudiso.com>
abstract: A zero dependency TAP compliant test library. Useable from commandline with no mocking
license: perl
generated_by: Jeremy Wall <Jeremy@marzhillstudiso.com>

View File

@ -1,2 +1,2 @@
test:
rhino harness/rhino_harness.js
node tests/01_tap.t.js

0
README
View File

11
README.md Normal file
View File

@ -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.

2
TODO
View File

@ -1,2 +0,0 @@
[] skip and todo tests need to handle exceptions better
[]

View File

@ -1,3 +0,0 @@
#!/bin/bash
rhino harness/rhino_harness.js

View File

@ -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();
}

View File

@ -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<arguments.length; i++) {
if (typeof(obj[arguments[i]]) != 'function') {
//this.diag('TypeOf ' + arguments[i] + ' method is: ' + typeof(obj[arguments[i]]) );
//this.diag('TypeOf prototype is: ' + typeof(obj.prototype) );
if (typeof(obj.prototype) != 'undefined') {
var result = typeof eval('obj.prototype.' + arguments[i]);
//this.diag('TypeOf prototype method is: ' + result);
if (result == 'undefined') {
pass = false;
this.diag('Missing ' + arguments[i] + ' method');
}
} else {
pass = false;
this.diag('Missing ' + arguments[i] + ' method');
}
}
desc += ' ' + arguments[i];
}
desc += ' ]';
this._pass_if(function(){
return pass;
}, desc);
}
/*
=head2 throws_ok()
t.throws_ok(func, /regex/);
Tests that the function throws an exception matching the regex. If the first argument is not a function it throws and exception.
=cut
*/
// exception tests
Test.TAP.prototype.throws_ok = function(func, msg) {
var errormsg = ' ';
if (typeof func != 'function')
this.diag('throws_ok needs a function to run');
try {
func();
}
catch(err) {
errormsg = err+'';
}
this.like(errormsg, msg, 'code threw [' + errormsg + '] expected: [' + msg + ']');
}
Test.TAP.prototype.dies_ok = function(func) {
var errormsg = ' ';
var msg = false;
if (typeof func != 'function')
this.diag('throws_ok needs a function to run');
try {
func();
}
catch(err) {
errormsg = err+'';
msg = true;
}
this.ok(msg, 'code died with [' + errormsg + ']');
}
Test.TAP.prototype.lives_ok = function(func, msg) {
var errormsg = true;
if (typeof func != 'function')
this.diag('throws_ok needs a function to run');
try {
func();
}
catch(err) {
errormsg = false;
}
this.ok(errormsg, msg);
}
/*
=head1 SEE ALSO
L<Test.Simple>
L<Test.AnotherWay>
=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
*/

View File

@ -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<Test.TAP> see L<Test.TAP> for useage
=cut
=head2 diag()
internal method inherited from L<Test.TAP> see L<Test.TAP> 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<Test.Simple>
L<Test.AnotherWay>
=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
*/

View File

@ -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<Test.TAP> see L<Test.TAP> for useage
=cut
=head2 diag()
internal method inherited from L<Test.TAP> see L<Test.TAP> 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<arguments.length; i++) {
all.push(this.run_it(arguments[i]));
this.out('\n');
}
return all;
};

View File

@ -1,103 +0,0 @@
function load(path) {
var url = location.pathname + "#" + encodeURIComponent(path.replace(/^\.\//, ''))
Test.TAP.prototype.diag('loading: '+path+' <a href="'+url+'">(run in a single window)</a>...');
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 class='fail'>" + div.innerHTML + "\n" + text + "</div>"
} else {
div.innerHTML = "<div class='pass'>" + div.innerHTML + "\n" + text + "</div>"
}
}
}
// 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]);
}
}
}

24
package-lock.json generated Normal file
View File

@ -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"
}
}
}
}

34
package.json Normal file
View File

@ -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"
}
}

View File

@ -1,75 +0,0 @@
#!/bin/bash
usage()
{
cat << HELPMSG
Usage:
add this library to a javascript project for you
$0 -d <project path>
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/

View File

@ -1,74 +0,0 @@
#!bash
usage()
{
cat << HELPMSG
Usage:
create a distribution directory with the specified version
$0 -d <dist directory> -v <version>
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 <<FILEMSG
///////////////////////////////////////
///// ${s} Version:${VERSION}
///////////////////////////////////////
FILEMSG
done
cp $LIB/Test/TAPBrowser.js $DIST/TAPBrowserHarness.js
cp $TLIB/TapHarness.html $DIST/TapHarness.html
tar -czv -f $DIST.tar.gz $DIST
rm -rf $DIST

View File

@ -1,66 +0,0 @@
#! /bin/bash
usage()
{
cat << HELPMSG
Usage:
create a javascript test in the specified location
$0 -d <test directory> <test_name>
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

View File

@ -1,52 +0,0 @@
#!/bin/bash
usage()
{
cat << HELPMSG
Usage:
update this library in a javascript project for you
$0 -d <project path>
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

448
src/TAP.mjs Normal file
View File

@ -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<PromiseLike>} */
#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 };

16
src/Tap.d.js Normal file
View File

@ -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<string>} lines
*/
comment(lines) {
}
}

View File

@ -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);

View File

@ -1,11 +1,6 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/javascript" src="../lib/Test/TAP.js"></script>
<script type="text/javascript" src="../lib/Test/TAP/Runner.js"></script>
<script type="text/javascript" src="../lib/Test/TAP/Class.js"></script>
</head>
<body>
<style type="text/css">
@ -30,26 +25,19 @@
</style>
<script type="text/javascript">
var top = this;
/** Configuration options
*
*/
var tests = [
'01_tap.t.js',
];
var testlib = '.';
/** Setup
*
*/
</script>
This is the Test.TAP.Class and company test harness for the browser.
<script type="text/javascript" src="../lib/Test/TAPBrowser.js"></script>
<script type="text/javascript">
window.onload = function() {
var browser = new Test.TAPBrowser(testlib, tests);
browser.run();
};
This is the Tap test harness for the browser.
<script type="module">
import { Tap, runTest } from '../src/TAP.mjs';
import { tapSuite } from './suite.mjs';
runTest(Tap.Browser(), 'Tap Dogfood Tests', tapSuite);
</script>
</body>
</html>

162
tests/suite.mjs Normal file
View File

@ -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 };

View File

@ -1,51 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/javascript" src="../ext/Test/TAP.js"></script>
<script type="text/javascript" src="../ext/Test/TAP/Class.js"></script>
</head>
<body>
<style type="text/css">
.test {
margin-top : 10px;
margin-bottom : 10px;
border : 3px;
border-style : inset;
overflow : auto;
}
.small {
height : 20px;
}
.big {
height : 600px;
}
.fail { background-color : red; }
.pass { background-color : green; }
.failsuite {border: 3px solid red;}
</style>
<!--Test Description here -->
<script type="text/javascript">
var top = this;
/** Configuration options
*
*/
var tests = [
'<list test files here>',
];
// Change this to the path of your test scripts
var testlib = '.';
/** Setup
*
*/
var loc = String(top.location);
var results = [];
</script>
<script type="text/javascript" src="../ext/Test/TAPBrowser.js"></script>
</body>
</html>

View File

@ -1,3 +0,0 @@
#!/bin/bash
rhino harness/rhino_harness.js

View File

@ -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 = [
'<list external libs here>'
];
var tests = [
'<list test files here>',
];
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();
}