Skip to content

Commit

Permalink
[flutter_tools] replace most MockBuildSystem instances with TestBuild…
Browse files Browse the repository at this point in the history
…System (#76821)
  • Loading branch information
jonahwilliams committed Feb 26, 2021
1 parent cca26d0 commit 666c950
Show file tree
Hide file tree
Showing 11 changed files with 262 additions and 232 deletions.
2 changes: 1 addition & 1 deletion packages/flutter_tools/lib/executable.dart
Expand Up @@ -144,7 +144,7 @@ List<FlutterCommand> generateCommands({
terminal: globals.terminal,
artifacts: globals.artifacts,
),
AssembleCommand(verboseHelp: verboseHelp),
AssembleCommand(verboseHelp: verboseHelp, buildSystem: globals.buildSystem),
AttachCommand(verboseHelp: verboseHelp),
BuildCommand(verboseHelp: verboseHelp),
ChannelCommand(verboseHelp: verboseHelp),
Expand Down
7 changes: 5 additions & 2 deletions packages/flutter_tools/lib/src/commands/assemble.dart
Expand Up @@ -82,7 +82,8 @@ const bool useLegacyNames = true;
/// Assemble provides a low level API to interact with the flutter tool build
/// system.
class AssembleCommand extends FlutterCommand {
AssembleCommand({ bool verboseHelp = false }) {
AssembleCommand({ bool verboseHelp = false, @required BuildSystem buildSystem })
: _buildSystem = buildSystem {
argParser.addMultiOption(
'define',
abbr: 'd',
Expand Down Expand Up @@ -124,6 +125,8 @@ class AssembleCommand extends FlutterCommand {
);
}

final BuildSystem _buildSystem;

@override
String get description => 'Assemble and build Flutter resources.';

Expand Down Expand Up @@ -229,7 +232,7 @@ class AssembleCommand extends FlutterCommand {
Future<FlutterCommandResult> runCommand() async {
final List<Target> targets = createTargets();
final Target target = targets.length == 1 ? targets.single : CompositeTarget(targets);
final BuildResult result = await globals.buildSystem.build(
final BuildResult result = await _buildSystem.build(
target,
createEnvironment(),
buildSystemConfig: BuildSystemConfig(
Expand Down
188 changes: 101 additions & 87 deletions packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart
Expand Up @@ -13,109 +13,117 @@ import 'package:flutter_tools/src/build_system/build_system.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/assemble.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:mockito/mockito.dart';
import 'package:flutter_tools/src/globals.dart' as globals;

import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/fakes.dart';
import '../../src/testbed.dart';

void main() {
Cache.disableLocking();
Cache.flutterRoot = '';
final StackTrace stackTrace = StackTrace.current;

final Testbed testbed = Testbed(overrides: <Type, Generator>{
BuildSystem: () => MockBuildSystem(),
Cache: () => FakeCache(),
});

testbed.test('flutter assemble can run a build', () async {
when(globals.buildSystem.build(any, any, buildSystemConfig: anyNamed('buildSystemConfig')))
.thenAnswer((Invocation invocation) async {
return BuildResult(success: true);
});
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand());
testUsingContext('flutter assemble can run a build', () async {
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
buildSystem: TestBuildSystem.all(BuildResult(success: true)),
));
await commandRunner.run(<String>['assemble', '-o Output', 'debug_macos_bundle_flutter_assets']);

expect(testLogger.traceText, contains('build succeeded.'));
}, overrides: <Type, Generator>{
Cache: () => FakeCache(),
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});

testbed.test('flutter assemble can parse defines whose values contain =', () async {
when(globals.buildSystem.build(any, any, buildSystemConfig: anyNamed('buildSystemConfig')))
.thenAnswer((Invocation invocation) async {
expect((invocation.positionalArguments[1] as Environment).defines, containsPair('FooBar', 'fizz=2'));
return BuildResult(success: true);
});
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand());
testUsingContext('flutter assemble can parse defines whose values contain =', () async {
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
buildSystem: TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) {
expect(environment.defines, containsPair('FooBar', 'fizz=2'));
})
));
await commandRunner.run(<String>['assemble', '-o Output', '-dFooBar=fizz=2', 'debug_macos_bundle_flutter_assets']);

expect(testLogger.traceText, contains('build succeeded.'));
}, overrides: <Type, Generator>{
Cache: () => FakeCache(),
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});

testbed.test('flutter assemble can parse inputs', () async {
when(globals.buildSystem.build(any, any, buildSystemConfig: anyNamed('buildSystemConfig')))
.thenAnswer((Invocation invocation) async {
expect((invocation.positionalArguments[1] as Environment).inputs, containsPair('Foo', 'Bar.txt'));
return BuildResult(success: true);
});
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand());
testUsingContext('flutter assemble can parse inputs', () async {
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
buildSystem: TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) {
expect(environment.inputs, containsPair('Foo', 'Bar.txt'));
})
));
await commandRunner.run(<String>['assemble', '-o Output', '-iFoo=Bar.txt', 'debug_macos_bundle_flutter_assets']);

expect(testLogger.traceText, contains('build succeeded.'));
}, overrides: <Type, Generator>{
Cache: () => FakeCache(),
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});

testbed.test('flutter assemble throws ToolExit if not provided with output', () async {
when(globals.buildSystem.build(any, any, buildSystemConfig: anyNamed('buildSystemConfig')))
.thenAnswer((Invocation invocation) async {
return BuildResult(success: true);
});
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand());
testUsingContext('flutter assemble throws ToolExit if not provided with output', () async {
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
buildSystem: TestBuildSystem.all(BuildResult(success: true)),
));

expect(commandRunner.run(<String>['assemble', 'debug_macos_bundle_flutter_assets']),
throwsToolExit());
expect(commandRunner.run(<String>['assemble', 'debug_macos_bundle_flutter_assets']), throwsToolExit());
}, overrides: <Type, Generator>{
Cache: () => FakeCache(),
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});

testbed.test('flutter assemble throws ToolExit if called with non-existent rule', () async {
when(globals.buildSystem.build(any, any, buildSystemConfig: anyNamed('buildSystemConfig')))
.thenAnswer((Invocation invocation) async {
return BuildResult(success: true);
});
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand());
testUsingContext('flutter assemble throws ToolExit if called with non-existent rule', () async {
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
buildSystem: TestBuildSystem.all(BuildResult(success: true)),
));

expect(commandRunner.run(<String>['assemble', '-o Output', 'undefined']),
throwsToolExit());
}, overrides: <Type, Generator>{
Cache: () => FakeCache(),
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});

testbed.test('flutter assemble does not log stack traces during build failure', () async {
final StackTrace testStackTrace = StackTrace.current;
when(globals.buildSystem.build(any, any, buildSystemConfig: anyNamed('buildSystemConfig')))
.thenAnswer((Invocation invocation) async {
return BuildResult(success: false, exceptions: <String, ExceptionMeasurement>{
'hello': ExceptionMeasurement('hello', 'bar', testStackTrace),
});
});
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand());
testUsingContext('flutter assemble does not log stack traces during build failure', () async {
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
buildSystem: TestBuildSystem.all(BuildResult(success: false, exceptions: <String, ExceptionMeasurement>{
'hello': ExceptionMeasurement('hello', 'bar', stackTrace),
}))
));

await expectLater(commandRunner.run(<String>['assemble', '-o Output', 'debug_macos_bundle_flutter_assets']),
throwsToolExit());
expect(testLogger.errorText, isNot(contains('bar')));
expect(testLogger.errorText, isNot(contains(testStackTrace.toString())));
expect(testLogger.errorText, isNot(contains(stackTrace.toString())));
}, overrides: <Type, Generator>{
Cache: () => FakeCache(),
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});

testbed.test('flutter assemble outputs JSON performance data to provided file', () async {
when(globals.buildSystem.build(any, any, buildSystemConfig: anyNamed('buildSystemConfig')))
.thenAnswer((Invocation invocation) async {
return BuildResult(success: true, performance: <String, PerformanceMeasurement>{
testUsingContext('flutter assemble outputs JSON performance data to provided file', () async {
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
buildSystem: TestBuildSystem.all(
BuildResult(success: true, performance: <String, PerformanceMeasurement>{
'hello': PerformanceMeasurement(
target: 'hello',
analyticsName: 'bar',
elapsedMilliseconds: 123,
skipped: false,
succeeded: true,
),
});
});
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand());
}),
),
));

await commandRunner.run(<String>[
'assemble',
Expand All @@ -131,34 +139,45 @@ void main() {
containsPair('name', 'bar'),
)),
);
}, overrides: <Type, Generator>{
Cache: () => FakeCache(),
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});

testbed.test('flutter assemble does not inject engine revision with local-engine', () async {
Environment environment;
when(globals.buildSystem.build(any, any, buildSystemConfig: anyNamed('buildSystemConfig')))
.thenAnswer((Invocation invocation) async {
environment = invocation.positionalArguments[1] as Environment;
return BuildResult(success: true);
});
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand());
testUsingContext('flutter assemble does not inject engine revision with local-engine', () async {
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(
buildSystem: TestBuildSystem.all(BuildResult(success: true), (Target target, Environment environment) {
expect(environment.engineVersion, isNull);
})
));
await commandRunner.run(<String>['assemble', '-o Output', 'debug_macos_bundle_flutter_assets']);

expect(environment.engineVersion, isNull);
}, overrides: <Type, Generator>{
Artifacts: () => Artifacts.test(localEngine: 'out/host_release'),
Cache: () => FakeCache(),
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});

testbed.test('flutter assemble only writes input and output files when the values change', () async {
when(globals.buildSystem.build(any, any, buildSystemConfig: anyNamed('buildSystemConfig')))
.thenAnswer((Invocation invocation) async {
return BuildResult(
success: true,
inputFiles: <File>[globals.fs.file('foo')..createSync()],
outputFiles: <File>[globals.fs.file('bar')..createSync()],
);
});

final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand());
testUsingContext('flutter assemble only writes input and output files when the values change', () async {
final BuildSystem buildSystem = TestBuildSystem.list(<BuildResult>[
BuildResult(
success: true,
inputFiles: <File>[globals.fs.file('foo')..createSync()],
outputFiles: <File>[globals.fs.file('bar')..createSync()],
),
BuildResult(
success: true,
inputFiles: <File>[globals.fs.file('foo')..createSync()],
outputFiles: <File>[globals.fs.file('bar')..createSync()],
),
BuildResult(
success: true,
inputFiles: <File>[globals.fs.file('foo'), globals.fs.file('fizz')..createSync()],
outputFiles: <File>[globals.fs.file('bar'), globals.fs.file(globals.fs.path.join('.dart_tool', 'fizz2'))..createSync(recursive: true)],
),
]);
final CommandRunner<void> commandRunner = createTestCommandRunner(AssembleCommand(buildSystem: buildSystem));
await commandRunner.run(<String>[
'assemble',
'-o Output',
Expand Down Expand Up @@ -186,13 +205,6 @@ void main() {
expect(inputs.lastModifiedSync(), theDistantPast);
expect(outputs.lastModifiedSync(), theDistantPast);

when(globals.buildSystem.build(any, any, buildSystemConfig: anyNamed('buildSystemConfig')))
.thenAnswer((Invocation invocation) async {
return BuildResult(
success: true,
inputFiles: <File>[globals.fs.file('foo'), globals.fs.file('fizz')..createSync()],
outputFiles: <File>[globals.fs.file('bar'), globals.fs.file(globals.fs.path.join('.dart_tool', 'fizz2'))..createSync(recursive: true)]);
});
await commandRunner.run(<String>[
'assemble',
'-o Output',
Expand All @@ -204,6 +216,10 @@ void main() {
expect(inputs.readAsStringSync(), contains('foo'));
expect(inputs.readAsStringSync(), contains('fizz'));
expect(inputs.lastModifiedSync(), isNot(theDistantPast));
}, overrides: <Type, Generator>{
Cache: () => FakeCache(),
FileSystem: () => MemoryFileSystem.test(),
ProcessManager: () => FakeProcessManager.any(),
});

testWithoutContext('writePerformanceData outputs performance data in JSON form', () {
Expand Down Expand Up @@ -236,5 +252,3 @@ void main() {
});
});
}

class MockBuildSystem extends Mock implements BuildSystem {}
Expand Up @@ -16,6 +16,7 @@ import 'package:mockito/mockito.dart';

import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/fakes.dart';

void main() {
group('build ios-framework', () {
Expand Down Expand Up @@ -70,7 +71,7 @@ void main() {
when(mockFlutterVersion.frameworkVersion).thenReturn(frameworkVersion);

final BuildIOSFrameworkCommand command = BuildIOSFrameworkCommand(
buildSystem: MockBuildSystem(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)),
platform: fakePlatform,
flutterVersion: mockFlutterVersion,
cache: cache,
Expand All @@ -95,7 +96,7 @@ void main() {
when(mockGitTagVersion.commits).thenReturn(2);

final BuildIOSFrameworkCommand command = BuildIOSFrameworkCommand(
buildSystem: MockBuildSystem(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)),
platform: fakePlatform,
flutterVersion: mockFlutterVersion,
cache: cache,
Expand All @@ -117,7 +118,7 @@ void main() {
when(mockGitTagVersion.commits).thenReturn(0);

final BuildIOSFrameworkCommand command = BuildIOSFrameworkCommand(
buildSystem: MockBuildSystem(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)),
platform: fakePlatform,
flutterVersion: mockFlutterVersion,
cache: cache,
Expand Down Expand Up @@ -155,7 +156,7 @@ void main() {

testUsingContext('created when forced', () async {
final BuildIOSFrameworkCommand command = BuildIOSFrameworkCommand(
buildSystem: MockBuildSystem(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)),
platform: fakePlatform,
flutterVersion: mockFlutterVersion,
cache: cache,
Expand All @@ -178,7 +179,7 @@ void main() {

testUsingContext('contains license and version', () async {
final BuildIOSFrameworkCommand command = BuildIOSFrameworkCommand(
buildSystem: MockBuildSystem(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)),
platform: fakePlatform,
flutterVersion: mockFlutterVersion,
cache: cache,
Expand All @@ -198,7 +199,7 @@ void main() {

testUsingContext('debug URL', () async {
final BuildIOSFrameworkCommand command = BuildIOSFrameworkCommand(
buildSystem: MockBuildSystem(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)),
platform: fakePlatform,
flutterVersion: mockFlutterVersion,
cache: cache,
Expand All @@ -216,7 +217,7 @@ void main() {

testUsingContext('profile URL', () async {
final BuildIOSFrameworkCommand command = BuildIOSFrameworkCommand(
buildSystem: MockBuildSystem(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)),
platform: fakePlatform,
flutterVersion: mockFlutterVersion,
cache: cache,
Expand All @@ -234,7 +235,7 @@ void main() {

testUsingContext('release URL', () async {
final BuildIOSFrameworkCommand command = BuildIOSFrameworkCommand(
buildSystem: MockBuildSystem(),
buildSystem: TestBuildSystem.all(BuildResult(success: true)),
platform: fakePlatform,
flutterVersion: mockFlutterVersion,
cache: cache,
Expand All @@ -257,4 +258,3 @@ void main() {

class MockFlutterVersion extends Mock implements FlutterVersion {}
class MockGitTagVersion extends Mock implements GitTagVersion {}
class MockBuildSystem extends Mock implements BuildSystem {}

0 comments on commit 666c950

Please sign in to comment.