Files
plezy/test/mpv/player_android_heap_size_test.dart
T
edde746 0f016e4e13 fix(player): start the playback fetch before player construction
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.
2026-08-17 13:46:51 +02:00

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);
});
}