jsunit.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. /*
  2. * jsunit.js
  3. *
  4. * Authors:
  5. * Chris Toshok ([email protected])
  6. *
  7. * (c) 2005 Novell, Inc. (http://www.novell.com)
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining
  10. * a copy of this software and associated documentation files (the
  11. * "Software"), to deal in the Software without restriction, including
  12. * without limitation the rights to use, copy, modify, merge, publish,
  13. * distribute, sublicense, and/or sell copies of the Software, and to
  14. * permit persons to whom the Software is furnished to do so, subject to
  15. * the following conditions:
  16. *
  17. * The above copyright notice and this permission notice shall be
  18. * included in all copies or substantial portions of the Software.
  19. *
  20. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  23. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  24. * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  25. * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. */
  28. /* For the time being, this is a total hack, precariously balanced and
  29. * ready to tip over if you look at it wrong. don't look at it
  30. * wrong. */
  31. var debugging = false;
  32. /* A trace object, that creates a console-esque window and lets us put debugging info there */
  33. Trace = function() { this.Init(); };
  34. Trace.prototype = {
  35. Init: function () {
  36. this.w = null;
  37. },
  38. ensure_window: function () {
  39. if (!this.w)
  40. this.w = window.open ("", "trace window", "height=300,width=400");
  41. this.w.focus();
  42. this.w.document.write ("<head><style>body {color:black; font-size: .7em;}</style></head><body>");
  43. },
  44. debug: function (msg){
  45. if (!debugging) return;
  46. this.ensure_window ();
  47. this.w.document.write ( "<p>" + msg + "</p>" );
  48. }
  49. };
  50. /* An Assert object, to make our tests look a little more like nunit's */
  51. var Assert = {
  52. IsTrue: function(expr, msg) {
  53. try {
  54. var result = eval(expr);
  55. if (result)
  56. test_passed (msg);
  57. else
  58. test_failed (msg, expr);
  59. } catch (e) {
  60. test_failed (msg, "Exception: " + e.message);
  61. }
  62. },
  63. IsFalse: function(expr, msg) {
  64. try {
  65. var result = eval(expr);
  66. if (!result)
  67. test_passed (msg);
  68. else
  69. test_failed (msg, expr);
  70. } catch (e) {
  71. test_failed (msg, "Exception: " + e.message);
  72. }
  73. },
  74. IsNull: function(expr, msg) {
  75. try {
  76. var result = eval(expr);
  77. if (result == null)
  78. test_passed (msg);
  79. else
  80. test_failed (msg, "'" + encode (expr) + "' returned non-null value '" + result + "'");
  81. } catch (e) {
  82. test_failed (msg, "Exception: " + e.message);
  83. }
  84. },
  85. NotNull: function(expr, msg) {
  86. try {
  87. var result = eval(expr);
  88. if (result != null)
  89. test_passed (msg);
  90. else
  91. test_failed (msg, "'" + encode (expr) + "' returned null");
  92. } catch (e) {
  93. test_failed (msg, "Exception: " + e.message);
  94. }
  95. },
  96. AreEqual: function(expected, expr, msg) {
  97. try {
  98. var result = eval(expr);
  99. /* gross hack because mozilla collapses these down to \n, but IE doesn't */
  100. result = string_trim (result.replace (/\r\n/g, "\n"));
  101. expected = string_trim (expected.replace (/\r\n/g, "\n"));
  102. if (result == expected)
  103. test_passed (msg);
  104. else
  105. test_failed (msg, "expected (len = " + expected.length + ") &lt;" + encode (expected) + "&gt;, got (len = " + result.length + " ) &lt;" + encode (result) + "&gt; " + string_charcode_diff(expected, result));
  106. } catch (e) {
  107. test_failed (msg, "Exception: " + e.message);
  108. }
  109. },
  110. AreEqualCase: function(expected, expr, msg) {
  111. try {
  112. var result = eval(expr);
  113. /* gross hack because mozilla collapses these down to \n, but IE doesn't */
  114. result = result.replace (/\r\n/g, "\n");
  115. expected = expected.replace (/\r\n/g, "\n");
  116. if (string_trim (result.toLowerCase()) == string_trim (expected.toLowerCase()))
  117. test_passed (msg);
  118. else
  119. test_failed (msg, "expected (len = " + expected.length + ") &lt;" + encode (expected.toLowerCase()) + "&gt;, got (len = " + result.length + " ) &lt;" + encode (result.toLowerCase()) + "&gt; " + string_charcode_diff(expected.toLowerCase(), result.toLowerCase()));
  120. } catch (e) {
  121. test_failed (msg, "Exception: " + e.message);
  122. }
  123. },
  124. NotEqual: function(expected, expr, msg) {
  125. try {
  126. var result = eval(expr);
  127. if (result != expected)
  128. test_passed (msg);
  129. else
  130. test_failed (msg, expr);
  131. } catch (e) {
  132. test_failed (msg, "Exception: " + e.message);
  133. }
  134. },
  135. Contains: function(expected, expr, msg) {
  136. try {
  137. var result = eval(expr);
  138. if (result.indexOf (expected) != -1)
  139. test_passed (msg);
  140. else
  141. test_failed (msg, expr);
  142. } catch (e) {
  143. test_failed (msg, "Exception: " + e.message);
  144. }
  145. },
  146. IsFunction: function(expr, msg) {
  147. try {
  148. var result = eval(expr);
  149. if (typeof (result) == 'function')
  150. test_passed (msg);
  151. else
  152. test_failed (msg, "expected &lt;function&gt;, got &lt;" + typeof (result) + "&gt;");
  153. } catch (e) {
  154. test_failed (msg, "Exception: " + e.message);
  155. }
  156. },
  157. AttributeHasValue: function (expected, attr, msg) {
  158. try {
  159. var result = JSUnit_GetAttribute (attr);
  160. if (result == expected)
  161. test_passed (msg);
  162. else
  163. test_failed (msg, "expected &lt;" + encode (expected) + "&gt;, got &lt;" + (result == null ? "null" : encode (result)) + "&gt;");
  164. } catch (e) {
  165. test_failed (msg, "Exception: " + e.message);
  166. }
  167. }
  168. };
  169. /* helper functions for tests */
  170. var element_name;
  171. var bound_element;
  172. var test_causes_page_load = false;
  173. function JSUnit_BindElement (n)
  174. {
  175. element_name = n;
  176. bound_element = top.test_run.document.getElementById (element_name);
  177. }
  178. function JSUnit_GetElement(id)
  179. {
  180. if (typeof (id) == 'undefined')
  181. return bound_element;
  182. else
  183. return top.test_run.document.getElementById (id);
  184. }
  185. function JSUnit_GetAttribute(a, id)
  186. {
  187. var o = JSUnit_GetElement (id);
  188. if (o == null)
  189. return null;
  190. if (o[a])
  191. return o[a];
  192. else if (o.getAttribute)
  193. return o.getAttribute (a);
  194. else
  195. return null;
  196. }
  197. function JSUnit_TestCausesPageLoad ()
  198. {
  199. trace.debug ("in JSUnit_TestCausesPageLoad");
  200. test_causes_page_load = true;
  201. }
  202. function JSUnit_Click (el)
  203. {
  204. trace.debug ("in JSUnit_Click");
  205. if (el == null) {
  206. trace.debug (" + returning early, element == null");
  207. return;
  208. }
  209. if (test_causes_page_load && !use_onload) {
  210. top.test_run.waiting = true;
  211. trace.debug ("adding checkReadState timeout");
  212. setTimeout ("checkReadyState()", 100);
  213. }
  214. if (el.click) {
  215. trace.debug ("+ using el.click()");
  216. el.click();
  217. }
  218. else if (el.getAttribute ("onClick")) {
  219. trace.debug ("+ using onClick handler");
  220. var handler = new Function (el.getAttribute ("onClick"));
  221. var evt = top.test_run.document.createEvent ("MouseEvents");
  222. evt.initEvent ("click", true, true);
  223. handler.call (el, evt);
  224. }
  225. else if (el.getAttribute ("href")) {
  226. var content_window = JSUnit_GetContentWindow (top.test_run.frame);
  227. trace.debug ("+ setting test_run src = " + el.getAttribute ("href") + " from " + content_window.location.href);
  228. content_window.location.href = el.getAttribute ("href");
  229. }
  230. else {
  231. alert ("uh oh...");
  232. }
  233. }
  234. function JSUnit_ExpectFailure(msg)
  235. {
  236. next_test_expected_failure = true;
  237. expected_failure_msg = msg;
  238. }
  239. /* the machinery */
  240. var trace = new Trace();
  241. var use_onload = true;
  242. var test_run_loaded = false;
  243. var test_scripts_loaded = false;
  244. var current_testpage = -1;
  245. var current_test = -1;
  246. var current_tests;
  247. var next_test_expected_failure;
  248. var expected_failure_msg;
  249. var current_test_html;
  250. var total_expected_failures = 0;
  251. var total_failed = 0;
  252. var total_tests = 0;
  253. var result_div;
  254. top.test_run = new Object();
  255. top.test_scripts = new Object();
  256. top.test_results = new Object();
  257. function updateStatusText (str)
  258. {
  259. status_text.innerHTML = "(" + str + ", " + parseInt (((current_testpage + 0.0) / (JSUnit_TestPages.length + 0.0) * 100) + "") + "% completed)";
  260. }
  261. function JSUnit_OnLoad ()
  262. {
  263. trace.debug ("in JSUnit_Onload");
  264. top.test_run.frame = document.getElementById ("test-run");
  265. top.test_scripts.frame = document.getElementById ("test-scripts");
  266. top.test_results.frame = document.getElementById ("test-results");
  267. top.test_results.document = JSUnit_GetContentDocument (top.test_results.frame);
  268. status_text = top.test_results.document.getElementById ("status_text");
  269. result_div = top.test_results.document.getElementById ("JSUnit_Results");
  270. if (result_div == null || typeof (result_div) == 'undefined') {
  271. alert ("Couldn't find result div");
  272. return;
  273. }
  274. result_div.innerHTML = "";
  275. if (navigator.userAgent.indexOf("MSIE") != -1) {
  276. use_onload = false;
  277. }
  278. else {
  279. top.test_run.frame.onload = test_run_onload;
  280. top.test_scripts.frame.onload = test_scripts_onload;
  281. use_onload = true;
  282. }
  283. /* set up the html for the list of pages we're testing */
  284. for (var i in JSUnit_TestPages) {
  285. html = "<img style=\"visibility:hidden;\" id=\"spinner-" + JSUnit_TestPages[i].url + "\" src=\"spinner-blue.gif\">";
  286. html += "<span id=\"indicator-" + JSUnit_TestPages[i].url + "\">&nbsp;</span>";
  287. html += "<a href=\"javascript:togglediv('results-" + JSUnit_TestPages[i].url + "')\"><b>+</b></a>" + "<b>" + JSUnit_TestPages[i].url + "</b>: <span id=\"failures-" + JSUnit_TestPages[i].url + "\">&nbsp;</span><br/>\n";
  288. html += "<div style='margin-left:50px;display:none;' id=\"results-" + JSUnit_TestPages[i].url + "\"></div>\n";
  289. result_div.innerHTML += html;
  290. }
  291. for (var i in JSUnit_TestPages) {
  292. JSUnit_TestPages[i].results_div = top.test_results.document.getElementById ("results-" + JSUnit_TestPages[i].url);
  293. JSUnit_TestPages[i].indicator = top.test_results.document.getElementById ("indicator-" + JSUnit_TestPages[i].url);
  294. JSUnit_TestPages[i].failures_span = top.test_results.document.getElementById ("failures-" + JSUnit_TestPages[i].url);
  295. JSUnit_TestPages[i].spinner = top.test_results.document.getElementById ("spinner-" + JSUnit_TestPages[i].url);
  296. }
  297. jsunit_RunTestPageStep();
  298. }
  299. var query_string_hack = 0;
  300. function checkReadyState ()
  301. {
  302. var need_timeout = false;
  303. if ((top.test_run.waiting && JSUnit_GetContentDocument(top.test_run.frame).readyState != "complete")
  304. || (top.test_scripts.waiting && JSUnit_GetContentDocument(top.test_scripts.frame).readyState != "complete")) {
  305. setTimeout("checkReadyState()", 100);
  306. }
  307. if (top.test_run.waiting) {
  308. if (JSUnit_GetContentDocument(top.test_run.frame).readyState == "complete") {
  309. top.test_run.waiting = false;
  310. test_run_onload();
  311. }
  312. }
  313. if (top.test_scripts.waiting) {
  314. if (JSUnit_GetContentDocument(top.test_scripts.frame).readyState == "complete") {
  315. top.test_run.waiting = false;
  316. test_scripts_onload();
  317. }
  318. }
  319. }
  320. function jsunit_RunTestPageStep ()
  321. {
  322. /* first hide the spinner from the old test, if there was one */
  323. if (current_testpage >= 0) {
  324. JSUnit_TestPages[current_testpage].spinner.style.visibility="hidden";
  325. }
  326. current_testpage ++;
  327. if (current_testpage >= JSUnit_TestPages.length) {
  328. jsunit_TestsCompleted();
  329. return;
  330. }
  331. status_text.style.display="inline";
  332. updateStatusText ("loading " + JSUnit_TestPages[current_testpage].url);
  333. JSUnit_TestPages[current_testpage].spinner.style.visibility = "visible";
  334. top.test_run.loaded = false;
  335. top.test_scripts.loaded = false;
  336. top.test_run.waiting = true;
  337. if (JSUnit_TestPages[current_testpage].script) {
  338. top.test_scripts.waiting = true;
  339. }
  340. else {
  341. top.test_scripts.waiting = false;
  342. }
  343. if (!use_onload) {
  344. setTimeout ("checkReadyState()", 100);
  345. }
  346. top.test_run.frame.src = "";
  347. top.test_scripts.frame.src = "";
  348. /* start the page loading */
  349. cw = JSUnit_GetContentWindow (top.test_run.frame);
  350. cw.location.href = JSUnit_TestPages[current_testpage].url + "?" + query_string_hack;
  351. /* start the script loading, if there is one */
  352. if (JSUnit_TestPages[current_testpage].script) {
  353. cw = JSUnit_GetContentWindow (top.test_scripts.frame);
  354. cw.location.href = JSUnit_TestPages[current_testpage].script + "?" + query_string_hack;
  355. query_string_hack++;
  356. }
  357. }
  358. function jsunit_TestsCompleted ()
  359. {
  360. trace.debug ("in jsunit_TestsCompleted");
  361. status_text.style.display="none";
  362. result_div.innerHTML += "<br/> <b>Totals:</b> " + total_tests + " tests, " + total_failed + " failure" + (total_failed != 1 ? "s" : "");
  363. if (total_expected_failures > 0) {
  364. result_div.innerHTML += " (" + total_expected_failures + " expected)";
  365. }
  366. result_div.innerHTML += ".";
  367. }
  368. function jsunit_FindTestFixture ()
  369. {
  370. var script_context = JSUnit_GetContentWindow (top.test_run.frame);
  371. if (!script_context['TestFixture']) {
  372. script_context = JSUnit_GetContentWindow (top.test_scripts.frame);
  373. if (!script_context['TestFixture'])
  374. return;
  375. }
  376. top.test_fixture = script_context['TestFixture'];
  377. top.test_fixture_context = script_context;
  378. }
  379. function jsunit_RunTestsForPage ()
  380. {
  381. trace.debug ("in jsunit_RunTestsForPage");
  382. // XXX for now, disable
  383. // netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
  384. jsunit_FindTestFixture ();
  385. current_test = -1;
  386. current_tests = new Array();
  387. for (var t in top.test_fixture)
  388. current_tests.push (t);
  389. updateStatusText ("testing " + JSUnit_TestPages[current_testpage].url);
  390. page_total_tests = 0;
  391. page_total_failed = 0;
  392. page_total_expected_failures = 0;
  393. current_test_html = "";
  394. JSUnit_TestPages[current_testpage].failures_span.innerHTML = "0 tests";
  395. jsunit_RunTestForPageStep ();
  396. }
  397. function jsunit_RunTestForPageStep ()
  398. {
  399. trace.debug ("in jsunit_RunTestForPageStep");
  400. // XXX for now, disable
  401. // netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
  402. // need this in case the test fixture was embedded in the test-run
  403. // page.
  404. jsunit_FindTestFixture ();
  405. // add the public api if it's not already there for the page
  406. if (!top.test_fixture_context['Assert'])
  407. jsunit_AddPublicAPI (top.test_fixture_context);
  408. current_test ++;
  409. if (current_test < current_tests.length) {
  410. var testfunc = top.test_fixture[current_tests[current_test]];
  411. if (typeof (testfunc) == 'function') {
  412. current_test_html += current_tests[current_test] + "<table width='800' cellpadding='0' cellspacing='0'>\n";
  413. try {
  414. trace.debug ("invoking test: " + current_tests[current_test]);
  415. testfunc ();
  416. } catch (e) {
  417. test_failed ("test function error", "Exception: " + e.message);
  418. }
  419. current_test_html += "</table>";
  420. }
  421. update_failures_span(false);
  422. JSUnit_TestPages[current_testpage].results_div.innerHTML = current_test_html;
  423. if (test_causes_page_load)
  424. return;
  425. else
  426. jsunit_RunTestForPageStep ();
  427. }
  428. else {
  429. if (page_total_failed > 0)
  430. current_test_html += "test html<br/><textarea cols='100' rows='20'>" + top.test_run.document.body.innerHTML + "</textarea>";
  431. JSUnit_TestPages[current_testpage].results_div.innerHTML = current_test_html;
  432. update_failures_span (true);
  433. /* once we're done with this page, advance to the next */
  434. jsunit_RunTestPageStep ();
  435. }
  436. }
  437. function jsunit_AddPublicAPI (ctx)
  438. {
  439. ctx['JSUnit_ExpectFailure'] = JSUnit_ExpectFailure;
  440. ctx['JSUnit_Click'] = JSUnit_Click;
  441. ctx['JSUnit_TestCausesPageLoad'] = JSUnit_TestCausesPageLoad;
  442. ctx['JSUnit_BindElement'] = JSUnit_BindElement;
  443. ctx['JSUnit_GetElement'] = JSUnit_GetElement;
  444. ctx['JSUnit_GetAttribute'] = JSUnit_GetAttribute;
  445. ctx['Assert'] = Assert;
  446. ctx['Trace'] = trace;
  447. }
  448. function update_failures_span (finished)
  449. {
  450. JSUnit_TestPages[current_testpage].failures_span.innerHTML = page_total_tests + " tests, " + page_total_failed + " failure" + (total_failed != 1 ? "s" : "");
  451. if (page_total_expected_failures > 0) {
  452. JSUnit_TestPages[current_testpage].failures_span.innerHTML += " (" + page_total_expected_failures + " expected)";
  453. }
  454. if (finished) {
  455. /* update the color to either green or red */
  456. JSUnit_TestPages[current_testpage].failures_span.style.background = (page_total_failed - page_total_expected_failures > 0) ? "#ff0000" : "#00ff00";
  457. }
  458. else {
  459. /* update the color to red if there's been a failure */
  460. if (page_total_failed - page_total_expected_failures > 0)
  461. JSUnit_TestPages[current_testpage].failures_span.style.background = "#ff0000";
  462. }
  463. }
  464. function test_run_onload ()
  465. {
  466. trace.debug ("in test_run_onload");
  467. top.test_run.document = JSUnit_GetContentDocument (top.test_run.frame);
  468. if (test_causes_page_load) {
  469. trace.debug ("+ resetting causes_page_load");
  470. test_causes_page_load = false;
  471. jsunit_RunTestForPageStep ();
  472. return;
  473. }
  474. top.test_run.loaded = true;
  475. if ((!top.test_scripts.waiting || top.test_scripts.loaded)) {
  476. trace.debug ("+ starting tests for page");
  477. /* both the page and its script have been loaded, let's run them */
  478. jsunit_RunTestsForPage ();
  479. }
  480. }
  481. function test_scripts_onload ()
  482. {
  483. trace.debug ("in test_scripts_onload");
  484. top.test_scripts.document = JSUnit_GetContentDocument (top.test_scripts.frame);
  485. top.test_scripts.loaded = true;
  486. if (top.test_run.loaded) {
  487. trace.debug ("+ starting tests for page");
  488. /* both the page and its script have been loaded, let's run them */
  489. jsunit_RunTestsForPage ();
  490. }
  491. }
  492. /* utility functions */
  493. function JSUnit_GetContentDocument (frame)
  494. {
  495. if (frame.contentDocument != null)
  496. return frame.contentDocument;
  497. else
  498. return frame.contentWindow.document;
  499. }
  500. function JSUnit_GetContentWindow (frame)
  501. {
  502. try {
  503. if (frame.contentDocument && frame.contentDocument.defaultView)
  504. return frame.contentDocument.defaultView;
  505. else
  506. return frame.contentWindow;
  507. } catch (e) {
  508. trace.debug ("exception getting content window: " + e);
  509. return null;
  510. }
  511. }
  512. function test_passed (msg)
  513. {
  514. next_test_expected_failure = false;
  515. current_test_html += "<tr class='passed'><td>" + msg + "</td><td width='400'>PASSED</td></tr>";
  516. page_total_tests ++;
  517. total_tests ++;
  518. }
  519. function test_failed (msg, extra)
  520. {
  521. if (next_test_expected_failure) {
  522. extra += "<br/>Expected failure: " + expected_failure_msg;
  523. next_test_expected_failure = false;
  524. page_total_expected_failures ++;
  525. total_expected_failures ++;
  526. }
  527. current_test_html += "<tr class='failed'><td>" + msg + "</td><td width='400'>FAILED " + extra + "</td></tr>";
  528. page_total_tests ++;
  529. page_total_failed ++;
  530. total_tests ++;
  531. total_failed ++;
  532. }
  533. function update_failures_span (finished)
  534. {
  535. JSUnit_TestPages[current_testpage].failures_span.innerHTML = page_total_tests + " tests, " + page_total_failed + " failure" + (total_failed != 1 ? "s" : "");
  536. if (page_total_expected_failures > 0) {
  537. JSUnit_TestPages[current_testpage].failures_span.innerHTML += " (" + page_total_expected_failures + " expected)";
  538. }
  539. if (finished) {
  540. /* update the color to either green or red */
  541. JSUnit_TestPages[current_testpage].failures_span.style.background = (page_total_failed - page_total_expected_failures > 0) ? "#ff0000" : "#00ff00";
  542. }
  543. else {
  544. /* update the color to red if there's been a failure */
  545. if (page_total_failed - page_total_expected_failures > 0)
  546. JSUnit_TestPages[current_testpage].failures_span.style.background = "#ff0000";
  547. }
  548. }
  549. function encode (str)
  550. {
  551. return str.replace (/</g, "&lt;").replace (/>/g, "&gt;").replace (/\n/g, "\\n");
  552. }
  553. function string_charcode_diff (str1, str2)
  554. {
  555. var length = str1.length;
  556. if (str2.length < str1.length)
  557. length = str2.length;
  558. for (i = 0; i < length; i ++) {
  559. var code1 = str1.charCodeAt (i);
  560. var code2 = str2.charCodeAt (i);
  561. if (code1 != code2)
  562. return "index = " + i + ", str1 = " + code1 + ", str2 = " + code2;
  563. }
  564. return "";
  565. }
  566. function string_trim (s)
  567. {
  568. s = s.replace (/^\s+/g, "");
  569. s = s.replace (/\s+$/g, "");
  570. return s;
  571. }