// Author: fruit.com.cn // 验证品牌名称、原生启动布局与平台图标资源。 import 'dart:convert'; import 'dart:io'; import 'dart:ui' as ui; import 'package:flutter_test/flutter_test.dart'; import 'package:fruitshorts/l10n/app_localizations.dart'; const _iconAsset = 'assets/icon/ymb.png'; const _iconSize = 1024; const _launchWidth = 390; const _launchHeight = 844; const _androidRoot = 'android/app/src/main/res'; const _iosRoot = 'ios/Runner/Assets.xcassets'; const _ink = [0, 0, 0, 255]; void main() { TestWidgetsFlutterBinding.ensureInitialized(); test('should_use_ymb_when_resolving_each_app_locale', () async { for (final locale in AppLocalizations.supportedLocales) { final l10n = await AppLocalizations.delegate.load(locale); expect(l10n.appName, 'ymb'); } }); test('should_keep_reference_colors_when_decoding_master_icon', () async { final image = await _decode(_iconAsset); addTearDown(image.dispose); expect(image.width, _iconSize); expect(image.height, _iconSize); final bytes = await image.toByteData(); final pixel = bytes!.buffer.asUint8List().sublist(0, _ink.length); for (var channel = 0; channel < _ink.length; channel++) { expect(pixel[channel], closeTo(_ink[channel], 2)); } }); test('should_match_declared_sizes_when_loading_ios_app_icons', () async { final manifest = jsonDecode( File( '$_iosRoot/AppIcon.appiconset/Contents.json', ).readAsStringSync(), ) as Map; for (final entry in manifest['images'] as List) { final size = double.parse((entry['size'] as String).split('x').first); final scale = int.parse((entry['scale'] as String).replaceAll('x', '')); final image = await _decode( '$_iosRoot/AppIcon.appiconset/${entry['filename']}', ); expect(image.width, (size * scale).round()); expect(image.height, image.width); image.dispose(); } }); test('should_fit_full_reference_when_loading_ios_launch_screen', () { final storyboard = File( 'ios/Runner/Base.lproj/LaunchScreen.storyboard', ).readAsStringSync(); expect(storyboard, contains('contentMode="scaleAspectFit"')); expect(storyboard, contains('firstAttribute="leading"')); expect(storyboard, contains('firstAttribute="trailing"')); }); test('should_keep_reference_ratio_when_loading_ios_launch_images', () async { for (var scale = 1; scale <= 3; scale++) { final suffix = scale == 1 ? '' : '@${scale}x'; final image = await _decode( '$_iosRoot/LaunchImage.imageset/LaunchImage$suffix.png', ); expect(image.width, _launchWidth * scale); expect(image.height, _launchHeight * scale); image.dispose(); } }); test('should_keep_reference_tint_when_loading_android_launch_layers', () { for (final qualifier in ['', '-v21', '-v31', '-night', '-night-v21']) { final layers = File( '$_androidRoot/drawable$qualifier/launch_background.xml', ).readAsStringSync(); expect(layers, contains('@color/splash_background')); expect(layers, isNot(contains(' data[(y * canvasSize + x) * 4 + 3]; expect(alphaAt(0, 0), 0); expect(alphaAt(markInset - 1, center), 0); expect(alphaAt(markInset + 1, center), 255); expect(alphaAt(center, center), 255); for (final qualifier in ['', '-night']) { final styles = File( '$_androidRoot/values$qualifier-v31/styles.xml', ).readAsStringSync(); expect(styles, contains('@drawable/android12splash')); } }); test('should_use_ymb_when_resolving_platform_display_names', () { final manifest = File( 'android/app/src/main/AndroidManifest.xml', ).readAsStringSync(); expect(manifest, contains('android:label="ymb"')); final plist = File('ios/Runner/Info.plist').readAsStringSync(); expect( RegExp( r'CFBundleDisplayName\s*ymb', ).hasMatch(plist), isTrue, ); }); } Future _decode(String path) async { final codec = await ui.instantiateImageCodec(File(path).readAsBytesSync()); final frame = await codec.getNextFrame(); codec.dispose(); return frame.image; }