Unverified Commit 5bea4d90 authored by yaakovschectman's avatar yaakovschectman Committed by GitHub

Revert "Assert that runApp is called in the same zone as...

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"
parent 62171dfe
...@@ -5,9 +5,7 @@ ...@@ -5,9 +5,7 @@
import 'dart:developer' as developer; import 'dart:developer' as developer;
import 'dart:isolate' as isolate; import 'dart:isolate' as isolate;
import 'package:flutter/foundation.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:vm_service/vm_service.dart'; import 'package:vm_service/vm_service.dart';
import 'package:vm_service/vm_service_io.dart'; import 'package:vm_service/vm_service_io.dart';
...@@ -54,29 +52,3 @@ Future<void> runFrame(VoidCallback callback) { ...@@ -54,29 +52,3 @@ Future<void> runFrame(VoidCallback callback) {
callback(); callback();
return result; 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'; ...@@ -13,8 +13,6 @@ import 'package:vm_service/vm_service.dart';
import 'package:vm_service/vm_service_io.dart'; import 'package:vm_service/vm_service_io.dart';
void main() { void main() {
LiveTestWidgetsFlutterBinding.ensureInitialized();
late VmService vmService; late VmService vmService;
late LiveTestWidgetsFlutterBinding binding; late LiveTestWidgetsFlutterBinding binding;
setUpAll(() async { setUpAll(() async {
...@@ -29,7 +27,7 @@ void main() { ...@@ -29,7 +27,7 @@ void main() {
await vmService.streamListen(EventStreams.kExtension); await vmService.streamListen(EventStreams.kExtension);
// Initialize bindings // Initialize bindings
binding = LiveTestWidgetsFlutterBinding.instance; binding = LiveTestWidgetsFlutterBinding();
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive; binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
binding.attachRootWidget(const SizedBox.expand()); binding.attachRootWidget(const SizedBox.expand());
expect(binding.framesEnabled, true); expect(binding.framesEnabled, true);
......
...@@ -16,7 +16,7 @@ final Set<String> interestingLabels = <String>{ ...@@ -16,7 +16,7 @@ final Set<String> interestingLabels = <String>{
}; };
void main() { void main() {
ZoneIgnoringTestBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
initTimelineTests(); initTimelineTests();
test('Children of MultiChildRenderObjectElement show up in tracing', () async { test('Children of MultiChildRenderObjectElement show up in tracing', () async {
// We don't have expectations around the first frame because there's a race around // 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'; ...@@ -9,7 +9,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'common.dart'; import 'common.dart';
void main() { void main() {
ZoneIgnoringTestBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
initTimelineTests(); initTimelineTests();
test('Widgets with updated keys produce well formed timelines', () async { test('Widgets with updated keys produce well formed timelines', () async {
await runFrame(() { runApp(const TestRoot()); }); await runFrame(() { runApp(const TestRoot()); });
......
...@@ -58,7 +58,7 @@ class TestRootState extends State<TestRoot> { ...@@ -58,7 +58,7 @@ class TestRootState extends State<TestRoot> {
} }
void main() { void main() {
ZoneIgnoringTestBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
initTimelineTests(); initTimelineTests();
test('Timeline', () async { test('Timeline', () async {
// We don't have expectations around the first frame because there's a race around // We don't have expectations around the first frame because there's a race around
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'dart:async';
import 'dart:convert' show json; import 'dart:convert' show json;
import 'dart:developer' as developer; import 'dart:developer' as developer;
import 'dart:io' show exit; import 'dart:io' show exit;
...@@ -266,7 +265,6 @@ abstract class BindingBase { ...@@ -266,7 +265,6 @@ abstract class BindingBase {
assert(_debugInitializedType == null); assert(_debugInitializedType == null);
assert(() { assert(() {
_debugInitializedType = runtimeType; _debugInitializedType = runtimeType;
_debugBindingZone = Zone.current;
return true; return true;
}()); }());
} }
...@@ -321,7 +319,7 @@ abstract class BindingBase { ...@@ -321,7 +319,7 @@ abstract class BindingBase {
), ),
ErrorHint( ErrorHint(
'It is also possible that $T does not implement "initInstances()" to assign a value to "instance". See the ' '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( ErrorHint(
'The binding that was initialized was of the type "$_debugInitializedType". ' 'The binding that was initialized was of the type "$_debugInitializedType". '
...@@ -401,95 +399,6 @@ abstract class BindingBase { ...@@ -401,95 +399,6 @@ abstract class BindingBase {
return _debugInitializedType; 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 /// Called when the binding is initialized, to register service
/// extensions. /// extensions.
/// ///
......
...@@ -1031,7 +1031,6 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB ...@@ -1031,7 +1031,6 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
/// ensure the widget, element, and render trees are all built. /// ensure the widget, element, and render trees are all built.
void runApp(Widget app) { void runApp(Widget app) {
final WidgetsBinding binding = WidgetsFlutterBinding.ensureInitialized(); final WidgetsBinding binding = WidgetsFlutterBinding.ensureInitialized();
assert(binding.debugCheckZone('runApp'));
binding binding
..scheduleAttachRootWidget(binding.wrapWithDefaultView(app)) ..scheduleAttachRootWidget(binding.wrapWithDefaultView(app))
..scheduleWarmUpFrame(); ..scheduleWarmUpFrame();
......
// 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 { ...@@ -27,6 +27,7 @@ class FooLibraryBinding extends BindingBase with FooBinding {
} }
} }
void main() { void main() {
test('BindingBase.debugBindingType', () async { test('BindingBase.debugBindingType', () async {
expect(BindingBase.debugBindingType(), isNull); expect(BindingBase.debugBindingType(), isNull);
......
...@@ -47,9 +47,6 @@ class TestBindingBase implements BindingBase { ...@@ -47,9 +47,6 @@ class TestBindingBase implements BindingBase {
@override @override
void initInstances() {} void initInstances() {}
@override
bool debugCheckZone(String entryPoint) { return true; }
@override @override
void initServiceExtensions() {} void initServiceExtensions() {}
......
...@@ -3,39 +3,12 @@ ...@@ -3,39 +3,12 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:fake_async/fake_async.dart'; import 'package:fake_async/fake_async.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.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() { void main() {
setUp(() { setUp(() {
TestBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
WidgetsBinding.instance.resetEpoch(); WidgetsBinding.instance.resetEpoch();
}); });
......
...@@ -39,11 +39,6 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding, ...@@ -39,11 +39,6 @@ class _DriverBinding extends BindingBase with SchedulerBinding, ServicesBinding,
final List<FinderExtension>? finders; final List<FinderExtension>? finders;
final List<CommandExtension>? commands; 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 @override
void initServiceExtensions() { void initServiceExtensions() {
super.initServiceExtensions(); super.initServiceExtensions();
......
...@@ -369,13 +369,6 @@ abstract class TestWidgetsFlutterBinding extends BindingBase ...@@ -369,13 +369,6 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
// doesn't get generated for tests. // 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. /// Whether there is currently a test executing.
bool get inTest; bool get inTest;
...@@ -822,9 +815,9 @@ abstract class TestWidgetsFlutterBinding extends BindingBase ...@@ -822,9 +815,9 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
}; };
FlutterError.demangleStackTrace = (StackTrace stack) { FlutterError.demangleStackTrace = (StackTrace stack) {
// package:stack_trace uses ZoneSpecification.errorCallback to add useful // package:stack_trace uses ZoneSpecification.errorCallback to add useful
// information to stack traces, meaning Trace and Chain classes can be // information to stack traces, in this case the Trace and Chain classes
// present. Because these StackTrace implementations do not follow the // can be present. Because these StackTrace implementations do not follow
// format the framework expects, we convert them to a vm trace here. // the format the framework expects, we covert them to a vm trace here.
if (stack is stack_trace.Trace) { if (stack is stack_trace.Trace) {
return stack.vmTrace; return stack.vmTrace;
} }
......
...@@ -2,38 +2,11 @@ ...@@ -2,38 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter_test/flutter_test.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 { class CountButton extends StatefulWidget {
const CountButton({super.key}); const CountButton({super.key});
...@@ -92,8 +65,6 @@ class _AnimateSampleState extends State<AnimateSample> ...@@ -92,8 +65,6 @@ class _AnimateSampleState extends State<AnimateSample>
} }
void main() { void main() {
TestBinding.ensureInitialized();
test('Test pump on LiveWidgetController', () async { test('Test pump on LiveWidgetController', () async {
runApp(const MaterialApp(home: Center(child: CountButton()))); runApp(const MaterialApp(home: Center(child: CountButton())));
...@@ -138,7 +109,7 @@ void main() { ...@@ -138,7 +109,7 @@ void main() {
final List<PointerEventRecord> records = <PointerEventRecord>[ final List<PointerEventRecord> records = <PointerEventRecord>[
PointerEventRecord(Duration.zero, <PointerEvent>[ PointerEventRecord(Duration.zero, <PointerEvent>[
// Typically PointerAddedEvent is not used in testers, but for records // 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( PointerAddedEvent(
position: location, position: location,
), ),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment