import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; import 'package:qlyra/core/config/app_icon.dart'; Set _iosAlternateIcons() { final plist = File('ios/Runner/Info.plist').readAsStringSync(); final anchor = plist.indexOf('CFBundleAlternateIcons'); expect( anchor, isNonNegative, reason: 'в Info.plist нет альтернативных иконок', ); final tokens = RegExp( r'||([^<]*)', ).allMatches(plist.substring(anchor)); final names = {}; var depth = 0; var entered = false; for (final token in tokens) { final text = token.group(0)!; if (text == '') { depth++; entered = true; } else if (text == '') { depth--; if (entered && depth == 0) break; } else if (entered && depth == 1) { names.add(token.group(1)!); } } return names; } Set _androidComponents() { final manifest = File( 'android/app/src/main/AndroidManifest.xml', ).readAsStringSync(); return RegExp( r'android:name="ru\.qlyra\.app\.(\w+)"', ).allMatches(manifest).map((m) => m.group(1)!).toSet(); } Set _androidIconKeys() { final source = File( 'android/app/src/main/kotlin/ru/qlyra/app/MainActivity.kt', ).readAsStringSync(); final start = source.indexOf('iconComponents = mapOf('); expect(start, isNonNegative, reason: 'в MainActivity нет карты иконок'); final body = source.substring(start, source.indexOf(')', start)); return RegExp(r'"(\w+)" to').allMatches(body).map((m) => m.group(1)!).toSet(); } void main() { test('дефолтная иконка на iOS — это primary, а не альтернативная', () { expect( AppIcon.defaultIcon.iosAlternateName, isNull, reason: 'setAlternateIconName ждёт nil, любое имя тут — APPLY_FAILED', ); }); test('каждая альтернативная иконка объявлена в Info.plist', () { final declared = _iosAlternateIcons(); for (final icon in AppIcon.values) { final name = icon.iosAlternateName; if (name == null) continue; expect( declared, contains(name), reason: 'иконка ${icon.id} шлёт в iOS имя $name', ); } }); test('каждый android alias объявлен в манифесте и в MainActivity', () { final components = _androidComponents(); final keys = _androidIconKeys(); for (final icon in AppIcon.values) { expect( components, contains(icon.androidAlias), reason: 'иконка ${icon.id} шлёт в Android имя ${icon.androidAlias}', ); expect(keys, contains(icon.androidAlias)); } }); test('имена иконок не пересекаются между платформами по смыслу', () { final ids = AppIcon.values.map((i) => i.id).toSet(); expect(ids.length, AppIcon.values.length); final aliases = AppIcon.values.map((i) => i.androidAlias).toSet(); expect(aliases.length, AppIcon.values.length); }); }