[flutter_tools] Remove mocking and simplify Dart target tests (#50688)
diff --git a/packages/flutter_tools/lib/src/compile.dart b/packages/flutter_tools/lib/src/compile.dart
index e89baa5..4df5b1d 100644
--- a/packages/flutter_tools/lib/src/compile.dart
+++ b/packages/flutter_tools/lib/src/compile.dart
@@ -241,7 +241,8 @@
}
}
-List<String> _buildModeOptions(BuildMode mode) {
+/// List the preconfigured build options for a given build mode.
+List<String> buildModeOptions(BuildMode mode) {
switch (mode) {
case BuildMode.debug:
return <String>[
@@ -316,7 +317,7 @@
'-Ddart.developer.causal_async_stacks=${buildMode == BuildMode.debug}',
for (final Object dartDefine in dartDefines)
'-D$dartDefine',
- ..._buildModeOptions(buildMode),
+ ...buildModeOptions(buildMode),
if (trackWidgetCreation) '--track-widget-creation',
if (!linkPlatformKernelIn) '--no-link-platform',
if (aot) ...<String>[
@@ -357,14 +358,9 @@
];
globals.printTrace(command.join(' '));
- final Process server = await globals.processManager
- .start(command)
- .catchError((dynamic error, StackTrace stack) {
- globals.printError('Failed to start frontend server $error, $stack');
- });
+ final Process server = await globals.processManager.start(command);
final StdoutHandler _stdoutHandler = StdoutHandler();
-
server.stderr
.transform<String>(utf8.decoder)
.listen(globals.printError);
@@ -678,7 +674,7 @@
'--packages',
packagesPath,
],
- ..._buildModeOptions(buildMode),
+ ...buildModeOptions(buildMode),
if (trackWidgetCreation) '--track-widget-creation',
if (fileSystemRoots != null)
for (final String root in fileSystemRoots) ...<String>[
diff --git a/packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart b/packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart
index 1afc129..cac3fbb 100644
--- a/packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart
+++ b/packages/flutter_tools/test/general.shard/build_system/targets/dart_test.dart
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'package:flutter_tools/src/base/build.dart';
+import 'package:file/memory.dart';
+import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
-import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/build_system/exceptions.dart';
@@ -12,32 +12,30 @@
import 'package:flutter_tools/src/build_system/targets/ios.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/compile.dart';
-import 'package:flutter_tools/src/macos/xcode.dart';
-import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
-
-import 'package:mockito/mockito.dart';
+import 'package:platform/platform.dart';
import 'package:process/process.dart';
import '../../../src/common.dart';
-import '../../../src/mocks.dart';
+import '../../../src/fake_process_manager.dart';
import '../../../src/testbed.dart';
+const String kBoundaryKey = '4d2d9609-c662-4571-afde-31410f96caa6';
+const String kElfAot = '--snapshot_kind=app-aot-elf';
+const String kAssemblyAot = '--snapshot_kind=app-aot-assembly';
+
void main() {
- const BuildSystem buildSystem = BuildSystem();
Testbed testbed;
+ FakeProcessManager processManager;
Environment androidEnvironment;
Environment iosEnvironment;
- MockProcessManager mockProcessManager;
- MockXcode mockXcode;
+ Artifacts artifacts;
setUpAll(() {
Cache.disableLocking();
});
setUp(() {
- mockXcode = MockXcode();
- mockProcessManager = MockProcessManager();
testbed = Testbed(setup: () {
androidEnvironment = Environment.test(
globals.fs.currentDirectory,
@@ -46,6 +44,7 @@
kTargetPlatform: getNameForTargetPlatform(TargetPlatform.android_arm),
},
);
+ androidEnvironment.buildDir.createSync(recursive: true);
iosEnvironment = Environment.test(
globals.fs.currentDirectory,
defines: <String, String>{
@@ -53,427 +52,462 @@
kTargetPlatform: getNameForTargetPlatform(TargetPlatform.ios),
},
);
- HostPlatform hostPlatform;
- if (globals.platform.isWindows) {
- hostPlatform = HostPlatform.windows_x64;
- } else if (globals.platform.isLinux) {
- hostPlatform = HostPlatform.linux_x64;
- } else if (globals.platform.isMacOS) {
- hostPlatform = HostPlatform.darwin_x64;
- } else {
- assert(false);
- }
-
- final String engineArtifacts = globals.fs.path.join('bin', 'cache',
- 'artifacts', 'engine');
- final List<String> paths = <String>[
- globals.fs.path.join('bin', 'cache', 'dart-sdk', 'bin', 'dart'),
- globals.fs.path.join('bin', 'cache', 'dart-sdk', 'bin', 'dart.exe'),
- globals.fs.path.join(engineArtifacts, getNameForHostPlatform(hostPlatform),
- 'frontend_server.dart.snapshot'),
- globals.fs.path.join(engineArtifacts, 'android-arm-profile',
- getNameForHostPlatform(hostPlatform), 'gen_snapshot'),
- globals.fs.path.join(engineArtifacts, 'ios-profile', 'gen_snapshot'),
- globals.fs.path.join(engineArtifacts, 'common', 'flutter_patched_sdk',
- 'platform_strong.dill'),
- globals.fs.path.join('lib', 'foo.dart'),
- globals.fs.path.join('lib', 'bar.dart'),
- globals.fs.path.join('lib', 'fizz'),
- globals.fs.path.join('packages', 'flutter_tools', 'lib', 'src', 'build_system', 'targets', 'dart.dart'),
- globals.fs.path.join('packages', 'flutter_tools', 'lib', 'src', 'build_system', 'targets', 'ios.dart'),
- ];
- for (final String path in paths) {
- globals.fs.file(path).createSync(recursive: true);
- }
+ iosEnvironment.buildDir.createSync(recursive: true);
+ artifacts = CachedArtifacts(
+ cache: globals.cache,
+ platform: globals.platform,
+ fileSystem: globals.fs,
+ );
}, overrides: <Type, Generator>{
- KernelCompilerFactory: () => FakeKernelCompilerFactory(),
- GenSnapshot: () => FakeGenSnapshot(),
+ Platform: () => FakePlatform(operatingSystem: 'macos', environment: <String, String>{}),
+ FileSystem: () => MemoryFileSystem.test(style: FileSystemStyle.posix),
+ ProcessManager: () => processManager,
});
});
- test('kernel_snapshot Produces correct output directory', () => testbed.run(() async {
- await buildSystem.build(const KernelSnapshot(), androidEnvironment);
-
- expect(globals.fs.file(globals.fs.path.join(androidEnvironment.buildDir.path,'app.dill')).existsSync(), true);
+ test('KernelSnapshot throws error if missing build mode', () => testbed.run(() async {
+ androidEnvironment.defines.remove(kBuildMode);
+ expect(
+ const KernelSnapshot().build(androidEnvironment),
+ throwsA(isInstanceOf<MissingDefineException>()));
}));
- test('kernel_snapshot throws error if missing build mode', () => testbed.run(() async {
- final BuildResult result = await buildSystem.build(const KernelSnapshot(),
- androidEnvironment..defines.remove(kBuildMode));
+ test('KernelSnapshot handles null result from kernel compilation', () => testbed.run(() async {
+ globals.fs.file('.packages').writeAsStringSync('\n');
+ final String build = androidEnvironment.buildDir.path;
+ processManager = FakeProcessManager.list(<FakeCommand>[
+ FakeCommand(command: <String>[
+ artifacts.getArtifactPath(Artifact.engineDartBinary),
+ artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk),
+ '--sdk-root',
+ artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath) + '/',
+ '--target=flutter',
+ '-Ddart.developer.causal_async_stacks=false',
+ ...buildModeOptions(BuildMode.profile),
+ '--aot',
+ '--tfa',
+ '--packages',
+ '/.packages',
+ '--output-dill',
+ '$build/app.dill',
+ '--depfile',
+ '$build/kernel_snapshot.d',
+ '/lib/main.dart',
+ ], exitCode: 1),
+ ]);
- expect(result.exceptions.values.single.exception, isA<MissingDefineException>());
+ await expectLater(() => const KernelSnapshot().build(androidEnvironment),
+ throwsA(isA<Exception>()));
+ expect(processManager.hasRemainingExpectations, false);
}));
- test('kernel_snapshot handles null result from kernel compilation', () => testbed.run(() async {
- final FakeKernelCompilerFactory fakeKernelCompilerFactory = kernelCompilerFactory as FakeKernelCompilerFactory;
- fakeKernelCompilerFactory.kernelCompiler = MockKernelCompiler();
- when(fakeKernelCompilerFactory.kernelCompiler.compile(
- sdkRoot: anyNamed('sdkRoot'),
- mainPath: anyNamed('mainPath'),
- outputFilePath: anyNamed('outputFilePath'),
- depFilePath: anyNamed('depFilePath'),
- targetModel: anyNamed('targetModel'),
- linkPlatformKernelIn: anyNamed('linkPlatformKernelIn'),
- aot: anyNamed('aot'),
- buildMode: anyNamed('buildMode'),
- trackWidgetCreation: anyNamed('trackWidgetCreation'),
- extraFrontEndOptions: anyNamed('extraFrontEndOptions'),
- packagesPath: anyNamed('packagesPath'),
- fileSystemRoots: anyNamed('fileSystemRoots'),
- fileSystemScheme: anyNamed('fileSystemScheme'),
- platformDill: anyNamed('platformDill'),
- initializeFromDill: anyNamed('initializeFromDill'),
- dartDefines: anyNamed('dartDefines'),
- )).thenAnswer((Invocation invocation) async {
- return null;
- });
- final BuildResult result = await buildSystem.build(const KernelSnapshot(), androidEnvironment);
-
- expect(result.exceptions.values.single.exception, isA<Exception>());
- }));
-
- test('kernel_snapshot does not use track widget creation on profile builds', () => testbed.run(() async {
- final MockKernelCompiler mockKernelCompiler = MockKernelCompiler();
- when(kernelCompilerFactory.create(any)).thenAnswer((Invocation _) async {
- return mockKernelCompiler;
- });
- when(mockKernelCompiler.compile(
- sdkRoot: anyNamed('sdkRoot'),
- aot: anyNamed('aot'),
- buildMode: anyNamed('buildMode'),
- trackWidgetCreation: false,
- targetModel: anyNamed('targetModel'),
- outputFilePath: anyNamed('outputFilePath'),
- depFilePath: anyNamed('depFilePath'),
- packagesPath: anyNamed('packagesPath'),
- mainPath: anyNamed('mainPath'),
- extraFrontEndOptions: anyNamed('extraFrontEndOptions'),
- fileSystemRoots: anyNamed('fileSystemRoots'),
- fileSystemScheme: anyNamed('fileSystemScheme'),
- linkPlatformKernelIn: anyNamed('linkPlatformKernelIn'),
- dartDefines: anyNamed('dartDefines'),
- )).thenAnswer((Invocation _) async {
- return const CompilerOutput('example', 0, <Uri>[]);
- });
+ test('KernelSnapshot does not use track widget creation on profile builds', () => testbed.run(() async {
+ globals.fs.file('.packages').writeAsStringSync('\n');
+ final String build = androidEnvironment.buildDir.path;
+ processManager = FakeProcessManager.list(<FakeCommand>[
+ FakeCommand(command: <String>[
+ artifacts.getArtifactPath(Artifact.engineDartBinary),
+ artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk),
+ '--sdk-root',
+ artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath) + '/',
+ '--target=flutter',
+ '-Ddart.developer.causal_async_stacks=false',
+ ...buildModeOptions(BuildMode.profile),
+ '--aot',
+ '--tfa',
+ '--packages',
+ '/.packages',
+ '--output-dill',
+ '$build/app.dill',
+ '--depfile',
+ '$build/kernel_snapshot.d',
+ '/lib/main.dart',
+ ], stdout: 'result $kBoundaryKey\n$kBoundaryKey\n$kBoundaryKey $build/app.dill 0\n'),
+ ]);
await const KernelSnapshot().build(androidEnvironment);
- }, overrides: <Type, Generator>{
- KernelCompilerFactory: () => MockKernelCompilerFactory(),
+
+ expect(processManager.hasRemainingExpectations, false);
}));
- test('kernel_snapshot can disable track-widget-creation on debug builds', () => testbed.run(() async {
- final MockKernelCompiler mockKernelCompiler = MockKernelCompiler();
- when(kernelCompilerFactory.create(any)).thenAnswer((Invocation _) async {
- return mockKernelCompiler;
- });
- when(mockKernelCompiler.compile(
- sdkRoot: anyNamed('sdkRoot'),
- aot: anyNamed('aot'),
- buildMode: anyNamed('buildMode'),
- trackWidgetCreation: false,
- targetModel: anyNamed('targetModel'),
- outputFilePath: anyNamed('outputFilePath'),
- depFilePath: anyNamed('depFilePath'),
- packagesPath: anyNamed('packagesPath'),
- mainPath: anyNamed('mainPath'),
- extraFrontEndOptions: anyNamed('extraFrontEndOptions'),
- fileSystemRoots: anyNamed('fileSystemRoots'),
- fileSystemScheme: anyNamed('fileSystemScheme'),
- linkPlatformKernelIn: false,
- dartDefines: anyNamed('dartDefines'),
- )).thenAnswer((Invocation _) async {
- return const CompilerOutput('example', 0, <Uri>[]);
- });
+ test('KernelSnapshot can disable track-widget-creation on debug builds', () => testbed.run(() async {
+ globals.fs.file('.packages').writeAsStringSync('\n');
+ final String build = androidEnvironment.buildDir.path;
+ processManager = FakeProcessManager.list(<FakeCommand>[
+ FakeCommand(command: <String>[
+ artifacts.getArtifactPath(Artifact.engineDartBinary),
+ artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk),
+ '--sdk-root',
+ artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath) + '/',
+ '--target=flutter',
+ '-Ddart.developer.causal_async_stacks=true',
+ ...buildModeOptions(BuildMode.debug),
+ '--no-link-platform',
+ '--packages',
+ '/.packages',
+ '--output-dill',
+ '$build/app.dill',
+ '--depfile',
+ '$build/kernel_snapshot.d',
+ '/lib/main.dart',
+ ], stdout: 'result $kBoundaryKey\n$kBoundaryKey\n$kBoundaryKey $build/app.dill 0\n'),
+ ]);
await const KernelSnapshot().build(androidEnvironment
- ..defines[kBuildMode] = 'debug'
+ ..defines[kBuildMode] = getNameForBuildMode(BuildMode.debug)
..defines[kTrackWidgetCreation] = 'false');
- }, overrides: <Type, Generator>{
- KernelCompilerFactory: () => MockKernelCompilerFactory(),
+
+ expect(processManager.hasRemainingExpectations, false);
}));
- test('kernel_snapshot forces platform linking on debug for darwin target platforms', () => testbed.run(() async {
- final MockKernelCompiler mockKernelCompiler = MockKernelCompiler();
- when(kernelCompilerFactory.create(any)).thenAnswer((Invocation _) async {
- return mockKernelCompiler;
- });
- when(mockKernelCompiler.compile(
- sdkRoot: anyNamed('sdkRoot'),
- aot: anyNamed('aot'),
- buildMode: anyNamed('buildMode'),
- trackWidgetCreation: anyNamed('trackWidgetCreation'),
- targetModel: anyNamed('targetModel'),
- outputFilePath: anyNamed('outputFilePath'),
- depFilePath: anyNamed('depFilePath'),
- packagesPath: anyNamed('packagesPath'),
- mainPath: anyNamed('mainPath'),
- extraFrontEndOptions: anyNamed('extraFrontEndOptions'),
- fileSystemRoots: anyNamed('fileSystemRoots'),
- fileSystemScheme: anyNamed('fileSystemScheme'),
- linkPlatformKernelIn: true,
- dartDefines: anyNamed('dartDefines'),
- )).thenAnswer((Invocation _) async {
- return const CompilerOutput('example', 0, <Uri>[]);
- });
+ test('KernelSnapshot forces platform linking on debug for darwin target platforms', () => testbed.run(() async {
+ globals.fs.file('.packages').writeAsStringSync('\n');
+ final String build = androidEnvironment.buildDir.path;
+ processManager = FakeProcessManager.list(<FakeCommand>[
+ FakeCommand(command: <String>[
+ artifacts.getArtifactPath(Artifact.engineDartBinary),
+ artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk),
+ '--sdk-root',
+ artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath) + '/',
+ '--target=flutter',
+ '-Ddart.developer.causal_async_stacks=true',
+ ...buildModeOptions(BuildMode.debug),
+ '--packages',
+ '/.packages',
+ '--output-dill',
+ '$build/app.dill',
+ '--depfile',
+ '$build/kernel_snapshot.d',
+ '/lib/main.dart',
+ ], stdout: 'result $kBoundaryKey\n$kBoundaryKey\n$kBoundaryKey $build/app.dill 0\n'),
+ ]);
await const KernelSnapshot().build(androidEnvironment
- ..defines[kTargetPlatform] = 'darwin-x64'
- ..defines[kBuildMode] = 'debug'
+ ..defines[kTargetPlatform] = getNameForTargetPlatform(TargetPlatform.darwin_x64)
+ ..defines[kBuildMode] = getNameForBuildMode(BuildMode.debug)
..defines[kTrackWidgetCreation] = 'false'
);
- }, overrides: <Type, Generator>{
- KernelCompilerFactory: () => MockKernelCompilerFactory(),
+
+ expect(processManager.hasRemainingExpectations, false);
}));
-
- test('kernel_snapshot does use track widget creation on debug builds', () => testbed.run(() async {
- final MockKernelCompiler mockKernelCompiler = MockKernelCompiler();
- when(kernelCompilerFactory.create(any)).thenAnswer((Invocation _) async {
- return mockKernelCompiler;
- });
- when(mockKernelCompiler.compile(
- sdkRoot: anyNamed('sdkRoot'),
- aot: anyNamed('aot'),
- buildMode: anyNamed('buildMode'),
- trackWidgetCreation: true,
- targetModel: anyNamed('targetModel'),
- outputFilePath: anyNamed('outputFilePath'),
- depFilePath: anyNamed('depFilePath'),
- packagesPath: anyNamed('packagesPath'),
- mainPath: anyNamed('mainPath'),
- extraFrontEndOptions: anyNamed('extraFrontEndOptions'),
- fileSystemRoots: anyNamed('fileSystemRoots'),
- fileSystemScheme: anyNamed('fileSystemScheme'),
- linkPlatformKernelIn: false,
- dartDefines: anyNamed('dartDefines'),
- )).thenAnswer((Invocation _) async {
- return const CompilerOutput('example', 0, <Uri>[]);
- });
-
- await const KernelSnapshot().build(Environment.test(
+ test('KernelSnapshot does use track widget creation on debug builds', () => testbed.run(() async {
+ globals.fs.file('.packages').writeAsStringSync('\n');
+ final Environment testEnvironment = Environment.test(
globals.fs.currentDirectory,
defines: <String, String>{
- kBuildMode: 'debug',
+ kBuildMode: getNameForBuildMode(BuildMode.debug),
kTargetPlatform: getNameForTargetPlatform(TargetPlatform.android_arm),
- }));
- }, overrides: <Type, Generator>{
- KernelCompilerFactory: () => MockKernelCompilerFactory(),
+ },
+ );
+ final String build = testEnvironment.buildDir.path;
+ processManager = FakeProcessManager.list(<FakeCommand>[
+ FakeCommand(command: <String>[
+ artifacts.getArtifactPath(Artifact.engineDartBinary),
+ artifacts.getArtifactPath(Artifact.frontendServerSnapshotForEngineDartSdk),
+ '--sdk-root',
+ artifacts.getArtifactPath(Artifact.flutterPatchedSdkPath) + '/',
+ '--target=flutter',
+ '-Ddart.developer.causal_async_stacks=true',
+ ...buildModeOptions(BuildMode.debug),
+ '--track-widget-creation',
+ '--no-link-platform',
+ '--packages',
+ '/.packages',
+ '--output-dill',
+ '$build/app.dill',
+ '--depfile',
+ '$build/kernel_snapshot.d',
+ '/lib/main.dart',
+ ], stdout: 'result $kBoundaryKey\n$kBoundaryKey\n$kBoundaryKey /build/653e11a8e6908714056a57cd6b4f602a/app.dill 0\n'),
+ ]);
+
+ await const KernelSnapshot().build(testEnvironment);
+
+ expect(processManager.hasRemainingExpectations, false);
}));
- test('aot_elf_profile Produces correct output directory', () => testbed.run(() async {
- await buildSystem.build(const AotElfProfile(), androidEnvironment);
+ test('AotElfProfile Produces correct output directory', () => testbed.run(() async {
+ final String build = androidEnvironment.buildDir.path;
+ processManager = FakeProcessManager.list(<FakeCommand>[
+ FakeCommand(command: <String>[
+ artifacts.getArtifactPath(Artifact.genSnapshot, mode: BuildMode.profile),
+ '--deterministic',
+ kElfAot,
+ '--elf=$build/app.so',
+ '--strip',
+ '--no-sim-use-hardfp',
+ '--no-use-integer-division',
+ '--no-causal-async-stacks',
+ '--lazy-async-stacks',
+ '$build/app.dill',
+ ])
+ ]);
+ androidEnvironment.buildDir.childFile('app.dill').createSync(recursive: true);
- expect(globals.fs.file(globals.fs.path.join(androidEnvironment.buildDir.path, 'app.dill')).existsSync(), true);
- expect(globals.fs.file(globals.fs.path.join(androidEnvironment.buildDir.path, 'app.so')).existsSync(), true);
+ await const AotElfProfile().build(androidEnvironment);
+
+ expect(processManager.hasRemainingExpectations, false);
}));
- test('aot_elf_profile throws error if missing build mode', () => testbed.run(() async {
- final BuildResult result = await buildSystem.build(const AotElfProfile(),
- androidEnvironment..defines.remove(kBuildMode));
+ test('AotElfProfile throws error if missing build mode', () => testbed.run(() async {
+ androidEnvironment.defines.remove(kBuildMode);
- expect(result.exceptions.values.single.exception, isA<MissingDefineException>());
+ expect(const AotElfProfile().build(androidEnvironment),
+ throwsA(isInstanceOf<MissingDefineException>()));
}));
- test('aot_elf_profile throws error if missing target platform', () => testbed.run(() async {
- final BuildResult result = await buildSystem.build(const AotElfProfile(),
- androidEnvironment..defines.remove(kTargetPlatform));
+ test('AotElfProfile throws error if missing target platform', () => testbed.run(() async {
+ androidEnvironment.defines.remove(kTargetPlatform);
- expect(result.exceptions.values.single.exception, isA<MissingDefineException>());
+ expect(const AotElfProfile().build(androidEnvironment),
+ throwsA(isInstanceOf<MissingDefineException>()));
}));
- test('aot_assembly_profile throws error if missing build mode', () => testbed.run(() async {
- final BuildResult result = await buildSystem.build(const AotAssemblyProfile(),
- iosEnvironment..defines.remove(kBuildMode));
+ test('AotAssemblyProfile throws error if missing build mode', () => testbed.run(() async {
+ iosEnvironment.defines.remove(kBuildMode);
- expect(result.exceptions.values.single.exception, isA<MissingDefineException>());
+ expect(const AotAssemblyProfile().build(iosEnvironment),
+ throwsA(isInstanceOf<MissingDefineException>()));
}));
- test('aot_assembly_profile throws error if missing target platform', () => testbed.run(() async {
- final BuildResult result = await buildSystem.build(const AotAssemblyProfile(),
- iosEnvironment..defines.remove(kTargetPlatform));
+ test('AotAssemblyProfile throws error if missing target platform', () => testbed.run(() async {
+ iosEnvironment.defines.remove(kTargetPlatform);
- expect(result.exceptions.values.single.exception, isA<MissingDefineException>());
+ expect(const AotAssemblyProfile().build(iosEnvironment),
+ throwsA(isInstanceOf<MissingDefineException>()));
}));
- test('aot_assembly_profile throws error if built for non-iOS platform', () => testbed.run(() async {
- final BuildResult result = await buildSystem
- .build(const AotAssemblyProfile(), androidEnvironment);
-
- expect(result.exceptions.values.single.exception, isA<Exception>());
+ test('AotAssemblyProfile throws error if built for non-iOS platform', () => testbed.run(() async {
+ expect(const AotAssemblyProfile().build(androidEnvironment),
+ throwsA(isInstanceOf<Exception>()));
}));
- test('aot_assembly_profile will lipo binaries together when multiple archs are requested', () => testbed.run(() async {
+ test('AotAssemblyProfile generates multiple arches and lipos together', () => testbed.run(() async {
+ final String build = iosEnvironment.buildDir.path;
+ processManager = FakeProcessManager.list(<FakeCommand>[
+ FakeCommand(command: <String>[
+ // This path is not known by the cache due to the iOS gen_snapshot split.
+ 'bin/cache/artifacts/engine/ios-profile/gen_snapshot_armv7',
+ '--deterministic',
+ kAssemblyAot,
+ '--assembly=$build/armv7/snapshot_assembly.S',
+ '--strip',
+ '--no-sim-use-hardfp',
+ '--no-use-integer-division',
+ '--no-causal-async-stacks',
+ '--lazy-async-stacks',
+ '$build/app.dill',
+ ]),
+ FakeCommand(command: <String>[
+ // This path is not known by the cache due to the iOS gen_snapshot split.
+ 'bin/cache/artifacts/engine/ios-profile/gen_snapshot_arm64',
+ '--deterministic',
+ kAssemblyAot,
+ '--assembly=$build/arm64/snapshot_assembly.S',
+ '--strip',
+ '--no-causal-async-stacks',
+ '--lazy-async-stacks',
+ '$build/app.dill',
+ ]),
+ const FakeCommand(command: <String>[
+ 'xcrun',
+ '--sdk',
+ 'iphoneos',
+ '--show-sdk-path',
+ ]),
+ const FakeCommand(command: <String>[
+ 'xcrun',
+ '--sdk',
+ 'iphoneos',
+ '--show-sdk-path',
+ ]),
+ FakeCommand(command: <String>[
+ 'xcrun',
+ 'cc',
+ '-arch',
+ 'armv7',
+ '-isysroot',
+ '',
+ '-c',
+ '$build/armv7/snapshot_assembly.S',
+ '-o',
+ '$build/armv7/snapshot_assembly.o',
+ ]),
+ FakeCommand(command: <String>[
+ 'xcrun',
+ 'cc',
+ '-arch',
+ 'arm64',
+ '-isysroot',
+ '',
+ '-c',
+ '$build/arm64/snapshot_assembly.S',
+ '-o',
+ '$build/arm64/snapshot_assembly.o',
+ ]),
+ FakeCommand(command: <String>[
+ 'xcrun',
+ 'clang',
+ '-arch',
+ 'armv7',
+ '-miphoneos-version-min=8.0',
+ '-dynamiclib',
+ '-Xlinker',
+ '-rpath',
+ '-Xlinker',
+ '@executable_path/Frameworks',
+ '-Xlinker',
+ '-rpath',
+ '-Xlinker',
+ '@loader_path/Frameworks',
+ '-install_name',
+ '@rpath/App.framework/App',
+ '-isysroot',
+ '',
+ '-o',
+ '$build/armv7/App.framework/App',
+ '$build/armv7/snapshot_assembly.o',
+ ]),
+ FakeCommand(command: <String>[
+ 'xcrun',
+ 'clang',
+ '-arch',
+ 'arm64',
+ '-miphoneos-version-min=8.0',
+ '-dynamiclib',
+ '-Xlinker',
+ '-rpath',
+ '-Xlinker',
+ '@executable_path/Frameworks',
+ '-Xlinker',
+ '-rpath',
+ '-Xlinker',
+ '@loader_path/Frameworks',
+ '-install_name',
+ '@rpath/App.framework/App',
+ '-isysroot',
+ '',
+ '-o',
+ '$build/arm64/App.framework/App',
+ '$build/arm64/snapshot_assembly.o',
+ ]),
+ FakeCommand(command: <String>[
+ 'lipo',
+ '$build/armv7/App.framework/App',
+ '$build/arm64/App.framework/App',
+ '-create',
+ '-output',
+ '$build/App.framework/App',
+ ]),
+ ]);
iosEnvironment.defines[kIosArchs] ='armv7 arm64';
- when(mockProcessManager.run(any)).thenAnswer((Invocation invocation) async {
- globals.fs.file(globals.fs.path.join(iosEnvironment.buildDir.path, 'App.framework', 'App'))
- .createSync(recursive: true);
- return FakeProcessResult(
- stdout: '',
- stderr: '',
- );
- });
- final BuildResult result = await buildSystem
- .build(const AotAssemblyProfile(), iosEnvironment);
- expect(result.success, true);
- }, overrides: <Type, Generator>{
- ProcessManager: () => mockProcessManager,
- }));
-
- test('aot_assembly_profile with bitcode sends correct argument to snapshotter (one arch)', () => testbed.run(() async {
- iosEnvironment.defines[kIosArchs] = 'arm64';
- iosEnvironment.defines[kBitcodeFlag] = 'true';
-
- final FakeProcessResult fakeProcessResult = FakeProcessResult(
- stdout: '',
- stderr: '',
- );
- final RunResult fakeRunResult = RunResult(fakeProcessResult, const <String>['foo']);
- when(mockProcessManager.run(any)).thenAnswer((Invocation invocation) async {
- globals.fs.file(globals.fs.path.join(iosEnvironment.buildDir.path, 'App.framework', 'App'))
- .createSync(recursive: true);
- return fakeProcessResult;
- });
-
- when(mockXcode.cc(any)).thenAnswer((_) => Future<RunResult>.value(fakeRunResult));
- when(mockXcode.clang(any)).thenAnswer((_) => Future<RunResult>.value(fakeRunResult));
-
- final BuildResult result = await buildSystem.build(const AotAssemblyProfile(), iosEnvironment);
-
- expect(result.success, true);
- verify(mockXcode.cc(argThat(contains('-fembed-bitcode')))).called(1);
- verify(mockXcode.clang(argThat(contains('-fembed-bitcode')))).called(1);
- }, overrides: <Type, Generator>{
- ProcessManager: () => mockProcessManager,
- Xcode: () => mockXcode,
- }));
-
- test('aot_assembly_profile with bitcode sends correct argument to snapshotter (mutli arch)', () => testbed.run(() async {
- iosEnvironment.defines[kIosArchs] = 'armv7 arm64';
- iosEnvironment.defines[kBitcodeFlag] = 'true';
-
- final FakeProcessResult fakeProcessResult = FakeProcessResult(
- stdout: '',
- stderr: '',
- );
- final RunResult fakeRunResult = RunResult(fakeProcessResult, const <String>['foo']);
- when(mockProcessManager.run(any)).thenAnswer((Invocation invocation) async {
- globals.fs.file(globals.fs.path.join(iosEnvironment.buildDir.path, 'App.framework', 'App'))
- .createSync(recursive: true);
- return fakeProcessResult;
- });
-
- when(mockXcode.cc(any)).thenAnswer((_) => Future<RunResult>.value(fakeRunResult));
- when(mockXcode.clang(any)).thenAnswer((_) => Future<RunResult>.value(fakeRunResult));
await const AotAssemblyProfile().build(iosEnvironment);
- verify(mockXcode.cc(argThat(contains('-fembed-bitcode')))).called(2);
- verify(mockXcode.clang(argThat(contains('-fembed-bitcode')))).called(2);
- }, overrides: <Type, Generator>{
- ProcessManager: () => mockProcessManager,
- Xcode: () => mockXcode,
+ expect(processManager.hasRemainingExpectations, false);
}));
- test('aot_assembly_profile will lipo binaries together when multiple archs are requested', () => testbed.run(() async {
- iosEnvironment.defines[kIosArchs] = 'armv7 arm64';
- when(mockProcessManager.run(any)).thenAnswer((Invocation invocation) async {
- globals.fs.file(globals.fs.path.join(iosEnvironment.buildDir.path, 'App.framework', 'App'))
- .createSync(recursive: true);
- return FakeProcessResult(
- stdout: '',
- stderr: '',
- );
- });
- final BuildResult result = await buildSystem.build(const AotAssemblyProfile(), iosEnvironment);
+ test('AotAssemblyProfile with bitcode sends correct argument to snapshotter (one arch)', () => testbed.run(() async {
+ iosEnvironment.defines[kIosArchs] = 'arm64';
+ iosEnvironment.defines[kBitcodeFlag] = 'true';
+ final String build = iosEnvironment.buildDir.path;
+ processManager = FakeProcessManager.list(<FakeCommand>[
+ FakeCommand(command: <String>[
+ // This path is not known by the cache due to the iOS gen_snapshot split.
+ 'bin/cache/artifacts/engine/ios-profile/gen_snapshot_arm64',
+ '--deterministic',
+ kAssemblyAot,
+ '--assembly=$build/arm64/snapshot_assembly.S',
+ '--strip',
+ '--no-causal-async-stacks',
+ '--lazy-async-stacks',
+ '$build/app.dill',
+ ]),
+ const FakeCommand(command: <String>[
+ 'xcrun',
+ '--sdk',
+ 'iphoneos',
+ '--show-sdk-path',
+ ]),
+ FakeCommand(command: <String>[
+ 'xcrun',
+ 'cc',
+ '-arch',
+ 'arm64',
+ '-isysroot',
+ '',
+ // Contains bitcode flag.
+ '-fembed-bitcode',
+ '-c',
+ '$build/arm64/snapshot_assembly.S',
+ '-o',
+ '$build/arm64/snapshot_assembly.o',
+ ]),
+ FakeCommand(command: <String>[
+ 'xcrun',
+ 'clang',
+ '-arch',
+ 'arm64',
+ '-miphoneos-version-min=8.0',
+ '-dynamiclib',
+ '-Xlinker',
+ '-rpath',
+ '-Xlinker',
+ '@executable_path/Frameworks',
+ '-Xlinker',
+ '-rpath',
+ '-Xlinker',
+ '@loader_path/Frameworks',
+ '-install_name',
+ '@rpath/App.framework/App',
+ // Contains bitcode flag.
+ '-fembed-bitcode',
+ '-isysroot',
+ '',
+ '-o',
+ '$build/arm64/App.framework/App',
+ '$build/arm64/snapshot_assembly.o',
+ ]),
+ FakeCommand(command: <String>[
+ 'lipo',
+ '$build/arm64/App.framework/App',
+ '-create',
+ '-output',
+ '$build/App.framework/App',
+ ]),
+ ]);
- expect(result.success, true);
- }, overrides: <Type, Generator>{
- ProcessManager: () => mockProcessManager,
+ await const AotAssemblyProfile().build(iosEnvironment);
+
+ expect(processManager.hasRemainingExpectations, false);
}));
test('kExtraGenSnapshotOptions passes values to gen_snapshot', () => testbed.run(() async {
androidEnvironment.defines[kExtraGenSnapshotOptions] = 'foo,bar,baz=2';
+ androidEnvironment.defines[kBuildMode] = getNameForBuildMode(BuildMode.profile);
+ final String build = androidEnvironment.buildDir.path;
- when(genSnapshot.run(
- snapshotType: anyNamed('snapshotType'),
- darwinArch: anyNamed('darwinArch'),
- additionalArgs: captureAnyNamed('additionalArgs'),
- )).thenAnswer((Invocation invocation) async {
- expect(invocation.namedArguments[#additionalArgs], containsAll(<String>[
+ processManager = FakeProcessManager.list(<FakeCommand>[
+ FakeCommand(command: <String>[
+ artifacts.getArtifactPath(Artifact.genSnapshot, mode: BuildMode.profile),
+ '--deterministic',
'foo',
'bar',
'baz=2',
- ]));
- return 0;
- });
-
+ kElfAot,
+ '--elf=$build/app.so',
+ '--strip',
+ '--no-sim-use-hardfp',
+ '--no-use-integer-division',
+ '--no-causal-async-stacks',
+ '--lazy-async-stacks',
+ '$build/app.dill',
+ ]),
+ ]);
await const AotElfRelease().build(androidEnvironment);
- }, overrides: <Type, Generator>{
- GenSnapshot: () => MockGenSnapshot(),
+
+ expect(processManager.hasRemainingExpectations, false);
}));
}
-
-class MockProcessManager extends Mock implements ProcessManager {}
-class MockGenSnapshot extends Mock implements GenSnapshot {}
-class MockXcode extends Mock implements Xcode {}
-
-class FakeGenSnapshot implements GenSnapshot {
- List<String> lastCallAdditionalArgs;
- @override
- Future<int> run({SnapshotType snapshotType, DarwinArch darwinArch, Iterable<String> additionalArgs = const <String>[]}) async {
- lastCallAdditionalArgs = additionalArgs.toList();
- final Directory out = globals.fs.file(lastCallAdditionalArgs.last).parent;
- if (darwinArch == null) {
- out.childFile('app.so').createSync();
- out.childFile('gen_snapshot.d').createSync();
- return 0;
- }
- out.childDirectory('App.framework').childFile('App').createSync(recursive: true);
-
- final String assembly = lastCallAdditionalArgs
- .firstWhere((String arg) => arg.startsWith('--assembly'))
- .substring('--assembly='.length);
- globals.fs.file(assembly).createSync();
- globals.fs.file(assembly.replaceAll('.S', '.o')).createSync();
- return 0;
- }
-}
-
-class FakeKernelCompilerFactory implements KernelCompilerFactory {
- KernelCompiler kernelCompiler = FakeKernelCompiler();
-
- @override
- Future<KernelCompiler> create(FlutterProject flutterProject) async {
- return kernelCompiler;
- }
-}
-
-class FakeKernelCompiler implements KernelCompiler {
- @override
- Future<CompilerOutput> compile({
- String sdkRoot,
- String mainPath,
- String outputFilePath,
- String depFilePath,
- TargetModel targetModel = TargetModel.flutter,
- bool linkPlatformKernelIn = false,
- bool aot = false,
- BuildMode buildMode,
- bool causalAsyncStacks = true,
- bool trackWidgetCreation,
- List<String> extraFrontEndOptions,
- String packagesPath,
- List<String> fileSystemRoots,
- String fileSystemScheme,
- String platformDill,
- String initializeFromDill,
- List<String> dartDefines,
- }) async {
- globals.fs.file(outputFilePath).createSync(recursive: true);
- return CompilerOutput(outputFilePath, 0, null);
- }
-}
-
-class MockKernelCompilerFactory extends Mock implements KernelCompilerFactory {}
-class MockKernelCompiler extends Mock implements KernelCompiler {}
diff --git a/packages/flutter_tools/test/src/fake_process_manager.dart b/packages/flutter_tools/test/src/fake_process_manager.dart
index 0077547..c31511d 100644
--- a/packages/flutter_tools/test/src/fake_process_manager.dart
+++ b/packages/flutter_tools/test/src/fake_process_manager.dart
@@ -202,6 +202,11 @@
/// This is a no-op on [FakeProcessManager.any].
void addCommand(FakeCommand command);
+ /// Whether this fake has more [FakeCommand]s that are expected to run.
+ ///
+ /// This is always `true` for [FakeProcessManager.any].
+ bool get hasRemainingExpectations;
+
@protected
FakeCommand findCommand(List<String> command, String workingDirectory, Map<String, String> environment);
@@ -299,6 +304,9 @@
@override
void addCommand(FakeCommand command) { }
+
+ @override
+ bool get hasRemainingExpectations => true;
}
class _SequenceProcessManager extends FakeProcessManager {
@@ -325,4 +333,7 @@
void addCommand(FakeCommand command) {
_commands.add(command);
}
+
+ @override
+ bool get hasRemainingExpectations => _commands.isNotEmpty;
}