import 'dart:io'; import 'package:flutter_test/flutter_test.dart'; void main() { test('Android launcher forwards args and pins the FVP SDK', () async { final project = await Directory.systemTemp.createTemp('smplayer-android-'); addTearDown(() => project.delete(recursive: true)); await File( '${project.path}/pubspec.yaml', ).writeAsString('version: 1.2.3\n'); final staleFvpSdk = await _writeStaleFvpAndroidSdk(project); final bin = Directory('${project.path}/bin')..createSync(); final log = File('${project.path}/flutter.log'); await _writeFakeFlutter(bin, log); final environment = Map.of(Platform.environment) ..['PATH'] = '${bin.path}${Platform.isWindows ? ';' : ':'}' '${Platform.environment['PATH'] ?? ''}' ..['ANDROID_HOME'] = '' ..['ANDROID_SDK_ROOT'] = '' ..['LOCALAPPDATA'] = project.path ..['SMPLAYER_TEST_LOG'] = log.path ..['FVP_DEPS_LATEST'] = 'stale'; final result = await Process.run(_dartExecutable, [ File('scripts/dev_android.dart').absolute.path, '--project-root', project.path, '--force', '--offline', '--', '--release', '--dart-define', 'SMPLAYER_VERSION=9.9.9', ], environment: environment); expect(result.exitCode, 0, reason: '${result.stderr}'); expect('${result.stdout}', contains('test-device')); expect('${result.stdout}', contains('App version: 1.2.3')); final calls = await log.readAsString(); expect(calls, contains('ARGS:pub get --offline')); expect( calls, contains( 'ARGS:run -d test-device --no-pub --release ' '--dart-define SMPLAYER_VERSION=9.9.9', ), ); expect(calls, contains('VERSION_CODE:1002003')); expect(calls, contains('FVP:$_fvpDepsUrl')); expect(calls, isNot(contains('LATEST:stale'))); expect(staleFvpSdk.sdkDirectory.existsSync(), isFalse); expect(staleFvpSdk.sdkArchive.existsSync(), isFalse); expect(await staleFvpSdk.versionMarker.readAsString(), '0.37.0'); if (!Platform.isWindows) { expect(calls, contains('STORAGE:https://storage.flutter-io.cn')); expect(calls, contains('PUB:https://pub.flutter-io.cn')); } }); } Future<({File sdkArchive, Directory sdkDirectory, File versionMarker})> _writeStaleFvpAndroidSdk(Directory project) async { final fvpDirectory = Directory('${project.path}/fvp')..createSync(); final fvpRootUriWithoutTrailingSlash = fvpDirectory.uri .toString() .replaceFirst(RegExp(r'/$'), ''); final fvpAndroidDirectory = Directory('${fvpDirectory.path}/android') ..createSync(); final sdkDirectory = Directory( '${fvpAndroidDirectory.path}/mdk-sdk/lib/cmake', )..createSync(recursive: true); await File('${sdkDirectory.path}/FindMDK.cmake').writeAsString('stale'); final sdkArchive = File('${fvpAndroidDirectory.path}/mdk-sdk-android.7z'); await sdkArchive.writeAsString('stale'); final versionMarker = File( '${fvpAndroidDirectory.path}/.smplayer-mdk-version', ); await versionMarker.writeAsString('0.36.0'); final packageConfigDirectory = Directory('${project.path}/.dart_tool') ..createSync(); await File( '${packageConfigDirectory.path}/package_config.json', ).writeAsString(''' { "configVersion": 2, "packages": [ { "name": "fvp", "rootUri": ${_jsonString(fvpRootUriWithoutTrailingSlash)}, "packageUri": "lib/", "languageVersion": "3.0" } ] } '''); return ( sdkArchive: sdkArchive, sdkDirectory: Directory('${fvpAndroidDirectory.path}/mdk-sdk'), versionMarker: versionMarker, ); } String _jsonString(String value) => '"${value.replaceAll('"', r'\"')}"'; Future _writeFakeFlutter(Directory bin, File log) async { if (Platform.isWindows) { await File('${bin.path}/flutter.bat').writeAsString('''@echo off if "%~1 %~2"=="devices --machine" ( echo [{"id":"test-device","targetPlatform":"android-arm64"}] exit /b 0 ) >>"%SMPLAYER_TEST_LOG%" echo ARGS:%* >>"%SMPLAYER_TEST_LOG%" echo FVP:%FVP_DEPS_URL% >>"%SMPLAYER_TEST_LOG%" echo LATEST:%FVP_DEPS_LATEST% >>"%SMPLAYER_TEST_LOG%" echo STORAGE:%FLUTTER_STORAGE_BASE_URL% >>"%SMPLAYER_TEST_LOG%" echo PUB:%PUB_HOSTED_URL% >>"%SMPLAYER_TEST_LOG%" echo VERSION_CODE:%SMPLAYER_ANDROID_VERSION_CODE% >>"%SMPLAYER_TEST_LOG%" echo REQUIRE_SIGNING:%SMPLAYER_REQUIRE_RELEASE_SIGNING% '''); return; } final flutter = File('${bin.path}/flutter'); await flutter.writeAsString(r'''#!/usr/bin/env bash if [[ "$1 $2" == 'devices --machine' ]]; then printf '[{"id":"test-device","targetPlatform":"android-arm64"}]\n' exit 0 fi printf 'ARGS:%s\n' "$*" >> "$SMPLAYER_TEST_LOG" printf 'FVP:%s\n' "$FVP_DEPS_URL" >> "$SMPLAYER_TEST_LOG" printf 'LATEST:%s\n' "${FVP_DEPS_LATEST-}" >> "$SMPLAYER_TEST_LOG" printf 'STORAGE:%s\n' "$FLUTTER_STORAGE_BASE_URL" >> "$SMPLAYER_TEST_LOG" printf 'PUB:%s\n' "$PUB_HOSTED_URL" >> "$SMPLAYER_TEST_LOG" printf 'VERSION_CODE:%s\n' "$SMPLAYER_ANDROID_VERSION_CODE" >> "$SMPLAYER_TEST_LOG" printf 'REQUIRE_SIGNING:%s\n' "$SMPLAYER_REQUIRE_RELEASE_SIGNING" >> "$SMPLAYER_TEST_LOG" '''); await Process.run('chmod', ['+x', flutter.path]); } const _fvpDepsUrl = 'https://github.com/wang-bin/mdk-sdk/releases/download/v0.37.0'; String get _dartExecutable { final currentExecutable = File(Platform.resolvedExecutable); if (!currentExecutable.path.toLowerCase().contains('flutter_tester')) { return currentExecutable.path; } final flutterCacheDirectory = currentExecutable.parent.parent.parent.parent; final executableName = Platform.isWindows ? 'dart.exe' : 'dart'; return File( '${flutterCacheDirectory.path}${Platform.pathSeparator}dart-sdk' '${Platform.pathSeparator}bin${Platform.pathSeparator}$executableName', ).path; }