binding.dart 70.7 KB
Newer Older
1 2 3 4
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'dart:async';
6
import 'dart:convert';
7
import 'dart:io';
8
import 'dart:typed_data';
9
import 'dart:ui' as ui;
10

11
import 'package:flutter/foundation.dart';
12
import 'package:flutter/gestures.dart';
13 14
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
15
import 'package:flutter/services.dart';
16
import 'package:flutter/widgets.dart';
17
import 'package:flutter_test/flutter_test.dart' show TestWindow;
18 19
import 'package:quiver/testing/async.dart';
import 'package:quiver/time.dart';
20
import 'package:path/path.dart' as path;
21
import 'package:test_api/test_api.dart' as test_package;
22
import 'package:stack_trace/stack_trace.dart' as stack_trace;
23 24
import 'package:vector_math/vector_math_64.dart';

25
import 'goldens.dart';
26
import 'platform.dart';
27
import 'stack_manipulation.dart';
28
import 'test_async_utils.dart';
29
import 'test_exception_reporter.dart';
30
import 'test_text_input.dart';
31

32 33
/// Phases that can be reached by [WidgetTester.pumpWidget] and
/// [TestWidgetsFlutterBinding.pump].
34
///
35
/// See [WidgetsBinding.drawFrame] for a more detailed description of some of
36
/// these phases.
37
enum EnginePhase {
38
  /// The build phase in the widgets library. See [BuildOwner.buildScope].
39 40 41
  build,

  /// The layout phase in the rendering library. See [PipelineOwner.flushLayout].
42
  layout,
43 44 45

  /// The compositing bits update phase in the rendering library. See
  /// [PipelineOwner.flushCompositingBits].
46
  compositingBits,
47 48

  /// The paint phase in the rendering library. See [PipelineOwner.flushPaint].
49
  paint,
50 51 52 53

  /// The compositing phase in the rendering library. See
  /// [RenderView.compositeFrame]. This is the phase in which data is sent to
  /// the GPU. If semantics are not enabled, then this is the last phase.
54
  composite,
55 56 57

  /// The semantics building phase in the rendering library. See
  /// [PipelineOwner.flushSemantics].
58
  flushSemantics,
59 60

  /// The final phase in the rendering library, wherein semantics information is
Ian Hickson's avatar
Ian Hickson committed
61
  /// sent to the embedder. See [SemanticsOwner.sendSemanticsUpdate].
62
  sendSemanticsUpdate,
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
}

/// Parts of the system that can generate pointer events that reach the test
/// binding.
///
/// This is used to identify how to handle events in the
/// [LiveTestWidgetsFlutterBinding]. See
/// [TestWidgetsFlutterBinding.dispatchEvent].
enum TestBindingEventSource {
  /// The pointer event came from the test framework itself, e.g. from a
  /// [TestGesture] created by [WidgetTester.startGesture].
  test,

  /// The pointer event came from the system, presumably as a result of the user
  /// interactive directly with the device while the test was running.
  device,
79 80
}

81
const Size _kDefaultTestViewportSize = Size(800.0, 600.0);
82 83 84 85 86 87 88 89 90

/// Base class for bindings used by widgets library tests.
///
/// The [ensureInitialized] method creates (if necessary) and returns
/// an instance of the appropriate subclass.
///
/// When using these bindings, certain features are disabled. For
/// example, [timeDilation] is reset to 1.0 on initialization.
abstract class TestWidgetsFlutterBinding extends BindingBase
91 92
  with ServicesBinding,
       SchedulerBinding,
93
       GestureBinding,
94
       SemanticsBinding,
95
       RendererBinding,
96
       PaintingBinding,
97
       WidgetsBinding {
98

99 100 101 102
  /// Constructor for [TestWidgetsFlutterBinding].
  ///
  /// This constructor overrides the [debugPrint] global hook to point to
  /// [debugPrintOverride], which can be overridden by subclasses.
103
  TestWidgetsFlutterBinding() : _window = TestWindow(window: ui.window) {
104
    debugPrint = debugPrintOverride;
105
    debugDisableShadows = disableShadows;
106
    debugCheckIntrinsicSizes = checkIntrinsicSizes;
107 108
  }

109 110 111 112
  @override
  TestWindow get window => _window;
  final TestWindow _window;

113 114 115 116 117
  /// The value to set [debugPrint] to while tests are running.
  ///
  /// This can be used to redirect console output from the framework, or to
  /// change the behavior of [debugPrint]. For example,
  /// [AutomatedTestWidgetsFlutterBinding] uses it to make [debugPrint]
118
  /// synchronous, disabling its normal throttling behavior.
119 120 121
  @protected
  DebugPrintCallback get debugPrintOverride => debugPrint;

122 123 124 125 126 127 128 129 130
  /// The value to set [debugDisableShadows] to while tests are running.
  ///
  /// This can be used to reduce the likelihood of golden file tests being
  /// flaky, because shadow rendering is not always deterministic. The
  /// [AutomatedTestWidgetsFlutterBinding] sets this to true, so that all tests
  /// always run with shadows disabled.
  @protected
  bool get disableShadows => false;

131
  /// Increase the timeout for the current test by the given duration.
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
  ///
  /// This only matters if the test has an `initialTimeout` set on
  /// [testWidgets], and the test is running via `flutter test`. By default,
  /// tests do not have such a timeout. Tests run using `flutter run` never time
  /// out even if one is specified.
  ///
  /// This method has no effect on the timeout specified via `timeout` on
  /// [testWidgets]. That timeout is implemented by the `test` package.
  ///
  /// By default, each [pump] and [pumpWidget] call increases the timeout by a
  /// hundred milliseconds, and each [matchesGoldenFile] expectation increases
  /// it by a minute. If there is no timeout in the first place, this has no
  /// effect.
  ///
  /// The granularity of timeouts is coarse: the time is checked once per
  /// second, and only when the test is not executing. It is therefore possible
  /// for a timeout to be exceeded by hundreds of milliseconds and for the test
  /// to still succeed. If precise timing is required, it should be implemented
  /// as a part of the test rather than relying on this mechanism.
  ///
  /// See also:
  ///
  ///  * [testWidgets], on which a timeout can be set using the `timeout`
  ///    argument.
  ///  * [defaultTestTimeout], the maximum that the timeout can reach.
  ///    (That timeout is implemented by the `test` package.)
  // See AutomatedTestWidgetsFlutterBinding.addTime for an actual implementation.
  void addTime(Duration duration);
160

161 162 163 164 165
  /// The value to set [debugCheckIntrinsicSizes] to while tests are running.
  ///
  /// This can be used to enable additional checks. For example,
  /// [AutomatedTestWidgetsFlutterBinding] sets this to true, so that all tests
  /// always run with aggressive intrinsic sizing tests enabled.
166 167 168
  @protected
  bool get checkIntrinsicSizes => false;

169
  /// Creates and initializes the binding. This function is
170 171
  /// idempotent; calling it a second time will just return the
  /// previously-created instance.
172 173 174 175 176 177
  ///
  /// This function will use [AutomatedTestWidgetsFlutterBinding] if
  /// the test was run using `flutter test`, and
  /// [LiveTestWidgetsFlutterBinding] otherwise (e.g. if it was run
  /// using `flutter run`). (This is determined by looking at the
  /// environment variables for a variable called `FLUTTER_TEST`.)
178
  static WidgetsBinding ensureInitialized() {
179
    if (WidgetsBinding.instance == null) {
180
      if (isBrowser || Platform.environment.containsKey('FLUTTER_TEST')) {
181
        AutomatedTestWidgetsFlutterBinding();
182
      } else {
183
        LiveTestWidgetsFlutterBinding();
184 185
      }
    }
186
    assert(WidgetsBinding.instance is TestWidgetsFlutterBinding);
187
    return WidgetsBinding.instance;
188 189
  }

190 191 192
  @override
  void initInstances() {
    timeDilation = 1.0; // just in case the developer has artificially changed it for development
193 194
    HttpOverrides.global = _MockHttpOverrides();
    _testTextInput = TestTextInput(onCleared: _resetFocusedEditable)..register();
195 196 197
    super.initInstances();
  }

198
  @override
199
  // ignore: MUST_CALL_SUPER
200 201 202 203 204
  void initLicenses() {
    // Do not include any licenses, because we're a test, and the LICENSE file
    // doesn't get generated for tests.
  }

205
  /// Whether there is currently a test executing.
206
  bool get inTest;
207

208 209 210
  /// The number of outstanding microtasks in the queue.
  int get microtaskCount;

211 212 213 214 215 216
  /// The default maximum test timeout for tests when using this binding.
  ///
  /// This controls the default for the `timeout` argument on `testWidgets`. It
  /// is 10 minutes for [AutomatedTestWidgetsFlutterBinding] (tests running
  /// using `flutter test`), and unlimited for tests using
  /// [LiveTestWidgetsFlutterBinding] (tests running using `flutter run`).
217
  ///
218 219
  /// This is the maximum that the timeout controlled by `initialTimeout` on
  /// [testWidgets] can reach when augmented using [addTime].
220
  test_package.Timeout get defaultTestTimeout;
221

222 223 224 225 226 227 228 229 230 231
  /// The current time.
  ///
  /// In the automated test environment (`flutter test`), this is a fake clock
  /// that begins in January 2015 at the start of the test and advances each
  /// time [pump] is called with a non-zero duration.
  ///
  /// In the live testing environment (`flutter run`), this object shows the
  /// actual current wall-clock time.
  Clock get clock;

232 233 234 235 236 237 238 239
  /// Triggers a frame sequence (build/layout/paint/etc),
  /// then flushes microtasks.
  ///
  /// If duration is set, then advances the clock by that much first.
  /// Doing this flushes microtasks.
  ///
  /// The supplied EnginePhase is the final phase reached during the pump pass;
  /// if not supplied, the whole pass is executed.
240 241 242
  ///
  /// See also [LiveTestWidgetsFlutterBindingFramePolicy], which affects how
  /// this method works when the test is run with `flutter run`.
243
  Future<void> pump([ Duration duration, EnginePhase newPhase = EnginePhase.sendSemanticsUpdate ]);
244

245
  /// Runs a `callback` that performs real asynchronous work.
246 247 248 249 250
  ///
  /// This is intended for callers who need to call asynchronous methods where
  /// the methods spawn isolates or OS threads and thus cannot be executed
  /// synchronously by calling [pump].
  ///
251 252
  /// If `callback` completes successfully, this will return the future
  /// returned by `callback`.
253
  ///
254
  /// If `callback` completes with an error, the error will be caught by the
255 256 257 258 259 260 261
  /// Flutter framework and made available via [takeException], and this method
  /// will return a future that completes will `null`.
  ///
  /// Re-entrant calls to this method are not allowed; callers of this method
  /// are required to wait for the returned future to complete before calling
  /// this method again. Attempts to do otherwise will result in a
  /// [TestFailure] error being thrown.
262 263 264
  ///
  /// The `additionalTime` argument is used by the
  /// [AutomatedTestWidgetsFlutterBinding] implementation to increase the
265 266
  /// current timeout, if any. See [AutomatedTestWidgetsFlutterBinding.addTime]
  /// for details.
267 268
  Future<T> runAsync<T>(
    Future<T> callback(), {
269
    Duration additionalTime = const Duration(milliseconds: 1000),
270
  });
271

272
  /// Artificially calls dispatchLocalesChanged on the Widget binding,
273
  /// then flushes microtasks.
274 275 276
  ///
  /// Passes only one single Locale. Use [setLocales] to pass a full preferred
  /// locales list.
277 278
  Future<void> setLocale(String languageCode, String countryCode) {
    return TestAsyncUtils.guard<void>(() async {
279
      assert(inTest);
280
      final Locale locale = Locale(languageCode, countryCode == '' ? null : countryCode);
281 282 283
      if (isBrowser) {
        return;
      }
284 285 286 287 288 289 290 291 292 293
      dispatchLocalesChanged(<Locale>[locale]);
    });
  }

  /// Artificially calls dispatchLocalesChanged on the Widget binding,
  /// then flushes microtasks.
  Future<void> setLocales(List<Locale> locales) {
    return TestAsyncUtils.guard<void>(() async {
      assert(inTest);
      dispatchLocalesChanged(locales);
294 295 296
    });
  }

297 298 299 300 301 302
  /// Re-attempts the initialization of the lifecycle state after providing
  /// test values in [TestWindow.initialLifecycleStateTestValue].
  void readTestInitialLifecycleStateFromNativeWindow() {
    readInitialLifecycleStateFromNativeWindow();
  }

303 304 305 306 307 308
  Size _surfaceSize;

  /// Artificially changes the surface size to `size` on the Widget binding,
  /// then flushes microtasks.
  ///
  /// Set to null to use the default surface size.
309 310
  Future<void> setSurfaceSize(Size size) {
    return TestAsyncUtils.guard<void>(() async {
311 312
      assert(inTest);
      if (_surfaceSize == size)
313
        return;
314 315 316 317 318 319 320
      _surfaceSize = size;
      handleMetricsChanged();
    });
  }

  @override
  ViewConfiguration createViewConfiguration() {
321 322
    final double devicePixelRatio = window.devicePixelRatio;
    final Size size = _surfaceSize ?? window.physicalSize / devicePixelRatio;
323
    return ViewConfiguration(
324 325 326 327 328
      size: size,
      devicePixelRatio: devicePixelRatio,
    );
  }

329 330 331
  /// Acts as if the application went idle.
  ///
  /// Runs all remaining microtasks, including those scheduled as a result of
332 333
  /// running them, until there are no more microtasks scheduled. Then, runs any
  /// previously scheduled timers with zero time, and completes the returned future.
334
  ///
335 336 337
  /// May result in an infinite loop or run out of memory if microtasks continue
  /// to recursively schedule new microtasks. Will not run any timers scheduled
  /// after this method was invoked, even if they are zero-time timers.
338 339 340
  Future<void> idle() {
    return TestAsyncUtils.guard<void>(() {
      final Completer<void> completer = Completer<void>();
341
      Timer.run(() {
342
        completer.complete();
343 344 345
      });
      return completer.future;
    });
346 347
  }

348
  /// Convert the given point from the global coordinate system (as used by
349 350
  /// pointer events from the device) to the coordinate system used by the
  /// tests (an 800 by 600 window).
351
  Offset globalToLocal(Offset point) => point;
352 353

  /// Convert the given point from the coordinate system used by the tests (an
354
  /// 800 by 600 window) to the global coordinate system (as used by pointer
355
  /// events from the device).
356
  Offset localToGlobal(Offset point) => point;
357

358
  @override
359 360 361
  void dispatchEvent(
    PointerEvent event,
    HitTestResult hitTestResult, {
362
    TestBindingEventSource source = TestBindingEventSource.device,
363 364
  }) {
    assert(source == TestBindingEventSource.test);
365
    super.dispatchEvent(event, hitTestResult);
366 367
  }

368 369 370 371 372 373 374 375
  /// A stub for the system's onscreen keyboard. Callers must set the
  /// [focusedEditable] before using this value.
  TestTextInput get testTextInput => _testTextInput;
  TestTextInput _testTextInput;

  /// The current client of the onscreen keyboard. Callers must pump
  /// an additional frame after setting this property to complete the
  /// the focus change.
376 377 378
  ///
  /// Instead of setting this directly, consider using
  /// [WidgetTester.showKeyboard].
379 380
  EditableTextState get focusedEditable => _focusedEditable;
  EditableTextState _focusedEditable;
381
  set focusedEditable(EditableTextState value) {
382 383 384 385 386 387 388 389
    if (_focusedEditable != value) {
      _focusedEditable = value;
      value?.requestKeyboard();
    }
  }

  void _resetFocusedEditable() {
    _focusedEditable = null;
390 391
  }

392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
  /// Returns the exception most recently caught by the Flutter framework.
  ///
  /// Call this if you expect an exception during a test. If an exception is
  /// thrown and this is not called, then the exception is rethrown when
  /// the [testWidgets] call completes.
  ///
  /// If two exceptions are thrown in a row without the first one being
  /// acknowledged with a call to this method, then when the second exception is
  /// thrown, they are both dumped to the console and then the second is
  /// rethrown from the exception handler. This will likely result in the
  /// framework entering a highly unstable state and everything collapsing.
  ///
  /// It's safe to call this when there's no pending exception; it will return
  /// null in that case.
  dynamic takeException() {
407
    assert(inTest);
408
    final dynamic result = _pendingExceptionDetails?.exception;
409
    _pendingExceptionDetails = null;
410 411
    return result;
  }
412 413
  FlutterExceptionHandler _oldExceptionHandler;
  FlutterErrorDetails _pendingExceptionDetails;
414

415 416
  static const TextStyle _messageStyle = TextStyle(
    color: Color(0xFF917FFF),
Ian Hickson's avatar
Ian Hickson committed
417
    fontSize: 40.0,
418 419
  );

420 421
  static const Widget _preTestMessage = Center(
    child: Text(
422
      'Test starting...',
423
      style: _messageStyle,
Ian Hickson's avatar
Ian Hickson committed
424
      textDirection: TextDirection.ltr,
425
    ),
426 427
  );

428 429
  static const Widget _postTestMessage = Center(
    child: Text(
430
      'Test finished.',
431
      style: _messageStyle,
Ian Hickson's avatar
Ian Hickson committed
432
      textDirection: TextDirection.ltr,
433
    ),
434 435 436 437 438 439
  );

  /// Whether to include the output of debugDumpApp() when reporting
  /// test failures.
  bool showAppDumpInErrors = false;

440
  /// Call the testBody inside a [FakeAsync] scope on which [pump] can
441 442 443 444 445 446
  /// advance time.
  ///
  /// Returns a future which completes when the test has run.
  ///
  /// Called by the [testWidgets] and [benchmarkWidgets] functions to
  /// run a test.
447 448 449
  ///
  /// The `invariantTester` argument is called after the `testBody`'s [Future]
  /// completes. If it throws, then the test is marked as failed.
450 451 452 453
  ///
  /// The `description` is used by the [LiveTestWidgetsFlutterBinding] to
  /// show a label on the screen during the test. The description comes from
  /// the value passed to [testWidgets]. It must not be null.
454 455 456 457
  ///
  /// The `timeout` argument sets the initial timeout, if any. It can
  /// be increased with [addTime]. By default there is no timeout.
  Future<void> runTest(Future<void> testBody(), VoidCallback invariantTester, { String description = '', Duration timeout });
458 459 460 461 462 463 464 465 466 467 468

  /// This is called during test execution before and after the body has been
  /// executed.
  ///
  /// It's used by [AutomatedTestWidgetsFlutterBinding] to drain the microtasks
  /// before the final [pump] that happens during test cleanup.
  void asyncBarrier() {
    TestAsyncUtils.verifyAllScopesClosed();
  }

  Zone _parentZone;
469

470
  VoidCallback _createTestCompletionHandler(String testDescription, Completer<void> completer) {
471 472 473 474 475 476 477 478 479 480
    return () {
      // This can get called twice, in the case of a Future without listeners failing, and then
      // our main future completing.
      assert(Zone.current == _parentZone);
      if (_pendingExceptionDetails != null) {
        debugPrint = debugPrintOverride; // just in case the test overrides it -- otherwise we won't see the error!
        reportTestException(_pendingExceptionDetails, testDescription);
        _pendingExceptionDetails = null;
      }
      if (!completer.isCompleted)
481
        completer.complete();
482
    };
483 484
  }

485 486 487 488 489 490 491 492 493 494 495 496
  /// Called when the framework catches an exception, even if that exception is
  /// being handled by [takeException].
  ///
  /// This is called when there is no pending exception; if multiple exceptions
  /// are thrown and [takeException] isn't used, then subsequent exceptions are
  /// logged to the console regardless (and the test will fail).
  @protected
  void reportExceptionNoticed(FlutterErrorDetails exception) {
    // By default we do nothing.
    // The LiveTestWidgetsFlutterBinding overrides this to report the exception to the console.
  }

497 498 499 500
  Future<void> _runTest(
    Future<void> testBody(),
    VoidCallback invariantTester,
    String description, {
501
    Future<void> timeout,
502
  }) {
503
    assert(description != null);
504 505 506
    assert(inTest);
    _oldExceptionHandler = FlutterError.onError;
    int _exceptionCount = 0; // number of un-taken exceptions
507
    FlutterError.onError = (FlutterErrorDetails details) {
508
      if (_pendingExceptionDetails != null) {
509
        debugPrint = debugPrintOverride; // just in case the test overrides it -- otherwise we won't see the errors!
510 511
        if (_exceptionCount == 0) {
          _exceptionCount = 2;
512
          FlutterError.dumpErrorToConsole(_pendingExceptionDetails, forceReport: true);
513 514
        } else {
          _exceptionCount += 1;
515
        }
516
        FlutterError.dumpErrorToConsole(details, forceReport: true);
517
        _pendingExceptionDetails = FlutterErrorDetails(
518
          exception: 'Multiple exceptions ($_exceptionCount) were detected during the running of the current test, and at least one was unexpected.',
519
          library: 'Flutter test framework',
520 521
        );
      } else {
522
        reportExceptionNoticed(details); // mostly this is just a hook for the LiveTestWidgetsFlutterBinding
523
        _pendingExceptionDetails = details;
524
      }
525
    };
526
    final Completer<void> testCompleter = Completer<void>();
527
    final VoidCallback testCompletionHandler = _createTestCompletionHandler(description, testCompleter);
528 529 530 531 532 533 534 535 536
    void handleUncaughtError(dynamic exception, StackTrace stack) {
      if (testCompleter.isCompleted) {
        // Well this is not a good sign.
        // Ideally, once the test has failed we would stop getting errors from the test.
        // However, if someone tries hard enough they could get in a state where this happens.
        // If we silently dropped these errors on the ground, nobody would ever know. So instead
        // we report them to the console. They don't cause test failures, but hopefully someone
        // will see them in the logs at some point.
        debugPrint = debugPrintOverride; // just in case the test overrides it -- otherwise we won't see the error!
537
        FlutterError.dumpErrorToConsole(FlutterErrorDetails(
538
          exception: exception,
539
          stack: _unmangle(stack),
540
          context: ErrorDescription('running a test (but after the test had completed)'),
541
          library: 'Flutter test framework',
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572
        ), forceReport: true);
        return;
      }
      // This is where test failures, e.g. those in expect(), will end up.
      // Specifically, runUnaryGuarded() will call this synchronously and
      // return our return value if _runTestBody fails synchronously (which it
      // won't, so this never happens), and Future will call this when the
      // Future completes with an error and it would otherwise call listeners
      // if the listener is in a different zone (which it would be for the
      // `whenComplete` handler below), or if the Future completes with an
      // error and the future has no listeners at all.
      //
      // This handler further calls the onError handler above, which sets
      // _pendingExceptionDetails. Nothing gets printed as a result of that
      // call unless we already had an exception pending, because in general
      // we want people to be able to cause the framework to report exceptions
      // and then use takeException to verify that they were really caught.
      // Now, if we actually get here, this isn't going to be one of those
      // cases. We only get here if the test has actually failed. So, once
      // we've carefully reported it, we then immediately end the test by
      // calling the testCompletionHandler in the _parentZone.
      //
      // We have to manually call testCompletionHandler because if the Future
      // library calls us, it is maybe _instead_ of calling a registered
      // listener from a different zone. In our case, that would be instead of
      // calling the whenComplete() listener below.
      //
      // We have to call it in the parent zone because if we called it in
      // _this_ zone, the test framework would find this zone was the current
      // zone and helpfully throw the error in this zone, causing us to be
      // directly called again.
573
      DiagnosticsNode treeDump;
574
      try {
575 576 577 578
        treeDump = renderViewElement?.toDiagnosticsNode() ?? DiagnosticsNode.message('<no tree>');
        // TODO(jacobr): this is a hack to make sure the tree can safely be fully dumped.
        // Potentially everything is good enough without this case.
        treeDump.toStringDeep();
579
      } catch (exception) {
580
        treeDump = DiagnosticsNode.message('<additional error caught while dumping tree: $exception>', level: DiagnosticLevel.error);
581
      }
582 583
      final List<DiagnosticsNode> omittedFrames = <DiagnosticsNode>[];
      final int stackLinesToOmit = reportExpectCall(stack, omittedFrames);
584
      FlutterError.reportError(FlutterErrorDetails(
585 586
        exception: exception,
        stack: _unmangle(stack),
587
        context: ErrorDescription('running a test'),
588 589 590 591
        library: 'Flutter test framework',
        stackFilter: (Iterable<String> frames) {
          return FlutterError.defaultStackFilter(frames.skip(stackLinesToOmit));
        },
592
        informationCollector: () sync* {
593
          if (stackLinesToOmit > 0)
594
            yield* omittedFrames;
595
          if (showAppDumpInErrors) {
596
            yield DiagnosticsProperty<DiagnosticsNode>('At the time of the failure, the widget tree looked as follows', treeDump, linePrefix: '# ', style: DiagnosticsTreeStyle.flat);
597
          }
598
          if (description.isNotEmpty)
599
            yield DiagnosticsProperty<String>('The test description was', description, style: DiagnosticsTreeStyle.errorProperty);
600
        },
601 602 603 604 605
      ));
      assert(_parentZone != null);
      assert(_pendingExceptionDetails != null, 'A test overrode FlutterError.onError but either failed to return it to its original state, or had unexpected additional errors that it could not handle. Typically, this is caused by using expect() before restoring FlutterError.onError.');
      _parentZone.run<void>(testCompletionHandler);
    }
606
    final ZoneSpecification errorHandlingZoneSpecification = ZoneSpecification(
607 608
      handleUncaughtError: (Zone self, ZoneDelegate parent, Zone zone, dynamic exception, StackTrace stack) {
        handleUncaughtError(exception, stack);
609 610 611
      }
    );
    _parentZone = Zone.current;
612
    final Zone testZone = _parentZone.fork(specification: errorHandlingZoneSpecification);
613
    testZone.runBinary<Future<void>, Future<void> Function(), VoidCallback>(_runTestBody, testBody, invariantTester)
614
      .whenComplete(testCompletionHandler);
615
    timeout?.catchError(handleUncaughtError);
616
    return testCompleter.future;
617 618
  }

619
  Future<void> _runTestBody(Future<void> testBody(), VoidCallback invariantTester) async {
620 621
    assert(inTest);

622
    runApp(Container(key: UniqueKey(), child: _preTestMessage)); // Reset the tree to a known state.
623 624
    await pump();

625
    final bool autoUpdateGoldensBeforeTest = autoUpdateGoldenFiles && !isBrowser;
626
    final TestExceptionReporter reportTestExceptionBeforeTest = reportTestException;
627
    final ErrorWidgetBuilder errorWidgetBuilderBeforeTest = ErrorWidget.builder;
628

629
    // run the test
630
    await testBody();
631 632 633 634 635 636
    asyncBarrier(); // drains the microtasks in `flutter test` mode (when using AutomatedTestWidgetsFlutterBinding)

    if (_pendingExceptionDetails == null) {
      // We only try to clean up and verify invariants if we didn't already
      // fail. If we got an exception already, then we instead leave everything
      // alone so that we don't cause more spurious errors.
637
      runApp(Container(key: UniqueKey(), child: _postTestMessage)); // Unmount any remaining widgets.
638
      await pump();
639
      invariantTester();
640
      _verifyAutoUpdateGoldensUnset(autoUpdateGoldensBeforeTest && !isBrowser);
641
      _verifyReportTestExceptionUnset(reportTestExceptionBeforeTest);
642
      _verifyErrorWidgetBuilderUnset(errorWidgetBuilderBeforeTest);
643 644 645 646
      _verifyInvariants();
    }

    assert(inTest);
647
    asyncBarrier(); // When using AutomatedTestWidgetsFlutterBinding, this flushes the microtasks.
648 649 650 651 652 653
  }

  void _verifyInvariants() {
    assert(debugAssertNoTransientCallbacks(
      'An animation is still running even after the widget tree was disposed.'
    ));
654 655 656 657
    assert(debugAssertAllFoundationVarsUnset(
      'The value of a foundation debug variable was changed by the test.',
      debugPrintOverride: debugPrintOverride,
    ));
658 659 660
    assert(debugAssertAllGesturesVarsUnset(
      'The value of a gestures debug variable was changed by the test.',
    ));
661 662 663 664
    assert(debugAssertAllPaintingVarsUnset(
      'The value of a painting debug variable was changed by the test.',
      debugDisableShadowsOverride: disableShadows,
    ));
665
    assert(debugAssertAllRenderVarsUnset(
666 667
      'The value of a rendering debug variable was changed by the test.',
      debugCheckIntrinsicSizesOverride: checkIntrinsicSizes,
668 669
    ));
    assert(debugAssertAllWidgetVarsUnset(
670
      'The value of a widget debug variable was changed by the test.',
671 672
    ));
    assert(debugAssertAllSchedulerVarsUnset(
673
      'The value of a scheduler debug variable was changed by the test.',
674
    ));
675 676
  }

677 678 679
  void _verifyAutoUpdateGoldensUnset(bool valueBeforeTest) {
    assert(() {
      if (autoUpdateGoldenFiles != valueBeforeTest) {
680 681
        FlutterError.reportError(FlutterErrorDetails(
          exception: FlutterError(
682 683 684 685 686 687 688 689 690 691
              'The value of autoUpdateGoldenFiles was changed by the test.',
          ),
          stack: StackTrace.current,
          library: 'Flutter test framework',
        ));
      }
      return true;
    }());
  }

692 693 694 695 696 697 698 699
  void _verifyReportTestExceptionUnset(TestExceptionReporter valueBeforeTest) {
    assert(() {
      if (reportTestException != valueBeforeTest) {
        // We can't report this error to their modified reporter because we
        // can't be guaranteed that their reporter will cause the test to fail.
        // So we reset the error reporter to its initial value and then report
        // this error.
        reportTestException = valueBeforeTest;
700 701
        FlutterError.reportError(FlutterErrorDetails(
          exception: FlutterError(
702 703 704 705 706 707 708 709 710 711
            'The value of reportTestException was changed by the test.',
          ),
          stack: StackTrace.current,
          library: 'Flutter test framework',
        ));
      }
      return true;
    }());
  }

712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
  void _verifyErrorWidgetBuilderUnset(ErrorWidgetBuilder valueBeforeTest) {
    assert(() {
      if (ErrorWidget.builder != valueBeforeTest) {
        FlutterError.reportError(FlutterErrorDetails(
          exception: FlutterError(
              'The value of ErrorWidget.builder was changed by the test.',
          ),
          stack: StackTrace.current,
          library: 'Flutter test framework',
        ));
      }
      return true;
    }());
  }

727 728 729 730 731 732
  /// Called by the [testWidgets] function after a test is executed.
  void postTest() {
    assert(inTest);
    FlutterError.onError = _oldExceptionHandler;
    _pendingExceptionDetails = null;
    _parentZone = null;
733
    buildOwner.focusManager = FocusManager();
734 735 736 737
    assert(!RendererBinding.instance.mouseTracker.mouseIsConnected,
        'The MouseTracker thinks that there is still a mouse connected, which indicates that a '
        'test has not removed the mouse pointer which it added. Call removePointer on the '
        'active mouse gesture to remove the mouse pointer.');
738 739 740 741 742 743 744 745
  }
}

/// A variant of [TestWidgetsFlutterBinding] for executing tests in
/// the `flutter test` environment.
///
/// This binding controls time, allowing tests to verify long
/// animation sequences without having to execute them in real time.
746 747 748
///
/// This class assumes it is always run in checked mode (since tests are always
/// run in checked mode).
749 750 751 752
class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
  @override
  void initInstances() {
    super.initInstances();
753 754
    window.onBeginFrame = null;
    window.onDrawFrame = null;
755
    _mockFlutterAssets();
756 757
  }

758
  FakeAsync _currentFakeAsync; // set in runTest; cleared in postTest
759
  Completer<void> _pendingAsyncTasks;
760 761 762

  @override
  Clock get clock => _clock;
763 764
  Clock _clock;

765 766 767
  @override
  DebugPrintCallback get debugPrintOverride => debugPrintSynchronously;

768 769 770
  @override
  bool get disableShadows => true;

771 772 773
  @override
  bool get checkIntrinsicSizes => true;

774
  @override
775
  test_package.Timeout get defaultTestTimeout => const test_package.Timeout(Duration(minutes: 10));
776 777

  @override
778
  bool get inTest => _currentFakeAsync != null;
779

780
  @override
781
  int get microtaskCount => _currentFakeAsync.microtaskCount;
782

783 784
  /// A whitelist [Set] that is used in mocking the asset message channel.
  static Set<String> _allowedAssetKeys;
785 786

  void _mockFlutterAssets() {
787 788 789
    if (isBrowser) {
      return;
    }
790 791 792 793 794
    if (!Platform.environment.containsKey('UNIT_TEST_ASSETS')) {
      return;
    }
    final String assetFolderPath = Platform.environment['UNIT_TEST_ASSETS'];
    _ensureInitialized(assetFolderPath);
795 796

    if (_allowedAssetKeys.isNotEmpty) {
797
      defaultBinaryMessenger.setMockMessageHandler('flutter/assets', (ByteData message) {
798 799 800 801 802 803
        final String key = utf8.decode(message.buffer.asUint8List());
        if (_allowedAssetKeys.contains(key)) {
          final File asset = File(path.join(assetFolderPath, key));
          final Uint8List encoded = Uint8List.fromList(asset.readAsBytesSync());
          return Future<ByteData>.value(encoded.buffer.asByteData());
        }
804
        return null;
805 806
      });
    }
807 808 809
  }

  void _ensureInitialized(String assetFolderPath) {
810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828
    if (_allowedAssetKeys != null) {
      return;
    }
    final File manifestFile = File(
        path.join(assetFolderPath, 'AssetManifest.json'));
    // If the file does not exist, it means there is no asset declared in
    // the project.
    if (!manifestFile.existsSync()) {
      _allowedAssetKeys = <String>{};
      return;
    }
    final Map<String, dynamic> manifest = json.decode(
        manifestFile.readAsStringSync());
    _allowedAssetKeys = <String>{
      'AssetManifest.json',
    };
    for (List<dynamic> value in manifest.values) {
      final List<String> strList = List<String>.from(value);
      _allowedAssetKeys.addAll(strList);
829 830 831
    }
  }

832
  @override
833 834
  Future<void> pump([ Duration duration, EnginePhase newPhase = EnginePhase.sendSemanticsUpdate ]) {
    return TestAsyncUtils.guard<void>(() {
835 836 837
      assert(inTest);
      assert(_clock != null);
      if (duration != null)
838
        _currentFakeAsync.elapse(duration);
839 840
      _phase = newPhase;
      if (hasScheduledFrame) {
841
        addTime(const Duration(milliseconds: 500));
842
        _currentFakeAsync.flushMicrotasks();
843
        handleBeginFrame(Duration(
844
          milliseconds: _clock.now().millisecondsSinceEpoch,
845
        ));
846
        _currentFakeAsync.flushMicrotasks();
847
        handleDrawFrame();
848
      }
849
      _currentFakeAsync.flushMicrotasks();
850
      return Future<void>.value();
851 852 853
    });
  }

854
  @override
855 856
  Future<T> runAsync<T>(
    Future<T> callback(), {
857
    Duration additionalTime = const Duration(milliseconds: 1000),
858 859
  }) {
    assert(additionalTime != null);
860 861 862
    assert(() {
      if (_pendingAsyncTasks == null)
        return true;
863
      throw test_package.TestFailure(
864 865 866 867 868 869 870
          'Reentrant call to runAsync() denied.\n'
          'runAsync() was called, then before its future completed, it '
          'was called again. You must wait for the first returned future '
          'to complete before calling runAsync() again.'
      );
    }());

871
    final Zone realAsyncZone = Zone.current.fork(
872
      specification: ZoneSpecification(
873 874 875 876 877 878 879 880 881 882 883 884
        scheduleMicrotask: (Zone self, ZoneDelegate parent, Zone zone, void f()) {
          Zone.root.scheduleMicrotask(f);
        },
        createTimer: (Zone self, ZoneDelegate parent, Zone zone, Duration duration, void f()) {
          return Zone.root.createTimer(duration, f);
        },
        createPeriodicTimer: (Zone self, ZoneDelegate parent, Zone zone, Duration period, void f(Timer timer)) {
          return Zone.root.createPeriodicTimer(period, f);
        },
      ),
    );

885 886
    addTime(additionalTime);

887
    return realAsyncZone.run<Future<T>>(() {
888
      _pendingAsyncTasks = Completer<void>();
889
      return callback().catchError((dynamic exception, StackTrace stack) {
890
        FlutterError.reportError(FlutterErrorDetails(
891 892 893
          exception: exception,
          stack: stack,
          library: 'Flutter test framework',
894
          context: ErrorDescription('while running async test code'),
895 896 897 898 899 900 901 902 903 904 905 906 907 908
        ));
        return null;
      }).whenComplete(() {
        // We complete the _pendingAsyncTasks future successfully regardless of
        // whether an exception occurred because in the case of an exception,
        // we already reported the exception to FlutterError. Moreover,
        // completing the future with an error would trigger an unhandled
        // exception due to zone error boundaries.
        _pendingAsyncTasks.complete();
        _pendingAsyncTasks = null;
      });
    });
  }

909 910 911 912 913
  @override
  void scheduleWarmUpFrame() {
    // We override the default version of this so that the application-startup warm-up frame
    // does not schedule timers which we might never get around to running.
    handleBeginFrame(null);
914
    _currentFakeAsync.flushMicrotasks();
915
    handleDrawFrame();
916
    _currentFakeAsync.flushMicrotasks();
917 918
  }

919
  @override
920 921
  Future<void> idle() {
    final Future<void> result = super.idle();
922
    _currentFakeAsync.elapse(Duration.zero);
923 924 925
    return result;
  }

926
  EnginePhase _phase = EnginePhase.sendSemanticsUpdate;
927

928
  // Cloned from RendererBinding.drawFrame() but with early-exit semantics.
929
  @override
930
  void drawFrame() {
931
    assert(inTest);
932 933 934
    try {
      debugBuildingDirtyElements = true;
      buildOwner.buildScope(renderViewElement);
935 936 937 938 939 940 941 942 943 944 945
      if (_phase != EnginePhase.build) {
        assert(renderView != null);
        pipelineOwner.flushLayout();
        if (_phase != EnginePhase.layout) {
          pipelineOwner.flushCompositingBits();
          if (_phase != EnginePhase.compositingBits) {
            pipelineOwner.flushPaint();
            if (_phase != EnginePhase.paint) {
              renderView.compositeFrame(); // this sends the bits to the GPU
              if (_phase != EnginePhase.composite) {
                pipelineOwner.flushSemantics();
946 947
                assert(_phase == EnginePhase.flushSemantics ||
                       _phase == EnginePhase.sendSemanticsUpdate);
948 949 950 951 952
              }
            }
          }
        }
      }
953
      buildOwner.finalizeTree();
954
    } finally {
955 956
      debugBuildingDirtyElements = false;
    }
957 958
  }

959 960 961
  Duration _timeout;
  Stopwatch _timeoutStopwatch;
  Timer _timeoutTimer;
962
  Completer<void> _timeoutCompleter;
963 964 965

  void _checkTimeout(Timer timer) {
    assert(_timeoutTimer == timer);
966
    assert(_timeout != null);
967 968
    if (_timeoutStopwatch.elapsed > _timeout) {
      _timeoutCompleter.completeError(
969
        TimeoutException(
970
          'The test exceeded the timeout. It may have hung.\n'
971
          'Consider using "tester.binding.addTime" to increase the timeout before expensive operations.',
972 973 974 975 976 977
          _timeout,
        ),
      );
    }
  }

978
  @override
979
  void addTime(Duration duration) {
980 981
    if (_timeout != null)
      _timeout += duration;
982 983
  }

984
  @override
985 986 987
  Future<void> runTest(
    Future<void> testBody(),
    VoidCallback invariantTester, {
988
    String description = '',
989
    Duration timeout,
990
  }) {
991
    assert(description != null);
992
    assert(!inTest);
993
    assert(_currentFakeAsync == null);
994
    assert(_clock == null);
995 996

    _timeout = timeout;
997 998 999 1000 1001
    if (_timeout != null) {
      _timeoutStopwatch = Stopwatch()..start();
      _timeoutTimer = Timer.periodic(const Duration(seconds: 1), _checkTimeout);
      _timeoutCompleter = Completer<void>();
    }
1002

1003
    final FakeAsync fakeAsync = FakeAsync();
1004
    _currentFakeAsync = fakeAsync; // reset in postTest
1005
    _clock = fakeAsync.getClock(DateTime.utc(2015, 1, 1));
1006
    Future<void> testBodyResult;
1007 1008 1009
    fakeAsync.run((FakeAsync localFakeAsync) {
      assert(fakeAsync == _currentFakeAsync);
      assert(fakeAsync == localFakeAsync);
1010
      testBodyResult = _runTest(testBody, invariantTester, description, timeout: _timeoutCompleter?.future);
1011 1012
      assert(inTest);
    });
1013

1014
    return Future<void>.microtask(() async {
1015 1016 1017 1018 1019 1020
      // testBodyResult is a Future that was created in the Zone of the
      // fakeAsync. This means that if we await it here, it will register a
      // microtask to handle the future _in the fake async zone_. We avoid this
      // by calling '.then' in the current zone. While flushing the microtasks
      // of the fake-zone below, the new future will be completed and can then
      // be used without fakeAsync.
1021
      final Future<void> resultFuture = testBodyResult.then<void>((_) {
1022 1023 1024
        // Do nothing.
      });

1025
      // Resolve interplay between fake async and real async calls.
1026
      fakeAsync.flushMicrotasks();
1027 1028
      while (_pendingAsyncTasks != null) {
        await _pendingAsyncTasks.future;
1029
        fakeAsync.flushMicrotasks();
1030
      }
1031
      return resultFuture;
1032
    });
1033 1034
  }

1035 1036
  @override
  void asyncBarrier() {
1037 1038
    assert(_currentFakeAsync != null);
    _currentFakeAsync.flushMicrotasks();
1039 1040
    super.asyncBarrier();
  }
1041

1042 1043 1044
  @override
  void _verifyInvariants() {
    super._verifyInvariants();
1045
    assert(
1046
      _currentFakeAsync.periodicTimerCount == 0,
1047 1048 1049
      'A periodic Timer is still running even after the widget tree was disposed.'
    );
    assert(
1050
      _currentFakeAsync.nonPeriodicTimerCount == 0,
1051 1052
      'A Timer is still pending even after the widget tree was disposed.'
    );
1053
    assert(_currentFakeAsync.microtaskCount == 0); // Shouldn't be possible.
1054 1055
  }

1056
  @override
1057
  void postTest() {
1058
    super.postTest();
1059
    assert(_currentFakeAsync != null);
1060 1061
    assert(_clock != null);
    _clock = null;
1062
    _currentFakeAsync = null;
1063
    _timeoutCompleter = null;
1064
    _timeoutTimer?.cancel();
1065 1066 1067
    _timeoutTimer = null;
    _timeoutStopwatch = null;
    _timeout = null;
1068 1069
  }

1070
}
1071

1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098
/// Available policies for how a [LiveTestWidgetsFlutterBinding] should paint
/// frames.
///
/// These values are set on the binding's
/// [LiveTestWidgetsFlutterBinding.framePolicy] property. The default is
/// [fadePointers].
enum LiveTestWidgetsFlutterBindingFramePolicy {
  /// Strictly show only frames that are explicitly pumped. This most closely
  /// matches the behavior of tests when run under `flutter test`.
  onlyPumps,

  /// Show pumped frames, and additionally schedule and run frames to fade
  /// out the pointer crosshairs and other debugging information shown by
  /// the binding.
  ///
  /// This can result in additional frames being pumped beyond those that
  /// the test itself requests, which can cause differences in behavior.
  fadePointers,

  /// Show every frame that the framework requests, even if the frames are not
  /// explicitly pumped.
  ///
  /// This can help with orienting the developer when looking at
  /// heavily-animated situations, and will almost certainly result in
  /// additional frames being pumped beyond those that the test itself requests,
  /// which can cause differences in behavior.
  fullyLive,
1099 1100 1101 1102 1103 1104

  /// Ignore any request to schedule a frame.
  ///
  /// This is intended to be used by benchmarks (hence the name) that drive the
  /// pipeline directly. It tells the binding to entirely ignore requests for a
  /// frame to be scheduled, while still allowing frames that are pumped
1105 1106
  /// directly to run (either by using [WidgetTester.pumpBenchmark] or invoking
  /// [Window.onBeginFrame] and [Window.onDrawFrame]).
1107 1108 1109 1110 1111 1112 1113
  ///
  /// The [SchedulerBinding.hasScheduledFrame] property will never be true in
  /// this mode. This can cause unexpected effects. For instance,
  /// [WidgetTester.pumpAndSettle] does not function in this mode, as it relies
  /// on the [SchedulerBinding.hasScheduledFrame] property to determine when the
  /// application has "settled".
  benchmark,
1114 1115
}

1116 1117 1118 1119 1120 1121 1122 1123
/// A variant of [TestWidgetsFlutterBinding] for executing tests in
/// the `flutter run` environment, on a device. This is intended to
/// allow interactive test development.
///
/// This is not the way to run a remote-control test. To run a test on
/// a device from a development computer, see the [flutter_driver]
/// package and the `flutter drive` command.
///
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
/// When running tests using `flutter run`, consider adding the
/// `--use-test-fonts` argument so that the fonts used match those used under
/// `flutter test`. (This forces all text to use the "Ahem" font, which is a
/// font that covers ASCII characters and gives them all the appearance of a
/// square whose size equals the font size.)
///
/// This binding overrides the default [SchedulerBinding] behavior to ensure
/// that tests work in the same way in this environment as they would under the
/// [AutomatedTestWidgetsFlutterBinding]. To override this (and see intermediate
/// frames that the test does not explicitly trigger), set [framePolicy] to
/// [LiveTestWidgetsFlutterBindingFramePolicy.fullyLive]. (This is likely to
/// make tests fail, though, especially if e.g. they test how many times a
/// particular widget was built.) The default behavior is to show pumped frames
/// and a few additional frames when pointers are triggered (to animate the
/// pointer crosshairs).
1139 1140 1141 1142 1143 1144 1145 1146 1147 1148
///
/// This binding does not support the [EnginePhase] argument to
/// [pump]. (There would be no point setting it to a value that
/// doesn't trigger a paint, since then you could not see anything
/// anyway.)
class LiveTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
  @override
  bool get inTest => _inTest;
  bool _inTest = false;

1149 1150 1151
  @override
  Clock get clock => const Clock();

1152 1153
  @override
  int get microtaskCount {
1154 1155
    // The Dart SDK doesn't report this number.
    assert(false, 'microtaskCount cannot be reported when running in real time');
1156 1157 1158
    return -1;
  }

1159 1160 1161
  @override
  test_package.Timeout get defaultTestTimeout => test_package.Timeout.none;

1162
  Completer<void> _pendingFrame;
1163
  bool _expectingFrame = false;
1164
  bool _viewNeedsPaint = false;
1165
  bool _runningAsyncTasks = false;
1166 1167 1168 1169 1170 1171 1172 1173

  /// Whether to have [pump] with a duration only pump a single frame
  /// (as would happen in a normal test environment using
  /// [AutomatedTestWidgetsFlutterBinding]), or whether to instead
  /// pump every frame that the system requests during any
  /// asynchronous pause in the test (as would normally happen when
  /// running an application with [WidgetsFlutterBinding]).
  ///
1174 1175 1176 1177 1178 1179 1180 1181
  /// * [LiveTestWidgetsFlutterBindingFramePolicy.fadePointers] is the default
  ///   behavior, which is to only pump once, except when there has been some
  ///   activity with [TestPointer]s, in which case those are shown and may pump
  ///   additional frames.
  ///
  /// * [LiveTestWidgetsFlutterBindingFramePolicy.onlyPumps] is the strictest
  ///   behavior, which is to only pump once. This most closely matches the
  ///   [AutomatedTestWidgetsFlutterBinding] (`flutter test`) behavior.
1182
  ///
1183 1184 1185
  /// * [LiveTestWidgetsFlutterBindingFramePolicy.fullyLive] allows all frame
  ///   requests from the engine to be serviced, even those the test did not
  ///   explicitly pump.
1186
  ///
1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
  /// * [LiveTestWidgetsFlutterBindingFramePolicy.benchmark] allows all frame
  ///   requests from the engine to be serviced, and allows all frame requests
  ///   that are artificially triggered to be serviced, but prevents the
  ///   framework from requesting any frames from the engine itself. The
  ///   [SchedulerBinding.hasScheduledFrame] property will never be true in this
  ///   mode. This can cause unexpected effects. For instance,
  ///   [WidgetTester.pumpAndSettle] does not function in this mode, as it
  ///   relies on the [SchedulerBinding.hasScheduledFrame] property to determine
  ///   when the application has "settled".
  ///
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
  /// Setting this to anything other than
  /// [LiveTestWidgetsFlutterBindingFramePolicy.onlyPumps] means pumping extra
  /// frames, which might involve calling builders more, or calling paint
  /// callbacks more, etc, which might interfere with the test. If you know your
  /// test file wouldn't be affected by this, you can set it to
  /// [LiveTestWidgetsFlutterBindingFramePolicy.fullyLive] persistently in that
  /// particular test file. To set this to
  /// [LiveTestWidgetsFlutterBindingFramePolicy.fullyLive] while still allowing
  /// the test file to work as a normal test, add the following code to your
  /// test file at the top of your `void main() { }` function, before calls to
  /// [testWidgets]:
1208 1209 1210 1211
  ///
  /// ```dart
  /// TestWidgetsFlutterBinding binding = TestWidgetsFlutterBinding.ensureInitialized();
  /// if (binding is LiveTestWidgetsFlutterBinding)
1212
  ///   binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
1213
  /// ```
1214
  LiveTestWidgetsFlutterBindingFramePolicy framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fadePointers;
1215

1216 1217 1218 1219 1220 1221
  @override
  void addTime(Duration duration) {
    // We don't support timeouts on the LiveTestWidgetsFlutterBinding.
    // See runTest().
  }

1222 1223 1224 1225 1226 1227 1228
  @override
  void scheduleFrame() {
    if (framePolicy == LiveTestWidgetsFlutterBindingFramePolicy.benchmark)
      return; // In benchmark mode, don't actually schedule any engine frames.
    super.scheduleFrame();
  }

1229 1230 1231 1232 1233 1234 1235
  @override
  void scheduleForcedFrame() {
    if (framePolicy == LiveTestWidgetsFlutterBindingFramePolicy.benchmark)
      return; // In benchmark mode, don't actually schedule any engine frames.
    super.scheduleForcedFrame();
  }

1236 1237
  bool _doDrawThisFrame;

1238 1239
  @override
  void handleBeginFrame(Duration rawTimeStamp) {
1240
    assert(_doDrawThisFrame == null);
1241 1242
    if (_expectingFrame ||
        (framePolicy == LiveTestWidgetsFlutterBindingFramePolicy.fullyLive) ||
1243
        (framePolicy == LiveTestWidgetsFlutterBindingFramePolicy.benchmark) ||
1244 1245
        (framePolicy == LiveTestWidgetsFlutterBindingFramePolicy.fadePointers && _viewNeedsPaint)) {
      _doDrawThisFrame = true;
1246
      super.handleBeginFrame(rawTimeStamp);
1247 1248 1249
    } else {
      _doDrawThisFrame = false;
    }
1250 1251 1252 1253 1254 1255 1256 1257
  }

  @override
  void handleDrawFrame() {
    assert(_doDrawThisFrame != null);
    if (_doDrawThisFrame)
      super.handleDrawFrame();
    _doDrawThisFrame = null;
1258 1259
    _viewNeedsPaint = false;
    if (_expectingFrame) { // set during pump
1260 1261 1262 1263
      assert(_pendingFrame != null);
      _pendingFrame.complete(); // unlocks the test API
      _pendingFrame = null;
      _expectingFrame = false;
1264
    } else if (framePolicy != LiveTestWidgetsFlutterBindingFramePolicy.benchmark) {
1265
      window.scheduleFrame();
1266 1267 1268
    }
  }

1269 1270 1271
  @override
  void initRenderView() {
    assert(renderView == null);
1272
    renderView = _LiveTestRenderView(
1273 1274
      configuration: createViewConfiguration(),
      onNeedPaint: _handleViewNeedsPaint,
1275
      window: window,
1276
    );
1277 1278 1279 1280 1281 1282
    renderView.scheduleInitialFrame();
  }

  @override
  _LiveTestRenderView get renderView => super.renderView;

1283 1284 1285 1286 1287
  void _handleViewNeedsPaint() {
    _viewNeedsPaint = true;
    renderView.markNeedsPaint();
  }

1288 1289 1290 1291 1292 1293 1294 1295 1296
  /// An object to which real device events should be routed.
  ///
  /// Normally, device events are silently dropped. However, if this property is
  /// set to a non-null value, then the events will be routed to its
  /// [HitTestDispatcher.dispatchEvent] method instead.
  ///
  /// Events dispatched by [TestGesture] are not affected by this.
  HitTestDispatcher deviceEventDispatcher;

1297
  @override
1298 1299 1300
  void dispatchEvent(
    PointerEvent event,
    HitTestResult hitTestResult, {
1301
    TestBindingEventSource source = TestBindingEventSource.device,
1302
  }) {
1303 1304 1305 1306
    switch (source) {
      case TestBindingEventSource.test:
        if (!renderView._pointers.containsKey(event.pointer)) {
          assert(event.down);
1307
          renderView._pointers[event.pointer] = _LiveTestPointerRecord(event.pointer, event.position);
1308 1309 1310 1311 1312
        } else {
          renderView._pointers[event.pointer].position = event.position;
          if (!event.down)
            renderView._pointers[event.pointer].decay = _kPointerDecay;
        }
1313
        _handleViewNeedsPaint();
1314
        super.dispatchEvent(event, hitTestResult, source: source);
1315 1316 1317
        break;
      case TestBindingEventSource.device:
        if (deviceEventDispatcher != null)
1318
          deviceEventDispatcher.dispatchEvent(event, hitTestResult);
1319
        break;
1320 1321 1322
    }
  }

1323
  @override
1324
  Future<void> pump([ Duration duration, EnginePhase newPhase = EnginePhase.sendSemanticsUpdate ]) {
1325
    assert(newPhase == EnginePhase.sendSemanticsUpdate);
1326 1327 1328
    assert(inTest);
    assert(!_expectingFrame);
    assert(_pendingFrame == null);
1329
    return TestAsyncUtils.guard<void>(() {
1330
      if (duration != null) {
1331
        Timer(duration, () {
1332 1333 1334 1335 1336 1337 1338
          _expectingFrame = true;
          scheduleFrame();
        });
      } else {
        _expectingFrame = true;
        scheduleFrame();
      }
1339
      _pendingFrame = Completer<void>();
1340 1341 1342 1343
      return _pendingFrame.future;
    });
  }

1344
  @override
1345 1346
  Future<T> runAsync<T>(
    Future<T> callback(), {
1347
    Duration additionalTime = const Duration(milliseconds: 1000),
1348
  }) async {
1349 1350 1351
    assert(() {
      if (!_runningAsyncTasks)
        return true;
1352
      throw test_package.TestFailure(
1353 1354 1355 1356 1357 1358 1359
          'Reentrant call to runAsync() denied.\n'
          'runAsync() was called, then before its future completed, it '
          'was called again. You must wait for the first returned future '
          'to complete before calling runAsync() again.'
      );
    }());

1360 1361
    addTime(additionalTime); // doesn't do anything since we don't actually track the timeout, but just for correctness...

1362 1363 1364 1365
    _runningAsyncTasks = true;
    try {
      return await callback();
    } catch (error, stack) {
1366
      FlutterError.reportError(FlutterErrorDetails(
1367 1368 1369
        exception: error,
        stack: stack,
        library: 'Flutter test framework',
1370
        context: ErrorSummary('while running async test code'),
1371 1372 1373 1374 1375 1376 1377
      ));
      return null;
    } finally {
      _runningAsyncTasks = false;
    }
  }

1378
  @override
1379
  Future<void> runTest(Future<void> testBody(), VoidCallback invariantTester, { String description = '', Duration timeout }) async {
1380
    assert(description != null);
1381 1382
    assert(!inTest);
    _inTest = true;
1383
    renderView._setDescription(description);
1384 1385 1386 1387
    // We drop the timeout on the floor in `flutter run` mode.
    // We could support it, but we'd have to automatically add the entire duration of pumps
    // and timers and so on, since those operate in real time when using this binding, but
    // the timeouts expect them to happen near-instantaneously.
1388
    return _runTest(testBody, invariantTester, description);
1389 1390
  }

1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405
  @override
  void reportExceptionNoticed(FlutterErrorDetails exception) {
    final DebugPrintCallback testPrint = debugPrint;
    debugPrint = debugPrintOverride;
    debugPrint('(The following exception is now available via WidgetTester.takeException:)');
    FlutterError.dumpErrorToConsole(exception, forceReport: true);
    debugPrint(
      '(If WidgetTester.takeException is called, the above exception will be ignored. '
      'If it is not, then the above exception will be dumped when another exception is '
      'caught by the framework or when the test ends, whichever happens first, and then '
      'the test will fail due to having not caught or expected the exception.)'
    );
    debugPrint = testPrint;
  }

1406 1407 1408 1409 1410 1411 1412 1413 1414 1415
  @override
  void postTest() {
    super.postTest();
    assert(!_expectingFrame);
    assert(_pendingFrame == null);
    _inTest = false;
  }

  @override
  ViewConfiguration createViewConfiguration() {
1416 1417 1418 1419
    return TestViewConfiguration(
      size: _surfaceSize ?? _kDefaultTestViewportSize,
      window: window,
    );
1420 1421 1422
  }

  @override
1423
  Offset globalToLocal(Offset point) {
1424 1425
    final Matrix4 transform = renderView.configuration.toHitTestMatrix();
    final double det = transform.invert();
1426
    assert(det != 0.0);
1427
    final Offset result = MatrixUtils.transformPoint(transform, point);
1428 1429 1430 1431
    return result;
  }

  @override
1432
  Offset localToGlobal(Offset point) {
1433
    final Matrix4 transform = renderView.configuration.toHitTestMatrix();
1434 1435
    return MatrixUtils.transformPoint(transform, point);
  }
1436
}
1437

1438 1439
/// A [ViewConfiguration] that pretends the display is of a particular size. The
/// size is in logical pixels. The resulting ViewConfiguration maps the given
1440
/// size onto the actual display using the [BoxFit.contain] algorithm.
1441 1442
class TestViewConfiguration extends ViewConfiguration {
  /// Creates a [TestViewConfiguration] with the given size. Defaults to 800x600.
1443 1444 1445
  ///
  /// If a [window] instance is not provided it defaults to [ui.window].
  factory TestViewConfiguration({
1446 1447
    Size size = _kDefaultTestViewportSize,
    ui.Window window,
1448 1449 1450 1451 1452
  }) {
    return TestViewConfiguration._(size, window ?? ui.window);
  }

  TestViewConfiguration._(Size size, ui.Window window)
1453 1454
    : _paintMatrix = _getMatrix(size, window.devicePixelRatio, window),
      _hitTestMatrix = _getMatrix(size, 1.0, window),
1455 1456
      super(size: size);

1457 1458 1459 1460
  static Matrix4 _getMatrix(Size size, double devicePixelRatio, ui.Window window) {
    final double inverseRatio = devicePixelRatio / window.devicePixelRatio;
    final double actualWidth = window.physicalSize.width * inverseRatio;
    final double actualHeight = window.physicalSize.height * inverseRatio;
1461 1462
    final double desiredWidth = size.width;
    final double desiredHeight = size.height;
1463 1464 1465 1466 1467 1468 1469 1470 1471 1472
    double scale, shiftX, shiftY;
    if ((actualWidth / actualHeight) > (desiredWidth / desiredHeight)) {
      scale = actualHeight / desiredHeight;
      shiftX = (actualWidth - desiredWidth * scale) / 2.0;
      shiftY = 0.0;
    } else {
      scale = actualWidth / desiredWidth;
      shiftX = 0.0;
      shiftY = (actualHeight - desiredHeight * scale) / 2.0;
    }
1473 1474 1475
    final Matrix4 matrix = Matrix4.compose(
      Vector3(shiftX, shiftY, 0.0), // translation
      Quaternion.identity(), // rotation
1476
      Vector3(scale, scale, 1.0), // scale
1477
    );
1478
    return matrix;
1479 1480
  }

1481 1482
  final Matrix4 _paintMatrix;
  final Matrix4 _hitTestMatrix;
1483 1484

  @override
1485
  Matrix4 toMatrix() => _paintMatrix.clone();
1486

1487 1488 1489
  /// Provides the transformation matrix that converts coordinates in the test
  /// coordinate space to coordinates in logical pixels on the real display.
  ///
1490
  /// This is essentially the same as [toMatrix] but ignoring the device pixel
1491 1492 1493 1494 1495
  /// ratio.
  ///
  /// This is useful because pointers are described in logical pixels, as
  /// opposed to graphics which are expressed in physical pixels.
  Matrix4 toHitTestMatrix() => _hitTestMatrix.clone();
1496 1497 1498 1499 1500

  @override
  String toString() => 'TestViewConfiguration';
}

1501 1502 1503 1504
const int _kPointerDecay = -2;

class _LiveTestPointerRecord {
  _LiveTestPointerRecord(
1505
    this.pointer,
1506
    this.position,
1507
  ) : color = HSVColor.fromAHSV(0.8, (35.0 * pointer) % 360.0, 1.0, 1.0).toColor(),
1508 1509 1510
      decay = 1;
  final int pointer;
  final Color color;
1511
  Offset position;
1512 1513 1514 1515 1516
  int decay; // >0 means down, <0 means up, increases by one each time, removed at 0
}

class _LiveTestRenderView extends RenderView {
  _LiveTestRenderView({
1517 1518
    ViewConfiguration configuration,
    this.onNeedPaint,
1519 1520
    @required ui.Window window,
  }) : super(configuration: configuration, window: window);
1521

1522
  @override
1523 1524
  TestViewConfiguration get configuration => super.configuration;
  @override
1525
  set configuration(covariant TestViewConfiguration value) { super.configuration = value; }
1526

1527 1528
  final VoidCallback onNeedPaint;

1529 1530
  final Map<int, _LiveTestPointerRecord> _pointers = <int, _LiveTestPointerRecord>{};

1531
  TextPainter _label;
1532
  static const TextStyle _labelStyle = TextStyle(
1533 1534 1535 1536 1537 1538 1539 1540 1541
    fontFamily: 'sans-serif',
    fontSize: 10.0,
  );
  void _setDescription(String value) {
    assert(value != null);
    if (value.isEmpty) {
      _label = null;
      return;
    }
Ian Hickson's avatar
Ian Hickson committed
1542
    // TODO(ianh): Figure out if the test name is actually RTL.
1543 1544
    _label ??= TextPainter(textAlign: TextAlign.left, textDirection: TextDirection.ltr);
    _label.text = TextSpan(text: value, style: _labelStyle);
1545 1546 1547 1548 1549
    _label.layout();
    if (onNeedPaint != null)
      onNeedPaint();
  }

1550
  @override
1551
  bool hitTest(HitTestResult result, { Offset position }) {
1552 1553
    final Matrix4 transform = configuration.toHitTestMatrix();
    final double det = transform.invert();
1554 1555 1556 1557 1558
    assert(det != 0.0);
    position = MatrixUtils.transformPoint(transform, position);
    return super.hitTest(result, position: position);
  }

1559 1560 1561 1562 1563 1564
  @override
  void paint(PaintingContext context, Offset offset) {
    assert(offset == Offset.zero);
    super.paint(context, offset);
    if (_pointers.isNotEmpty) {
      final double radius = configuration.size.shortestSide * 0.05;
1565 1566
      final Path path = Path()
        ..addOval(Rect.fromCircle(center: Offset.zero, radius: radius))
1567 1568 1569 1570 1571
        ..moveTo(0.0, -radius * 2.0)
        ..lineTo(0.0, radius * 2.0)
        ..moveTo(-radius * 2.0, 0.0)
        ..lineTo(radius * 2.0, 0.0);
      final Canvas canvas = context.canvas;
1572
      final Paint paint = Paint()
1573 1574 1575 1576
        ..strokeWidth = radius / 10.0
        ..style = PaintingStyle.stroke;
      bool dirty = false;
      for (int pointer in _pointers.keys) {
1577
        final _LiveTestPointerRecord record = _pointers[pointer];
1578
        paint.color = record.color.withOpacity(record.decay < 0 ? (record.decay / (_kPointerDecay - 1)) : 1.0);
1579
        canvas.drawPath(path.shift(record.position), paint);
1580 1581 1582 1583 1584 1585 1586 1587
        if (record.decay < 0)
          dirty = true;
        record.decay += 1;
      }
      _pointers
        .keys
        .where((int pointer) => _pointers[pointer].decay == 0)
        .toList()
1588
        .forEach(_pointers.remove);
1589 1590
      if (dirty && onNeedPaint != null)
        scheduleMicrotask(onNeedPaint);
1591
    }
1592
    _label?.paint(context.canvas, offset - const Offset(0.0, 10.0));
1593 1594 1595
  }
}

1596 1597 1598 1599 1600 1601 1602
StackTrace _unmangle(StackTrace stack) {
  if (stack is stack_trace.Trace)
    return stack.vmTrace;
  if (stack is stack_trace.Chain)
    return stack.toTrace().vmTrace;
  return stack;
}
1603 1604 1605 1606 1607 1608 1609 1610

/// Provides a default [HttpClient] which always returns empty 400 responses.
///
/// If another [HttpClient] is provided using [HttpOverrides.runZoned], that will
/// take precedence over this provider.
class _MockHttpOverrides extends HttpOverrides {
  @override
  HttpClient createHttpClient(SecurityContext _) {
1611
    return _MockHttpClient();
1612 1613 1614 1615 1616 1617 1618 1619
  }
}

/// A mocked [HttpClient] which always returns a [_MockHttpRequest].
class _MockHttpClient implements HttpClient {
  @override
  bool autoUncompress;

1620 1621 1622
  @override
  Duration connectionTimeout;

1623 1624 1625 1626 1627 1628 1629 1630 1631 1632
  @override
  Duration idleTimeout;

  @override
  int maxConnectionsPerHost;

  @override
  String userAgent;

  @override
1633
  void addCredentials(Uri url, String realm, HttpClientCredentials credentials) { }
1634 1635

  @override
1636
  void addProxyCredentials(String host, int port, String realm, HttpClientCredentials credentials) { }
1637 1638

  @override
1639
  set authenticate(Future<bool> Function(Uri url, String scheme, String realm) f) { }
1640 1641

  @override
1642
  set authenticateProxy(Future<bool> Function(String host, int port, String scheme, String realm) f) { }
1643 1644

  @override
1645
  set badCertificateCallback(bool Function(X509Certificate cert, String host, int port) callback) { }
1646 1647

  @override
1648
  void close({ bool force = false }) { }
1649 1650 1651

  @override
  Future<HttpClientRequest> delete(String host, int port, String path) {
1652
    return Future<HttpClientRequest>.value(_MockHttpRequest());
1653 1654 1655 1656
  }

  @override
  Future<HttpClientRequest> deleteUrl(Uri url) {
1657
    return Future<HttpClientRequest>.value(_MockHttpRequest());
1658 1659 1660
  }

  @override
1661
  set findProxy(String Function(Uri url) f) { }
1662 1663 1664

  @override
  Future<HttpClientRequest> get(String host, int port, String path) {
1665
    return Future<HttpClientRequest>.value(_MockHttpRequest());
1666 1667 1668 1669
  }

  @override
  Future<HttpClientRequest> getUrl(Uri url) {
1670
    return Future<HttpClientRequest>.value(_MockHttpRequest());
1671 1672 1673 1674
  }

  @override
  Future<HttpClientRequest> head(String host, int port, String path) {
1675
    return Future<HttpClientRequest>.value(_MockHttpRequest());
1676 1677 1678 1679
  }

  @override
  Future<HttpClientRequest> headUrl(Uri url) {
1680
    return Future<HttpClientRequest>.value(_MockHttpRequest());
1681 1682 1683 1684
  }

  @override
  Future<HttpClientRequest> open(String method, String host, int port, String path) {
1685
    return Future<HttpClientRequest>.value(_MockHttpRequest());
1686 1687 1688 1689
  }

  @override
  Future<HttpClientRequest> openUrl(String method, Uri url) {
1690
    return Future<HttpClientRequest>.value(_MockHttpRequest());
1691 1692 1693 1694
  }

  @override
  Future<HttpClientRequest> patch(String host, int port, String path) {
1695
    return Future<HttpClientRequest>.value(_MockHttpRequest());
1696 1697 1698 1699
  }

  @override
  Future<HttpClientRequest> patchUrl(Uri url) {
1700
    return Future<HttpClientRequest>.value(_MockHttpRequest());
1701 1702 1703 1704
  }

  @override
  Future<HttpClientRequest> post(String host, int port, String path) {
1705
    return Future<HttpClientRequest>.value(_MockHttpRequest());
1706 1707 1708 1709
  }

  @override
  Future<HttpClientRequest> postUrl(Uri url) {
1710
    return Future<HttpClientRequest>.value(_MockHttpRequest());
1711 1712 1713 1714
  }

  @override
  Future<HttpClientRequest> put(String host, int port, String path) {
1715
    return Future<HttpClientRequest>.value(_MockHttpRequest());
1716 1717 1718 1719
  }

  @override
  Future<HttpClientRequest> putUrl(Uri url) {
1720
    return Future<HttpClientRequest>.value(_MockHttpRequest());
1721 1722 1723 1724 1725 1726 1727 1728 1729
  }
}

/// A mocked [HttpClientRequest] which always returns a [_MockHttpClientResponse].
class _MockHttpRequest extends HttpClientRequest {
  @override
  Encoding encoding;

  @override
1730
  final HttpHeaders headers = _MockHttpHeaders();
1731 1732

  @override
1733
  void add(List<int> data) { }
1734 1735

  @override
1736
  void addError(Object error, [ StackTrace stackTrace ]) { }
1737 1738

  @override
1739 1740
  Future<void> addStream(Stream<List<int>> stream) {
    return Future<void>.value();
1741 1742 1743 1744
  }

  @override
  Future<HttpClientResponse> close() {
1745
    return Future<HttpClientResponse>.value(_MockHttpResponse());
1746 1747 1748 1749 1750 1751 1752 1753 1754
  }

  @override
  HttpConnectionInfo get connectionInfo => null;

  @override
  List<Cookie> get cookies => null;

  @override
1755
  Future<HttpClientResponse> get done async => null;
1756 1757

  @override
1758 1759
  Future<void> flush() {
    return Future<void>.value();
1760 1761 1762 1763 1764 1765 1766 1767 1768
  }

  @override
  String get method => null;

  @override
  Uri get uri => null;

  @override
1769
  void write(Object obj) { }
1770 1771

  @override
1772
  void writeAll(Iterable<Object> objects, [ String separator = '' ]) { }
1773 1774

  @override
1775
  void writeCharCode(int charCode) { }
1776 1777

  @override
1778
  void writeln([ Object obj = '' ]) { }
1779 1780 1781
}

/// A mocked [HttpClientResponse] which is empty and has a [statusCode] of 400.
1782 1783 1784 1785 1786
// TODO(tvolkert): Change to `extends Stream<Uint8List>` once
// https://dart-review.googlesource.com/c/sdk/+/104525 is rolled into the framework.
class _MockHttpResponse implements HttpClientResponse {
  final Stream<Uint8List> _delegate = Stream<Uint8List>.fromIterable(const Iterable<Uint8List>.empty());

1787
  @override
1788
  final HttpHeaders headers = _MockHttpHeaders();
1789 1790 1791 1792 1793 1794 1795 1796 1797 1798

  @override
  X509Certificate get certificate => null;

  @override
  HttpConnectionInfo get connectionInfo => null;

  @override
  int get contentLength => -1;

1799 1800 1801 1802
  @override
  HttpClientResponseCompressionState get compressionState {
    return HttpClientResponseCompressionState.decompressed;
  }
1803

1804 1805 1806 1807 1808
  @override
  List<Cookie> get cookies => null;

  @override
  Future<Socket> detachSocket() {
1809
    return Future<Socket>.error(UnsupportedError('Mocked response'));
1810 1811 1812 1813 1814 1815
  }

  @override
  bool get isRedirect => false;

  @override
1816 1817
  StreamSubscription<Uint8List> listen(void Function(Uint8List event) onData, { Function onError, void Function() onDone, bool cancelOnError }) {
    return const Stream<Uint8List>.empty().listen(onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError);
1818 1819 1820 1821 1822 1823 1824 1825 1826
  }

  @override
  bool get persistentConnection => null;

  @override
  String get reasonPhrase => null;

  @override
1827
  Future<HttpClientResponse> redirect([ String method, Uri url, bool followLoops ]) {
1828
    return Future<HttpClientResponse>.error(UnsupportedError('Mocked response'));
1829 1830 1831 1832 1833 1834 1835
  }

  @override
  List<RedirectInfo> get redirects => <RedirectInfo>[];

  @override
  int get statusCode => 400;
1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902

  @override
  Future<bool> any(bool Function(Uint8List element) test) {
    return _delegate.any(test);
  }

  @override
  Stream<Uint8List> asBroadcastStream({
    void Function(StreamSubscription<Uint8List> subscription) onListen,
    void Function(StreamSubscription<Uint8List> subscription) onCancel,
  }) {
    return _delegate.asBroadcastStream(onListen: onListen, onCancel: onCancel);
  }

  @override
  Stream<E> asyncExpand<E>(Stream<E> Function(Uint8List event) convert) {
    return _delegate.asyncExpand<E>(convert);
  }

  @override
  Stream<E> asyncMap<E>(FutureOr<E> Function(Uint8List event) convert) {
    return _delegate.asyncMap<E>(convert);
  }

  @override
  Stream<R> cast<R>() {
    return _delegate.cast<R>();
  }

  @override
  Future<bool> contains(Object needle) {
    return _delegate.contains(needle);
  }

  @override
  Stream<Uint8List> distinct([bool Function(Uint8List previous, Uint8List next) equals]) {
    return _delegate.distinct(equals);
  }

  @override
  Future<E> drain<E>([E futureValue]) {
    return _delegate.drain<E>(futureValue);
  }

  @override
  Future<Uint8List> elementAt(int index) {
    return _delegate.elementAt(index);
  }

  @override
  Future<bool> every(bool Function(Uint8List element) test) {
    return _delegate.every(test);
  }

  @override
  Stream<S> expand<S>(Iterable<S> Function(Uint8List element) convert) {
    return _delegate.expand(convert);
  }

  @override
  Future<Uint8List> get first => _delegate.first;

  @override
  Future<Uint8List> firstWhere(
    bool Function(Uint8List element) test, {
    List<int> Function() orElse,
  }) {
1903 1904 1905
    return _delegate.firstWhere(test, orElse: () {
      return Uint8List.fromList(orElse());
    });
1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944
  }

  @override
  Future<S> fold<S>(S initialValue, S Function(S previous, Uint8List element) combine) {
    return _delegate.fold<S>(initialValue, combine);
  }

  @override
  Future<dynamic> forEach(void Function(Uint8List element) action) {
    return _delegate.forEach(action);
  }

  @override
  Stream<Uint8List> handleError(
    Function onError, {
    bool Function(dynamic error) test,
  }) {
    return _delegate.handleError(onError, test: test);
  }

  @override
  bool get isBroadcast => _delegate.isBroadcast;

  @override
  Future<bool> get isEmpty => _delegate.isEmpty;

  @override
  Future<String> join([String separator = '']) {
    return _delegate.join(separator);
  }

  @override
  Future<Uint8List> get last => _delegate.last;

  @override
  Future<Uint8List> lastWhere(
    bool Function(Uint8List element) test, {
    List<int> Function() orElse,
  }) {
1945 1946 1947
    return _delegate.lastWhere(test, orElse: () {
      return Uint8List.fromList(orElse());
    });
1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959
  }

  @override
  Future<int> get length => _delegate.length;

  @override
  Stream<S> map<S>(S Function(Uint8List event) convert) {
    return _delegate.map<S>(convert);
  }

  @override
  Future<dynamic> pipe(StreamConsumer<List<int>> streamConsumer) {
1960
    return _delegate.cast<List<int>>().pipe(streamConsumer);
1961 1962 1963 1964
  }

  @override
  Future<Uint8List> reduce(List<int> Function(Uint8List previous, Uint8List element) combine) {
1965 1966 1967
    return _delegate.reduce((Uint8List previous, Uint8List element) {
      return Uint8List.fromList(combine(previous, element));
    });
1968 1969 1970 1971 1972 1973 1974
  }

  @override
  Future<Uint8List> get single => _delegate.single;

  @override
  Future<Uint8List> singleWhere(bool Function(Uint8List element) test, {List<int> Function() orElse}) {
1975 1976 1977
    return _delegate.singleWhere(test, orElse: () {
      return Uint8List.fromList(orElse());
    });
1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019
  }

  @override
  Stream<Uint8List> skip(int count) {
    return _delegate.skip(count);
  }

  @override
  Stream<Uint8List> skipWhile(bool Function(Uint8List element) test) {
    return _delegate.skipWhile(test);
  }

  @override
  Stream<Uint8List> take(int count) {
    return _delegate.take(count);
  }

  @override
  Stream<Uint8List> takeWhile(bool Function(Uint8List element) test) {
    return _delegate.takeWhile(test);
  }

  @override
  Stream<Uint8List> timeout(
    Duration timeLimit, {
    void Function(EventSink<Uint8List> sink) onTimeout,
  }) {
    return _delegate.timeout(timeLimit, onTimeout: onTimeout);
  }

  @override
  Future<List<Uint8List>> toList() {
    return _delegate.toList();
  }

  @override
  Future<Set<Uint8List>> toSet() {
    return _delegate.toSet();
  }

  @override
  Stream<S> transform<S>(StreamTransformer<List<int>, S> streamTransformer) {
2020
    return _delegate.cast<List<int>>().transform<S>(streamTransformer);
2021 2022 2023 2024 2025 2026
  }

  @override
  Stream<Uint8List> where(bool Function(Uint8List event) test) {
    return _delegate.where(test);
  }
2027 2028 2029 2030 2031 2032 2033 2034
}

/// A mocked [HttpHeaders] that ignores all writes.
class _MockHttpHeaders extends HttpHeaders {
  @override
  List<String> operator [](String name) => <String>[];

  @override
2035
  void add(String name, Object value) { }
2036 2037

  @override
2038
  void clear() { }
2039 2040

  @override
2041
  void forEach(void Function(String name, List<String> values) f) { }
2042 2043

  @override
2044
  void noFolding(String name) { }
2045 2046

  @override
2047
  void remove(String name, Object value) { }
2048 2049

  @override
2050
  void removeAll(String name) { }
2051 2052

  @override
2053
  void set(String name, Object value) { }
2054 2055 2056

  @override
  String value(String name) => null;
2057
}