bc72bba981
Changelog: No more Firebase analytics or crash reporting
201 lines
6.2 KiB
Dart
201 lines
6.2 KiB
Dart
import 'dart:async';
|
|
import 'dart:math';
|
|
|
|
import 'package:fl_clash/common/boot_record.dart';
|
|
import 'package:fl_clash/common/constant.dart';
|
|
import 'package:fl_clash/plugins/app.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
|
|
void main() {
|
|
TestWidgetsFlutterBinding.ensureInitialized();
|
|
|
|
const channel = MethodChannel('$packageName/app');
|
|
|
|
setUp(() {
|
|
App().clearPackageIconCache();
|
|
});
|
|
|
|
tearDown(() {
|
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
.setMockMethodCallHandler(channel, null);
|
|
App().clearPackageIconCache();
|
|
});
|
|
|
|
test('requests every package icon from Android only once', () async {
|
|
var iconCallCount = 0;
|
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
.setMockMethodCallHandler(channel, (call) async {
|
|
iconCallCount++;
|
|
return '/icons/${call.arguments['packageName']}.png';
|
|
});
|
|
|
|
final app = App();
|
|
final results = await Future.wait([
|
|
app.getPackageIcon('com.a'),
|
|
app.getPackageIcon('com.a'),
|
|
]);
|
|
final cached = await app.getPackageIcon('com.a');
|
|
|
|
expect(iconCallCount, 1);
|
|
expect(results.first, isNotNull);
|
|
expect(cached, same(results.first));
|
|
expect(app.getCachedPackageIcon('com.a'), same(results.first));
|
|
|
|
await app.getPackageIcon('com.b');
|
|
|
|
expect(iconCallCount, 2);
|
|
});
|
|
|
|
test(
|
|
'falls back to the default activity icon for unknown packages',
|
|
() async {
|
|
final requested = <String?>[];
|
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
.setMockMethodCallHandler(channel, (call) async {
|
|
final packageName = call.arguments['packageName'] as String?;
|
|
requested.add(packageName);
|
|
return packageName == '' ? '/icons/default_icon.webp' : null;
|
|
});
|
|
|
|
final app = App();
|
|
|
|
final fallback = await app.getPackageIcon('com.a');
|
|
final defaultIcon = await app.getPackageIcon('');
|
|
|
|
expect(fallback, isNotNull);
|
|
expect(fallback, same(defaultIcon));
|
|
expect(requested, ['com.a', '']);
|
|
|
|
expect(await app.getPackageIcon('com.b'), same(defaultIcon));
|
|
expect(requested, ['com.a', '', 'com.b']);
|
|
},
|
|
);
|
|
|
|
test(
|
|
'asks Android for a bounded number of package icons at a time',
|
|
() async {
|
|
var inFlight = 0;
|
|
var peak = 0;
|
|
final release = Completer<void>();
|
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
.setMockMethodCallHandler(channel, (call) async {
|
|
inFlight++;
|
|
peak = max(peak, inFlight);
|
|
await release.future;
|
|
inFlight--;
|
|
return '/icons/${call.arguments['packageName']}.png';
|
|
});
|
|
|
|
final app = App();
|
|
final icons = Future.wait([
|
|
for (var i = 0; i < maxConcurrentIconLoads * 2; i++)
|
|
app.getPackageIcon('com.$i'),
|
|
]);
|
|
await pumpEventQueue();
|
|
|
|
expect(inFlight, maxConcurrentIconLoads);
|
|
|
|
release.complete();
|
|
|
|
expect(await icons, everyElement(isNotNull));
|
|
expect(peak, maxConcurrentIconLoads);
|
|
},
|
|
);
|
|
|
|
test('caches a failed package icon lookup', () async {
|
|
var iconCallCount = 0;
|
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
.setMockMethodCallHandler(channel, (_) async {
|
|
iconCallCount++;
|
|
throw PlatformException(code: 'unavailable');
|
|
});
|
|
|
|
final app = App();
|
|
|
|
expect(await app.getPackageIcon('com.a'), isNull);
|
|
expect(await app.getPackageIcon('com.a'), isNull);
|
|
expect(await app.getPackageIcon(''), isNull);
|
|
expect(iconCallCount, 2);
|
|
});
|
|
|
|
test('reads the last process exit info from Android', () async {
|
|
MethodCall? receivedCall;
|
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
.setMockMethodCallHandler(channel, (call) async {
|
|
receivedCall = call;
|
|
return <String, Object?>{
|
|
'reason': 10,
|
|
'timestamp': 1234,
|
|
'description': 'user requested',
|
|
};
|
|
});
|
|
|
|
final info = await App().getLastExitInfo();
|
|
|
|
expect(receivedCall?.method, 'getLastExitInfo');
|
|
expect(info?.reason, AppExitReason.userRequested);
|
|
expect(info?.timestamp, 1234);
|
|
expect(info?.description, 'user requested');
|
|
});
|
|
|
|
test('uses no exit info when Android cannot report one', () async {
|
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
.setMockMethodCallHandler(channel, (_) async => null);
|
|
|
|
expect(await App().getLastExitInfo(), isNull);
|
|
});
|
|
|
|
test('uses no exit info when the platform call fails', () async {
|
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
.setMockMethodCallHandler(channel, (_) async {
|
|
throw PlatformException(code: 'unavailable');
|
|
});
|
|
|
|
expect(await App().getLastExitInfo(), isNull);
|
|
});
|
|
|
|
test('forwards package change notices from Android', () async {
|
|
var changes = 0;
|
|
final app = App();
|
|
app.onPackagesChanged = () => changes++;
|
|
addTearDown(() => app.onPackagesChanged = null);
|
|
|
|
await TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
.handlePlatformMessage(
|
|
channel.name,
|
|
channel.codec.encodeMethodCall(const MethodCall('packagesChanged')),
|
|
(_) {},
|
|
);
|
|
|
|
expect(changes, 1);
|
|
});
|
|
|
|
test('reports the installed apps permission Android answers with', () async {
|
|
final methods = <String>[];
|
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
.setMockMethodCallHandler(channel, (call) async {
|
|
methods.add(call.method);
|
|
return false;
|
|
});
|
|
|
|
expect(await App().isInstalledAppsPermissionGranted(), isFalse);
|
|
expect(await App().requestInstalledAppsPermission(), isFalse);
|
|
expect(methods, [
|
|
'isInstalledAppsPermissionGranted',
|
|
'requestInstalledAppsPermission',
|
|
]);
|
|
});
|
|
|
|
test(
|
|
'treats a missing installed apps permission answer as granted',
|
|
() async {
|
|
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
|
|
.setMockMethodCallHandler(channel, (_) async => null);
|
|
|
|
expect(await App().isInstalledAppsPermissionGranted(), isTrue);
|
|
expect(await App().requestInstalledAppsPermission(), isFalse);
|
|
},
|
|
);
|
|
}
|