testing/xpcshell/selftest.py

Wed, 31 Dec 2014 06:55:46 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:46 +0100
changeset 1
ca08bd8f51b2
permissions
-rw-r--r--

Added tag TORBROWSER_REPLICA for changeset 6474c204b198

michael@0 1 #!/usr/bin/env python
michael@0 2 #
michael@0 3 # Any copyright is dedicated to the Public Domain.
michael@0 4 # http://creativecommons.org/publicdomain/zero/1.0/
michael@0 5 #
michael@0 6
michael@0 7 from __future__ import with_statement
michael@0 8 import sys, os, unittest, tempfile, shutil
michael@0 9 import mozinfo
michael@0 10
michael@0 11 from StringIO import StringIO
michael@0 12 from xml.etree.ElementTree import ElementTree
michael@0 13
michael@0 14 from mozbuild.base import MozbuildObject
michael@0 15 build_obj = MozbuildObject.from_environment()
michael@0 16
michael@0 17 from runxpcshelltests import XPCShellTests
michael@0 18
michael@0 19 mozinfo.find_and_update_from_json()
michael@0 20
michael@0 21 objdir = build_obj.topobjdir.encode("utf-8")
michael@0 22 xpcshellBin = os.path.join(objdir, "dist", "bin", "xpcshell")
michael@0 23 if sys.platform == "win32":
michael@0 24 xpcshellBin += ".exe"
michael@0 25
michael@0 26 SIMPLE_PASSING_TEST = "function run_test() { do_check_true(true); }"
michael@0 27 SIMPLE_FAILING_TEST = "function run_test() { do_check_true(false); }"
michael@0 28
michael@0 29 ADD_TEST_SIMPLE = '''
michael@0 30 function run_test() { run_next_test(); }
michael@0 31
michael@0 32 add_test(function test_simple() {
michael@0 33 do_check_true(true);
michael@0 34 run_next_test();
michael@0 35 });
michael@0 36 '''
michael@0 37
michael@0 38 ADD_TEST_FAILING = '''
michael@0 39 function run_test() { run_next_test(); }
michael@0 40
michael@0 41 add_test(function test_failing() {
michael@0 42 do_check_true(false);
michael@0 43 run_next_test();
michael@0 44 });
michael@0 45 '''
michael@0 46
michael@0 47 CHILD_TEST_PASSING = '''
michael@0 48 function run_test () { run_next_test(); }
michael@0 49
michael@0 50 add_test(function test_child_simple () {
michael@0 51 run_test_in_child("test_pass.js");
michael@0 52 run_next_test();
michael@0 53 });
michael@0 54 '''
michael@0 55
michael@0 56 CHILD_TEST_FAILING = '''
michael@0 57 function run_test () { run_next_test(); }
michael@0 58
michael@0 59 add_test(function test_child_simple () {
michael@0 60 run_test_in_child("test_fail.js");
michael@0 61 run_next_test();
michael@0 62 });
michael@0 63 '''
michael@0 64
michael@0 65 CHILD_TEST_HANG = '''
michael@0 66 function run_test () { run_next_test(); }
michael@0 67
michael@0 68 add_test(function test_child_simple () {
michael@0 69 do_test_pending("hang test");
michael@0 70 do_load_child_test_harness();
michael@0 71 sendCommand("_log('child_test_start', {_message: 'CHILD-TEST-STARTED'}); " +
michael@0 72 + "const _TEST_FILE=['test_pass.js']; _execute_test(); ",
michael@0 73 do_test_finished);
michael@0 74 run_next_test();
michael@0 75 });
michael@0 76 '''
michael@0 77
michael@0 78 ADD_TASK_SINGLE = '''
michael@0 79 Components.utils.import("resource://gre/modules/Promise.jsm");
michael@0 80
michael@0 81 function run_test() { run_next_test(); }
michael@0 82
michael@0 83 add_task(function test_task() {
michael@0 84 yield Promise.resolve(true);
michael@0 85 yield Promise.resolve(false);
michael@0 86 });
michael@0 87 '''
michael@0 88
michael@0 89 ADD_TASK_MULTIPLE = '''
michael@0 90 Components.utils.import("resource://gre/modules/Promise.jsm");
michael@0 91
michael@0 92 function run_test() { run_next_test(); }
michael@0 93
michael@0 94 add_task(function test_task() {
michael@0 95 yield Promise.resolve(true);
michael@0 96 });
michael@0 97
michael@0 98 add_task(function test_2() {
michael@0 99 yield Promise.resolve(true);
michael@0 100 });
michael@0 101 '''
michael@0 102
michael@0 103 ADD_TASK_REJECTED = '''
michael@0 104 Components.utils.import("resource://gre/modules/Promise.jsm");
michael@0 105
michael@0 106 function run_test() { run_next_test(); }
michael@0 107
michael@0 108 add_task(function test_failing() {
michael@0 109 yield Promise.reject(new Error("I fail."));
michael@0 110 });
michael@0 111 '''
michael@0 112
michael@0 113 ADD_TASK_FAILURE_INSIDE = '''
michael@0 114 Components.utils.import("resource://gre/modules/Promise.jsm");
michael@0 115
michael@0 116 function run_test() { run_next_test(); }
michael@0 117
michael@0 118 add_task(function test() {
michael@0 119 let result = yield Promise.resolve(false);
michael@0 120
michael@0 121 do_check_true(result);
michael@0 122 });
michael@0 123 '''
michael@0 124
michael@0 125 ADD_TASK_RUN_NEXT_TEST = '''
michael@0 126 function run_test() { run_next_test(); }
michael@0 127
michael@0 128 add_task(function () {
michael@0 129 Assert.ok(true);
michael@0 130
michael@0 131 run_next_test();
michael@0 132 });
michael@0 133 '''
michael@0 134
michael@0 135 ADD_TEST_THROW_STRING = '''
michael@0 136 function run_test() {do_throw("Passing a string to do_throw")};
michael@0 137 '''
michael@0 138
michael@0 139 ADD_TEST_THROW_OBJECT = '''
michael@0 140 let error = {
michael@0 141 message: "Error object",
michael@0 142 fileName: "failure.js",
michael@0 143 stack: "ERROR STACK",
michael@0 144 toString: function() {return this.message;}
michael@0 145 };
michael@0 146 function run_test() {do_throw(error)};
michael@0 147 '''
michael@0 148
michael@0 149 ADD_TEST_REPORT_OBJECT = '''
michael@0 150 let error = {
michael@0 151 message: "Error object",
michael@0 152 fileName: "failure.js",
michael@0 153 stack: "ERROR STACK",
michael@0 154 toString: function() {return this.message;}
michael@0 155 };
michael@0 156 function run_test() {do_report_unexpected_exception(error)};
michael@0 157 '''
michael@0 158
michael@0 159 # A test for genuine JS-generated Error objects
michael@0 160 ADD_TEST_REPORT_REF_ERROR = '''
michael@0 161 function run_test() {
michael@0 162 let obj = {blah: 0};
michael@0 163 try {
michael@0 164 obj.noSuchFunction();
michael@0 165 }
michael@0 166 catch (error) {
michael@0 167 do_report_unexpected_exception(error);
michael@0 168 }
michael@0 169 };
michael@0 170 '''
michael@0 171
michael@0 172 # A test for failure to load a test due to a syntax error
michael@0 173 LOAD_ERROR_SYNTAX_ERROR = '''
michael@0 174 function run_test(
michael@0 175 '''
michael@0 176
michael@0 177 # A test for failure to load a test due to an error other than a syntax error
michael@0 178 LOAD_ERROR_OTHER_ERROR = '''
michael@0 179 function run_test() {
michael@0 180 yield "foo";
michael@0 181 return "foo"; // can't use return in a generator!
michael@0 182 };
michael@0 183 '''
michael@0 184
michael@0 185 # A test for asynchronous cleanup functions
michael@0 186 ASYNC_CLEANUP = '''
michael@0 187 function run_test() {
michael@0 188 Components.utils.import("resource://gre/modules/Promise.jsm", this);
michael@0 189
michael@0 190 // The list of checkpoints in the order we encounter them.
michael@0 191 let checkpoints = [];
michael@0 192
michael@0 193 // Cleanup tasks, in reverse order
michael@0 194 do_register_cleanup(function cleanup_checkout() {
michael@0 195 do_check_eq(checkpoints.join(""), "1234");
michael@0 196 do_print("At this stage, the test has succeeded");
michael@0 197 do_throw("Throwing an error to force displaying the log");
michael@0 198 });
michael@0 199
michael@0 200 do_register_cleanup(function sync_cleanup_2() {
michael@0 201 checkpoints.push(4);
michael@0 202 });
michael@0 203
michael@0 204 do_register_cleanup(function async_cleanup_2() {
michael@0 205 let deferred = Promise.defer();
michael@0 206 do_execute_soon(deferred.resolve);
michael@0 207 return deferred.promise.then(function() {
michael@0 208 checkpoints.push(3);
michael@0 209 });
michael@0 210 });
michael@0 211
michael@0 212 do_register_cleanup(function sync_cleanup() {
michael@0 213 checkpoints.push(2);
michael@0 214 });
michael@0 215
michael@0 216 do_register_cleanup(function async_cleanup() {
michael@0 217 let deferred = Promise.defer();
michael@0 218 do_execute_soon(deferred.resolve);
michael@0 219 return deferred.promise.then(function() {
michael@0 220 checkpoints.push(1);
michael@0 221 });
michael@0 222 });
michael@0 223
michael@0 224 }
michael@0 225 '''
michael@0 226
michael@0 227
michael@0 228 class XPCShellTestsTests(unittest.TestCase):
michael@0 229 """
michael@0 230 Yes, these are unit tests for a unit test harness.
michael@0 231 """
michael@0 232 def setUp(self):
michael@0 233 self.log = StringIO()
michael@0 234 self.tempdir = tempfile.mkdtemp()
michael@0 235 self.x = XPCShellTests(log=self.log)
michael@0 236
michael@0 237 def tearDown(self):
michael@0 238 shutil.rmtree(self.tempdir)
michael@0 239
michael@0 240 def writeFile(self, name, contents):
michael@0 241 """
michael@0 242 Write |contents| to a file named |name| in the temp directory,
michael@0 243 and return the full path to the file.
michael@0 244 """
michael@0 245 fullpath = os.path.join(self.tempdir, name)
michael@0 246 with open(fullpath, "w") as f:
michael@0 247 f.write(contents)
michael@0 248 return fullpath
michael@0 249
michael@0 250 def writeManifest(self, tests):
michael@0 251 """
michael@0 252 Write an xpcshell.ini in the temp directory and set
michael@0 253 self.manifest to its pathname. |tests| is a list containing
michael@0 254 either strings (for test names), or tuples with a test name
michael@0 255 as the first element and manifest conditions as the following
michael@0 256 elements.
michael@0 257 """
michael@0 258 testlines = []
michael@0 259 for t in tests:
michael@0 260 testlines.append("[%s]" % (t if isinstance(t, basestring)
michael@0 261 else t[0]))
michael@0 262 if isinstance(t, tuple):
michael@0 263 testlines.extend(t[1:])
michael@0 264 self.manifest = self.writeFile("xpcshell.ini", """
michael@0 265 [DEFAULT]
michael@0 266 head =
michael@0 267 tail =
michael@0 268
michael@0 269 """ + "\n".join(testlines))
michael@0 270
michael@0 271 def assertTestResult(self, expected, shuffle=False, xunitFilename=None, verbose=False):
michael@0 272 """
michael@0 273 Assert that self.x.runTests with manifest=self.manifest
michael@0 274 returns |expected|.
michael@0 275 """
michael@0 276 self.assertEquals(expected,
michael@0 277 self.x.runTests(xpcshellBin,
michael@0 278 manifest=self.manifest,
michael@0 279 mozInfo=mozinfo.info,
michael@0 280 shuffle=shuffle,
michael@0 281 testsRootDir=self.tempdir,
michael@0 282 verbose=verbose,
michael@0 283 xunitFilename=xunitFilename,
michael@0 284 sequential=True),
michael@0 285 msg="""Tests should have %s, log:
michael@0 286 ========
michael@0 287 %s
michael@0 288 ========
michael@0 289 """ % ("passed" if expected else "failed", self.log.getvalue()))
michael@0 290
michael@0 291 def _assertLog(self, s, expected):
michael@0 292 l = self.log.getvalue()
michael@0 293 self.assertEqual(expected, s in l,
michael@0 294 msg="""Value %s %s in log:
michael@0 295 ========
michael@0 296 %s
michael@0 297 ========""" % (s, "expected" if expected else "not expected", l))
michael@0 298
michael@0 299 def assertInLog(self, s):
michael@0 300 """
michael@0 301 Assert that the string |s| is contained in self.log.
michael@0 302 """
michael@0 303 self._assertLog(s, True)
michael@0 304
michael@0 305 def assertNotInLog(self, s):
michael@0 306 """
michael@0 307 Assert that the string |s| is not contained in self.log.
michael@0 308 """
michael@0 309 self._assertLog(s, False)
michael@0 310
michael@0 311 def testPass(self):
michael@0 312 """
michael@0 313 Check that a simple test without any manifest conditions passes.
michael@0 314 """
michael@0 315 self.writeFile("test_basic.js", SIMPLE_PASSING_TEST)
michael@0 316 self.writeManifest(["test_basic.js"])
michael@0 317
michael@0 318 self.assertTestResult(True)
michael@0 319 self.assertEquals(1, self.x.testCount)
michael@0 320 self.assertEquals(1, self.x.passCount)
michael@0 321 self.assertEquals(0, self.x.failCount)
michael@0 322 self.assertEquals(0, self.x.todoCount)
michael@0 323 self.assertInLog("TEST-PASS")
michael@0 324 self.assertNotInLog("TEST-UNEXPECTED-FAIL")
michael@0 325
michael@0 326 def testFail(self):
michael@0 327 """
michael@0 328 Check that a simple failing test without any manifest conditions fails.
michael@0 329 """
michael@0 330 self.writeFile("test_basic.js", SIMPLE_FAILING_TEST)
michael@0 331 self.writeManifest(["test_basic.js"])
michael@0 332
michael@0 333 self.assertTestResult(False)
michael@0 334 self.assertEquals(1, self.x.testCount)
michael@0 335 self.assertEquals(0, self.x.passCount)
michael@0 336 self.assertEquals(1, self.x.failCount)
michael@0 337 self.assertEquals(0, self.x.todoCount)
michael@0 338 self.assertInLog("TEST-UNEXPECTED-FAIL")
michael@0 339 self.assertNotInLog("TEST-PASS")
michael@0 340
michael@0 341 @unittest.skipIf(build_obj.defines.get('MOZ_B2G'),
michael@0 342 'selftests with child processes fail on b2g desktop builds')
michael@0 343 def testChildPass(self):
michael@0 344 """
michael@0 345 Check that a simple test running in a child process passes.
michael@0 346 """
michael@0 347 self.writeFile("test_pass.js", SIMPLE_PASSING_TEST)
michael@0 348 self.writeFile("test_child_pass.js", CHILD_TEST_PASSING)
michael@0 349 self.writeManifest(["test_child_pass.js"])
michael@0 350
michael@0 351 self.assertTestResult(True, verbose=True)
michael@0 352 self.assertEquals(1, self.x.testCount)
michael@0 353 self.assertEquals(1, self.x.passCount)
michael@0 354 self.assertEquals(0, self.x.failCount)
michael@0 355 self.assertEquals(0, self.x.todoCount)
michael@0 356 self.assertInLog("TEST-PASS")
michael@0 357 self.assertInLog("CHILD-TEST-STARTED")
michael@0 358 self.assertInLog("CHILD-TEST-COMPLETED")
michael@0 359 self.assertNotInLog("TEST-UNEXPECTED-FAIL")
michael@0 360
michael@0 361
michael@0 362 @unittest.skipIf(build_obj.defines.get('MOZ_B2G'),
michael@0 363 'selftests with child processes fail on b2g desktop builds')
michael@0 364 def testChildFail(self):
michael@0 365 """
michael@0 366 Check that a simple failing test running in a child process fails.
michael@0 367 """
michael@0 368 self.writeFile("test_fail.js", SIMPLE_FAILING_TEST)
michael@0 369 self.writeFile("test_child_fail.js", CHILD_TEST_FAILING)
michael@0 370 self.writeManifest(["test_child_fail.js"])
michael@0 371
michael@0 372 self.assertTestResult(False)
michael@0 373 self.assertEquals(1, self.x.testCount)
michael@0 374 self.assertEquals(0, self.x.passCount)
michael@0 375 self.assertEquals(1, self.x.failCount)
michael@0 376 self.assertEquals(0, self.x.todoCount)
michael@0 377 self.assertInLog("TEST-UNEXPECTED-FAIL")
michael@0 378 self.assertInLog("CHILD-TEST-STARTED")
michael@0 379 self.assertInLog("CHILD-TEST-COMPLETED")
michael@0 380 self.assertNotInLog("TEST-PASS")
michael@0 381
michael@0 382 @unittest.skipIf(build_obj.defines.get('MOZ_B2G'),
michael@0 383 'selftests with child processes fail on b2g desktop builds')
michael@0 384 def testChildHang(self):
michael@0 385 """
michael@0 386 Check that incomplete output from a child process results in a
michael@0 387 test failure.
michael@0 388 """
michael@0 389 self.writeFile("test_pass.js", SIMPLE_PASSING_TEST)
michael@0 390 self.writeFile("test_child_hang.js", CHILD_TEST_HANG)
michael@0 391 self.writeManifest(["test_child_hang.js"])
michael@0 392
michael@0 393 self.assertTestResult(False)
michael@0 394 self.assertEquals(1, self.x.testCount)
michael@0 395 self.assertEquals(0, self.x.passCount)
michael@0 396 self.assertEquals(1, self.x.failCount)
michael@0 397 self.assertEquals(0, self.x.todoCount)
michael@0 398 self.assertInLog("TEST-UNEXPECTED-FAIL")
michael@0 399 self.assertInLog("CHILD-TEST-STARTED")
michael@0 400 self.assertNotInLog("CHILD-TEST-COMPLETED")
michael@0 401 self.assertNotInLog("TEST-PASS")
michael@0 402
michael@0 403 def testSyntaxError(self):
michael@0 404 """
michael@0 405 Check that running a test file containing a syntax error produces
michael@0 406 a test failure and expected output.
michael@0 407 """
michael@0 408 self.writeFile("test_syntax_error.js", '"')
michael@0 409 self.writeManifest(["test_syntax_error.js"])
michael@0 410
michael@0 411 self.assertTestResult(False, verbose=True)
michael@0 412 self.assertEquals(1, self.x.testCount)
michael@0 413 self.assertEquals(0, self.x.passCount)
michael@0 414 self.assertEquals(1, self.x.failCount)
michael@0 415 self.assertEquals(0, self.x.todoCount)
michael@0 416 self.assertInLog("TEST-UNEXPECTED-FAIL")
michael@0 417 self.assertNotInLog("TEST-PASS")
michael@0 418
michael@0 419 def testPassFail(self):
michael@0 420 """
michael@0 421 Check that running more than one test works.
michael@0 422 """
michael@0 423 self.writeFile("test_pass.js", SIMPLE_PASSING_TEST)
michael@0 424 self.writeFile("test_fail.js", SIMPLE_FAILING_TEST)
michael@0 425 self.writeManifest(["test_pass.js", "test_fail.js"])
michael@0 426
michael@0 427 self.assertTestResult(False)
michael@0 428 self.assertEquals(2, self.x.testCount)
michael@0 429 self.assertEquals(1, self.x.passCount)
michael@0 430 self.assertEquals(1, self.x.failCount)
michael@0 431 self.assertEquals(0, self.x.todoCount)
michael@0 432 self.assertInLog("TEST-PASS")
michael@0 433 self.assertInLog("TEST-UNEXPECTED-FAIL")
michael@0 434
michael@0 435 def testSkip(self):
michael@0 436 """
michael@0 437 Check that a simple failing test skipped in the manifest does
michael@0 438 not cause failure.
michael@0 439 """
michael@0 440 self.writeFile("test_basic.js", SIMPLE_FAILING_TEST)
michael@0 441 self.writeManifest([("test_basic.js", "skip-if = true")])
michael@0 442 self.assertTestResult(True)
michael@0 443 self.assertEquals(1, self.x.testCount)
michael@0 444 self.assertEquals(0, self.x.passCount)
michael@0 445 self.assertEquals(0, self.x.failCount)
michael@0 446 self.assertEquals(0, self.x.todoCount)
michael@0 447 self.assertNotInLog("TEST-UNEXPECTED-FAIL")
michael@0 448 self.assertNotInLog("TEST-PASS")
michael@0 449
michael@0 450 def testKnownFail(self):
michael@0 451 """
michael@0 452 Check that a simple failing test marked as known-fail in the manifest
michael@0 453 does not cause failure.
michael@0 454 """
michael@0 455 self.writeFile("test_basic.js", SIMPLE_FAILING_TEST)
michael@0 456 self.writeManifest([("test_basic.js", "fail-if = true")])
michael@0 457 self.assertTestResult(True)
michael@0 458 self.assertEquals(1, self.x.testCount)
michael@0 459 self.assertEquals(0, self.x.passCount)
michael@0 460 self.assertEquals(0, self.x.failCount)
michael@0 461 self.assertEquals(1, self.x.todoCount)
michael@0 462 self.assertInLog("TEST-KNOWN-FAIL")
michael@0 463 # This should be suppressed because the harness doesn't include
michael@0 464 # the full log from the xpcshell run when things pass.
michael@0 465 self.assertNotInLog("TEST-UNEXPECTED-FAIL")
michael@0 466 self.assertNotInLog("TEST-PASS")
michael@0 467
michael@0 468 def testUnexpectedPass(self):
michael@0 469 """
michael@0 470 Check that a simple failing test marked as known-fail in the manifest
michael@0 471 that passes causes an unexpected pass.
michael@0 472 """
michael@0 473 self.writeFile("test_basic.js", SIMPLE_PASSING_TEST)
michael@0 474 self.writeManifest([("test_basic.js", "fail-if = true")])
michael@0 475 self.assertTestResult(False)
michael@0 476 self.assertEquals(1, self.x.testCount)
michael@0 477 self.assertEquals(0, self.x.passCount)
michael@0 478 self.assertEquals(1, self.x.failCount)
michael@0 479 self.assertEquals(0, self.x.todoCount)
michael@0 480 # From the outer (Python) harness
michael@0 481 self.assertInLog("TEST-UNEXPECTED-PASS")
michael@0 482 self.assertNotInLog("TEST-KNOWN-FAIL")
michael@0 483 # From the inner (JS) harness
michael@0 484 self.assertInLog("TEST-PASS")
michael@0 485
michael@0 486 def testReturnNonzero(self):
michael@0 487 """
michael@0 488 Check that a test where xpcshell returns nonzero fails.
michael@0 489 """
michael@0 490 self.writeFile("test_error.js", "throw 'foo'")
michael@0 491 self.writeManifest(["test_error.js"])
michael@0 492
michael@0 493 self.assertTestResult(False)
michael@0 494 self.assertEquals(1, self.x.testCount)
michael@0 495 self.assertEquals(0, self.x.passCount)
michael@0 496 self.assertEquals(1, self.x.failCount)
michael@0 497 self.assertEquals(0, self.x.todoCount)
michael@0 498 self.assertInLog("TEST-UNEXPECTED-FAIL")
michael@0 499 self.assertNotInLog("TEST-PASS")
michael@0 500
michael@0 501 def testAddTestSimple(self):
michael@0 502 """
michael@0 503 Ensure simple add_test() works.
michael@0 504 """
michael@0 505 self.writeFile("test_add_test_simple.js", ADD_TEST_SIMPLE)
michael@0 506 self.writeManifest(["test_add_test_simple.js"])
michael@0 507
michael@0 508 self.assertTestResult(True)
michael@0 509 self.assertEquals(1, self.x.testCount)
michael@0 510 self.assertEquals(1, self.x.passCount)
michael@0 511 self.assertEquals(0, self.x.failCount)
michael@0 512
michael@0 513 def testAddTestFailing(self):
michael@0 514 """
michael@0 515 Ensure add_test() with a failing test is reported.
michael@0 516 """
michael@0 517 self.writeFile("test_add_test_failing.js", ADD_TEST_FAILING)
michael@0 518 self.writeManifest(["test_add_test_failing.js"])
michael@0 519
michael@0 520 self.assertTestResult(False)
michael@0 521 self.assertEquals(1, self.x.testCount)
michael@0 522 self.assertEquals(0, self.x.passCount)
michael@0 523 self.assertEquals(1, self.x.failCount)
michael@0 524
michael@0 525 def testAddTaskTestSingle(self):
michael@0 526 """
michael@0 527 Ensure add_test_task() with a single passing test works.
michael@0 528 """
michael@0 529 self.writeFile("test_add_task_simple.js", ADD_TASK_SINGLE)
michael@0 530 self.writeManifest(["test_add_task_simple.js"])
michael@0 531
michael@0 532 self.assertTestResult(True)
michael@0 533 self.assertEquals(1, self.x.testCount)
michael@0 534 self.assertEquals(1, self.x.passCount)
michael@0 535 self.assertEquals(0, self.x.failCount)
michael@0 536
michael@0 537 def testAddTaskTestMultiple(self):
michael@0 538 """
michael@0 539 Ensure multiple calls to add_test_task() work as expected.
michael@0 540 """
michael@0 541 self.writeFile("test_add_task_multiple.js",
michael@0 542 ADD_TASK_MULTIPLE)
michael@0 543 self.writeManifest(["test_add_task_multiple.js"])
michael@0 544
michael@0 545 self.assertTestResult(True)
michael@0 546 self.assertEquals(1, self.x.testCount)
michael@0 547 self.assertEquals(1, self.x.passCount)
michael@0 548 self.assertEquals(0, self.x.failCount)
michael@0 549
michael@0 550 def testAddTaskTestRejected(self):
michael@0 551 """
michael@0 552 Ensure rejected task reports as failure.
michael@0 553 """
michael@0 554 self.writeFile("test_add_task_rejected.js",
michael@0 555 ADD_TASK_REJECTED)
michael@0 556 self.writeManifest(["test_add_task_rejected.js"])
michael@0 557
michael@0 558 self.assertTestResult(False)
michael@0 559 self.assertEquals(1, self.x.testCount)
michael@0 560 self.assertEquals(0, self.x.passCount)
michael@0 561 self.assertEquals(1, self.x.failCount)
michael@0 562
michael@0 563 def testAddTaskTestFailureInside(self):
michael@0 564 """
michael@0 565 Ensure tests inside task are reported as failures.
michael@0 566 """
michael@0 567 self.writeFile("test_add_task_failure_inside.js",
michael@0 568 ADD_TASK_FAILURE_INSIDE)
michael@0 569 self.writeManifest(["test_add_task_failure_inside.js"])
michael@0 570
michael@0 571 self.assertTestResult(False)
michael@0 572 self.assertEquals(1, self.x.testCount)
michael@0 573 self.assertEquals(0, self.x.passCount)
michael@0 574 self.assertEquals(1, self.x.failCount)
michael@0 575
michael@0 576 def testAddTaskRunNextTest(self):
michael@0 577 """
michael@0 578 Calling run_next_test() from inside add_task() results in failure.
michael@0 579 """
michael@0 580 self.writeFile("test_add_task_run_next_test.js",
michael@0 581 ADD_TASK_RUN_NEXT_TEST)
michael@0 582 self.writeManifest(["test_add_task_run_next_test.js"])
michael@0 583
michael@0 584 self.assertTestResult(False)
michael@0 585 self.assertEquals(1, self.x.testCount)
michael@0 586 self.assertEquals(0, self.x.passCount)
michael@0 587 self.assertEquals(1, self.x.failCount)
michael@0 588
michael@0 589 def testMissingHeadFile(self):
michael@0 590 """
michael@0 591 Ensure that missing head file results in fatal error.
michael@0 592 """
michael@0 593 self.writeFile("test_basic.js", SIMPLE_PASSING_TEST)
michael@0 594 self.writeManifest([("test_basic.js", "head = missing.js")])
michael@0 595
michael@0 596 raised = False
michael@0 597
michael@0 598 try:
michael@0 599 # The actual return value is never checked because we raise.
michael@0 600 self.assertTestResult(True)
michael@0 601 except Exception, ex:
michael@0 602 raised = True
michael@0 603 self.assertEquals(ex.message[0:9], "head file")
michael@0 604
michael@0 605 self.assertTrue(raised)
michael@0 606
michael@0 607 def testMissingTailFile(self):
michael@0 608 """
michael@0 609 Ensure that missing tail file results in fatal error.
michael@0 610 """
michael@0 611 self.writeFile("test_basic.js", SIMPLE_PASSING_TEST)
michael@0 612 self.writeManifest([("test_basic.js", "tail = missing.js")])
michael@0 613
michael@0 614 raised = False
michael@0 615
michael@0 616 try:
michael@0 617 self.assertTestResult(True)
michael@0 618 except Exception, ex:
michael@0 619 raised = True
michael@0 620 self.assertEquals(ex.message[0:9], "tail file")
michael@0 621
michael@0 622 self.assertTrue(raised)
michael@0 623
michael@0 624 def testRandomExecution(self):
michael@0 625 """
michael@0 626 Check that random execution doesn't break.
michael@0 627 """
michael@0 628 manifest = []
michael@0 629 for i in range(0, 10):
michael@0 630 filename = "test_pass_%d.js" % i
michael@0 631 self.writeFile(filename, SIMPLE_PASSING_TEST)
michael@0 632 manifest.append(filename)
michael@0 633
michael@0 634 self.writeManifest(manifest)
michael@0 635 self.assertTestResult(True, shuffle=True)
michael@0 636 self.assertEquals(10, self.x.testCount)
michael@0 637 self.assertEquals(10, self.x.passCount)
michael@0 638
michael@0 639 def testXunitOutput(self):
michael@0 640 """
michael@0 641 Check that Xunit XML files are written.
michael@0 642 """
michael@0 643 self.writeFile("test_00.js", SIMPLE_PASSING_TEST)
michael@0 644 self.writeFile("test_01.js", SIMPLE_FAILING_TEST)
michael@0 645 self.writeFile("test_02.js", SIMPLE_PASSING_TEST)
michael@0 646
michael@0 647 manifest = [
michael@0 648 "test_00.js",
michael@0 649 "test_01.js",
michael@0 650 ("test_02.js", "skip-if = true")
michael@0 651 ]
michael@0 652
michael@0 653 self.writeManifest(manifest)
michael@0 654
michael@0 655 filename = os.path.join(self.tempdir, "xunit.xml")
michael@0 656
michael@0 657 self.assertTestResult(False, xunitFilename=filename)
michael@0 658
michael@0 659 self.assertTrue(os.path.exists(filename))
michael@0 660 self.assertTrue(os.path.getsize(filename) > 0)
michael@0 661
michael@0 662 tree = ElementTree()
michael@0 663 tree.parse(filename)
michael@0 664 suite = tree.getroot()
michael@0 665
michael@0 666 self.assertTrue(suite is not None)
michael@0 667 self.assertEqual(suite.get("tests"), "3")
michael@0 668 self.assertEqual(suite.get("failures"), "1")
michael@0 669 self.assertEqual(suite.get("skip"), "1")
michael@0 670
michael@0 671 testcases = suite.findall("testcase")
michael@0 672 self.assertEqual(len(testcases), 3)
michael@0 673
michael@0 674 for testcase in testcases:
michael@0 675 attributes = testcase.keys()
michael@0 676 self.assertTrue("classname" in attributes)
michael@0 677 self.assertTrue("name" in attributes)
michael@0 678 self.assertTrue("time" in attributes)
michael@0 679
michael@0 680 self.assertTrue(testcases[1].find("failure") is not None)
michael@0 681 self.assertTrue(testcases[2].find("skipped") is not None)
michael@0 682
michael@0 683 def testDoThrowString(self):
michael@0 684 """
michael@0 685 Check that do_throw produces reasonable messages when the
michael@0 686 input is a string instead of an object
michael@0 687 """
michael@0 688 self.writeFile("test_error.js", ADD_TEST_THROW_STRING)
michael@0 689 self.writeManifest(["test_error.js"])
michael@0 690
michael@0 691 self.assertTestResult(False)
michael@0 692 self.assertInLog("TEST-UNEXPECTED-FAIL")
michael@0 693 self.assertInLog("Passing a string to do_throw")
michael@0 694 self.assertNotInLog("TEST-PASS")
michael@0 695
michael@0 696 def testDoThrowForeignObject(self):
michael@0 697 """
michael@0 698 Check that do_throw produces reasonable messages when the
michael@0 699 input is a generic object with 'filename', 'message' and 'stack' attributes
michael@0 700 but 'object instanceof Error' returns false
michael@0 701 """
michael@0 702 self.writeFile("test_error.js", ADD_TEST_THROW_OBJECT)
michael@0 703 self.writeManifest(["test_error.js"])
michael@0 704
michael@0 705 self.assertTestResult(False)
michael@0 706 self.assertInLog("TEST-UNEXPECTED-FAIL")
michael@0 707 self.assertInLog("failure.js")
michael@0 708 self.assertInLog("Error object")
michael@0 709 self.assertInLog("ERROR STACK")
michael@0 710 self.assertNotInLog("TEST-PASS")
michael@0 711
michael@0 712 def testDoReportForeignObject(self):
michael@0 713 """
michael@0 714 Check that do_report_unexpected_exception produces reasonable messages when the
michael@0 715 input is a generic object with 'filename', 'message' and 'stack' attributes
michael@0 716 but 'object instanceof Error' returns false
michael@0 717 """
michael@0 718 self.writeFile("test_error.js", ADD_TEST_REPORT_OBJECT)
michael@0 719 self.writeManifest(["test_error.js"])
michael@0 720
michael@0 721 self.assertTestResult(False)
michael@0 722 self.assertInLog("TEST-UNEXPECTED-FAIL")
michael@0 723 self.assertInLog("failure.js")
michael@0 724 self.assertInLog("Error object")
michael@0 725 self.assertInLog("ERROR STACK")
michael@0 726 self.assertNotInLog("TEST-PASS")
michael@0 727
michael@0 728 def testDoReportRefError(self):
michael@0 729 """
michael@0 730 Check that do_report_unexpected_exception produces reasonable messages when the
michael@0 731 input is a JS-generated Error
michael@0 732 """
michael@0 733 self.writeFile("test_error.js", ADD_TEST_REPORT_REF_ERROR)
michael@0 734 self.writeManifest(["test_error.js"])
michael@0 735
michael@0 736 self.assertTestResult(False)
michael@0 737 self.assertInLog("TEST-UNEXPECTED-FAIL")
michael@0 738 self.assertInLog("test_error.js")
michael@0 739 self.assertInLog("obj.noSuchFunction is not a function")
michael@0 740 self.assertInLog("run_test@")
michael@0 741 self.assertNotInLog("TEST-PASS")
michael@0 742
michael@0 743 def testDoReportSyntaxError(self):
michael@0 744 """
michael@0 745 Check that attempting to load a test file containing a syntax error
michael@0 746 generates details of the error in the log
michael@0 747 """
michael@0 748 self.writeFile("test_error.js", LOAD_ERROR_SYNTAX_ERROR)
michael@0 749 self.writeManifest(["test_error.js"])
michael@0 750
michael@0 751 self.assertTestResult(False)
michael@0 752 self.assertInLog("TEST-UNEXPECTED-FAIL")
michael@0 753 self.assertInLog("test_error.js")
michael@0 754 self.assertInLog("test_error.js contains SyntaxError")
michael@0 755 self.assertInLog("Diagnostic: SyntaxError: missing formal parameter at")
michael@0 756 self.assertInLog("test_error.js:3")
michael@0 757 self.assertNotInLog("TEST-PASS")
michael@0 758
michael@0 759 def testDoReportNonSyntaxError(self):
michael@0 760 """
michael@0 761 Check that attempting to load a test file containing an error other
michael@0 762 than a syntax error generates details of the error in the log
michael@0 763 """
michael@0 764 self.writeFile("test_error.js", LOAD_ERROR_OTHER_ERROR)
michael@0 765 self.writeManifest(["test_error.js"])
michael@0 766
michael@0 767 self.assertTestResult(False)
michael@0 768 self.assertInLog("TEST-UNEXPECTED-FAIL")
michael@0 769 self.assertInLog("Diagnostic: TypeError: generator function run_test returns a value at")
michael@0 770 self.assertInLog("test_error.js:4")
michael@0 771 self.assertNotInLog("TEST-PASS")
michael@0 772
michael@0 773 def testAsyncCleanup(self):
michael@0 774 """
michael@0 775 Check that do_register_cleanup handles nicely cleanup tasks that
michael@0 776 return a promise
michael@0 777 """
michael@0 778 self.writeFile("test_asyncCleanup.js", ASYNC_CLEANUP)
michael@0 779 self.writeManifest(["test_asyncCleanup.js"])
michael@0 780 self.assertTestResult(False)
michael@0 781 self.assertInLog("\"1234\" == \"1234\"")
michael@0 782 self.assertInLog("At this stage, the test has succeeded")
michael@0 783 self.assertInLog("Throwing an error to force displaying the log")
michael@0 784
michael@0 785 if __name__ == "__main__":
michael@0 786 unittest.main()

mercurial