//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, func) { var self = this; if (crit) { var tapper = self.mk_tap; self.mk_tap = function(ok, desc) { tapper.apply(self, [ok, "# SKIP: "+reason]); } func(); self.mk_tap = tapper; } } /* =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(){ return string.match(regex); }, 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 */