The playback data resolve — the one network request that must land before open() — was kicked off only after the SharedPreferences load, the Windows display-mode sync, the music-session teardown in claimVideo(), Player construction, and (Android/Exo) a native setLogLevel, so none of that setup overlapped the round trip. Move the kickoff to immediately after the settings reads; the resolve depends only on settings and provider lookups, so display sync, player construction, and the whole mpv property chain now hide behind the network latency instead of preceding it. Also remove redundant work elsewhere on the start path: memoize PlayerAndroid.getHeapSize (asked again on every open for an immutable device value), skip the ten subtitle-style settings reads on mpv backends where setSubtitleStyle is a no-op, and stop navigateToVideoPlayer awaiting SettingsService.getInstance twice per launch — the external-player read now sits behind the supportsExternalPlayers guard.
78 lines
2.6 KiB
Dart
78 lines
2.6 KiB
Dart
import 'package:flutter/services.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:plezy/mpv/player/platform/player_android.dart';
|
|
|
|
import '../test_helpers/mock_player_channels.dart';
|
|
|
|
/// The device heap is immutable per process, so [PlayerAndroid.getHeapSize]
|
|
/// memoizes the first successful result: the second read on the playback-open
|
|
/// hot path (`_applyNetworkStreamTuning`) must not pay a channel round trip.
|
|
/// Failures keep the documented `0` sentinel and must never be pinned.
|
|
void main() {
|
|
TestWidgetsFlutterBinding.ensureInitialized();
|
|
|
|
setUp(PlayerAndroid.debugResetHeapSizeCache);
|
|
|
|
Future<void> withHeapSizeHandler({
|
|
required Future<Object?> Function(MethodCall call) methodHandler,
|
|
required Future<void> Function() testBody,
|
|
}) {
|
|
return withMockPlayerChannels(
|
|
methodChannelName: 'com.plezy/exo_player',
|
|
eventChannelName: 'com.plezy/exo_player/events',
|
|
methodHandler: methodHandler,
|
|
testBody: testBody,
|
|
);
|
|
}
|
|
|
|
test('a successful heap read is served from cache on subsequent calls', () async {
|
|
var channelCalls = 0;
|
|
await withHeapSizeHandler(
|
|
methodHandler: (call) async {
|
|
if (call.method != 'getHeapSize') return null;
|
|
channelCalls++;
|
|
return 512;
|
|
},
|
|
testBody: () async {
|
|
expect(await PlayerAndroid.getHeapSize(), 512);
|
|
expect(await PlayerAndroid.getHeapSize(), 512);
|
|
},
|
|
);
|
|
expect(channelCalls, 1);
|
|
});
|
|
|
|
test('a failed heap read returns 0 and is not cached', () async {
|
|
await withHeapSizeHandler(
|
|
methodHandler: (call) async => throw PlatformException(code: 'unavailable'),
|
|
testBody: () async {
|
|
expect(await PlayerAndroid.getHeapSize(), 0);
|
|
},
|
|
);
|
|
// The channel recovers: the earlier failure must not have pinned the 0
|
|
// sentinel, or Auto buffer sizing would stay degraded for the whole run.
|
|
await withHeapSizeHandler(
|
|
methodHandler: (call) async => call.method == 'getHeapSize' ? 256 : null,
|
|
testBody: () async {
|
|
expect(await PlayerAndroid.getHeapSize(), 256);
|
|
},
|
|
);
|
|
});
|
|
|
|
test('a null heap report keeps the 0 sentinel without caching it', () async {
|
|
var channelCalls = 0;
|
|
await withHeapSizeHandler(
|
|
methodHandler: (call) async {
|
|
if (call.method != 'getHeapSize') return null;
|
|
channelCalls++;
|
|
return null;
|
|
},
|
|
testBody: () async {
|
|
expect(await PlayerAndroid.getHeapSize(), 0);
|
|
expect(await PlayerAndroid.getHeapSize(), 0);
|
|
},
|
|
);
|
|
// Unavailable is re-asked, never memoized.
|
|
expect(channelCalls, 2);
|
|
});
|
|
}
|