Files
ReelShort/test/player/player_opening_frame_test.dart
T

180 lines
4.8 KiB
Dart

// Author: fruit.com.cn
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:fruitshorts/core/data/services/sprite_thumbnail_asset_loader.dart';
import 'package:fruitshorts/core/widgets/remote_image.dart';
import 'package:fruitshorts/pages/player/widgets/player_opening_frame.dart';
const String _spriteVtt = '''
WEBVTT
00:00:00.000 --> 00:00:01.000
sprite_001.jpg#xywh=0,0,160,90
''';
void main() {
test('should_return_no_opening_frame_when_thumbnails_url_is_empty', () {
expect(playerOpeningFrame(null, posterUrl: ' '), isNull);
expect(playerOpeningFrame(' '), isNull);
});
test('should_keep_opening_frame_when_only_poster_is_available', () {
expect(
playerOpeningFrame(null, posterUrl: 'https://cdn.test/poster.jpg'),
isA<PlayerOpeningFrame>(),
);
});
testWidgets('should_load_and_reuse_first_sprite_frame', (tester) async {
final loader = _FakeSpriteLoader();
final cache = OpeningFrameCache();
addTearDown(cache.clear);
final first = await cache.load(
'https://cdn.test/thumbnails.vtt',
loader: loader,
);
final second = await cache.load(
'https://cdn.test/thumbnails.vtt',
loader: loader,
);
expect(first, isNotNull);
expect(second, same(first));
expect(loader.vttCalls, 1);
expect(loader.spriteCalls, ['sprite_001.jpg']);
});
testWidgets('should_render_decoded_opening_frame', (tester) async {
final loader = _FakeSpriteLoader();
final cache = OpeningFrameCache();
addTearDown(cache.clear);
await tester.pumpWidget(
MaterialApp(
home: PlayerOpeningFrame(
thumbnailsUrl: 'https://cdn.test/thumbnails.vtt',
loader: loader,
cache: cache,
),
),
);
await tester.pumpAndSettle();
expect(find.byKey(const Key('player-opening-sprite')), findsOneWidget);
});
testWidgets('should_show_poster_while_sprite_is_loading', (tester) async {
final cache = OpeningFrameCache();
addTearDown(cache.clear);
await tester.pumpWidget(
MaterialApp(
home: PlayerOpeningFrame(
thumbnailsUrl: 'https://cdn.test/thumbnails.vtt',
posterUrl: 'https://cdn.test/poster.jpg',
loader: _FakeSpriteLoader(),
cache: cache,
),
),
);
expect(find.byKey(const Key('player-opening-poster')), findsOneWidget);
});
testWidgets('should_use_surface_fit_without_extra_frame_constraint', (
tester,
) async {
await tester.pumpWidget(
const MaterialApp(
home: PlayerOpeningFrame(
posterUrl: 'https://cdn.test/poster.jpg',
),
),
);
final poster = tester.widget<RemoteImage>(
find.byKey(const Key('player-opening-poster')),
);
expect(poster.fit, BoxFit.cover);
expect(find.byType(AspectRatio), findsNothing);
});
test('should_forward_video_fit_to_opening_frame', () {
final frame = playerOpeningFrame(
null,
posterUrl: 'https://cdn.test/poster.jpg',
fit: BoxFit.contain,
);
expect(frame, isA<PlayerOpeningFrame>());
expect((frame! as PlayerOpeningFrame).fit, BoxFit.contain);
});
testWidgets('should_reuse_decoded_sprite_when_parent_rebuilds', (
tester,
) async {
final loader = _FakeSpriteLoader();
final cache = OpeningFrameCache();
addTearDown(cache.clear);
Widget build() => MaterialApp(
home: PlayerOpeningFrame(
thumbnailsUrl: 'https://cdn.test/thumbnails.vtt',
posterUrl: 'https://cdn.test/poster.jpg',
loader: loader,
cache: cache,
),
);
await tester.pumpWidget(build());
await tester.pumpAndSettle();
expect(loader.vttCalls, 1);
expect(loader.spriteCalls, hasLength(1));
await tester.pumpWidget(build());
await tester.pumpAndSettle();
expect(loader.vttCalls, 1);
expect(loader.spriteCalls, hasLength(1));
expect(find.byKey(const Key('player-opening-sprite')), findsOneWidget);
});
}
class _FakeSpriteLoader implements SpriteThumbnailAssetLoader {
int vttCalls = 0;
final List<String> spriteCalls = [];
@override
Future<String?> loadVtt(Uri uri) async {
vttCalls++;
return _spriteVtt;
}
@override
Future<SpriteThumbnailDecodedImage?> loadSprite(Uri uri) async {
spriteCalls.add(uri.pathSegments.last);
return SpriteThumbnailDecodedImage(
image: await _createImage(320, 180),
originalWidth: 320,
originalHeight: 180,
);
}
}
Future<ui.Image> _createImage(int width, int height) async {
final recorder = ui.PictureRecorder();
final canvas = Canvas(recorder);
canvas.drawRect(
Rect.fromLTWH(0, 0, width.toDouble(), height.toDouble()),
Paint()..color = Colors.blue,
);
final picture = recorder.endRecording();
final image = await picture.toImage(width, height);
picture.dispose();
return image;
}