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

Side by Side Diff: lib/src/internal_test_case.dart

Issue 869043002: Clean up unittest a bunch. (Closed) Base URL: git@github.com:dart-lang/unittest@master
Patch Set: Code review changes Created 5 years, 10 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 unified diff | Download patch
« no previous file with comments | « lib/src/group_context.dart ('k') | lib/src/simple_configuration.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 library unittest.internal_test_case;
6
7 import 'dart:async';
8
9 import '../unittest.dart';
10 import 'test_environment.dart';
11 import 'utils.dart';
12
13 /// An implementation of [TestCase] that exposes internal properties for other
14 /// unittest use.
15 class InternalTestCase implements TestCase {
16 final int id;
17 final String description;
18
19 /// The setup function to call before the test, if any.
20 Function _setUp;
21
22 /// The teardown function to call after the test, if any.
23 Function _tearDown;
24
25 /// The body of the test case.
26 TestFunction _testFunction;
27
28 /// Remaining number of callback functions that must reach a 'done' state
29 /// before the test completes.
30 int callbackFunctionsOutstanding = 0;
31
32 /// The error or failure message for the tests.
33 ///
34 /// Initially an empty string.
35 String message = '';
36
37 /// The result of the test case.
38 ///
39 /// If the test case has is completed, this will be one of [PASS], [FAIL], or
40 /// [ERROR]. Otherwise, it will be `null`.
41 String result;
42
43 /// Returns whether this test case passed.
44 bool get passed => result == PASS;
45
46 /// The stack trace for the error that caused this test case to fail, or
47 /// `null` if it succeeded.
48 StackTrace stackTrace;
49
50 /// The name of the group within which this test is running.
51 final String currentGroup;
52
53 /// The time the test case started running.
54 ///
55 /// `null` if the test hasn't yet begun running.
56 DateTime get startTime => _startTime;
57 DateTime _startTime;
58
59 /// The amount of time the test case took.
60 ///
61 /// `null` if the test hasn't finished running.
62 Duration get runningTime => _runningTime;
63 Duration _runningTime;
64
65 /// Whether this test is enabled.
66 ///
67 /// Disabled tests won't be run.
68 bool enabled = true;
69
70 /// A completer that will complete when the test is finished.
71 ///
72 /// This is only non-`null` when outstanding callbacks exist.
73 Completer _testComplete;
74
75 /// Whether this test case has finished running.
76 bool get isComplete => !enabled || result != null;
77
78 InternalTestCase(this.id, this.description, this._testFunction)
79 : currentGroup = environment.currentContext.fullName,
80 _setUp = environment.currentContext.testSetUp,
81 _tearDown = environment.currentContext.testTearDown;
82
83 /// A function that returns another function to handle errors from [Future]s.
84 ///
85 /// [stage] is a string description of the stage of testing that failed.
86 Function _errorHandler(String stage) => (e, stack) {
87 if (stack == null && e is Error) {
88 stack = e.stackTrace;
89 }
90 if (result == null || result == PASS) {
91 if (e is TestFailure) {
92 fail("$e", stack);
93 } else {
94 error("$stage failed: Caught $e", stack);
95 }
96 }
97 };
98
99 /// Performs any associated [_setUp] function and runs the test.
100 ///
101 /// Returns a [Future] that can be used to schedule the next test. If the test
102 /// runs to completion synchronously, or is disabled, null is returned, to
103 /// tell unittest to schedule the next test immediately.
104 Future run() {
105 if (!enabled) return new Future.value();
106
107 result = stackTrace = null;
108 message = '';
109
110 // Avoid calling [new Future] to avoid issue 11911.
111 return new Future.value().then((_) {
112 if (_setUp != null) return _setUp();
113 }).catchError(_errorHandler('Setup')).then((_) {
114 // Skip the test if setup failed.
115 if (result != null) return new Future.value();
116 config.onTestStart(this);
117 _startTime = new DateTime.now();
118 _runningTime = null;
119 callbackFunctionsOutstanding++;
120 var testReturn = _testFunction();
121 // If _testFunction() returned a future, we want to wait for it like we
122 // would a callback, so if a failure occurs while waiting, we can abort.
123 if (testReturn is Future) {
124 callbackFunctionsOutstanding++;
125 testReturn.catchError(_errorHandler('Test'))
126 .whenComplete(markCallbackComplete);
127 }
128 }).catchError(_errorHandler('Test')).then((_) {
129 markCallbackComplete();
130 if (result == null) {
131 // Outstanding callbacks exist; we need to return a Future.
132 _testComplete = new Completer();
133 return _testComplete.future.whenComplete(() {
134 if (_tearDown != null) {
135 return _tearDown();
136 }
137 }).catchError(_errorHandler('Teardown'));
138 } else if (_tearDown != null) {
139 return _tearDown();
140 }
141 }).catchError(_errorHandler('Teardown')).whenComplete(() {
142 _setUp = null;
143 _tearDown = null;
144 _testFunction = null;
145 });
146 }
147
148 /// Marks the test as having completed with [testResult], which should be one
149 /// of [PASS], [FAIL], or [ERROR].
150 void _complete(String testResult, [String messageText = '',
151 StackTrace stack]) {
152 if (runningTime == null) {
153 // The startTime can be `null` if an error happened during setup. In this
154 // case we simply report a running time of 0.
155 if (startTime != null) {
156 _runningTime = new DateTime.now().difference(startTime);
157 } else {
158 _runningTime = const Duration(seconds: 0);
159 }
160 }
161 _setResult(testResult, messageText, stack);
162 if (_testComplete != null) {
163 var t = _testComplete;
164 _testComplete = null;
165 t.complete(this);
166 }
167 }
168
169 // Sets [this]'s fields to reflect the test result, and notifies the current
170 // configuration that the test has completed.
171 //
172 // Returns true if this is the first time the result has been set.
173 void _setResult(String testResult, String messageText, StackTrace stack) {
174 message = messageText;
175 stackTrace = getTrace(stack, formatStacks, filterStacks);
176 if (stackTrace == null) stackTrace = stack;
177 if (result == null) {
178 result = testResult;
179 config.onTestResult(this);
180 } else {
181 result = testResult;
182 config.onTestResultChanged(this);
183 }
184 }
185
186 /// Marks the test as having passed.
187 void pass() {
188 _complete(PASS);
189 }
190
191 void registerException(error, [StackTrace stackTrace]) {
192 var message = error is TestFailure ? error.message : 'Caught $error';
193 if (result == null) {
194 fail(message, stackTrace);
195 } else {
196 error(message, stackTrace);
197 }
198 }
199
200 /// Marks the test as having failed.
201 void fail(String messageText, [StackTrace stack]) {
202 if (result != null) {
203 var newMessage = result == PASS
204 ? 'Test failed after initially passing: $messageText'
205 : 'Test failed more than once: $messageText';
206 // TODO(gram): Should we combine the stack with the old one?
207 _complete(ERROR, newMessage, stack);
208 } else {
209 _complete(FAIL, messageText, stack);
210 }
211 }
212
213 /// Marks the test as having had an unexpected error.
214 void error(String messageText, [StackTrace stack]) {
215 _complete(ERROR, messageText, stack);
216 }
217
218 /// Indicates that an asynchronous callback has completed, and marks the test
219 /// as passing if all outstanding callbacks are complete.
220 void markCallbackComplete() {
221 callbackFunctionsOutstanding--;
222 if (callbackFunctionsOutstanding == 0 && !isComplete) pass();
223 }
224
225 String toString() => result != null ? "$description: $result" : description;
226 }
227
OLDNEW
« no previous file with comments | « lib/src/group_context.dart ('k') | lib/src/simple_configuration.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698