Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Unified Diff: client/testing/unittest/unittestsuite.dart

Issue 8418013: Huge internal clean-up of unittestsuite. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rename constant. Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: client/testing/unittest/unittestsuite.dart
diff --git a/client/testing/unittest/unittestsuite.dart b/client/testing/unittest/unittestsuite.dart
index 90d60ba75fdee4d6f82b0163ff271f5eed5e3224..5f03cc51f264c1e9d10a60a56c95f479c8163051 100644
--- a/client/testing/unittest/unittestsuite.dart
+++ b/client/testing/unittest/unittestsuite.dart
@@ -2,260 +2,39 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// TODO(rnystrom): This code is gradually moving from a Java/JUnit style to
-// something closer to JS/Jasmine. Eventually, the UnitTestSuite class can go
-// away completely (or become private to this library) and the only exposed API
-// will be group()/test()/expect(). Until then, both ways are supported, which
-// is why things look a bit weird in here.
-
-UnitTestSuite _currentSuite;
-
/**
* Description text of the current test group. If multiple groups are nested,
* this will contain all of their text concatenated.
*/
String _currentGroup = '';
-/** Base class for unit test suites run in a browser. */
-class UnitTestSuite {
-
- /** Tests executed in this suite. */
- List<TestCase> _tests;
-
- /** Whether this suite is run within dartium layout tests. */
- bool _isLayoutTest;
-
- /** Current test being executed. */
- int _currentTest;
-
- /** Total number of callbacks that have been executed in the current test. */
- int _callbacksCalled;
-
- /**
- * Whether an undetected error occurred while running the last test. This
- * errors are commonly caused by DOM callbacks that were not guarded in a
- * try-catch block.
- */
- bool _uncaughtError;
- EventListener _onErrorClosure;
-
- bool _queuedToRun = false;
-
- /** Whether a test is currently being executed by [runTest]. */
- bool _testIsRunning = false;
-
- // TODO(sigmund): remove isLayoutTest argument after converting all DOM tests
- // to use the named constructor below.
- // TODO(vsm): remove the ignoredWindow parameter once all tests are fixed.
- UnitTestSuite([var ignoredWindow = null, bool isLayoutTest = false])
- : _isLayoutTest = isLayoutTest,
- _tests = new List<TestCase>(),
- _currentTest = 0,
- _callbacksCalled = 0 {
- _onErrorClosure = (e) { _onError(e); };
- if (_currentSuite != null) {
- throw 'Cannot have two UnitTestSuites in flight at the same time.';
- }
- _currentSuite = this;
-
- // Immediately queue the suite up. It will run after a timeout (i.e. after
- // main() has returned).
- run();
- }
-
- // TODO(jacobr): remove the ignoredWindow parameter once all tests are fixed.
- UnitTestSuite.forLayoutTests([var ignoredWindow = null]) : this(null, true);
-
- /** Starts running the testsuite. */
- void run() {
- if (_queuedToRun) {
- return;
- }
-
- _queuedToRun = true;
-
- listener(e) {
- _currentGroup = '';
- setUpTestSuite();
- runTests();
- };
-
- try {
- window.dynamic.on.contentLoaded.add(listener);
- } catch(var e) {
- // TODO(jacobr): remove this horrible hack to work around dartc bugs.
- window.dynamic.addEventListener("DOMContentLoaded", listener, false);
- }
- }
-
- /** Subclasses should override this method to register tests. */
- void setUpTestSuite() {}
-
- /** Enqueues a synchronous test. */
- void addTest(TestFunction body) {
- test(null, body);
- }
-
- /** Enqueues an asynchronous test that waits for [callbacks] callbacks. */
- void addAsyncTest(TestFunction body, int callbacks) {
- asyncTest(null, callbacks, body);
- }
-
- /** Runs all queued tests, one at a time. */
- void runTests() {
- window.postMessage('unittest-suite-start', '*');
- window.setTimeout(() {
- assert (_currentTest == 0);
- // Listen for uncaught errors (see [_uncaughtError]).
- // TODO(jacobr): remove this horrible hack when dartc bugs are fixed.
- try {
- window.dynamic.on.error.add(_onErrorClosure);
- } catch(var e) {
- window.dynamic.onerror = _onErrorClosure;
- }
- _nextBatch();
- }, 0);
- }
-
- void _onError(e) {
- if (_currentTest < _tests.length) {
- final testCase = _tests[_currentTest];
- // TODO(vsm): figure out how to expose the stack trace here
- // Currently e.message works in dartium, but not in dartc.
- testCase.recordError('(DOM callback has errors) Caught ${e}', '');
- _uncaughtError = true;
- if (testCase.callbacks > 0) {
- _currentTest++;
- _nextBatch();
- }
- }
- }
-
- /** Called by subclasses to indicate that an asynchronous test completed. */
- void callbackDone() {
- _callbacksCalled++;
- final testCase = _tests[_currentTest];
- if (testCase.callbacks == 0) {
- testCase.recordError(
- "Can't call callbackDone() on a synchronous test", '');
- _uncaughtError = true;
- } else if (_callbacksCalled > testCase.callbacks) {
- final expected = testCase.callbacks;
- testCase.recordError(
- 'More calls to callbackDone() than expected. '
- + 'Actual: ${_callbacksCalled}, expected: ${expected}', '');
- _uncaughtError = true;
- } else if (_callbacksCalled == testCase.callbacks && !_testIsRunning) {
- testCase.recordSuccess();
- _currentTest++;
- _nextBatch();
- }
- }
+/** Tests executed in this suite. */
+List<TestCase> _tests;
- /**
- * Runs a batch of tests, yielding whenever an asynchronous test starts
- * running. Tests will resume executing when such asynchronous test calls
- * [done] or if it fails with an exception.
- */
- void _nextBatch() {
- while (_currentTest < _tests.length) {
- final testCase = _tests[_currentTest];
- runTest(testCase);
- if (!testCase.isComplete() && testCase.callbacks > 0) {
- return;
- }
- _currentTest++;
- }
- _completeTests();
- }
+/** Whether this is run within dartium layout tests. */
+bool _isLayoutTest = false;
- /** Runs a single test. */
- void runTest(TestCase testCase) {
- // TODO(sigmund): remove this declaration once dartc supports trapping error
- // traces.
- var trace = '';
- _uncaughtError = false;
- _callbacksCalled = 0;
- try {
- _testIsRunning = true;
- (testCase.test)();
- if (!_uncaughtError) {
- if (testCase.callbacks == _callbacksCalled) {
- testCase.recordSuccess();
- }
- }
- } catch (ExpectException e, var trace) {
- if (!_uncaughtError) {
- testCase.recordFail(e.message, trace.toString());
- }
- } catch (var e, var trace) {
- if (!_uncaughtError) {
- testCase.recordError('Caught ${e}', trace.toString());
- }
- } finally {
- _testIsRunning = false;
- }
- }
+/** Current test being executed. */
+int _currentTest = 0;
- /** Publish results on the page and notify controller. */
- void _completeTests() {
- try {
- window.dynamic.on.error.remove(_onErrorClosure);
- } catch (var e) {
- // TODO(jacobr): remove this horrible hack to work around dartc bugs.
- window.dynamic.onerror = null;
- }
+/** Total number of callbacks that have been executed in the current test. */
+int _callbacksCalled = 0;
- // This suite is done now, so discard it.
- _currentSuite = null;
+// TODO(rnystrom): Get rid of this if we get canonical closures for methods.
+EventListener _onErrorClosure;
- int testsFailed = 0;
- int testsErrors = 0;
- int testsPassed = 0;
-
- for (TestCase t in _tests) {
- if (t.success) {
- testsPassed++;
- }
- if (t.fail) {
- testsFailed++;
- }
- if (t.error) {
- testsErrors++;
- }
- }
+final _UNINITIALIZED = 0;
+final _READY = 1;
+final _RUNNING_TEST = 2;
- if (_isLayoutTest && testsPassed == _tests.length) {
- document.body.innerHTML = "PASS";
- } else {
- StringBuffer newBody = new StringBuffer();
- newBody.add("<table class='unittest-table'><tbody>");
- newBody.add(testsPassed == _tests.length
- ? "<tr><td colspan='3' class='unittest-pass'>PASS</td></tr>"
- : "<tr><td colspan='3' class='unittest-fail'>FAIL</td></tr>");
-
- for (TestCase t in _tests) {
- newBody.add(t.message);
- }
+/**
+ * Whether an undetected error occurred while running the last test. These
+ * errors are commonly caused by DOM callbacks that were not guarded in a
+ * try-catch block.
+ */
+final _UNCAUGHT_ERROR = 3;
- if (testsPassed == _tests.length) {
- newBody.add("<tr><td colspan='3' class='unittest-pass'>All "
- + testsPassed + " tests passed</td></tr>");
- } else {
- newBody.add("""
- <tr><td colspan='3'>Total
- <span class='unittest-pass'>${testsPassed} passed</span>,
- <span class='unittest-fail'>${testsFailed} failed</span>
- <span class='unittest-error'>${testsErrors} errors</span>
- </td></tr>""");
- }
- newBody.add("</tbody></table>");
- document.body.innerHTML = newBody.toString();
- }
-
- window.dynamic/*TODO(5389254)*/.postMessage('unittest-suite-done', '*');
- }
-}
+int _state = _UNINITIALIZED;
/** Creates an expectation for the given value. */
Expectation expect(value) => new Expectation(value);
@@ -277,10 +56,9 @@ void expectThrow(function) {
* calls.
*/
void test(String spec, TestFunction body) {
- _ensureActiveSuite();
+ _ensureInitialized();
- _currentSuite._tests.add(new TestCase(
- _currentSuite._tests.length + 1, _fullSpec(spec), body, 0));
+ _tests.add(new TestCase(_tests.length + 1, _fullSpec(spec), body, 0));
}
/**
@@ -289,11 +67,11 @@ void test(String spec, TestFunction body) {
* calls.
*/
void asyncTest(String spec, int callbacks, TestFunction body) {
- _ensureActiveSuite();
+ _ensureInitialized();
final testCase = new TestCase(
- _currentSuite._tests.length + 1, _fullSpec(spec), body, callbacks);
- _currentSuite._tests.add(testCase);
+ _tests.length + 1, _fullSpec(spec), body, callbacks);
+ _tests.add(testCase);
if (callbacks < 1) {
testCase.recordError(
@@ -306,7 +84,7 @@ void asyncTest(String spec, int callbacks, TestFunction body) {
* body of the function passed to this will inherit this group's description.
*/
void group(String description, void body()) {
- _ensureActiveSuite();
+ _ensureInitialized();
// Concatenate the new group.
final oldGroup = _currentGroup;
@@ -326,16 +104,160 @@ void group(String description, void body()) {
}
}
+/** Called by subclasses to indicate that an asynchronous test completed. */
void callbackDone() {
- if (_currentSuite == null) {
- throw 'There is no currently-running test suite.';
+ _callbacksCalled++;
+ final testCase = _tests[_currentTest];
+ if (testCase.callbacks == 0) {
+ testCase.recordError(
+ "Can't call callbackDone() on a synchronous test", '');
+ _state = _UNCAUGHT_ERROR;
+ } else if (_callbacksCalled > testCase.callbacks) {
+ final expected = testCase.callbacks;
+ testCase.recordError(
+ 'More calls to callbackDone() than expected. '
+ + 'Actual: ${_callbacksCalled}, expected: ${expected}', '');
+ _state = _UNCAUGHT_ERROR;
+ } else if ((_callbacksCalled == testCase.callbacks) &&
+ (_state != _RUNNING_TEST)) {
+ testCase.recordSuccess();
+ _currentTest++;
+ _nextBatch();
}
- _currentSuite.callbackDone();
}
void forLayoutTests() {
- _ensureActiveSuite();
- _currentSuite._isLayoutTest = true;
+ _isLayoutTest = true;
+}
+
+/** Runs all queued tests, one at a time. */
+_runTests() {
+ window.postMessage('unittest-suite-start', '*');
+ window.setTimeout(() {
+ assert (_currentTest == 0);
+ // Listen for uncaught errors.
+ try {
+ window.on.error.add(_onErrorClosure);
+ } catch(var e) {
+ // TODO(jacobr): remove this horrible hack when dartc bugs are fixed.
+ window.dynamic.onerror = _onErrorClosure;
+ }
+ _nextBatch();
+ }, 0);
+}
+
+/** Runs a single test. */
+_runTest(TestCase testCase) {
+ try {
+ // TODO(sigmund): remove this declaration once dartc supports trapping error
+ // traces.
+ var trace = '';
+ _callbacksCalled = 0;
+ _state = _RUNNING_TEST;
+
+ testCase.test();
+
+ if (_state != _UNCAUGHT_ERROR) {
+ if (testCase.callbacks == _callbacksCalled) {
+ testCase.recordSuccess();
+ }
+ }
+ } catch (ExpectException e, var trace) {
+ if (_state != _UNCAUGHT_ERROR) {
+ testCase.recordFail(e.message, trace.toString());
+ }
+ } catch (var e, var trace) {
+ if (_state != _UNCAUGHT_ERROR) {
+ testCase.recordError('Caught ${e}', trace.toString());
+ }
+ } finally {
+ _state = _READY;
+ }
+}
+
+/**
+ * Runs a batch of tests, yielding whenever an asynchronous test starts
+ * running. Tests will resume executing when such asynchronous test calls
+ * [done] or if it fails with an exception.
+ */
+_nextBatch() {
+ while (_currentTest < _tests.length) {
+ final testCase = _tests[_currentTest];
+
+ _runTest(testCase);
+
+ if (!testCase.isComplete && testCase.callbacks > 0) return;
+
+ _currentTest++;
+ }
+
+ _completeTests();
+}
+
+/** Publish results on the page and notify controller. */
+_completeTests() {
+ try {
+ window.on.error.remove(_onErrorClosure);
+ } catch (var e) {
+ // TODO(jacobr): remove this horrible hack to work around dartc bugs.
+ window.dynamic.onerror = null;
+ }
+
+ _state = _UNINITIALIZED;
+
+ int testsFailed = 0;
+ int testsErrors = 0;
+ int testsPassed = 0;
+
+ for (TestCase t in _tests) {
+ if (t.success) testsPassed++;
+ if (t.fail) testsFailed++;
+ if (t.error) testsErrors++;
+ }
+
+ if (_isLayoutTest && testsPassed == _tests.length) {
+ document.body.innerHTML = "PASS";
+ } else {
+ var newBody = new StringBuffer();
+ newBody.add("<table class='unittest-table'><tbody>");
+ newBody.add(testsPassed == _tests.length
+ ? "<tr><td colspan='3' class='unittest-pass'>PASS</td></tr>"
+ : "<tr><td colspan='3' class='unittest-fail'>FAIL</td></tr>");
+
+ for (final test in _tests) {
+ newBody.add(test.message);
+ }
+
+ if (testsPassed == _tests.length) {
+ newBody.add("<tr><td colspan='3' class='unittest-pass'>All "
+ + testsPassed + " tests passed</td></tr>");
+ } else {
+ newBody.add("""
+ <tr><td colspan='3'>Total
+ <span class='unittest-pass'>${testsPassed} passed</span>,
+ <span class='unittest-fail'>${testsFailed} failed</span>
+ <span class='unittest-error'>${testsErrors} errors</span>
+ </td></tr>""");
+ }
+ newBody.add("</tbody></table>");
+ document.body.innerHTML = newBody.toString();
+ }
+
+ window.dynamic/*TODO(5389254)*/.postMessage('unittest-suite-done', '*');
+}
+
+void _onError(e) {
+ if (_currentTest < _tests.length) {
+ final testCase = _tests[_currentTest];
+ // TODO(vsm): figure out how to expose the stack trace here
+ // Currently e.message works in dartium, but not in dartc.
+ testCase.recordError('(DOM callback has errors) Caught ${e}', '');
+ _state = _UNCAUGHT_ERROR;
+ if (testCase.callbacks > 0) {
+ _currentTest++;
+ _nextBatch();
+ }
+ }
}
String _fullSpec(String spec) {
@@ -344,15 +266,29 @@ String _fullSpec(String spec) {
}
/**
- * Lazily creates a UnitTestSuite if there isn't already an active one. Returns
- * whether or not one was created.
+ * Lazily initializes the test library if not already initialized.
*/
-_ensureActiveSuite() {
- if (_currentSuite != null) {
- return;
+_ensureInitialized() {
+ if (_state != _UNINITIALIZED) return;
+
+ _tests = <TestCase>[];
+ _onErrorClosure = (e) { _onError(e); };
+
+ // Immediately queue the suite up. It will run after a timeout (i.e. after
+ // main() has returned).
+ listener(e) {
+ _currentGroup = '';
+ _runTests();
+ };
+
+ try {
+ window.dynamic.on.contentLoaded.add(listener);
+ } catch(var e) {
+ // TODO(jacobr): remove this horrible hack to work around dartc bugs.
+ window.dynamic.addEventListener("DOMContentLoaded", listener, false);
}
- _currentSuite = new UnitTestSuite();
+ _state = _READY;
}
/**
@@ -443,53 +379,44 @@ class TestCase {
: success = false,
fail = false,
error = false {
- message = """<tr>
+ message = '''<tr>
<td>${id}</td>
- <td class='unittest-error'>NO STATUS</td>
+ <td class="unittest-error">NO STATUS</td>
<td>Test did not complete</td>
- </tr>""";
+ </tr>''';
}
- bool isComplete() => success || fail || error;
+ bool get isComplete() => success || fail || error;
void recordSuccess() {
- message = "<tr><td>${id}</td><td class='unittest-pass'>PASS</td></tr>";
+ _setMessage('pass', '', null);
success = true;
}
void recordError(String msg, String stackTrace) {
- message = """
- <tr>
- <td>${id}</td>
- <td class='unittest-error'>ERROR</td>
- <td>${msg}</td>
- </tr>""";
- if (stackTrace != null) {
- message +=
- "<tr><td></td><td colspan='2'><pre>${stackTrace}</pre></td></tr>";
- }
+ _setMessage('error', msg, stackTrace);
error = true;
}
void recordFail(String msg, String stackTrace) {
- // Include the spec description if we have one.
- // TODO(rnystrom): When all of our tests are using group() and test(), we
- // can assume description will be non-null and eliminate this check.
- if (description != null) {
- msg = 'Expectation: $description. $msg';
- }
+ _setMessage('fail', msg, stackTrace);
+ fail = true;
+ }
- message = """
+ void _setMessage(String type, String msg, String stackTrace) {
+ message =
+ '''
<tr>
<td>${id}</td>
- <td class='unittest-fail'>FAIL</td>
- <td>${msg}</td>
- </tr>""";
+ <td class="unittest-$type">${type.toUpperCase()}</td>
+ <td>Expectation: $description. $msg</td>
+ </tr>
+ ''';
+
if (stackTrace != null) {
message +=
- "<tr><td></td><td colspan='2'><pre>${stackTrace}</pre></td></tr>";
+ '<tr><td></td><td colspan="2"><pre>${stackTrace}</pre></td></tr>';
}
- fail = true;
}
}
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698