Added in support for new HPC Dashboard View, ability to retrieve HPC Dashboard view...
[plstackapi.git] / planetstack / core / static / log4javascript-1.4.6 / test / xntest.js
1 // Next three methods are primarily for IE5, which is missing them
2 if (!Array.prototype.push) {
3         Array.prototype.push = function() {
4                 for (var i = 0; i < arguments.length; i++){
5                                 this[this.length] = arguments[i];
6                 }
7                 return this.length;
8         };
9 }
10
11 if (!Array.prototype.shift) {
12         Array.prototype.shift = function() {
13                 if (this.length > 0) {
14                         var firstItem = this[0];
15                         for (var i = 0; i < this.length - 1; i++) {
16                                 this[i] = this[i + 1];
17                         }
18                         this.length = this.length - 1;
19                         return firstItem;
20                 }
21         };
22 }
23
24 if (!Function.prototype.apply) {
25         Function.prototype.apply = function(obj, args) {
26                 var methodName = "__apply__";
27                 if (typeof obj[methodName] != "undefined") {
28                         methodName += (String(Math.random())).substr(2);
29                 }
30                 obj[methodName] = this;
31
32                 var argsStrings = new Array(args.length);
33                 for (var i = 0; i < args.length; i++) {
34                         argsStrings[i] = "args[" + i + "]";
35                 }
36                 var script = "obj." + methodName + "(" + argsStrings.join(",") + ")";
37                 var returnValue = eval(script);
38                 delete obj[methodName];
39                 return returnValue;
40         };
41 }
42
43 /* -------------------------------------------------------------------------- */
44
45 var xn = new Object();
46
47 (function() {
48         // Utility functions
49
50         // Event listeners
51         var getListenersPropertyName = function(eventName) {
52                 return "__listeners__" + eventName;
53         };
54
55         var addEventListener = function(node, eventName, listener, useCapture) {
56                 useCapture = Boolean(useCapture);
57                 if (node.addEventListener) {
58                         node.addEventListener(eventName, listener, useCapture);
59                 } else if (node.attachEvent) {
60                         node.attachEvent("on" + eventName, listener);
61                 } else {
62                         var propertyName = getListenersPropertyName(eventName);
63                         if (!node[propertyName]) {
64                                 node[propertyName] = new Array();
65
66                                 // Set event handler
67                                 node["on" + eventName] = function(evt) {
68                                         evt = module.getEvent(evt);
69                                         var listenersPropertyName = getListenersPropertyName(eventName);
70
71                                         // Clone the array of listeners to leave the original untouched
72                                         var listeners = cloneArray(this[listenersPropertyName]);
73                                         var currentListener;
74
75                                         // Call each listener in turn
76                                         while (currentListener = listeners.shift()) {
77                                                 currentListener.call(this, evt);
78                                         }
79                                 };
80                         }
81                         node[propertyName].push(listener);
82                 }
83         };
84
85         // Clones an array
86         var cloneArray = function(arr) {
87                 var clonedArray = [];
88                 for (var i = 0; i < arr.length; i++) {
89                         clonedArray[i] = arr[i];
90                 }
91                 return clonedArray;
92         }
93
94         var isFunction = function(f) {
95                 if (!f){ return false; }
96                 return (f instanceof Function || typeof f == "function");
97         };
98
99         // CSS Utilities
100         
101         function array_contains(arr, val) {
102                 for (var i = 0, len = arr.length; i < len; i++) {
103                         if (arr[i] === val) {
104                                 return true;
105                         }
106                 }
107                 return false;
108         }
109
110         function addClass(el, cssClass) {
111                 if (!hasClass(el, cssClass)) {
112                         if (el.className) {
113                                 el.className += " " + cssClass;
114                         } else {
115                                 el.className = cssClass;
116                         }
117                 }
118         }
119
120         function hasClass(el, cssClass) {
121                 if (el.className) {
122                         var classNames = el.className.split(" ");
123                         return array_contains(classNames, cssClass);
124                 }
125                 return false;
126         }
127
128         function removeClass(el, cssClass) {
129                 if (hasClass(el, cssClass)) {
130                         // Rebuild the className property
131                         var existingClasses = el.className.split(" ");
132                         var newClasses = [];
133                         for (var i = 0; i < existingClasses.length; i++) {
134                                 if (existingClasses[i] != cssClass) {
135                                         newClasses[newClasses.length] = existingClasses[i];
136                                 }
137                         }
138                         el.className = newClasses.join(" ");
139                 }
140         }
141
142         function replaceClass(el, newCssClass, oldCssClass) {
143                 removeClass(el, oldCssClass);
144                 addClass(el, newCssClass);
145         }
146
147         function getExceptionStringRep(ex) {
148                 if (ex) {
149                         var exStr = "Exception: ";
150                         if (ex.message) {
151                                 exStr += ex.message;
152                         } else if (ex.description) {
153                                 exStr += ex.description;
154                         }
155                         if (ex.lineNumber) {
156                                 exStr += " on line number " + ex.lineNumber;
157                         }
158                         if (ex.fileName) {
159                                 exStr += " in file " + ex.fileName;
160                         }
161                         return exStr;
162                 }
163                 return null;
164         }
165
166
167         /* ---------------------------------------------------------------------- */
168
169         /* Configure the test logger try to use FireBug */
170         var log, error;
171         if (window["console"] && typeof console.log == "function") {
172                 log = function() {
173                         if (xn.test.enableTestDebug) {
174                                 console.log.apply(console, arguments);
175                         }
176                 };
177                 error = function() {
178                         if (xn.test.enableTestDebug) {
179                                 console.error.apply(console, arguments);
180                         }
181                 };
182         } else {
183                 log = function() {};
184         }
185
186         /* Set up something to report to */
187
188         var initialized = false;
189         var container;
190         var progressBarContainer, progressBar, overallSummaryText;
191         var currentTest = null;
192         var suites = [];
193         var totalTestCount = 0;
194         var currentTestIndex = 0;
195         var testFailed = false;
196         var testsPassedCount = 0;
197         var startTime;
198         
199         var log4javascriptEnabled = false;
200         
201         var nextSuiteIndex = 0;
202         
203         function runNextSuite() {
204                 if (nextSuiteIndex < suites.length) {
205                         suites[nextSuiteIndex++].run();
206                 }
207         }
208         
209         var init = function() {
210                 if (initialized) { return true; }
211                 
212                 container = document.createElement("div");
213                 
214                 // Create the overall progress bar
215                 progressBarContainer = container.appendChild(document.createElement("div"));
216                 progressBarContainer.className = "xn_test_progressbar_container xn_test_overallprogressbar_container";
217                 progressBar = progressBarContainer.appendChild(document.createElement("div"));
218                 progressBar.className = "success";
219
220                 document.body.appendChild(container);
221
222                 var h1 = progressBar.appendChild(document.createElement("h1"));
223                 overallSummaryText = h1.appendChild(document.createTextNode(""));
224
225                 initialized = true;
226                 
227                 // Set up logging
228                 log4javascriptEnabled = !!log4javascript && xn.test.enable_log4javascript;
229                 
230                 function TestLogAppender() {}
231                 
232                 if (log4javascriptEnabled) {
233                         TestLogAppender.prototype = new log4javascript.Appender();
234                         TestLogAppender.prototype.layout = new log4javascript.PatternLayout("%d{HH:mm:ss,SSS} %-5p %m");
235                         TestLogAppender.prototype.append = function(loggingEvent) {
236                                 var formattedMessage = this.getLayout().format(loggingEvent);
237                                 if (this.getLayout().ignoresThrowable()) {
238                                         formattedMessage += loggingEvent.getThrowableStrRep();
239                                 }
240                                 currentTest.addLogMessage(formattedMessage);
241                         };
242                         
243                         var appender = new TestLogAppender();
244                         appender.setThreshold(log4javascript.Level.ALL);
245                         log4javascript.getRootLogger().addAppender(appender);
246                         log4javascript.getRootLogger().setLevel(log4javascript.Level.ALL);
247                 }
248
249                 startTime = new Date();
250
251                 // First, build each suite
252                 for (var i = 0; i < suites.length; i++) {
253                         suites[i].build();
254                         totalTestCount += suites[i].tests.length;
255                 }
256                 
257                 // Now run each suite
258                 runNextSuite();
259         };
260         
261         function updateProgressBar() {
262                 progressBar.style.width = "" + parseInt(100 * (currentTestIndex) / totalTestCount) + "%";
263                 var s = (totalTestCount === 1) ? "" : "s";
264                 var timeTaken = new Date().getTime() - startTime.getTime();
265                 overallSummaryText.nodeValue = "" + testsPassedCount + " of " + totalTestCount + " test" + s + " passed in " + timeTaken + "ms";
266         }
267
268         addEventListener(window, "load", init);
269
270         /* ---------------------------------------------------------------------- */
271
272         /* Test Suite */
273         var Suite = function(name, callback, hideSuccessful) {
274                 this.name = name;
275                 this.callback = callback;
276                 this.hideSuccessful = hideSuccessful;
277                 this.tests = [];
278                 this.log = log;
279                 this.error = error;
280                 this.expanded = true;
281                 suites.push(this);
282         }
283
284         Suite.prototype.test = function(name, callback, setUp, tearDown) {
285                 this.log("adding a test named " + name)
286                 var t = new Test(name, callback, this, setUp, tearDown);
287                 this.tests.push(t);
288         };
289
290         Suite.prototype.build = function() {
291                 // Build the elements used by the suite
292                 var suite = this;
293                 this.testFailed = false;
294                 this.container = document.createElement("div");
295                 this.container.className = "xn_test_suite_container";
296
297                 var heading = document.createElement("h2");
298                 this.expander = document.createElement("span");
299                 this.expander.className = "xn_test_expander";
300                 this.expander.onclick = function() {
301                         if (suite.expanded) {
302                                 suite.collapse();
303                         } else {
304                                 suite.expand();
305                         }
306                 };
307                 heading.appendChild(this.expander);
308                 
309                 this.headingTextNode = document.createTextNode(this.name);
310                 heading.appendChild(this.headingTextNode);
311                 this.container.appendChild(heading);
312
313                 this.reportContainer = document.createElement("dl");
314                 this.container.appendChild(this.reportContainer);
315
316                 this.progressBarContainer = document.createElement("div");
317                 this.progressBarContainer.className = "xn_test_progressbar_container";
318                 this.progressBar = document.createElement("div");
319                 this.progressBar.className = "success";
320                 this.progressBar.innerHTML = "&nbsp;";
321                 this.progressBarContainer.appendChild(this.progressBar);
322                 this.reportContainer.appendChild(this.progressBarContainer);
323
324                 this.expand();
325
326                 container.appendChild(this.container);
327
328                 // invoke callback to build the tests
329                 this.callback.apply(this, [this]);
330         };
331
332         Suite.prototype.run = function() {
333                 this.log("running suite '%s'", this.name)
334                 this.startTime = new Date();
335
336                 // now run the first test
337                 this._currentIndex = 0;
338                 this.runNextTest();
339         };
340
341         Suite.prototype.updateProgressBar = function() {
342                 // Update progress bar
343                 this.progressBar.style.width = "" + parseInt(100 * (this._currentIndex) / this.tests.length) + "%";
344                 //log(this._currentIndex + ", " + this.tests.length + ", " + progressBar.style.width + ", " + progressBar.className);
345         };
346
347         Suite.prototype.expand = function() {
348                 this.expander.innerHTML = "-";
349                 replaceClass(this.reportContainer, "xn_test_expanded", "xn_test_collapsed");
350                 this.expanded = true;
351         };
352
353         Suite.prototype.collapse = function() {
354                 this.expander.innerHTML = "+";
355                 replaceClass(this.reportContainer, "xn_test_collapsed", "xn_test_expanded");
356                 this.expanded = false;
357         };
358
359         Suite.prototype.finish = function(timeTaken) {
360                 var newClass = this.testFailed ? "xn_test_suite_failure" : "xn_test_suite_success";
361                 var oldClass = this.testFailed ? "xn_test_suite_success" : "xn_test_suite_failure";
362                 replaceClass(this.container, newClass, oldClass);
363
364                 this.headingTextNode.nodeValue += " (" + timeTaken + "ms)";
365
366                 if (this.hideSuccessful && !this.testFailed) {
367                         this.collapse();
368                 }
369                 runNextSuite();
370         };
371
372         /**
373          * Works recursively with external state (the next index)
374          * so that we can handle async tests differently
375          */
376         Suite.prototype.runNextTest = function() {
377                 if (this._currentIndex == this.tests.length) {
378                         // finished!
379                         var timeTaken = new Date().getTime() - this.startTime.getTime();
380
381                         this.finish(timeTaken);
382                         return;
383                 }
384
385                 var suite = this;
386                 var t = this.tests[this._currentIndex++];
387                 currentTestIndex++;
388
389                 if (isFunction(suite.setUp)) {
390                         suite.setUp.apply(suite, [t]);
391                 }
392                 if (isFunction(t.setUp)) {
393                         t.setUp.apply(t, [t]);
394                 }
395
396                 t._run();
397                 
398                 function afterTest() {
399                         if (isFunction(suite.tearDown)) {
400                                 suite.tearDown.apply(suite, [t]);
401                         }
402                         if (isFunction(t.tearDown)) {
403                                 t.tearDown.apply(t, [t]);
404                         }
405                         suite.log("finished test [%s]", t.name);
406                         updateProgressBar();
407                         suite.updateProgressBar();
408                         suite.runNextTest();
409                 }
410                 
411                 if (t.isAsync) {
412                         t.whenFinished = afterTest;
413                 } else {
414                         setTimeout(afterTest, 1);
415                 }
416         };
417
418         Suite.prototype.reportSuccess = function() {
419         };
420
421         /* ---------------------------------------------------------------------- */
422         /**
423          * Create a new test
424          */
425         var Test = function(name, callback, suite, setUp, tearDown) {
426                 this.name = name;
427                 this.callback = callback;
428                 this.suite = suite;
429                 this.setUp = setUp;
430                 this.tearDown = tearDown;
431                 this.log = log;
432                 this.error = error;
433                 this.assertCount = 0;
434                 this.logMessages = [];
435                 this.logExpanded = false;
436         };
437
438         /**
439          * Default success reporter, please override
440          */
441         Test.prototype.reportSuccess = function(name, timeTaken) {
442                 /* default success reporting handler */
443                 this.reportHeading = document.createElement("dt");
444                 var text = this.name + " passed in " + timeTaken + "ms";
445                 
446                 this.reportHeading.appendChild(document.createTextNode(text));
447
448                 this.reportHeading.className = "success";
449                 var dd = document.createElement("dd");
450                 dd.className = "success";
451
452                 this.suite.reportContainer.appendChild(this.reportHeading);
453                 this.suite.reportContainer.appendChild(dd);
454                 this.createLogReport();
455         };
456
457         /**
458          * Cause the test to immediately fail
459          */
460         Test.prototype.reportFailure = function(name, msg, ex) {
461                 this.suite.testFailed = true;
462                 this.suite.progressBar.className = "failure";
463                 progressBar.className = "failure";
464                 this.reportHeading = document.createElement("dt");
465                 this.reportHeading.className = "failure";
466                 var text = document.createTextNode(this.name);
467                 this.reportHeading.appendChild(text);
468
469                 var dd = document.createElement("dd");
470                 dd.appendChild(document.createTextNode(msg));
471                 dd.className = "failure";
472
473                 this.suite.reportContainer.appendChild(this.reportHeading);
474                 this.suite.reportContainer.appendChild(dd);
475                 if (ex && ex.stack) {
476                         var stackTraceContainer = this.suite.reportContainer.appendChild(document.createElement("code"));
477                         stackTraceContainer.className = "xn_test_stacktrace";
478                         stackTraceContainer.innerHTML = ex.stack.replace(/\r/g, "\n").replace(/\n{1,2}/g, "<br />");
479                 }
480                 this.createLogReport();
481         };
482         
483         Test.prototype.createLogReport = function() {
484                 if (this.logMessages.length > 0) {
485                         this.reportHeading.appendChild(document.createTextNode(" ("));
486                         var logToggler = this.reportHeading.appendChild(document.createElement("a"));
487                         logToggler.href = "#";
488                         logToggler.innerHTML = "show log";
489                         var test = this;
490                         
491                         logToggler.onclick = function() {
492                                 if (test.logExpanded) {
493                                         test.hideLogReport();
494                                         this.innerHTML = "show log";
495                                         test.logExpanded = false;
496                                 } else {
497                                         test.showLogReport();
498                                         this.innerHTML = "hide log";
499                                         test.logExpanded = true;
500                                 }
501                                 return false;
502                         };
503
504                         this.reportHeading.appendChild(document.createTextNode(")"));
505                         
506                         // Create log report
507                         this.logReport = this.suite.reportContainer.appendChild(document.createElement("pre"));
508                         this.logReport.style.display = "none";
509                         this.logReport.className = "xn_test_log_report";
510                         var logMessageDiv;
511                         for (var i = 0, len = this.logMessages.length; i < len; i++) {
512                                 logMessageDiv = this.logReport.appendChild(document.createElement("div"));
513                                 logMessageDiv.appendChild(document.createTextNode(this.logMessages[i]));
514                         }
515                 }
516         };
517
518         Test.prototype.showLogReport = function() {
519                 this.logReport.style.display = "inline-block";
520         };
521                 
522         Test.prototype.hideLogReport = function() {
523                 this.logReport.style.display = "none";
524         };
525
526         Test.prototype.async = function(timeout, callback) {
527                 timeout = timeout || 250;
528                 var self = this;
529                 var timedOutFunc = function() {
530                         if (!self.completed) {
531                                 var message = (typeof callback === "undefined") ?
532                                                         "Asynchronous test timed out" : callback(self);
533                                 self.fail(message);
534                         }
535                 }
536                 var timer = setTimeout(function () { timedOutFunc.apply(self, []); }, timeout)
537                 this.isAsync = true;
538         };
539
540         /**
541          * Run the test
542          */
543         Test.prototype._run = function() {
544                 this.log("starting test [%s]", this.name);
545                 this.startTime = new Date();
546                 currentTest = this;
547                 try {
548                         this.callback(this);
549                         if (!this.completed && !this.isAsync) {
550                                 this.succeed();
551                         }
552                 } catch (e) {
553                         this.log("test [%s] threw exception [%s]", this.name, e);
554                         var s = (this.assertCount === 1) ? "" : "s";
555                         this.fail("Exception thrown after " + this.assertCount + " successful assertion" + s + ": " + getExceptionStringRep(e), e);
556                 }
557         };
558
559         /**
560          * Cause the test to immediately succeed
561          */
562         Test.prototype.succeed = function() {
563                 if (this.completed) { return false; }
564                 // this.log("test [%s] succeeded", this.name);
565                 this.completed = true;
566                 var timeTaken = new Date().getTime() - this.startTime.getTime();
567                 testsPassedCount++;
568                 this.reportSuccess(this.name, timeTaken);
569                 if (this.whenFinished) {
570                         this.whenFinished();
571                 }
572         };
573
574         Test.prototype.fail = function(msg, ex) {
575                 if (typeof msg != "string") {
576                         msg = getExceptionStringRep(msg);
577                 }
578                 if (this.completed) { return false; }
579                 this.completed = true;
580                 // this.log("test [%s] failed", this.name);
581                 this.reportFailure(this.name, msg, ex);
582                 if (this.whenFinished) {
583                         this.whenFinished();
584                 }
585         };
586         
587         Test.prototype.addLogMessage = function(logMessage) {
588                 this.logMessages.push(logMessage);
589         };
590
591         /* assertions */
592         var displayStringForValue = function(obj) {
593                 if (obj === null) {
594                         return "null";
595                 } else if (typeof obj === "undefined") {
596                         return "undefined";
597                 }
598                 return obj.toString();
599         };
600
601         var assert = function(args, expectedArgsCount, testFunction, defaultComment) {
602                 this.assertCount++;
603                 var comment = defaultComment;
604                 var i;
605                 var success;
606                 var values = [];
607                 if (args.length == expectedArgsCount) {
608                         for (i = 0; i < args.length; i++) {
609                                 values[i] = args[i];
610                         }
611                 } else if (args.length == expectedArgsCount + 1) {
612                         comment = args[0];
613                         for (i = 1; i < args.length; i++) {
614                                 values[i - 1] = args[i];
615                         }
616                 } else {
617                         throw new Error("Invalid number of arguments passed to assert function");
618                 }
619                 success = testFunction(values);
620                 if (!success) {
621                         var regex = /\{([0-9]+)\}/;
622                         while (regex.test(comment)) {
623                                 comment = comment.replace(regex, displayStringForValue(values[parseInt(RegExp.$1)]));
624                         }
625                         this.fail("Test failed on assertion " + this.assertCount + ": " + comment);
626                 }
627         };
628
629         var testNull = function(values) {
630                 return (values[0] === null);
631         };
632
633         Test.prototype.assertNull = function() {
634                 assert.apply(this, [arguments, 1, testNull, "Expected to be null but was {0}"]);
635         }
636
637         var testNotNull = function(values) {
638                 return (values[0] !== null);
639         };
640
641         Test.prototype.assertNotNull = function() {
642                 assert.apply(this, [arguments, 1, testNotNull, "Expected not to be null but was {0}"]);
643         }
644
645         var testBoolean = function(values) {
646                 return (Boolean(values[0]));
647         };
648
649         Test.prototype.assert = function() {
650                 assert.apply(this, [arguments, 1, testBoolean, "Expected not to be equivalent to false"]);
651         };
652
653         var testTrue = function(values) {
654                 return (values[0] === true);
655         };
656
657         Test.prototype.assertTrue = function() {
658                 assert.apply(this, [arguments, 1, testTrue, "Expected to be true but was {0}"]);
659         };
660
661         Test.prototype.assert = function() {
662                 assert.apply(this, [arguments, 1, testTrue, "Expected to be true but was {0}"]);
663         };
664
665         var testFalse = function(values) {
666                 return (values[0] === false);
667         };
668
669         Test.prototype.assertFalse = function() {
670                 assert.apply(this, [arguments, 1, testFalse, "Expected to be false but was {0}"]);
671         }
672
673         var testEquivalent = function(values) {
674                 return (values[0] === values[1]);
675         };
676
677         Test.prototype.assertEquivalent = function() {
678                 assert.apply(this, [arguments, 2, testEquivalent, "Expected to be equal but values were {0} and {1}"]);
679         }
680
681         var testNotEquivalent = function(values) {
682                 return (values[0] !== values[1]);
683         };
684
685         Test.prototype.assertNotEquivalent = function() {
686                 assert.apply(this, [arguments, 2, testNotEquivalent, "Expected to be not equal but values were {0} and {1}"]);
687         }
688
689         var testEquals = function(values) {
690                 return (values[0] == values[1]);
691         };
692
693         Test.prototype.assertEquals = function() {
694                 assert.apply(this, [arguments, 2, testEquals, "Expected to be equal but values were {0} and {1}"]);
695         }
696
697         var testNotEquals = function(values) {
698                 return (values[0] != values[1]);
699         };
700
701         Test.prototype.assertNotEquals = function() {
702                 assert.apply(this, [arguments, 2, testNotEquals, "Expected to be not equal but values were {0} and {1}"]);
703         }
704
705         var testRegexMatches = function(values) {
706                 return (values[0].test(values[1]));
707         };
708
709         Test.prototype.assertRegexMatches = function() {
710                 assert.apply(this, [arguments, 2, testRegexMatches, "Expected regex {0} to match value {1} but it didn't"]);
711         }
712
713         Test.prototype.assertError = function(f, errorType) {
714                 try {
715                         f();
716                         this.fail("Expected error to be thrown");
717                 } catch (e) {
718                         if (errorType && (!(e instanceof errorType))) {
719                                 this.fail("Expected error of type " + errorType + " to be thrown but error thrown was " + e);
720                         }
721                 }
722         };
723
724         /**
725          * Execute a synchronous test
726          */
727         xn.test = function(name, callback) {
728                 xn.test.suite("Anonymous", function(s) {
729                         s.test(name, callback);
730                 });
731         }
732
733         /**
734          * Create a test suite with a given name
735          */
736         xn.test.suite = function(name, callback, hideSuccessful) {
737                 var s = new Suite(name, callback, hideSuccessful);
738         }
739 })();