Revert "Assert that runApp is called in the same zone as binding.ensureInitialized (#117113)" (#122830)
Revert "Assert that runApp is called in the same zone as binding.ensureInitialized"
This commit is contained in:
parent
62171dfe38
commit
5bea4d9023
@ -5,9 +5,7 @@
|
||||
import 'dart:developer' as developer;
|
||||
import 'dart:isolate' as isolate;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:vm_service/vm_service.dart';
|
||||
import 'package:vm_service/vm_service_io.dart';
|
||||
@ -54,29 +52,3 @@ Future<void> runFrame(VoidCallback callback) {
|
||||
callback();
|
||||
return result;
|
||||
}
|
||||
|
||||
// This binding skips the zones tests. These tests were written before we
|
||||
// verified zones properly, and they have been legacied-in to avoid having
|
||||
// to refactor them.
|
||||
//
|
||||
// When creating new tests, avoid relying on this class.
|
||||
class ZoneIgnoringTestBinding extends WidgetsFlutterBinding {
|
||||
@override
|
||||
void initInstances() {
|
||||
super.initInstances();
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
@override
|
||||
bool debugCheckZone(String entryPoint) { return true; }
|
||||
|
||||
static ZoneIgnoringTestBinding get instance => BindingBase.checkInstance(_instance);
|
||||
static ZoneIgnoringTestBinding? _instance;
|
||||
|
||||
static ZoneIgnoringTestBinding ensureInitialized() {
|
||||
if (ZoneIgnoringTestBinding._instance == null) {
|
||||
ZoneIgnoringTestBinding();
|
||||
}
|
||||
return ZoneIgnoringTestBinding.instance;
|
||||
}
|
||||
}
|
||||
|
@ -13,8 +13,6 @@ import 'package:vm_service/vm_service.dart';
|
||||
import 'package:vm_service/vm_service_io.dart';
|
||||
|
||||
void main() {
|
||||
LiveTestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
late VmService vmService;
|
||||
late LiveTestWidgetsFlutterBinding binding;
|
||||
setUpAll(() async {
|
||||
@ -29,7 +27,7 @@ void main() {
|
||||
await vmService.streamListen(EventStreams.kExtension);
|
||||
|
||||
// Initialize bindings
|
||||
binding = LiveTestWidgetsFlutterBinding.instance;
|
||||
binding = LiveTestWidgetsFlutterBinding();
|
||||
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
|
||||
binding.attachRootWidget(const SizedBox.expand());
|
||||
expect(binding.framesEnabled, true);
|
||||
|
@ -16,7 +16,7 @@ final Set<String> interestingLabels = <String>{
|
||||
};
|
||||
|
||||
void main() {
|
||||
ZoneIgnoringTestBinding.ensureInitialized();
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
initTimelineTests();
|
||||
test('Children of MultiChildRenderObjectElement show up in tracing', () async {
|
||||
// We don't have expectations around the first frame because there's a race around
|
||||
|
@ -9,7 +9,7 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
import 'common.dart';
|
||||
|
||||
void main() {
|
||||
ZoneIgnoringTestBinding.ensureInitialized();
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
initTimelineTests();
|
||||
test('Widgets with updated keys produce well formed timelines', () async {
|
||||
await runFrame(() { runApp(const TestRoot()); });
|
||||
|
@ -58,7 +58,7 @@ class TestRootState extends State<TestRoot> {
|
||||
}
|
||||
|
||||
void main() {
|
||||
ZoneIgnoringTestBinding.ensureInitialized();
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
initTimelineTests();
|
||||
test('Timeline', () async {
|
||||
// We don't have expectations around the first frame because there's a race around
|
||||
|
@ -2,7 +2,6 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert' show json;
|
||||
import 'dart:developer' as developer;
|
||||
import 'dart:io' show exit;
|
||||
@ -266,7 +265,6 @@ abstract class BindingBase {
|
||||
assert(_debugInitializedType == null);
|
||||
assert(() {
|
||||
_debugInitializedType = runtimeType;
|
||||
_debugBindingZone = Zone.current;
|
||||
return true;
|
||||
}());
|
||||
}
|
||||
@ -321,7 +319,7 @@ abstract class BindingBase {
|
||||
),
|
||||
ErrorHint(
|
||||
'It is also possible that $T does not implement "initInstances()" to assign a value to "instance". See the '
|
||||
'documentation of the BindingBase class for more details.',
|
||||
'documentation of the BaseBinding class for more details.',
|
||||
),
|
||||
ErrorHint(
|
||||
'The binding that was initialized was of the type "$_debugInitializedType". '
|
||||
@ -401,95 +399,6 @@ abstract class BindingBase {
|
||||
return _debugInitializedType;
|
||||
}
|
||||
|
||||
Zone? _debugBindingZone;
|
||||
|
||||
/// Whether [debugCheckZone] should throw (true) or just report the error (false).
|
||||
///
|
||||
/// Setting this to true makes it easier to catch cases where the zones are
|
||||
/// misconfigured, by allowing debuggers to stop at the point of error.
|
||||
///
|
||||
/// Currently this defaults to false, to avoid suddenly breaking applications
|
||||
/// that are affected by this check but appear to be working today. Applications
|
||||
/// are encouraged to resolve any issues that cause the [debugCheckZone] message
|
||||
/// to appear, as even if they appear to be working today, they are likely to be
|
||||
/// hiding hard-to-find bugs, and are more brittle (likely to collect bugs in
|
||||
/// the future).
|
||||
///
|
||||
/// To silence the message displayed by [debugCheckZone], ensure that the same
|
||||
/// zone is used when calling `ensureInitialized()` as when calling the framework
|
||||
/// in any other context (e.g. via [runApp]).
|
||||
static bool debugZoneErrorsAreFatal = false;
|
||||
|
||||
/// Checks that the current [Zone] is the same as that which was used
|
||||
/// to initialize the binding.
|
||||
///
|
||||
/// If the current zone ([Zone.current]) is not the zone that was active when
|
||||
/// the binding was initialized, then this method generates a [FlutterError]
|
||||
/// exception with detailed information. The exception is either thrown
|
||||
/// directly, or reported via [FlutterError.reportError], depending on the
|
||||
/// value of [BindingBase.debugZoneErrorsAreFatal].
|
||||
///
|
||||
/// To silence the message displayed by [debugCheckZone], ensure that the same
|
||||
/// zone is used when calling `ensureInitialized()` as when calling the
|
||||
/// framework in any other context (e.g. via [runApp]). For example, consider
|
||||
/// keeping a reference to the zone used to initialize the binding, and using
|
||||
/// [Zone.run] to use it again when calling into the framework.
|
||||
///
|
||||
/// ## Usage
|
||||
///
|
||||
/// The binding is considered initialized once [BindingBase.initInstances] has
|
||||
/// run; if this is called before then, it will throw an [AssertionError].
|
||||
///
|
||||
/// The `entryPoint` parameter is the name of the API that is checking the
|
||||
/// zones are consistent, for example, `'runApp'`.
|
||||
///
|
||||
/// This function always returns true (if it does not throw). It is expected
|
||||
/// to be invoked via the binding instance, e.g.:
|
||||
///
|
||||
/// ```dart
|
||||
/// void startup() {
|
||||
/// WidgetsBinding binding = WidgetsFlutterBinding.ensureInitialized();
|
||||
/// assert(binding.debugCheckZone('startup'));
|
||||
/// // ...
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// If the binding expects to be used with multiple zones, it should override
|
||||
/// this method to return true always without throwing. (For example, the
|
||||
/// bindings used with [flutter_test] do this as they make heavy use of zones
|
||||
/// to drive the framework with an artificial clock and to catch errors and
|
||||
/// report them as test failures.)
|
||||
bool debugCheckZone(String entryPoint) {
|
||||
assert(() {
|
||||
assert(_debugBindingZone != null, 'debugCheckZone can only be used after the binding is fully initialized.');
|
||||
if (Zone.current != _debugBindingZone) {
|
||||
final Error message = FlutterError(
|
||||
'Zone mismatch.\n'
|
||||
'The Flutter bindings were initialized in a different zone than is now being used. '
|
||||
'This will likely cause confusion and bugs as any zone-specific configuration will '
|
||||
'inconsistently use the configuration of the original binding initialization zone '
|
||||
'or this zone based on hard-to-predict factors such as which zone was active when '
|
||||
'a particular callback was set.\n'
|
||||
'It is important to use the same zone when calling `ensureInitialized` on the binding '
|
||||
'as when calling `$entryPoint` later.\n'
|
||||
'To make this ${ debugZoneErrorsAreFatal ? 'error non-fatal' : 'warning fatal' }, '
|
||||
'set BindingBase.debugZoneErrorsAreFatal to ${!debugZoneErrorsAreFatal} before the '
|
||||
'bindings are initialized (i.e. as the first statement in `void main() { }`).',
|
||||
);
|
||||
if (debugZoneErrorsAreFatal) {
|
||||
throw message;
|
||||
}
|
||||
FlutterError.reportError(FlutterErrorDetails(
|
||||
exception: message,
|
||||
stack: StackTrace.current,
|
||||
context: ErrorDescription('during $entryPoint'),
|
||||
));
|
||||
}
|
||||
return true;
|
||||
}());
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Called when the binding is initialized, to register service
|
||||
/// extensions.
|
||||
///
|
||||
|
@ -1031,7 +1031,6 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
|
||||
/// ensure the widget, element, and render trees are all built.
|
||||
void runApp(Widget app) {
|
||||
final WidgetsBinding binding = WidgetsFlutterBinding.ensureInitialized();
|
||||
assert(binding.debugCheckZone('runApp'));
|
||||
binding
|
||||
..scheduleAttachRootWidget(binding.wrapWithDefaultView(app))
|
||||
..scheduleWarmUpFrame();
|
||||
|
@ -1,63 +0,0 @@
|
||||
// Copyright 2014 The Flutter Authors. 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:flutter/foundation.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
class TestBinding extends BindingBase { }
|
||||
|
||||
void main() {
|
||||
test('BindingBase.debugCheckZone', () async {
|
||||
final BindingBase binding = TestBinding();
|
||||
binding.debugCheckZone('test1');
|
||||
BindingBase.debugZoneErrorsAreFatal = true;
|
||||
Zone.current.fork().run(() {
|
||||
try {
|
||||
binding.debugCheckZone('test2');
|
||||
fail('expected an exception');
|
||||
} catch (error) {
|
||||
expect(error, isA<FlutterError>());
|
||||
expect(error.toString(),
|
||||
'Zone mismatch.\n'
|
||||
'The Flutter bindings were initialized in a different zone than is now being used. '
|
||||
'This will likely cause confusion and bugs as any zone-specific configuration will '
|
||||
'inconsistently use the configuration of the original binding initialization zone '
|
||||
'or this zone based on hard-to-predict factors such as which zone was active when '
|
||||
'a particular callback was set.\n'
|
||||
'It is important to use the same zone when calling `ensureInitialized` on the '
|
||||
'binding as when calling `test2` later.\n'
|
||||
'To make this error non-fatal, set BindingBase.debugZoneErrorsAreFatal to false '
|
||||
'before the bindings are initialized (i.e. as the first statement in `void main() { }`).',
|
||||
);
|
||||
}
|
||||
});
|
||||
BindingBase.debugZoneErrorsAreFatal = false;
|
||||
Zone.current.fork().run(() {
|
||||
bool sawError = false;
|
||||
final FlutterExceptionHandler? lastHandler = FlutterError.onError;
|
||||
FlutterError.onError = (FlutterErrorDetails details) {
|
||||
final Object error = details.exception;
|
||||
expect(error, isA<FlutterError>());
|
||||
expect(error.toString(),
|
||||
'Zone mismatch.\n'
|
||||
'The Flutter bindings were initialized in a different zone than is now being used. '
|
||||
'This will likely cause confusion and bugs as any zone-specific configuration will '
|
||||
'inconsistently use the configuration of the original binding initialization zone '
|
||||
'or this zone based on hard-to-predict factors such as which zone was active when '
|
||||
'a particular callback was set.\n'
|
||||
'It is important to use the same zone when calling `ensureInitialized` on the '
|
||||
'binding as when calling `test3` later.\n'
|
||||
'To make this warning fatal, set BindingBase.debugZoneErrorsAreFatal to true '
|
||||
'before the bindings are initialized (i.e. as the first statement in `void main() { }`).',
|
||||
);
|
||||
sawError = true;
|
||||
};
|
||||
binding.debugCheckZone('test3');
|
||||
expect(sawError, isTrue);
|
||||
FlutterError.onError = lastHandler;
|
||||
});
|
||||
});
|
||||
}
|
@ -27,6 +27,7 @@ class FooLibraryBinding extends BindingBase with FooBinding {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void main() {
|
||||
test('BindingBase.debugBindingType', () async {
|
||||
expect(BindingBase.debugBindingType(), isNull);
|
||||
|
@ -47,9 +47,6 @@ class TestBindingBase implements BindingBase {
|
||||
@override
|
||||
void initInstances() {}
|
||||
|
||||
@override
|
||||
bool debugCheckZone(String entryPoint) { return true; }
|
||||
|
||||
@override
|
||||
void initServiceExtensions() {}
|
||||
|
||||
|
@ -3,39 +3,12 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:fake_async/fake_async.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
// This test is very fragile and bypasses some zone-related checks.
|
||||
// It is written this way to verify some invariants that would otherwise
|
||||
// be difficult to check.
|
||||
// Do not use this test as a guide for writing good Flutter code.
|
||||
|
||||
class TestBinding extends WidgetsFlutterBinding {
|
||||
@override
|
||||
void initInstances() {
|
||||
super.initInstances();
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
@override
|
||||
bool debugCheckZone(String entryPoint) { return true; }
|
||||
|
||||
static TestBinding get instance => BindingBase.checkInstance(_instance);
|
||||
static TestBinding? _instance;
|
||||
|
||||
static TestBinding ensureInitialized() {
|
||||
if (TestBinding._instance == null) {
|
||||
TestBinding();
|
||||
}
|
||||
return TestBinding.instance;
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
setUp(() {
|
||||
TestBinding.ensureInitialized();
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
WidgetsBinding.instance.resetEpoch();
|
||||
});
|
||||
|
||||
|
@ -39,11 +39,6 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding,
|
||||
final List<FinderExtension>? finders;
|
||||
final List<CommandExtension>? commands;
|
||||
|
||||
// Because you can't really control which zone a driver test uses,
|
||||
// we override the test for zones here.
|
||||
@override
|
||||
bool debugCheckZone(String entryPoint) { return true; }
|
||||
|
||||
@override
|
||||
void initServiceExtensions() {
|
||||
super.initServiceExtensions();
|
||||
|
@ -369,13 +369,6 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
// doesn't get generated for tests.
|
||||
}
|
||||
|
||||
@override
|
||||
bool debugCheckZone(String entryPoint) {
|
||||
// We skip all the zone checks in tests because the test framework makes heavy use
|
||||
// of zones and so the zones never quite match the way the framework expects.
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Whether there is currently a test executing.
|
||||
bool get inTest;
|
||||
|
||||
@ -822,9 +815,9 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
||||
};
|
||||
FlutterError.demangleStackTrace = (StackTrace stack) {
|
||||
// package:stack_trace uses ZoneSpecification.errorCallback to add useful
|
||||
// information to stack traces, meaning Trace and Chain classes can be
|
||||
// present. Because these StackTrace implementations do not follow the
|
||||
// format the framework expects, we convert them to a vm trace here.
|
||||
// information to stack traces, in this case the Trace and Chain classes
|
||||
// can be present. Because these StackTrace implementations do not follow
|
||||
// the format the framework expects, we covert them to a vm trace here.
|
||||
if (stack is stack_trace.Trace) {
|
||||
return stack.vmTrace;
|
||||
}
|
||||
|
@ -2,38 +2,11 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
// This test is very fragile and bypasses some zone-related checks.
|
||||
// It is written this way to verify some invariants that would otherwise
|
||||
// be difficult to check.
|
||||
// Do not use this test as a guide for writing good Flutter code.
|
||||
|
||||
class TestBinding extends WidgetsFlutterBinding {
|
||||
@override
|
||||
void initInstances() {
|
||||
super.initInstances();
|
||||
_instance = this;
|
||||
}
|
||||
|
||||
@override
|
||||
bool debugCheckZone(String entryPoint) { return true; }
|
||||
|
||||
static TestBinding get instance => BindingBase.checkInstance(_instance);
|
||||
static TestBinding? _instance;
|
||||
|
||||
static TestBinding ensureInitialized() {
|
||||
if (TestBinding._instance == null) {
|
||||
TestBinding();
|
||||
}
|
||||
return TestBinding.instance;
|
||||
}
|
||||
}
|
||||
|
||||
class CountButton extends StatefulWidget {
|
||||
const CountButton({super.key});
|
||||
|
||||
@ -92,8 +65,6 @@ class _AnimateSampleState extends State<AnimateSample>
|
||||
}
|
||||
|
||||
void main() {
|
||||
TestBinding.ensureInitialized();
|
||||
|
||||
test('Test pump on LiveWidgetController', () async {
|
||||
runApp(const MaterialApp(home: Center(child: CountButton())));
|
||||
|
||||
@ -138,7 +109,7 @@ void main() {
|
||||
final List<PointerEventRecord> records = <PointerEventRecord>[
|
||||
PointerEventRecord(Duration.zero, <PointerEvent>[
|
||||
// Typically PointerAddedEvent is not used in testers, but for records
|
||||
// captured on a device it is usually what starts a gesture.
|
||||
// captured on a device it is usually what start a gesture.
|
||||
PointerAddedEvent(
|
||||
position: location,
|
||||
),
|
||||
|
Loading…
x
Reference in New Issue
Block a user