Test service extensions (#7849)
...and fix bugs that the tests uncovered. WRITE TEST FIND BUG
This commit is contained in:
parent
cce70d7069
commit
be7be2b8b6
@ -2,9 +2,16 @@
|
|||||||
// 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/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
class TestTestBinding extends AutomatedTestWidgetsFlutterBinding {
|
||||||
|
@override
|
||||||
|
DebugPrintCallback get debugPrintOverride => testPrint;
|
||||||
|
static void testPrint(String message, { int wrapWidth }) { print(message); }
|
||||||
|
}
|
||||||
|
|
||||||
Future<Null> guardedHelper(WidgetTester tester) {
|
Future<Null> guardedHelper(WidgetTester tester) {
|
||||||
return TestAsyncUtils.guard(() async {
|
return TestAsyncUtils.guard(() async {
|
||||||
await tester.pumpWidget(new Text('Hello'));
|
await tester.pumpWidget(new Text('Hello'));
|
||||||
@ -12,8 +19,8 @@ Future<Null> guardedHelper(WidgetTester tester) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
new TestTestBinding();
|
||||||
testWidgets('TestAsyncUtils - custom guarded sections', (WidgetTester tester) async {
|
testWidgets('TestAsyncUtils - custom guarded sections', (WidgetTester tester) async {
|
||||||
debugPrint = (String message, { int wrapWidth }) { print(message); };
|
|
||||||
await tester.pumpWidget(new Container());
|
await tester.pumpWidget(new Container());
|
||||||
expect(find.byElementType(Container), isNotNull);
|
expect(find.byElementType(Container), isNotNull);
|
||||||
guardedHelper(tester);
|
guardedHelper(tester);
|
||||||
|
@ -2,16 +2,22 @@
|
|||||||
// 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/widgets.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
class TestTestBinding extends AutomatedTestWidgetsFlutterBinding {
|
||||||
|
@override
|
||||||
|
DebugPrintCallback get debugPrintOverride => testPrint;
|
||||||
|
static void testPrint(String message, { int wrapWidth }) { print(message); }
|
||||||
|
}
|
||||||
|
|
||||||
Future<Null> helperFunction(WidgetTester tester) async {
|
Future<Null> helperFunction(WidgetTester tester) async {
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
new TestTestBinding();
|
||||||
testWidgets('TestAsyncUtils - handling unguarded async helper functions', (WidgetTester tester) async {
|
testWidgets('TestAsyncUtils - handling unguarded async helper functions', (WidgetTester tester) async {
|
||||||
debugPrint = (String message, { int wrapWidth }) { print(message); };
|
|
||||||
helperFunction(tester);
|
helperFunction(tester);
|
||||||
helperFunction(tester);
|
helperFunction(tester);
|
||||||
// this should fail
|
// this should fail
|
||||||
|
@ -46,7 +46,7 @@ class TestAssetBundle extends AssetBundle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<dynamic> loadStructuredData<T>(String key, Future<T> parser(String value)) async {
|
Future<T> loadStructuredData<T>(String key, Future<T> parser(String value)) async {
|
||||||
return parser(await loadString(key));
|
return parser(await loadString(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ export 'src/foundation/assertions.dart';
|
|||||||
export 'src/foundation/basic_types.dart';
|
export 'src/foundation/basic_types.dart';
|
||||||
export 'src/foundation/binding.dart';
|
export 'src/foundation/binding.dart';
|
||||||
export 'src/foundation/change_notifier.dart';
|
export 'src/foundation/change_notifier.dart';
|
||||||
|
export 'src/foundation/debug.dart';
|
||||||
export 'src/foundation/licenses.dart';
|
export 'src/foundation/licenses.dart';
|
||||||
export 'src/foundation/observer_list.dart';
|
export 'src/foundation/observer_list.dart';
|
||||||
export 'src/foundation/platform.dart';
|
export 'src/foundation/platform.dart';
|
||||||
|
@ -19,7 +19,7 @@ import 'basic_types.dart';
|
|||||||
/// "type" key will be set to the string `_extensionType` to indicate
|
/// "type" key will be set to the string `_extensionType` to indicate
|
||||||
/// that this is a return value from a service extension, and the
|
/// that this is a return value from a service extension, and the
|
||||||
/// "method" key will be set to the full name of the method.
|
/// "method" key will be set to the full name of the method.
|
||||||
typedef Future<Map<String, dynamic>> ServiceExtensionCallback(Map<String, String> parameters);
|
typedef Future<Map<String, String>> ServiceExtensionCallback(Map<String, String> parameters);
|
||||||
|
|
||||||
/// Base class for mixins that provide singleton services (also known as
|
/// Base class for mixins that provide singleton services (also known as
|
||||||
/// "bindings").
|
/// "bindings").
|
||||||
@ -56,7 +56,7 @@ abstract class BindingBase {
|
|||||||
initServiceExtensions();
|
initServiceExtensions();
|
||||||
assert(_debugServiceExtensionsRegistered);
|
assert(_debugServiceExtensionsRegistered);
|
||||||
|
|
||||||
developer.postEvent('Flutter.FrameworkInitialization', <String, dynamic>{});
|
developer.postEvent('Flutter.FrameworkInitialization', <String, String>{});
|
||||||
|
|
||||||
developer.Timeline.finishSync();
|
developer.Timeline.finishSync();
|
||||||
}
|
}
|
||||||
@ -150,7 +150,7 @@ abstract class BindingBase {
|
|||||||
name: name,
|
name: name,
|
||||||
callback: (Map<String, String> parameters) async {
|
callback: (Map<String, String> parameters) async {
|
||||||
await callback();
|
await callback();
|
||||||
return <String, dynamic>{};
|
return <String, String>{};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -181,7 +181,7 @@ abstract class BindingBase {
|
|||||||
callback: (Map<String, String> parameters) async {
|
callback: (Map<String, String> parameters) async {
|
||||||
if (parameters.containsKey('enabled'))
|
if (parameters.containsKey('enabled'))
|
||||||
await setter(parameters['enabled'] == 'true');
|
await setter(parameters['enabled'] == 'true');
|
||||||
return <String, dynamic>{ 'enabled': await getter() };
|
return <String, String>{ 'enabled': await getter() ? 'true' : 'false' };
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -211,7 +211,7 @@ abstract class BindingBase {
|
|||||||
callback: (Map<String, String> parameters) async {
|
callback: (Map<String, String> parameters) async {
|
||||||
if (parameters.containsKey(name))
|
if (parameters.containsKey(name))
|
||||||
await setter(double.parse(parameters[name]));
|
await setter(double.parse(parameters[name]));
|
||||||
return <String, dynamic>{ name: await getter() };
|
return <String, String>{ name: (await getter()).toString() };
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -240,7 +240,7 @@ abstract class BindingBase {
|
|||||||
callback: (Map<String, String> parameters) async {
|
callback: (Map<String, String> parameters) async {
|
||||||
if (parameters.containsKey('value'))
|
if (parameters.containsKey('value'))
|
||||||
await setter(parameters['value']);
|
await setter(parameters['value']);
|
||||||
return <String, dynamic>{ 'value': await getter() };
|
return <String, String>{ 'value': await getter() };
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -267,7 +267,7 @@ abstract class BindingBase {
|
|||||||
assert(method == methodName);
|
assert(method == methodName);
|
||||||
dynamic caughtException;
|
dynamic caughtException;
|
||||||
StackTrace caughtStack;
|
StackTrace caughtStack;
|
||||||
Map<String, dynamic> result;
|
Map<String, String> result;
|
||||||
try {
|
try {
|
||||||
result = await callback(parameters);
|
result = await callback(parameters);
|
||||||
} catch (exception, stack) {
|
} catch (exception, stack) {
|
||||||
@ -286,10 +286,10 @@ abstract class BindingBase {
|
|||||||
));
|
));
|
||||||
return new developer.ServiceExtensionResponse.error(
|
return new developer.ServiceExtensionResponse.error(
|
||||||
developer.ServiceExtensionResponse.extensionError,
|
developer.ServiceExtensionResponse.extensionError,
|
||||||
JSON.encode(<String, dynamic>{
|
JSON.encode(<String, String>{
|
||||||
'exception': caughtException.toString(),
|
'exception': caughtException.toString(),
|
||||||
'stack': caughtStack.toString(),
|
'stack': caughtStack.toString(),
|
||||||
'method': method
|
'method': method,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
28
packages/flutter/lib/src/foundation/debug.dart
Normal file
28
packages/flutter/lib/src/foundation/debug.dart
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
import 'assertions.dart';
|
||||||
|
import 'print.dart';
|
||||||
|
|
||||||
|
/// Returns true if none of the foundation library debug variables have been
|
||||||
|
/// changed.
|
||||||
|
///
|
||||||
|
/// This function is used by the test framework to ensure that debug variables
|
||||||
|
/// haven't been inadvertently changed.
|
||||||
|
///
|
||||||
|
/// The `debugPrintOverride` argument can be specified to indicate the expected
|
||||||
|
/// value of the [debugPrint] variable. This is useful for test frameworks that
|
||||||
|
/// override [debugPrint] themselves and want to check that their own custom
|
||||||
|
/// value wasn't overridden by a test.
|
||||||
|
///
|
||||||
|
/// See [https://docs.flutter.io/flutter/foundation/foundation-library.html] for
|
||||||
|
/// a complete list.
|
||||||
|
bool debugAssertAllFoundationVarsUnset(String reason, { DebugPrintCallback debugPrintOverride: debugPrintThrottled }) {
|
||||||
|
assert(() {
|
||||||
|
if (debugPrint != debugPrintOverride)
|
||||||
|
throw new FlutterError(reason);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
@ -57,8 +57,7 @@ abstract class RendererBinding extends BindingBase implements SchedulerBinding,
|
|||||||
if (debugPaintSizeEnabled == value)
|
if (debugPaintSizeEnabled == value)
|
||||||
return new Future<Null>.value();
|
return new Future<Null>.value();
|
||||||
debugPaintSizeEnabled = value;
|
debugPaintSizeEnabled = value;
|
||||||
_forceRepaint();
|
return _forceRepaint();
|
||||||
return endOfFrame;
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
@ -78,8 +77,8 @@ abstract class RendererBinding extends BindingBase implements SchedulerBinding,
|
|||||||
bool repaint = debugRepaintRainbowEnabled && !value;
|
bool repaint = debugRepaintRainbowEnabled && !value;
|
||||||
debugRepaintRainbowEnabled = value;
|
debugRepaintRainbowEnabled = value;
|
||||||
if (repaint)
|
if (repaint)
|
||||||
_forceRepaint();
|
return _forceRepaint();
|
||||||
return endOfFrame;
|
return new Future<Null>.value();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
@ -249,13 +248,14 @@ abstract class RendererBinding extends BindingBase implements SchedulerBinding,
|
|||||||
super.hitTest(result, position); // ignore: abstract_super_member_reference
|
super.hitTest(result, position); // ignore: abstract_super_member_reference
|
||||||
}
|
}
|
||||||
|
|
||||||
void _forceRepaint() {
|
Future<Null> _forceRepaint() {
|
||||||
RenderObjectVisitor visitor;
|
RenderObjectVisitor visitor;
|
||||||
visitor = (RenderObject child) {
|
visitor = (RenderObject child) {
|
||||||
child.markNeedsPaint();
|
child.markNeedsPaint();
|
||||||
child.visitChildren(visitor);
|
child.visitChildren(visitor);
|
||||||
};
|
};
|
||||||
instance?.renderView?.visitChildren(visitor);
|
instance?.renderView?.visitChildren(visitor);
|
||||||
|
return endOfFrame;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ abstract class AssetBundle {
|
|||||||
///
|
///
|
||||||
/// Implementations may cache the result, so a particular key should only be
|
/// Implementations may cache the result, so a particular key should only be
|
||||||
/// used with one parser for the lifetime of the asset bundle.
|
/// used with one parser for the lifetime of the asset bundle.
|
||||||
Future<dynamic> loadStructuredData<T>(String key, Future<T> parser(String value));
|
Future<T> loadStructuredData<T>(String key, Future<T> parser(String value));
|
||||||
|
|
||||||
/// If this is a caching asset bundle, and the given key describes a cached
|
/// If this is a caching asset bundle, and the given key describes a cached
|
||||||
/// asset, then evict the asset from the cache so that the next time it is
|
/// asset, then evict the asset from the cache so that the next time it is
|
||||||
@ -110,7 +110,7 @@ class NetworkAssetBundle extends AssetBundle {
|
|||||||
/// The result is not cached. The parser is run each time the resource is
|
/// The result is not cached. The parser is run each time the resource is
|
||||||
/// fetched.
|
/// fetched.
|
||||||
@override
|
@override
|
||||||
Future<dynamic> loadStructuredData<T>(String key, Future<T> parser(String value)) async {
|
Future<T> loadStructuredData<T>(String key, Future<T> parser(String value)) async {
|
||||||
assert(key != null);
|
assert(key != null);
|
||||||
assert(parser != null);
|
assert(parser != null);
|
||||||
return parser(await loadString(key));
|
return parser(await loadString(key));
|
||||||
@ -159,7 +159,7 @@ abstract class CachingAssetBundle extends AssetBundle {
|
|||||||
/// subsequent calls will be a [SynchronousFuture], which resolves its
|
/// subsequent calls will be a [SynchronousFuture], which resolves its
|
||||||
/// callback synchronously.
|
/// callback synchronously.
|
||||||
@override
|
@override
|
||||||
Future<dynamic> loadStructuredData<T>(String key, Future<T> parser(String value)) {
|
Future<T> loadStructuredData<T>(String key, Future<T> parser(String value)) {
|
||||||
assert(key != null);
|
assert(key != null);
|
||||||
assert(parser != null);
|
assert(parser != null);
|
||||||
if (_structuredDataCache.containsKey(key))
|
if (_structuredDataCache.containsKey(key))
|
||||||
|
@ -86,8 +86,7 @@ abstract class WidgetsBinding extends BindingBase implements GestureBinding, Ren
|
|||||||
if (WidgetsApp.showPerformanceOverlayOverride == value)
|
if (WidgetsApp.showPerformanceOverlayOverride == value)
|
||||||
return new Future<Null>.value();
|
return new Future<Null>.value();
|
||||||
WidgetsApp.showPerformanceOverlayOverride = value;
|
WidgetsApp.showPerformanceOverlayOverride = value;
|
||||||
buildOwner.reassemble(renderViewElement);
|
return _forceRebuild();
|
||||||
return endOfFrame;
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -98,12 +97,19 @@ abstract class WidgetsBinding extends BindingBase implements GestureBinding, Ren
|
|||||||
if (WidgetsApp.debugAllowBannerOverride == value)
|
if (WidgetsApp.debugAllowBannerOverride == value)
|
||||||
return new Future<Null>.value();
|
return new Future<Null>.value();
|
||||||
WidgetsApp.debugAllowBannerOverride = value;
|
WidgetsApp.debugAllowBannerOverride = value;
|
||||||
buildOwner.reassemble(renderViewElement);
|
return _forceRebuild();
|
||||||
return endOfFrame;
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Null> _forceRebuild() {
|
||||||
|
if (renderViewElement != null) {
|
||||||
|
buildOwner.reassemble(renderViewElement);
|
||||||
|
return endOfFrame;
|
||||||
|
}
|
||||||
|
return new Future<Null>.value();
|
||||||
|
}
|
||||||
|
|
||||||
/// The [BuildOwner] in charge of executing the build pipeline for the
|
/// The [BuildOwner] in charge of executing the build pipeline for the
|
||||||
/// widget tree rooted at this binding.
|
/// widget tree rooted at this binding.
|
||||||
BuildOwner get buildOwner => _buildOwner;
|
BuildOwner get buildOwner => _buildOwner;
|
||||||
|
336
packages/flutter/test/foundation/service_extensions_test.dart
Normal file
336
packages/flutter/test/foundation/service_extensions_test.dart
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
// Copyright 2017 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.
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/gestures.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
|
import 'package:flutter/scheduler.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
|
class TestServiceExtensionsBinding extends BindingBase
|
||||||
|
with SchedulerBinding,
|
||||||
|
ServicesBinding,
|
||||||
|
GestureBinding,
|
||||||
|
RendererBinding,
|
||||||
|
WidgetsBinding {
|
||||||
|
|
||||||
|
final Map<String, ServiceExtensionCallback> extensions = <String, ServiceExtensionCallback>{};
|
||||||
|
|
||||||
|
@override
|
||||||
|
void registerServiceExtension({
|
||||||
|
@required String name,
|
||||||
|
@required ServiceExtensionCallback callback
|
||||||
|
}) {
|
||||||
|
expect(extensions.containsKey(name), isFalse);
|
||||||
|
extensions[name] = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Map<String, String>> testExtension(String name, Map<String, String> arguments) {
|
||||||
|
expect(extensions.containsKey(name), isTrue);
|
||||||
|
return extensions[name](arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
int reassembled = 0;
|
||||||
|
@override
|
||||||
|
Future<Null> reassembleApplication() {
|
||||||
|
reassembled += 1;
|
||||||
|
return super.reassembleApplication();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool frameScheduled = false;
|
||||||
|
@override
|
||||||
|
void scheduleFrame() {
|
||||||
|
frameScheduled = true;
|
||||||
|
}
|
||||||
|
void doFrame() {
|
||||||
|
frameScheduled = false;
|
||||||
|
if (ui.window.onBeginFrame != null)
|
||||||
|
ui.window.onBeginFrame(const Duration());
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Null> flushMicrotasks() {
|
||||||
|
Completer<Null> completer = new Completer<Null>();
|
||||||
|
new Timer(const Duration(), () {
|
||||||
|
completer.complete();
|
||||||
|
});
|
||||||
|
return completer.future;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TestServiceExtensionsBinding binding;
|
||||||
|
List<String> console = <String>[];
|
||||||
|
|
||||||
|
test('Service extensions - pretest', () async {
|
||||||
|
binding = new TestServiceExtensionsBinding();
|
||||||
|
expect(binding.frameScheduled, isTrue);
|
||||||
|
binding.doFrame(); // initial frame scheduled by creating the binding
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
|
||||||
|
expect(debugPrint, equals(debugPrintThrottled));
|
||||||
|
debugPrint = (String message, { int wrapWidth }) {
|
||||||
|
console.add(message);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// The following list is alphabetical, one test per extension.
|
||||||
|
//
|
||||||
|
// The order doesn't really matter except that the pretest and posttest tests
|
||||||
|
// must be first and last respectively.
|
||||||
|
|
||||||
|
test('Service extensions - debugAllowBanner', () async {
|
||||||
|
Map<String, String> result;
|
||||||
|
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
expect(WidgetsApp.debugAllowBannerOverride, true);
|
||||||
|
result = await binding.testExtension('debugAllowBanner', <String, String>{});
|
||||||
|
expect(result, <String, String>{ 'enabled': 'true' });
|
||||||
|
expect(WidgetsApp.debugAllowBannerOverride, true);
|
||||||
|
result = await binding.testExtension('debugAllowBanner', <String, String>{ 'enabled': 'false' });
|
||||||
|
expect(result, <String, String>{ 'enabled': 'false' });
|
||||||
|
expect(WidgetsApp.debugAllowBannerOverride, false);
|
||||||
|
result = await binding.testExtension('debugAllowBanner', <String, String>{});
|
||||||
|
expect(result, <String, String>{ 'enabled': 'false' });
|
||||||
|
expect(WidgetsApp.debugAllowBannerOverride, false);
|
||||||
|
result = await binding.testExtension('debugAllowBanner', <String, String>{ 'enabled': 'true' });
|
||||||
|
expect(result, <String, String>{ 'enabled': 'true' });
|
||||||
|
expect(WidgetsApp.debugAllowBannerOverride, true);
|
||||||
|
result = await binding.testExtension('debugAllowBanner', <String, String>{});
|
||||||
|
expect(result, <String, String>{ 'enabled': 'true' });
|
||||||
|
expect(WidgetsApp.debugAllowBannerOverride, true);
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Service extensions - debugDumpApp', () async {
|
||||||
|
Map<String, String> result;
|
||||||
|
|
||||||
|
result = await binding.testExtension('debugDumpApp', <String, String>{});
|
||||||
|
expect(result, <String, String>{});
|
||||||
|
expect(console, <String>['TestServiceExtensionsBinding - CHECKED MODE', '<no tree currently mounted>']);
|
||||||
|
console.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Service extensions - debugDumpRenderTree', () async {
|
||||||
|
Map<String, String> result;
|
||||||
|
|
||||||
|
result = await binding.testExtension('debugDumpRenderTree', <String, String>{});
|
||||||
|
expect(result, <String, String>{});
|
||||||
|
expect(console, <String>[
|
||||||
|
'RenderView\n'
|
||||||
|
' debug mode enabled - linux\n'
|
||||||
|
' window size: Size(800.0, 600.0) (in physical pixels)\n'
|
||||||
|
' device pixel ratio: 1.0 (physical pixels per logical pixel)\n'
|
||||||
|
' configuration: Size(800.0, 600.0) at 1.0x (in logical pixels)\n'
|
||||||
|
'\n'
|
||||||
|
]);
|
||||||
|
console.clear();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Service extensions - debugPaint', () async {
|
||||||
|
Map<String, String> result;
|
||||||
|
Future<Map<String, String>> pendingResult;
|
||||||
|
bool completed;
|
||||||
|
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
expect(debugPaintSizeEnabled, false);
|
||||||
|
result = await binding.testExtension('debugPaint', <String, String>{});
|
||||||
|
expect(result, <String, String>{ 'enabled': 'false' });
|
||||||
|
expect(debugPaintSizeEnabled, false);
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
pendingResult = binding.testExtension('debugPaint', <String, String>{ 'enabled': 'true' });
|
||||||
|
completed = false;
|
||||||
|
pendingResult.whenComplete(() { completed = true; });
|
||||||
|
await binding.flushMicrotasks();
|
||||||
|
expect(binding.frameScheduled, isTrue);
|
||||||
|
expect(completed, isFalse);
|
||||||
|
binding.doFrame();
|
||||||
|
await binding.flushMicrotasks();
|
||||||
|
expect(completed, isTrue);
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
result = await pendingResult;
|
||||||
|
expect(result, <String, String>{ 'enabled': 'true' });
|
||||||
|
expect(debugPaintSizeEnabled, true);
|
||||||
|
result = await binding.testExtension('debugPaint', <String, String>{});
|
||||||
|
expect(result, <String, String>{ 'enabled': 'true' });
|
||||||
|
expect(debugPaintSizeEnabled, true);
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
pendingResult = binding.testExtension('debugPaint', <String, String>{ 'enabled': 'false' });
|
||||||
|
await binding.flushMicrotasks();
|
||||||
|
expect(binding.frameScheduled, isTrue);
|
||||||
|
binding.doFrame();
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
result = await pendingResult;
|
||||||
|
expect(result, <String, String>{ 'enabled': 'false' });
|
||||||
|
expect(debugPaintSizeEnabled, false);
|
||||||
|
result = await binding.testExtension('debugPaint', <String, String>{});
|
||||||
|
expect(result, <String, String>{ 'enabled': 'false' });
|
||||||
|
expect(debugPaintSizeEnabled, false);
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Service extensions - evict', () async {
|
||||||
|
Map<String, String> result;
|
||||||
|
bool completed;
|
||||||
|
|
||||||
|
completed = false;
|
||||||
|
PlatformMessages.setMockBinaryMessageHandler('flutter/assets', (ByteData message) async {
|
||||||
|
expect(UTF8.decode(message.buffer.asUint8List()), 'test');
|
||||||
|
completed = true;
|
||||||
|
return new ByteData(5); // 0x0000000000
|
||||||
|
});
|
||||||
|
bool data;
|
||||||
|
data = await rootBundle.loadStructuredData<bool>('test', (String value) async { expect(value, '\x00\x00\x00\x00\x00'); return true; });
|
||||||
|
expect(data, isTrue);
|
||||||
|
expect(completed, isTrue);
|
||||||
|
completed = false;
|
||||||
|
data = await rootBundle.loadStructuredData('test', (String value) async { expect(true, isFalse); return null; });
|
||||||
|
expect(data, isTrue);
|
||||||
|
expect(completed, isFalse);
|
||||||
|
result = await binding.testExtension('evict', <String, String>{ 'value': 'test' });
|
||||||
|
expect(result, <String, String>{ 'value': '' });
|
||||||
|
expect(completed, isFalse);
|
||||||
|
data = await rootBundle.loadStructuredData<bool>('test', (String value) async { expect(value, '\x00\x00\x00\x00\x00'); return false; });
|
||||||
|
expect(data, isFalse);
|
||||||
|
expect(completed, isTrue);
|
||||||
|
PlatformMessages.setMockBinaryMessageHandler('flutter/assets', null);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Service extensions - exit', () async {
|
||||||
|
// no test for _calling_ 'exit', because that should terminate the process!
|
||||||
|
expect(binding.extensions.containsKey('exit'), isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Service extensions - frameworkPresent', () async {
|
||||||
|
Map<String, String> result;
|
||||||
|
|
||||||
|
result = await binding.testExtension('frameworkPresent', <String, String>{});
|
||||||
|
expect(result, <String, String>{});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Service extensions - repaintRainbow', () async {
|
||||||
|
Map<String, String> result;
|
||||||
|
Future<Map<String, String>> pendingResult;
|
||||||
|
bool completed;
|
||||||
|
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
expect(debugRepaintRainbowEnabled, false);
|
||||||
|
result = await binding.testExtension('repaintRainbow', <String, String>{});
|
||||||
|
expect(result, <String, String>{ 'enabled': 'false' });
|
||||||
|
expect(debugRepaintRainbowEnabled, false);
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
pendingResult = binding.testExtension('repaintRainbow', <String, String>{ 'enabled': 'true' });
|
||||||
|
completed = false;
|
||||||
|
pendingResult.whenComplete(() { completed = true; });
|
||||||
|
await binding.flushMicrotasks();
|
||||||
|
expect(completed, true);
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
result = await pendingResult;
|
||||||
|
expect(result, <String, String>{ 'enabled': 'true' });
|
||||||
|
expect(debugRepaintRainbowEnabled, true);
|
||||||
|
result = await binding.testExtension('repaintRainbow', <String, String>{});
|
||||||
|
expect(result, <String, String>{ 'enabled': 'true' });
|
||||||
|
expect(debugRepaintRainbowEnabled, true);
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
pendingResult = binding.testExtension('repaintRainbow', <String, String>{ 'enabled': 'false' });
|
||||||
|
completed = false;
|
||||||
|
pendingResult.whenComplete(() { completed = true; });
|
||||||
|
await binding.flushMicrotasks();
|
||||||
|
expect(completed, false);
|
||||||
|
expect(binding.frameScheduled, isTrue);
|
||||||
|
binding.doFrame();
|
||||||
|
await binding.flushMicrotasks();
|
||||||
|
expect(completed, true);
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
result = await pendingResult;
|
||||||
|
expect(result, <String, String>{ 'enabled': 'false' });
|
||||||
|
expect(debugRepaintRainbowEnabled, false);
|
||||||
|
result = await binding.testExtension('repaintRainbow', <String, String>{});
|
||||||
|
expect(result, <String, String>{ 'enabled': 'false' });
|
||||||
|
expect(debugRepaintRainbowEnabled, false);
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Service extensions - reassemble', () async {
|
||||||
|
Map<String, String> result;
|
||||||
|
Future<Map<String, String>> pendingResult;
|
||||||
|
bool completed;
|
||||||
|
|
||||||
|
completed = false;
|
||||||
|
expect(binding.reassembled, 0);
|
||||||
|
pendingResult = binding.testExtension('reassemble', <String, String>{});
|
||||||
|
pendingResult.whenComplete(() { completed = true; });
|
||||||
|
await binding.flushMicrotasks();
|
||||||
|
expect(binding.frameScheduled, isTrue);
|
||||||
|
expect(completed, false);
|
||||||
|
binding.doFrame();
|
||||||
|
await binding.flushMicrotasks();
|
||||||
|
expect(completed, true);
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
result = await pendingResult;
|
||||||
|
expect(result, <String, String>{});
|
||||||
|
expect(binding.reassembled, 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Service extensions - showPerformanceOverlay', () async {
|
||||||
|
Map<String, String> result;
|
||||||
|
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
expect(WidgetsApp.showPerformanceOverlayOverride, false);
|
||||||
|
result = await binding.testExtension('showPerformanceOverlay', <String, String>{});
|
||||||
|
expect(result, <String, String>{ 'enabled': 'false' });
|
||||||
|
expect(WidgetsApp.showPerformanceOverlayOverride, false);
|
||||||
|
result = await binding.testExtension('showPerformanceOverlay', <String, String>{ 'enabled': 'true' });
|
||||||
|
expect(result, <String, String>{ 'enabled': 'true' });
|
||||||
|
expect(WidgetsApp.showPerformanceOverlayOverride, true);
|
||||||
|
result = await binding.testExtension('showPerformanceOverlay', <String, String>{});
|
||||||
|
expect(result, <String, String>{ 'enabled': 'true' });
|
||||||
|
expect(WidgetsApp.showPerformanceOverlayOverride, true);
|
||||||
|
result = await binding.testExtension('showPerformanceOverlay', <String, String>{ 'enabled': 'false' });
|
||||||
|
expect(result, <String, String>{ 'enabled': 'false' });
|
||||||
|
expect(WidgetsApp.showPerformanceOverlayOverride, false);
|
||||||
|
result = await binding.testExtension('showPerformanceOverlay', <String, String>{});
|
||||||
|
expect(result, <String, String>{ 'enabled': 'false' });
|
||||||
|
expect(WidgetsApp.showPerformanceOverlayOverride, false);
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Service extensions - timeDilation', () async {
|
||||||
|
Map<String, String> result;
|
||||||
|
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
expect(timeDilation, 1.0);
|
||||||
|
result = await binding.testExtension('timeDilation', <String, String>{});
|
||||||
|
expect(result, <String, String>{ 'timeDilation': '1.0' });
|
||||||
|
expect(timeDilation, 1.0);
|
||||||
|
result = await binding.testExtension('timeDilation', <String, String>{ 'timeDilation': '100.0' });
|
||||||
|
expect(result, <String, String>{ 'timeDilation': '100.0' });
|
||||||
|
expect(timeDilation, 100.0);
|
||||||
|
result = await binding.testExtension('timeDilation', <String, String>{});
|
||||||
|
expect(result, <String, String>{ 'timeDilation': '100.0' });
|
||||||
|
expect(timeDilation, 100.0);
|
||||||
|
result = await binding.testExtension('timeDilation', <String, String>{ 'timeDilation': '1.0' });
|
||||||
|
expect(result, <String, String>{ 'timeDilation': '1.0' });
|
||||||
|
expect(timeDilation, 1.0);
|
||||||
|
result = await binding.testExtension('timeDilation', <String, String>{});
|
||||||
|
expect(result, <String, String>{ 'timeDilation': '1.0' });
|
||||||
|
expect(timeDilation, 1.0);
|
||||||
|
expect(binding.frameScheduled, isFalse);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Service extensions - posttest', () async {
|
||||||
|
// If you add a service extension... TEST IT! :-)
|
||||||
|
// ...then increment this number.
|
||||||
|
expect(binding.extensions.length, 11);
|
||||||
|
|
||||||
|
expect(console, isEmpty);
|
||||||
|
debugPrint = debugPrintThrottled;
|
||||||
|
});
|
||||||
|
}
|
@ -86,6 +86,14 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
|||||||
RendererBinding,
|
RendererBinding,
|
||||||
// Services binding omitted to avoid dragging in the licenses code.
|
// Services binding omitted to avoid dragging in the licenses code.
|
||||||
WidgetsBinding {
|
WidgetsBinding {
|
||||||
|
|
||||||
|
TestWidgetsFlutterBinding() {
|
||||||
|
debugPrint = debugPrintOverride;
|
||||||
|
}
|
||||||
|
|
||||||
|
@protected
|
||||||
|
DebugPrintCallback get debugPrintOverride => debugPrint;
|
||||||
|
|
||||||
/// Creates and initializes the binding. This function is
|
/// Creates and initializes the binding. This function is
|
||||||
/// idempotent; calling it a second time will just return the
|
/// idempotent; calling it a second time will just return the
|
||||||
/// previously-created instance.
|
/// previously-created instance.
|
||||||
@ -399,6 +407,10 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
|||||||
assert(debugAssertNoTransientCallbacks(
|
assert(debugAssertNoTransientCallbacks(
|
||||||
'An animation is still running even after the widget tree was disposed.'
|
'An animation is still running even after the widget tree was disposed.'
|
||||||
));
|
));
|
||||||
|
assert(debugAssertAllFoundationVarsUnset(
|
||||||
|
'The value of a foundation debug variable was changed by the test.',
|
||||||
|
debugPrintOverride: debugPrintOverride,
|
||||||
|
));
|
||||||
assert(debugAssertAllRenderVarsUnset(
|
assert(debugAssertAllRenderVarsUnset(
|
||||||
'The value of a rendering debug variable was changed by the test.'
|
'The value of a rendering debug variable was changed by the test.'
|
||||||
));
|
));
|
||||||
@ -431,7 +443,6 @@ abstract class TestWidgetsFlutterBinding extends BindingBase
|
|||||||
class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
|
class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
|
||||||
@override
|
@override
|
||||||
void initInstances() {
|
void initInstances() {
|
||||||
debugPrint = debugPrintSynchronously;
|
|
||||||
super.initInstances();
|
super.initInstances();
|
||||||
ui.window.onBeginFrame = null;
|
ui.window.onBeginFrame = null;
|
||||||
}
|
}
|
||||||
@ -439,6 +450,9 @@ class AutomatedTestWidgetsFlutterBinding extends TestWidgetsFlutterBinding {
|
|||||||
FakeAsync _fakeAsync;
|
FakeAsync _fakeAsync;
|
||||||
Clock _clock;
|
Clock _clock;
|
||||||
|
|
||||||
|
@override
|
||||||
|
DebugPrintCallback get debugPrintOverride => debugPrintSynchronously;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
test_package.Timeout get defaultTestTimeout => const test_package.Timeout(const Duration(seconds: 5));
|
test_package.Timeout get defaultTestTimeout => const test_package.Timeout(const Duration(seconds: 5));
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ Future<Null> _testFile(String testName, int wantedExitCode, String workingDirect
|
|||||||
expect(haveSeenStdErrMarker, isFalse);
|
expect(haveSeenStdErrMarker, isFalse);
|
||||||
haveSeenStdErrMarker = true;
|
haveSeenStdErrMarker = true;
|
||||||
}
|
}
|
||||||
expect(outputLine, matches(expectationLine));
|
expect(outputLine, matches(expectationLine), verbose: true, reason: 'Full output:\n- - - -----8<----- - - -\n${output.join("\n")}\n- - - -----8<----- - - -');
|
||||||
expectationLineNumber += 1;
|
expectationLineNumber += 1;
|
||||||
outputLineNumber += 1;
|
outputLineNumber += 1;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user