Initial commit
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
import 'dart:ui' as ui;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:smplayer/core/contracts/cancellation.dart';
|
||||
import 'package:smplayer/core/infra/player_engine/player_engine.dart';
|
||||
import 'package:smplayer/features/player/session/player_engine_holder.dart';
|
||||
import 'package:smplayer/features/player/session/player_engine_resolution.dart';
|
||||
|
||||
void main() {
|
||||
group('PlayerEngineHolder', () {
|
||||
test('同 kind 复用:第二次 acquire 不再调 create', () async {
|
||||
final holder = PlayerEngineHolder();
|
||||
var createCalls = 0;
|
||||
_FakeEngine factory(String tag) {
|
||||
createCalls++;
|
||||
return _FakeEngine(tag);
|
||||
}
|
||||
|
||||
final first = await holder.acquire(
|
||||
PlayerEngineKind.media3,
|
||||
() => factory('a'),
|
||||
);
|
||||
final second = await holder.acquire(
|
||||
PlayerEngineKind.media3,
|
||||
() => factory('b'),
|
||||
);
|
||||
|
||||
expect(createCalls, 1);
|
||||
expect(identical(first, second), isTrue);
|
||||
expect((second as _FakeEngine).tag, 'a');
|
||||
});
|
||||
|
||||
test('异 kind dispose+create:旧引擎先 dispose 再新建', () async {
|
||||
final holder = PlayerEngineHolder();
|
||||
final disposeOrder = <String>[];
|
||||
final acquireOrder = <String>[];
|
||||
|
||||
final fvp = _FakeEngine(
|
||||
'fvp',
|
||||
onDispose: () async {
|
||||
await Future<void>.delayed(const Duration(milliseconds: 10));
|
||||
disposeOrder.add('fvp');
|
||||
},
|
||||
);
|
||||
await holder.acquire(PlayerEngineKind.fvp, () => fvp);
|
||||
acquireOrder.add('fvp');
|
||||
|
||||
final media3 = _FakeEngine('media3');
|
||||
final second = await holder.acquire(PlayerEngineKind.media3, () {
|
||||
acquireOrder.add('media3-create');
|
||||
return media3;
|
||||
});
|
||||
|
||||
expect(disposeOrder, ['fvp']);
|
||||
expect(acquireOrder, ['fvp', 'media3-create']);
|
||||
expect(second, media3);
|
||||
expect(fvp.disposed, isTrue);
|
||||
expect(media3.disposed, isFalse);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class _FakeEngine implements PlayerEngine {
|
||||
final String tag;
|
||||
final Future<void> Function()? onDispose;
|
||||
bool disposed = false;
|
||||
_FakeEngine(this.tag, {this.onDispose});
|
||||
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
if (disposed) return;
|
||||
if (onDispose != null) await onDispose!();
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
@override
|
||||
String get displayName => tag;
|
||||
|
||||
@override
|
||||
bool get usesPlatformSurface => false;
|
||||
|
||||
@override
|
||||
Future<int?> totalRxBytes() async => null;
|
||||
|
||||
@override
|
||||
bool isNetworkStreamError(String error) => false;
|
||||
|
||||
@override
|
||||
void configureHardwareDecoding(String mode) {}
|
||||
|
||||
@override
|
||||
Future<void> open(
|
||||
String url, {
|
||||
Duration start = Duration.zero,
|
||||
bool play = true,
|
||||
Map<String, String>? headers,
|
||||
CancellationToken? cancel,
|
||||
}) async {}
|
||||
|
||||
@override
|
||||
Future<void> play() async {}
|
||||
@override
|
||||
Future<void> pause() async {}
|
||||
@override
|
||||
Future<void> stop() async {}
|
||||
@override
|
||||
Future<void> seek(Duration position) async {}
|
||||
@override
|
||||
Future<void> setRate(double rate) async {}
|
||||
@override
|
||||
Future<void> setVolume(double volume) async {}
|
||||
@override
|
||||
Future<void> toggleMute() async {}
|
||||
@override
|
||||
Future<void> setAudioTrack(AudioTrack track) async {}
|
||||
@override
|
||||
Future<void> setSubtitleTrack(SubtitleTrack track) async {}
|
||||
|
||||
@override
|
||||
void setNativeSubtitleRendering(bool enabled) {}
|
||||
|
||||
@override
|
||||
void setSubtitleStyle({
|
||||
required double fontSize,
|
||||
required double bgOpacity,
|
||||
required int position,
|
||||
}) {}
|
||||
|
||||
@override
|
||||
Widget buildVideoView(BuildContext context, ValueListenable<BoxFit> fit) =>
|
||||
const SizedBox.shrink();
|
||||
|
||||
Future<String> getProperty(String name) async => '';
|
||||
|
||||
@override
|
||||
PlayerState get state => PlayerState();
|
||||
|
||||
@override
|
||||
PlayerStreams get stream => PlayerStreams();
|
||||
|
||||
@override
|
||||
ValueListenable<int?> get textureId => ValueNotifier<int?>(null);
|
||||
|
||||
@override
|
||||
ValueListenable<int> get textureVersion => ValueNotifier<int>(0);
|
||||
|
||||
@override
|
||||
ValueNotifier<ui.Size?> get videoSize => ValueNotifier<ui.Size?>(null);
|
||||
|
||||
@override
|
||||
ValueListenable<PlaybackStats?> get debugStats =>
|
||||
ValueNotifier<PlaybackStats?>(null);
|
||||
}
|
||||
Reference in New Issue
Block a user