// Copyright (c) 2021, 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. import 'dart:async'; import 'package:stack_trace/stack_trace.dart'; import 'src/backend/closed_exception.dart'; import 'src/backend/invoker.dart'; import 'src/backend/stack_trace_formatter.dart'; export 'src/backend/test_failure.dart' show TestFailure; export 'src/scaffolding/utils.dart' show pumpEventQueue; final class TestHandle { /// Returns handle for the currently running test. /// /// This must be called from within the zone that the test is running in. If /// the current zone is not a test's zone throws [OutsideTestException]. static TestHandle get current { final invoker = Invoker.current; if (invoker == null) throw OutsideTestException(); return TestHandle._( invoker, StackTraceFormatter.current ?? _defaultFormatter); } static final _defaultFormatter = StackTraceFormatter(); final Invoker _invoker; final StackTraceFormatter _stackTraceFormatter; TestHandle._(this._invoker, this._stackTraceFormatter); String get name => _invoker.liveTest.test.name; /// Whether this test has already completed successfully. /// /// If a callback originating from a test case is invoked after the test has /// already passed it may be an indication of a test that fails to wait for /// all work to be finished, or of an asynchronous callback that is called /// more times or later than expected. bool get shouldBeDone => _invoker.liveTest.state.shouldBeDone; /// Marks this test as skipped. /// /// A skipped test may still fail if any exception is thrown, including /// uncaught asynchronous errors. void markSkipped(String message) { if (_invoker.closed) throw ClosedException(); _invoker.skip(message); } /// Indicates that this test should not be considered done until the returned /// [OutstandingWork] is marked as complete. /// /// The test may time out before the outstanding work completes. OutstandingWork markPending() { if (_invoker.closed) throw ClosedException(); return OutstandingWork._(_invoker, Zone.current); } /// Converts [stackTrace] to a [Chain] according to the current test's /// configuration. Chain formatStackTrace(StackTrace stackTrace) => _stackTraceFormatter.formatStackTrace(stackTrace); } final class OutstandingWork { final Invoker _invoker; final Zone _zone; var _isComplete = false; OutstandingWork._(this._invoker, this._zone) { _invoker.addOutstandingCallback(); } void complete() { if (_isComplete) return; _isComplete = true; _zone.run(_invoker.removeOutstandingCallback); } } final class OutsideTestException implements Exception {}