From 88e49ed274b5515caa9faaf03b261f9a73cf7e37 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Thu, 10 Nov 2022 20:17:12 -0800 Subject: [PATCH] Load assets in flutter_test without turning event loop. (#115123) * Load assets in flutter_test without turning event loop. This makes it possible to load an asset without actually turning the event loop. This is importnat because our FakeAsync zones may cause people to sprinkle in extra pumpAndSettles in when running tests that load assets, which is undesirable. * fix null checking --- .../src/foundation/synchronous_future.dart | 4 ++-- .../lib/src/services/asset_bundle.dart | 23 ++++++++++++------- .../flutter_test/lib/src/_binding_io.dart | 6 ++--- packages/flutter_test/test/bindings_test.dart | 10 ++++++++ 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/packages/flutter/lib/src/foundation/synchronous_future.dart b/packages/flutter/lib/src/foundation/synchronous_future.dart index d214697ad98c..ccdd1073dbde 100644 --- a/packages/flutter/lib/src/foundation/synchronous_future.dart +++ b/packages/flutter/lib/src/foundation/synchronous_future.dart @@ -38,11 +38,11 @@ class SynchronousFuture implements Future { @override Future then(FutureOr Function(T value) onValue, { Function? onError }) { - final dynamic result = onValue(_value); + final FutureOr result = onValue(_value); if (result is Future) { return result; } - return SynchronousFuture(result as R); + return SynchronousFuture(result); } @override diff --git a/packages/flutter/lib/src/services/asset_bundle.dart b/packages/flutter/lib/src/services/asset_bundle.dart index 5b9fadd9e6f2..776035aa6871 100644 --- a/packages/flutter/lib/src/services/asset_bundle.dart +++ b/packages/flutter/lib/src/services/asset_bundle.dart @@ -247,17 +247,24 @@ abstract class CachingAssetBundle extends AssetBundle { /// An [AssetBundle] that loads resources using platform messages. class PlatformAssetBundle extends CachingAssetBundle { @override - Future load(String key) async { + Future load(String key) { final Uint8List encoded = utf8.encoder.convert(Uri(path: Uri.encodeFull(key)).path); - final ByteData? asset = - await ServicesBinding.instance.defaultBinaryMessenger.send('flutter/assets', encoded.buffer.asByteData()); - if (asset == null) { + final Future? future = ServicesBinding.instance.defaultBinaryMessenger.send('flutter/assets', encoded.buffer.asByteData())?.then((ByteData? asset) { + if (asset == null) { + throw FlutterError.fromParts([ + _errorSummaryWithKey(key), + ErrorDescription('The asset does not exist or has empty data.'), + ]); + } + return asset; + }); + if (future == null) { throw FlutterError.fromParts([ - _errorSummaryWithKey(key), - ErrorDescription('The asset does not exist or has empty data.'), - ]); + _errorSummaryWithKey(key), + ErrorDescription('The asset does not exist or has empty data.'), + ]); } - return asset; + return future; } @override diff --git a/packages/flutter_test/lib/src/_binding_io.dart b/packages/flutter_test/lib/src/_binding_io.dart index 0dc72180fde8..468dd9b5d548 100644 --- a/packages/flutter_test/lib/src/_binding_io.dart +++ b/packages/flutter_test/lib/src/_binding_io.dart @@ -6,8 +6,8 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; +import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart'; import 'package:path/path.dart' as path; // ignore: deprecated_member_use import 'package:test_api/test_api.dart' as test_package; @@ -42,7 +42,7 @@ void mockFlutterAssets() { /// platform messages. SystemChannels.navigation.setMockMethodCallHandler((MethodCall methodCall) async {}); - ServicesBinding.instance.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', (ByteData? message) async { + ServicesBinding.instance.defaultBinaryMessenger.setMockMessageHandler('flutter/assets', (ByteData? message) { assert(message != null); String key = utf8.decode(message!.buffer.asUint8List()); File asset = File(path.join(assetFolderPath, key)); @@ -62,7 +62,7 @@ void mockFlutterAssets() { } final Uint8List encoded = Uint8List.fromList(asset.readAsBytesSync()); - return Future.value(encoded.buffer.asByteData()); + return SynchronousFuture(encoded.buffer.asByteData()); }); } diff --git a/packages/flutter_test/test/bindings_test.dart b/packages/flutter_test/test/bindings_test.dart index 8773abfc278d..8e5a31690a70 100644 --- a/packages/flutter_test/test/bindings_test.dart +++ b/packages/flutter_test/test/bindings_test.dart @@ -10,6 +10,7 @@ import 'dart:async'; import 'dart:io'; +import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -90,4 +91,13 @@ void main() { binding.idle(); }); }); + + testWidgets('Assets in the tester can be loaded without turning event loop', (WidgetTester tester) async { + bool responded = false; + // The particular asset does not matter, as long as it exists. + rootBundle.load('AssetManifest.json').then((ByteData data) { + responded = true; + }); + expect(responded, true); + }); }