| Index: mojo/public/dart/third_party/unittest/lib/src/internal_test_case.dart | 
| diff --git a/mojo/public/dart/third_party/unittest/lib/src/internal_test_case.dart b/mojo/public/dart/third_party/unittest/lib/src/internal_test_case.dart | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..9763666172bc4ee788d14fd5370b5546b9384409 | 
| --- /dev/null | 
| +++ b/mojo/public/dart/third_party/unittest/lib/src/internal_test_case.dart | 
| @@ -0,0 +1,227 @@ | 
| +// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file | 
| +// 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. | 
| + | 
| +library unittest.internal_test_case; | 
| + | 
| +import 'dart:async'; | 
| + | 
| +import '../unittest.dart'; | 
| +import 'test_environment.dart'; | 
| +import 'utils.dart'; | 
| + | 
| +/// An implementation of [TestCase] that exposes internal properties for other | 
| +/// unittest use. | 
| +class InternalTestCase implements TestCase { | 
| +  final int id; | 
| +  final String description; | 
| + | 
| +  /// The setup function to call before the test, if any. | 
| +  Function _setUp; | 
| + | 
| +  /// The teardown function to call after the test, if any. | 
| +  Function _tearDown; | 
| + | 
| +  /// The body of the test case. | 
| +  TestFunction _testFunction; | 
| + | 
| +  /// Remaining number of callback functions that must reach a 'done' state | 
| +  /// before the test completes. | 
| +  int callbackFunctionsOutstanding = 0; | 
| + | 
| +  /// The error or failure message for the tests. | 
| +  /// | 
| +  /// Initially an empty string. | 
| +  String message = ''; | 
| + | 
| +  /// The result of the test case. | 
| +  /// | 
| +  /// If the test case has is completed, this will be one of [PASS], [FAIL], or | 
| +  /// [ERROR]. Otherwise, it will be `null`. | 
| +  String result; | 
| + | 
| +  /// Returns whether this test case passed. | 
| +  bool get passed => result == PASS; | 
| + | 
| +  /// The stack trace for the error that caused this test case to fail, or | 
| +  /// `null` if it succeeded. | 
| +  StackTrace stackTrace; | 
| + | 
| +  /// The name of the group within which this test is running. | 
| +  final String currentGroup; | 
| + | 
| +  /// The time the test case started running. | 
| +  /// | 
| +  /// `null` if the test hasn't yet begun running. | 
| +  DateTime get startTime => _startTime; | 
| +  DateTime _startTime; | 
| + | 
| +  /// The amount of time the test case took. | 
| +  /// | 
| +  /// `null` if the test hasn't finished running. | 
| +  Duration get runningTime => _runningTime; | 
| +  Duration _runningTime; | 
| + | 
| +  /// Whether this test is enabled. | 
| +  /// | 
| +  /// Disabled tests won't be run. | 
| +  bool enabled = true; | 
| + | 
| +  /// A completer that will complete when the test is finished. | 
| +  /// | 
| +  /// This is only non-`null` when outstanding callbacks exist. | 
| +  Completer _testComplete; | 
| + | 
| +  /// Whether this test case has finished running. | 
| +  bool get isComplete => !enabled || result != null; | 
| + | 
| +  InternalTestCase(this.id, this.description, this._testFunction) | 
| +      : currentGroup = environment.currentContext.fullName, | 
| +        _setUp = environment.currentContext.testSetUp, | 
| +        _tearDown = environment.currentContext.testTearDown; | 
| + | 
| +  /// A function that returns another function to handle errors from [Future]s. | 
| +  /// | 
| +  /// [stage] is a string description of the stage of testing that failed. | 
| +  Function _errorHandler(String stage) => (e, stack) { | 
| +    if (stack == null && e is Error) { | 
| +      stack = e.stackTrace; | 
| +    } | 
| +    if (result == null || result == PASS) { | 
| +      if (e is TestFailure) { | 
| +        fail("$e", stack); | 
| +      } else { | 
| +        error("$stage failed: Caught $e", stack); | 
| +      } | 
| +    } | 
| +  }; | 
| + | 
| +  /// Performs any associated [_setUp] function and runs the test. | 
| +  /// | 
| +  /// Returns a [Future] that can be used to schedule the next test. If the test | 
| +  /// runs to completion synchronously, or is disabled, null is returned, to | 
| +  /// tell unittest to schedule the next test immediately. | 
| +  Future run() { | 
| +    if (!enabled) return new Future.value(); | 
| + | 
| +    result = stackTrace = null; | 
| +    message = ''; | 
| + | 
| +    // Avoid calling [new Future] to avoid issue 11911. | 
| +    return new Future.value().then((_) { | 
| +      if (_setUp != null) return _setUp(); | 
| +    }).catchError(_errorHandler('Setup')).then((_) { | 
| +      // Skip the test if setup failed. | 
| +      if (result != null) return new Future.value(); | 
| +      config.onTestStart(this); | 
| +      _startTime = new DateTime.now(); | 
| +      _runningTime = null; | 
| +      callbackFunctionsOutstanding++; | 
| +      var testReturn = _testFunction(); | 
| +      // If _testFunction() returned a future, we want to wait for it like we | 
| +      // would a callback, so if a failure occurs while waiting, we can abort. | 
| +      if (testReturn is Future) { | 
| +        callbackFunctionsOutstanding++; | 
| +        testReturn | 
| +            .catchError(_errorHandler('Test')) | 
| +            .whenComplete(markCallbackComplete); | 
| +      } | 
| +    }).catchError(_errorHandler('Test')).then((_) { | 
| +      markCallbackComplete(); | 
| +      if (result == null) { | 
| +        // Outstanding callbacks exist; we need to return a Future. | 
| +        _testComplete = new Completer(); | 
| +        return _testComplete.future.whenComplete(() { | 
| +          if (_tearDown != null) { | 
| +            return _tearDown(); | 
| +          } | 
| +        }).catchError(_errorHandler('Teardown')); | 
| +      } else if (_tearDown != null) { | 
| +        return _tearDown(); | 
| +      } | 
| +    }).catchError(_errorHandler('Teardown')).whenComplete(() { | 
| +      _setUp = null; | 
| +      _tearDown = null; | 
| +      _testFunction = null; | 
| +    }); | 
| +  } | 
| + | 
| +  /// Marks the test as having completed with [testResult], which should be one | 
| +  /// of [PASS], [FAIL], or [ERROR]. | 
| +  void _complete(String testResult, | 
| +      [String messageText = '', StackTrace stack]) { | 
| +    if (runningTime == null) { | 
| +      // The startTime can be `null` if an error happened during setup. In this | 
| +      // case we simply report a running time of 0. | 
| +      if (startTime != null) { | 
| +        _runningTime = new DateTime.now().difference(startTime); | 
| +      } else { | 
| +        _runningTime = const Duration(seconds: 0); | 
| +      } | 
| +    } | 
| +    _setResult(testResult, messageText, stack); | 
| +    if (_testComplete != null) { | 
| +      var t = _testComplete; | 
| +      _testComplete = null; | 
| +      t.complete(this); | 
| +    } | 
| +  } | 
| + | 
| +  // Sets [this]'s fields to reflect the test result, and notifies the current | 
| +  // configuration that the test has completed. | 
| +  // | 
| +  // Returns true if this is the first time the result has been set. | 
| +  void _setResult(String testResult, String messageText, StackTrace stack) { | 
| +    message = messageText; | 
| +    stackTrace = getTrace(stack, formatStacks, filterStacks); | 
| +    if (stackTrace == null) stackTrace = stack; | 
| +    if (result == null) { | 
| +      result = testResult; | 
| +      config.onTestResult(this); | 
| +    } else { | 
| +      result = testResult; | 
| +      config.onTestResultChanged(this); | 
| +    } | 
| +  } | 
| + | 
| +  /// Marks the test as having passed. | 
| +  void pass() { | 
| +    _complete(PASS); | 
| +  } | 
| + | 
| +  void registerException(error, [StackTrace stackTrace]) { | 
| +    var message = error is TestFailure ? error.message : 'Caught $error'; | 
| +    if (result == null) { | 
| +      fail(message, stackTrace); | 
| +    } else { | 
| +      this.error(message, stackTrace); | 
| +    } | 
| +  } | 
| + | 
| +  /// Marks the test as having failed. | 
| +  void fail(String messageText, [StackTrace stack]) { | 
| +    if (result != null) { | 
| +      var newMessage = result == PASS | 
| +          ? 'Test failed after initially passing: $messageText' | 
| +          : 'Test failed more than once: $messageText'; | 
| +      // TODO(gram): Should we combine the stack with the old one? | 
| +      _complete(ERROR, newMessage, stack); | 
| +    } else { | 
| +      _complete(FAIL, messageText, stack); | 
| +    } | 
| +  } | 
| + | 
| +  /// Marks the test as having had an unexpected error. | 
| +  void error(String messageText, [StackTrace stack]) { | 
| +    _complete(ERROR, messageText, stack); | 
| +  } | 
| + | 
| +  /// Indicates that an asynchronous callback has completed, and marks the test | 
| +  /// as passing if all outstanding callbacks are complete. | 
| +  void markCallbackComplete() { | 
| +    callbackFunctionsOutstanding--; | 
| +    if (callbackFunctionsOutstanding == 0 && !isComplete) pass(); | 
| +  } | 
| + | 
| +  String toString() => result != null ? "$description: $result" : description; | 
| +} | 
|  |