// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'dart:io' show File, Platform; import 'dart:typed_data'; import 'package:collection/collection.dart'; import 'package:flutter_devicelab/framework/devices.dart'; import 'package:flutter_devicelab/framework/framework.dart'; import 'package:flutter_devicelab/framework/task_result.dart'; import 'package:flutter_devicelab/framework/utils.dart'; import 'package:flutter_devicelab/tasks/integration_tests.dart'; import 'package:path/path.dart' as path; import 'package:standard_message_codec/standard_message_codec.dart'; Future main() async { deviceOperatingSystem = DeviceOperatingSystem.android; await task(() async { await createFlavorsTest().call(); await createIntegrationTestFlavorsTest().call(); final String projectPath = '${flutterDirectory.path}/dev/integration_tests/flavors'; final TaskResult installTestsResult = await inDirectory(projectPath, () async { final List testResults = [ await _testInstallDebugPaidFlavor(projectPath), await _testInstallBogusFlavor(), ]; final TaskResult? firstInstallFailure = testResults.firstWhereOrNull( (TaskResult element) => element.failed, ); return firstInstallFailure ?? TaskResult.success(null); }); await _testFlavorsWhenBuildStartsWithGradle(projectPath); return installTestsResult; }); } // Ensures installation works. Also tests asset bundling while we are at it. Future _testInstallDebugPaidFlavor(String projectDir) async { await evalFlutter('install', options: ['--debug', '--flavor', 'paid']); final Uint8List assetManifestFileData = File( path.join( projectDir, 'build', 'app', 'intermediates', 'assets', 'paidDebug', 'mergePaidDebugAssets', 'flutter_assets', 'AssetManifest.bin', ), ).readAsBytesSync(); final Map assetManifest = const StandardMessageCodec().decodeMessage(ByteData.sublistView(assetManifestFileData)) as Map; if (assetManifest.containsKey('assets/free/free.txt')) { return TaskResult.failure( 'Expected the asset "assets/free/free.txt", which ' ' was declared with a flavor of "free" to not be included in the asset bundle ' ' because the --flavor was set to "paid".', ); } if (!assetManifest.containsKey('assets/paid/paid.txt')) { return TaskResult.failure( 'Expected the asset "assets/paid/paid.txt", which ' ' was declared with a flavor of "paid" to be included in the asset bundle ' ' because the --flavor was set to "paid".', ); } await flutter('install', options: ['--debug', '--flavor', 'paid', '--uninstall-only']); return TaskResult.success(null); } Future _testInstallBogusFlavor() async { final StringBuffer stderr = StringBuffer(); await evalFlutter( 'install', canFail: true, stderr: stderr, options: ['--flavor', 'bogus'], ); final String stderrString = stderr.toString(); final String expectedApkPath = path.join( 'build', 'app', 'outputs', 'flutter-apk', 'app-bogus-release.apk', ); if (!stderrString.contains('"$expectedApkPath" does not exist.')) { print(stderrString); return TaskResult.failure('Should not succeed with bogus flavor'); } return TaskResult.success(null); } Future _testFlavorsWhenBuildStartsWithGradle(String projectDir) async { final String gradlew = Platform.isWindows ? 'gradlew.bat' : 'gradlew'; final String gradlewExecutable = Platform.isWindows ? '.\\$gradlew' : './$gradlew'; final String androidDirPath = '$projectDir/android'; final StringBuffer stdout = StringBuffer(); // Prebuild the project to generate the Android gradle wrapper files. await inDirectory(projectDir, () async { await flutter('build', options: ['apk', '--config-only']); }); await inDirectory(androidDirPath, () async { await exec(gradlewExecutable, ['clean']); await exec(gradlewExecutable, [':app:assemblePaidDebug', '--info'], output: stdout); }); final String stdoutString = stdout.toString(); if (!stdoutString.contains('-dFlavor=paid')) { return TaskResult.failure('Expected to see -dFlavor=paid in the gradle verbose output'); } final String appPath = path.join( projectDir, 'build', 'app', 'outputs', 'flutter-apk', 'app-paid-debug.apk', ); return createFlavorsTest( extraOptions: ['--flavor', 'paid', '--use-application-binary=$appPath'], ).call(); }