jones-test/lib/Test.js (229 lines of code) (raw):

/* Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ "use strict"; var assert = require("assert"), path = require("path"), util = require("util"), udebug = require("unified_debug").getLogger("Test.js"); function Test() { this.filename = ""; this.name = ""; // This is set by the derived constructor this.phase = 2; // Serial Test (default) this.errorMessages = ''; this.suite = null; // will be set by Suite.addTest() this.index = 0; // index in suite; will be set by Suite.createTest() this.original = 0; // used by Suite when sorting tests this.failed = null; // will be set to true by fail(), or false by pass() this.skipped = false; this.result = null; // will be set by Test.test() this.enabled = true; } Test.prototype.test = function(result) { var runReturnCode; this.result = result; if(! this.enabled) { this.result.skipNotStarted(this, "disabled"); return; } result.startTest(this); udebug.log("Starting test", this.name); try { runReturnCode = this.run(); } catch(e) { console.log(this.name, 'threw exception & failed\n', e.stack); this.failed = true; result.fail(this, e); return; } if(! runReturnCode) { // async test must call Test.pass or Test.fail when done return; } // Test ran synchronously. Fail if any error messages have been reported. if(! this.skipped) { if (this.errorMessages === '') { this.pass(); } else { this.fail(); } } }; Test.prototype.onComplete = function() { return; }; Test.prototype.pass = function() { if (this.failed !== null) { console.log('Error: pass called with status already ' + (this.failed?'failed':'passed') + " for " + this.fullName()); assert(this.failed === null); } else { this.onComplete(); this.failed = false; this.result.pass(this); } }; Test.prototype.fail = function(message) { if (this.failed !== null) { console.log('Error: pass called with status already ' + (this.failed?'failed':'passed') + " for " + this.fullName()); assert(this.failed === null); } else { this.onComplete(); this.failed = true; if (message) { this.appendErrorMessage(message); this.stack = message.stack; } this.result.fail(this, { 'message' : this.errorMessages, 'stack': this.stack}); } }; Test.prototype.appendErrorMessage = function(message) { this.errorMessages += message; this.errorMessages += '\n'; }; Test.prototype.error = Test.prototype.appendErrorMessage; Test.prototype.failOnError = function() { if (this.errorMessages !== '') { this.fail(); } else { this.pass(); } }; Test.prototype.skip = function(message,result) { this.skipped = true; if(result) { this.result = result; this.result.skipNotStarted(this, message); } else { this.result.skipStarted(this, message); } return true; }; Test.prototype.isTest = function() { return true; }; Test.prototype.fullName = function() { var n = ""; if(this.suite) { n = n + this.suite.name + " "; } if(this.filename) { n = n + path.basename(this.filename) + " "; } return n + this.name; }; Test.prototype.run = function() { throw { "name" : "unimplementedTest", "message" : "this test does not have a run() method" }; }; function getType(obj) { var type = typeof obj; if (type === 'object' && obj !== null) { type = obj.constructor.name; } if (type === 'undefined') { return " "; } return " (" + type + ") "; } function compare(o1, o2) { if (o1 === undefined && o2 === undefined) { return true; } if (o1 === undefined || o2 === undefined) { return false; } if (o1 == o2) { return true; } if (o1 == null && o2 == null) { return true; } if (o1 == null || o2 == null) { return false; } if (typeof o1 !== typeof o2) { return false; } if (o1.toString() === o2.toString()) { return true; } return false; } Test.prototype.errorIfNotEqual = function(message, o1, o2) { if (!compare(o1, o2)) { var o1type = getType(o1); var o2type = getType(o2); message += ': expected' + o1type + o1 + '; actual' + o2type + o2 + '\n'; this.errorMessages += message; } }; Test.prototype.errorIfNotStrictEqual = function(message, o1, o2) { if(o1 !== o2) { var o1type = getType(o1); var o2type = getType(o2); message += ': expected' + o1type + o1 + '; actual' + o2type + o2 + '\n'; this.errorMessages += message; } }; Test.prototype.errorIfTrue = function(message, o1) { if (o1) { message += ': expected not true; actual ' + o1 + '\n'; this.errorMessages += message; } }; Test.prototype.errorIfNotTrue = function(message, o1) { if (o1 !== true) { message += ': expected true; actual ' + o1 + '\n'; this.errorMessages += message; } }; Test.prototype.errorIfNotError = function(message, o1) { if (!o1) { message += ' did not occur.\n'; this.errorMessages += message; } }; Test.prototype.errorIfNull = function(message, val) { if(val === null) { this.errorMessages += message; } }; Test.prototype.errorIfNotNull = function(message, val) { if(val !== null) { this.errorMessages += message; } }; /* Use this with the error argument in a callback */ Test.prototype.errorIfError = function(val) { if(val !== undefined && val !== null) { this.errorMessages += util.inspect(val); } }; /* Value must be defined and not-null Function returns true if there was no error; false on error */ Test.prototype.errorIfUnset = function(message, value) { var r = (value === undefined || value === null); if(r) { this.errorMessages += message; } return ! r; }; Test.prototype.errorIfLessThan = function(message, cmp, value) { if((typeof value !== 'number' || value < cmp)) { this.errorMessages += message; } }; Test.prototype.errorIfGreaterThan = function(message, cmp, value) { if((typeof value !== 'number' || value > cmp)) { this.errorMessages += message; } }; Test.prototype.hasNoErrors = function() { return this.errorMessages.length === 0; }; /* Reset this test so it can be called again (with a different adapter) */ Test.prototype.reset = function() { this.failed = null; this.result = null; }; /* Derived Classes */ function SmokeTest(name) { this.name = name; this.phase = 0; } SmokeTest.prototype = new Test(); function ClearSmokeTest(name) { this.name = name; this.phase = 3; } ClearSmokeTest.prototype = new Test(); function ConcurrentTest(name) { this.name = name; this.phase = 1; } ConcurrentTest.prototype = new Test(); function SerialTest(name) { this.name = name; this.phase = 2; } SerialTest.prototype = new Test(); /* Exports from this module */ exports.Test = Test; exports.SmokeTest = SmokeTest; exports.ClearSmokeTest = ClearSmokeTest; exports.ConcurrentTest = ConcurrentTest; exports.SerialTest = SerialTest;