Skip to content

Commit

Permalink
Load assets in flutter_test without turning event loop. (#115123)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
dnfield authored Nov 11, 2022
1 parent 6e89042 commit 88e49ed
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 13 deletions.
4 changes: 2 additions & 2 deletions packages/flutter/lib/src/foundation/synchronous_future.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,11 @@ class SynchronousFuture<T> implements Future<T> {

@override
Future<R> then<R>(FutureOr<R> Function(T value) onValue, { Function? onError }) {
final dynamic result = onValue(_value);
final FutureOr<R> result = onValue(_value);
if (result is Future<R>) {
return result;
}
return SynchronousFuture<R>(result as R);
return SynchronousFuture<R>(result);
}

@override
Expand Down
23 changes: 15 additions & 8 deletions packages/flutter/lib/src/services/asset_bundle.dart
Original file line number Diff line number Diff line change
Expand Up @@ -247,17 +247,24 @@ abstract class CachingAssetBundle extends AssetBundle {
/// An [AssetBundle] that loads resources using platform messages.
class PlatformAssetBundle extends CachingAssetBundle {
@override
Future<ByteData> load(String key) async {
Future<ByteData> 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<ByteData>? future = ServicesBinding.instance.defaultBinaryMessenger.send('flutter/assets', encoded.buffer.asByteData())?.then((ByteData? asset) {
if (asset == null) {
throw FlutterError.fromParts(<DiagnosticsNode>[
_errorSummaryWithKey(key),
ErrorDescription('The asset does not exist or has empty data.'),
]);
}
return asset;
});
if (future == null) {
throw FlutterError.fromParts(<DiagnosticsNode>[
_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
Expand Down
6 changes: 3 additions & 3 deletions packages/flutter_test/lib/src/_binding_io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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));
Expand All @@ -62,7 +62,7 @@ void mockFlutterAssets() {
}

final Uint8List encoded = Uint8List.fromList(asset.readAsBytesSync());
return Future<ByteData>.value(encoded.buffer.asByteData());
return SynchronousFuture<ByteData>(encoded.buffer.asByteData());
});
}

Expand Down
10 changes: 10 additions & 0 deletions packages/flutter_test/test/bindings_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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);
});
}

0 comments on commit 88e49ed

Please sign in to comment.