// 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/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), isNull); expect(playerOpeningFrame(' '), isNull); }); 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); }); } class _FakeSpriteLoader implements SpriteThumbnailAssetLoader { int vttCalls = 0; final List spriteCalls = []; @override Future loadVtt(Uri uri) async { vttCalls++; return _spriteVtt; } @override Future loadSprite(Uri uri) async { spriteCalls.add(uri.pathSegments.last); return SpriteThumbnailDecodedImage( image: await _createImage(320, 180), originalWidth: 320, originalHeight: 180, ); } } Future _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; }