cleanup of tool build tests (#50904)

This commit is contained in:
Jonah Williams 2020-02-19 18:46:04 -08:00 committed by GitHub
parent 1793108ba1
commit 9295b34850
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 331 additions and 331 deletions

View file

@ -3,6 +3,7 @@
// found in the LICENSE file.
import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart';
import 'package:platform/platform.dart';
import 'package:flutter_tools/src/base/file_system.dart';
@ -16,104 +17,106 @@ import 'package:flutter_tools/src/project.dart';
import 'package:meta/meta.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/mocks.dart';
// Defined globally for mocks to use.
FileSystem fileSystem;
void main() {
Cache.disableLocking();
MockPlatform linuxPlatform;
MockPlatform windowsPlatform;
final Platform linuxPlatform = FakePlatform(
operatingSystem: 'linux',
environment: const <String, String>{
'FLUTTER_ROOT': '/',
},
);
final Platform windowsPlatform = FakePlatform(
operatingSystem: 'windows',
environment: const <String, String>{
'FLUTTER_ROOT': '/'
},
);
MockFuchsiaSdk fuchsiaSdk;
setUp(() {
linuxPlatform = MockPlatform();
windowsPlatform = MockPlatform();
fuchsiaSdk = MockFuchsiaSdk();
when(linuxPlatform.isLinux).thenReturn(true);
when(linuxPlatform.isWindows).thenReturn(false);
when(linuxPlatform.isMacOS).thenReturn(false);
when(windowsPlatform.isWindows).thenReturn(true);
when(windowsPlatform.isLinux).thenReturn(false);
when(windowsPlatform.isMacOS).thenReturn(false);
fileSystem = MemoryFileSystem.test();
});
group('Fuchsia build fails gracefully when', () {
testUsingContext('there is no Fuchsia project', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
expect(
createTestCommandRunner(command)
.run(const <String>['build', 'fuchsia']),
throwsToolExit());
createTestCommandRunner(command).run(const <String>['build', 'fuchsia']),
throwsToolExit(),
);
}, overrides: <Type, Generator>{
Platform: () => linuxPlatform,
FileSystem: () => MemoryFileSystem(),
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('there is no cmx file', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
globals.fs.directory('fuchsia').createSync(recursive: true);
globals.fs.file('.packages').createSync();
globals.fs.file('pubspec.yaml').createSync();
fileSystem.directory('fuchsia').createSync(recursive: true);
fileSystem.file('.packages').createSync();
fileSystem.file('pubspec.yaml').createSync();
expect(
createTestCommandRunner(command)
.run(const <String>['build', 'fuchsia']),
throwsToolExit());
createTestCommandRunner(command).run(const <String>['build', 'fuchsia']),
throwsToolExit(),
);
}, overrides: <Type, Generator>{
Platform: () => linuxPlatform,
FileSystem: () => MemoryFileSystem(),
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('on Windows platform', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
const String appName = 'app_name';
globals.fs
.file(globals.fs.path.join('fuchsia', 'meta', '$appName.cmx'))
..createSync(recursive: true)
..writeAsStringSync('{}');
globals.fs.file('.packages').createSync();
final File pubspecFile = globals.fs.file('pubspec.yaml')..createSync();
fileSystem
.file(fileSystem.path.join('fuchsia', 'meta', '$appName.cmx'))
..createSync(recursive: true)
..writeAsStringSync('{}');
fileSystem.file('.packages').createSync();
final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync();
pubspecFile.writeAsStringSync('name: $appName');
expect(
createTestCommandRunner(command)
.run(const <String>['build', 'fuchsia']),
throwsToolExit());
createTestCommandRunner(command).run(const <String>['build', 'fuchsia']),
throwsToolExit(),
);
}, overrides: <Type, Generator>{
Platform: () => windowsPlatform,
FileSystem: () => MemoryFileSystem(),
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
testUsingContext('there is no Fuchsia kernel compiler', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
const String appName = 'app_name';
globals.fs
.file(globals.fs.path.join('fuchsia', 'meta', '$appName.cmx'))
..createSync(recursive: true)
..writeAsStringSync('{}');
globals.fs.file('.packages').createSync();
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
final File pubspecFile = globals.fs.file('pubspec.yaml')..createSync();
fileSystem
.file(fileSystem.path.join('fuchsia', 'meta', '$appName.cmx'))
..createSync(recursive: true)
..writeAsStringSync('{}');
fileSystem.file('.packages').createSync();
fileSystem.file(fileSystem.path.join('lib', 'main.dart')).createSync(recursive: true);
final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync();
pubspecFile.writeAsStringSync('name: $appName');
expect(
createTestCommandRunner(command)
.run(const <String>['build', 'fuchsia']),
throwsToolExit());
createTestCommandRunner(command).run(const <String>['build', 'fuchsia']),
throwsToolExit(),
);
}, overrides: <Type, Generator>{
Platform: () => linuxPlatform,
FileSystem: () => MemoryFileSystem(),
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
});
});
@ -122,45 +125,40 @@ void main() {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
const String appName = 'app_name';
globals.fs
.file(globals.fs.path.join('fuchsia', 'meta', '$appName.cmx'))
fileSystem
.file(fileSystem.path.join('fuchsia', 'meta', '$appName.cmx'))
..createSync(recursive: true)
..writeAsStringSync('{}');
globals.fs.file('.packages').createSync();
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
final File pubspecFile = globals.fs.file('pubspec.yaml')..createSync();
fileSystem.file('.packages').createSync();
fileSystem.file(fileSystem.path.join('lib', 'main.dart')).createSync(recursive: true);
final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync();
pubspecFile.writeAsStringSync('name: $appName');
await createTestCommandRunner(command)
.run(const <String>['build', 'fuchsia']);
final String farPath =
globals.fs.path.join(getFuchsiaBuildDirectory(), 'pkg', 'app_name-0.far');
expect(globals.fs.file(farPath).existsSync(), isTrue);
.run(const <String>['build', 'fuchsia']);
final String farPath = fileSystem.path.join(
getFuchsiaBuildDirectory(), 'pkg', 'app_name-0.far',
);
expect(fileSystem.file(farPath), exists);
}, overrides: <Type, Generator>{
Platform: () => linuxPlatform,
FileSystem: () => MemoryFileSystem(),
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
FuchsiaSdk: () => fuchsiaSdk,
});
}
class MockPlatform extends Mock implements Platform {
@override
Map<String, String> environment = <String, String>{
'FLUTTER_ROOT': '/',
};
}
class MockFuchsiaPM extends Mock implements FuchsiaPM {
String _appName;
@override
Future<bool> init(String buildPath, String appName) async {
if (!globals.fs.directory(buildPath).existsSync()) {
if (!fileSystem.directory(buildPath).existsSync()) {
return false;
}
globals.fs
.file(globals.fs.path.join(buildPath, 'meta', 'package'))
fileSystem
.file(fileSystem.path.join(buildPath, 'meta', 'package'))
.createSync(recursive: true);
_appName = appName;
return true;
@ -168,36 +166,36 @@ class MockFuchsiaPM extends Mock implements FuchsiaPM {
@override
Future<bool> genkey(String buildPath, String outKeyPath) async {
if (!globals.fs.file(globals.fs.path.join(buildPath, 'meta', 'package')).existsSync()) {
if (!fileSystem.file(fileSystem.path.join(buildPath, 'meta', 'package')).existsSync()) {
return false;
}
globals.fs.file(outKeyPath).createSync(recursive: true);
fileSystem.file(outKeyPath).createSync(recursive: true);
return true;
}
@override
Future<bool> build(String buildPath, String keyPath, String manifestPath) async {
if (!globals.fs.file(globals.fs.path.join(buildPath, 'meta', 'package')).existsSync() ||
!globals.fs.file(keyPath).existsSync() ||
!globals.fs.file(manifestPath).existsSync()) {
if (!fileSystem.file(fileSystem.path.join(buildPath, 'meta', 'package')).existsSync() ||
!fileSystem.file(keyPath).existsSync() ||
!fileSystem.file(manifestPath).existsSync()) {
return false;
}
globals.fs.file(globals.fs.path.join(buildPath, 'meta.far')).createSync(recursive: true);
fileSystem.file(fileSystem.path.join(buildPath, 'meta.far')).createSync(recursive: true);
return true;
}
@override
Future<bool> archive(String buildPath, String keyPath, String manifestPath) async {
if (!globals.fs.file(globals.fs.path.join(buildPath, 'meta', 'package')).existsSync() ||
!globals.fs.file(keyPath).existsSync() ||
!globals.fs.file(manifestPath).existsSync()) {
if (!fileSystem.file(fileSystem.path.join(buildPath, 'meta', 'package')).existsSync() ||
!fileSystem.file(keyPath).existsSync() ||
!fileSystem.file(manifestPath).existsSync()) {
return false;
}
if (_appName == null) {
return false;
}
globals.fs
.file(globals.fs.path.join(buildPath, '$_appName-0.far'))
fileSystem
.file(fileSystem.path.join(buildPath, '$_appName-0.far'))
.createSync(recursive: true);
return true;
}
@ -212,8 +210,8 @@ class MockFuchsiaKernelCompiler extends Mock implements FuchsiaKernelCompiler {
}) async {
final String outDir = getFuchsiaBuildDirectory();
final String appName = fuchsiaProject.project.manifest.appName;
final String manifestPath = globals.fs.path.join(outDir, '$appName.dilpmanifest');
globals.fs.file(manifestPath).createSync(recursive: true);
final String manifestPath = fileSystem.path.join(outDir, '$appName.dilpmanifest');
fileSystem.file(manifestPath).createSync(recursive: true);
}
}

View file

@ -4,98 +4,77 @@
import 'package:args/command_runner.dart';
import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart';
import 'package:platform/platform.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/build.dart';
import 'package:flutter_tools/src/commands/build_linux.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/linux/makefile.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/mocks.dart';
import '../../src/testbed.dart';
void main() {
MockProcessManager mockProcessManager;
MockProcess mockProcess;
MockPlatform linuxPlatform;
MockPlatform notLinuxPlatform;
final Platform linuxPlatform = FakePlatform(
operatingSystem: 'linux',
environment: <String, String>{
'FLUTTER_ROOT': '/',
}
);
final Platform notLinuxPlatform = FakePlatform(
operatingSystem: 'macos',
environment: <String, String>{
'FLUTTER_ROOT': '/',
}
);
void main() {
setUpAll(() {
Cache.disableLocking();
});
FileSystem fileSystem;
ProcessManager processManager;
setUp(() {
mockProcessManager = MockProcessManager();
mockProcess = MockProcess();
linuxPlatform = MockPlatform();
notLinuxPlatform = MockPlatform();
when(mockProcess.exitCode).thenAnswer((Invocation invocation) async {
return 0;
});
when(mockProcess.stderr).thenAnswer((Invocation invocation) {
return const Stream<List<int>>.empty();
});
when(mockProcess.stdout).thenAnswer((Invocation invocation) {
return Stream<List<int>>.fromIterable(<List<int>>[utf8.encode('STDOUT STUFF')]);
});
when(linuxPlatform.isLinux).thenReturn(true);
when(linuxPlatform.isWindows).thenReturn(false);
when(notLinuxPlatform.isLinux).thenReturn(false);
when(notLinuxPlatform.isWindows).thenReturn(false);
fileSystem = MemoryFileSystem.test();
});
// Creates the mock files necessary to look like a Flutter project.
void setUpMockCoreProjectFiles() {
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
fileSystem.file('pubspec.yaml').createSync();
fileSystem.file('.packages').createSync();
fileSystem.file(fileSystem.path.join('lib', 'main.dart')).createSync(recursive: true);
}
// Creates the mock files necessary to run a build.
void setUpMockProjectFilesForBuild() {
globals.fs.file(globals.fs.path.join('linux', 'Makefile')).createSync(recursive: true);
fileSystem.file(fileSystem.path.join('linux', 'Makefile')).createSync(recursive: true);
setUpMockCoreProjectFiles();
}
// Sets up mock expectation for running 'make'.
void expectMakeInvocationWithMode(String buildModeName) {
when(mockProcessManager.start(<String>[
'make',
'-C',
'/linux',
'BUILD=$buildModeName',
])).thenAnswer((Invocation invocation) async {
return mockProcess;
});
}
testUsingContext('Linux build fails when there is no linux project', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
setUpMockCoreProjectFiles();
expect(createTestCommandRunner(command).run(
const <String>['build', 'linux']
), throwsToolExit(message: 'No Linux desktop project configured'));
}, overrides: <Type, Generator>{
Platform: () => linuxPlatform,
FileSystem: () => MemoryFileSystem(),
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
});
testUsingContext('Linux build fails on non-linux platform', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
setUpMockProjectFilesForBuild();
expect(createTestCommandRunner(command).run(
@ -103,54 +82,72 @@ void main() {
), throwsToolExit());
}, overrides: <Type, Generator>{
Platform: () => notLinuxPlatform,
FileSystem: () => MemoryFileSystem(),
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
});
testUsingContext('Linux build invokes make and writes temporary files', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
processManager = FakeProcessManager.list(<FakeCommand>[
FakeCommand(command: const <String>[
'make',
'-C',
'/linux',
'BUILD=release',
], onRun: () {
})
]);
setUpMockProjectFilesForBuild();
expectMakeInvocationWithMode('release');
await createTestCommandRunner(command).run(
const <String>['build', 'linux']
);
expect(globals.fs.file('linux/flutter/ephemeral/generated_config.mk').existsSync(), true);
expect(fileSystem.file('linux/flutter/ephemeral/generated_config.mk'), exists);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(),
ProcessManager: () => mockProcessManager,
FileSystem: () => fileSystem,
ProcessManager: () => processManager,
Platform: () => linuxPlatform,
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
});
testUsingContext('Handles argument error from missing make', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
setUpMockProjectFilesForBuild();
when(mockProcessManager.start(<String>[
'make',
'-C',
'/linux',
'BUILD=release',
])).thenThrow(ArgumentError());
processManager = FakeProcessManager.list(<FakeCommand>[
FakeCommand(command: const <String>[
'make',
'-C',
'/linux',
'BUILD=release',
], onRun: () {
throw ArgumentError();
}),
]);
expect(createTestCommandRunner(command).run(
const <String>['build', 'linux']
), throwsToolExit(message: "make not found. Run 'flutter doctor' for more information."));
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(),
ProcessManager: () => mockProcessManager,
FileSystem: () => fileSystem,
ProcessManager: () => processManager,
Platform: () => linuxPlatform,
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
});
testUsingContext('Linux build does not spew stdout to status logger', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
setUpMockProjectFilesForBuild();
expectMakeInvocationWithMode('debug');
processManager = FakeProcessManager.list(<FakeCommand>[
const FakeCommand(command: <String>[
'make',
'-C',
'/linux',
'BUILD=debug',
], stdout: 'STDOUT STUFF'),
]);
await createTestCommandRunner(command).run(
const <String>['build', 'linux', '--debug']
@ -158,59 +155,72 @@ void main() {
expect(testLogger.statusText, isNot(contains('STDOUT STUFF')));
expect(testLogger.traceText, contains('STDOUT STUFF'));
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(),
ProcessManager: () => mockProcessManager,
FileSystem: () => fileSystem,
ProcessManager: () => processManager,
Platform: () => linuxPlatform,
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
});
testUsingContext('Linux build --debug passes debug mode to make', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
setUpMockProjectFilesForBuild();
expectMakeInvocationWithMode('debug');
processManager = FakeProcessManager.list(<FakeCommand>[
const FakeCommand(command: <String>[
'make',
'-C',
'/linux',
'BUILD=debug',
]),
]);
await createTestCommandRunner(command).run(
const <String>['build', 'linux', '--debug']
);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(),
ProcessManager: () => mockProcessManager,
FileSystem: () => fileSystem,
ProcessManager: () => processManager,
Platform: () => linuxPlatform,
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
});
testUsingContext('Linux build --profile passes profile mode to make', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
setUpMockProjectFilesForBuild();
expectMakeInvocationWithMode('profile');
processManager = FakeProcessManager.list(<FakeCommand>[
const FakeCommand(command: <String>[
'make',
'-C',
'/linux',
'BUILD=profile',
]),
]);
await createTestCommandRunner(command).run(
const <String>['build', 'linux', '--profile']
);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(),
ProcessManager: () => mockProcessManager,
FileSystem: () => fileSystem,
ProcessManager: () => processManager,
Platform: () => linuxPlatform,
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
});
testUsingContext('linux can extract binary name from Makefile', () async {
globals.fs.file('linux/Makefile')
fileSystem.file('linux/Makefile')
..createSync(recursive: true)
..writeAsStringSync(r'''
# Comment
SOMETHING_ELSE=FOO
BINARY_NAME=fizz_bar
''');
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
fileSystem.file('pubspec.yaml').createSync();
fileSystem.file('.packages').createSync();
final FlutterProject flutterProject = FlutterProject.current();
expect(makefileExecutableName(flutterProject.linux), 'fizz_bar');
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(),
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
});
@ -219,53 +229,45 @@ BINARY_NAME=fizz_bar
final CommandRunner<void> runner = createTestCommandRunner(BuildCommand());
expect(() => runner.run(<String>['build', 'linux']),
throwsToolExit());
throwsToolExit());
}, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: false),
});
testUsingContext('Release build prints an under-construction warning', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
setUpMockProjectFilesForBuild();
expectMakeInvocationWithMode('release');
processManager = FakeProcessManager.list(<FakeCommand>[
const FakeCommand(command: <String>[
'make',
'-C',
'/linux',
'BUILD=release',
]),
]);
await createTestCommandRunner(command).run(
const <String>['build', 'linux']
);
expect(testLogger.statusText, contains('🚧'));
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(),
ProcessManager: () => mockProcessManager,
FileSystem: () => fileSystem,
ProcessManager: () => processManager,
Platform: () => linuxPlatform,
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
});
testUsingContext('hidden when not enabled on Linux host', () {
when(globals.platform.isLinux).thenReturn(true);
expect(BuildLinuxCommand().hidden, true);
}, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: false),
Platform: () => MockPlatform(),
Platform: () => notLinuxPlatform,
});
testUsingContext('Not hidden when enabled and on Linux host', () {
when(globals.platform.isLinux).thenReturn(true);
expect(BuildLinuxCommand().hidden, false);
}, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
Platform: () => MockPlatform(),
Platform: () => linuxPlatform,
});
}
class MockProcessManager extends Mock implements ProcessManager {}
class MockProcess extends Mock implements Process {}
class MockPlatform extends Mock implements Platform {
@override
Map<String, String> environment = <String, String>{
'FLUTTER_ROOT': '/',
};
}

View file

@ -5,24 +5,18 @@
import 'package:args/command_runner.dart';
import 'package:file/memory.dart';
import 'package:platform/platform.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/build.dart';
import 'package:flutter_tools/src/commands/build_macos.dart';
import 'package:flutter_tools/src/convert.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/mocks.dart';
import '../../src/testbed.dart';
class FakeXcodeProjectInterpreterWithProfile extends FakeXcodeProjectInterpreter {
@ -36,109 +30,104 @@ class FakeXcodeProjectInterpreterWithProfile extends FakeXcodeProjectInterpreter
}
}
final Platform macosPlatform = FakePlatform(
operatingSystem: 'macos',
environment: <String, String>{
'FLUTTER_ROOT': '/',
}
);
final Platform notMacosPlatform = FakePlatform(
operatingSystem: 'linux',
environment: <String, String>{
'FLUTTER_ROOT': '/',
}
);
void main() {
MockProcessManager mockProcessManager;
MockProcess mockProcess;
MockPlatform macosPlatform;
MockPlatform notMacosPlatform;
FileSystem fileSystem;
setUpAll(() {
Cache.disableLocking();
});
setUp(() {
mockProcessManager = MockProcessManager();
mockProcess = MockProcess();
macosPlatform = MockPlatform();
notMacosPlatform = MockPlatform();
when(mockProcess.exitCode).thenAnswer((Invocation invocation) async {
return 0;
});
when(mockProcess.stderr).thenAnswer((Invocation invocation) {
return const Stream<List<int>>.empty();
});
when(mockProcess.stdout).thenAnswer((Invocation invocation) {
return Stream<List<int>>.fromIterable(<List<int>>[utf8.encode('STDOUT STUFF')]);
});
when(macosPlatform.isMacOS).thenReturn(true);
when(macosPlatform.isWindows).thenReturn(false);
when(notMacosPlatform.isMacOS).thenReturn(false);
when(notMacosPlatform.isWindows).thenReturn(false);
fileSystem = MemoryFileSystem.test();
});
// Sets up the minimal mock project files necessary to look like a Flutter project.
void createCoreMockProjectFiles() {
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
fileSystem.file('pubspec.yaml').createSync();
fileSystem.file('.packages').createSync();
fileSystem.file(fileSystem.path.join('lib', 'main.dart')).createSync(recursive: true);
}
// Sets up the minimal mock project files necessary for macOS builds to succeed.
void createMinimalMockProjectFiles() {
globals.fs.directory(globals.fs.path.join('macos', 'Runner.xcworkspace')).createSync(recursive: true);
fileSystem.directory(fileSystem.path.join('macos', 'Runner.xcworkspace')).createSync(recursive: true);
createCoreMockProjectFiles();
}
// Mocks the process manager to handle an xcodebuild call to build the app
// Creates a FakeCommand for the xcodebuild call to build the app
// in the given configuration.
void setUpMockXcodeBuildHandler(String configuration) {
final FlutterProject flutterProject = FlutterProject.fromDirectory(globals.fs.currentDirectory);
final Directory flutterBuildDir = globals.fs.directory(getMacOSBuildDirectory());
when(mockProcessManager.start(<String>[
'/usr/bin/env',
'xcrun',
'xcodebuild',
'-workspace', flutterProject.macos.xcodeWorkspace.path,
'-configuration', configuration,
'-scheme', 'Runner',
'-derivedDataPath', flutterBuildDir.absolute.path,
'OBJROOT=${globals.fs.path.join(flutterBuildDir.absolute.path, 'Build', 'Intermediates.noindex')}',
'SYMROOT=${globals.fs.path.join(flutterBuildDir.absolute.path, 'Build', 'Products')}',
'COMPILER_INDEX_STORE_ENABLE=NO',
])).thenAnswer((Invocation invocation) async {
globals.fs.file(globals.fs.path.join('macos', 'Flutter', 'ephemeral', '.app_filename'))
..createSync(recursive: true)
..writeAsStringSync('example.app');
return mockProcess;
});
FakeCommand setUpMockXcodeBuildHandler(String configuration) {
final FlutterProject flutterProject = FlutterProject.fromDirectory(fileSystem.currentDirectory);
final Directory flutterBuildDir = fileSystem.directory(getMacOSBuildDirectory());
return FakeCommand(
command: <String>[
'/usr/bin/env',
'xcrun',
'xcodebuild',
'-workspace', flutterProject.macos.xcodeWorkspace.path,
'-configuration', configuration,
'-scheme', 'Runner',
'-derivedDataPath', flutterBuildDir.absolute.path,
'OBJROOT=${fileSystem.path.join(flutterBuildDir.absolute.path, 'Build', 'Intermediates.noindex')}',
'SYMROOT=${fileSystem.path.join(flutterBuildDir.absolute.path, 'Build', 'Products')}',
'COMPILER_INDEX_STORE_ENABLE=NO',
],
stdout: 'STDOUT STUFF',
onRun: () {
fileSystem.file(fileSystem.path.join('macos', 'Flutter', 'ephemeral', '.app_filename'))
..createSync(recursive: true)
..writeAsStringSync('example.app');
}
);
}
testUsingContext('macOS build fails when there is no macos project', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
createCoreMockProjectFiles();
expect(createTestCommandRunner(command).run(
const <String>['build', 'macos']
), throwsToolExit(message: 'No macOS desktop project configured'));
}, overrides: <Type, Generator>{
Platform: () => macosPlatform,
FileSystem: () => MemoryFileSystem(),
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
});
testUsingContext('macOS build fails on non-macOS platform', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
fileSystem.file('pubspec.yaml').createSync();
fileSystem.file('.packages').createSync();
fileSystem.file(fileSystem.path.join('lib', 'main.dart'))
.createSync(recursive: true);
expect(createTestCommandRunner(command).run(
const <String>['build', 'macos']
), throwsToolExit());
}, overrides: <Type, Generator>{
Platform: () => notMacosPlatform,
FileSystem: () => MemoryFileSystem(),
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(),
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
});
testUsingContext('macOS build does not spew stdout to status logger', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
createMinimalMockProjectFiles();
setUpMockXcodeBuildHandler('Debug');
await createTestCommandRunner(command).run(
const <String>['build', 'macos', '--debug']
@ -146,40 +135,42 @@ void main() {
expect(testLogger.statusText, isNot(contains('STDOUT STUFF')));
expect(testLogger.traceText, contains('STDOUT STUFF'));
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(),
ProcessManager: () => mockProcessManager,
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
setUpMockXcodeBuildHandler('Debug')
]),
Platform: () => macosPlatform,
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
});
testUsingContext('macOS build invokes xcode build (debug)', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
createMinimalMockProjectFiles();
setUpMockXcodeBuildHandler('Debug');
await createTestCommandRunner(command).run(
const <String>['build', 'macos', '--debug']
);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(),
ProcessManager: () => mockProcessManager,
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
setUpMockXcodeBuildHandler('Debug')
]),
Platform: () => macosPlatform,
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
});
testUsingContext('macOS build invokes xcode build (profile)', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
createMinimalMockProjectFiles();
setUpMockXcodeBuildHandler('Profile');
await createTestCommandRunner(command).run(
const <String>['build', 'macos', '--profile']
);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(),
ProcessManager: () => mockProcessManager,
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
setUpMockXcodeBuildHandler('Profile')
]),
Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithProfile(),
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
@ -187,16 +178,16 @@ void main() {
testUsingContext('macOS build invokes xcode build (release)', () async {
final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
createMinimalMockProjectFiles();
setUpMockXcodeBuildHandler('Release');
await createTestCommandRunner(command).run(
const <String>['build', 'macos', '--release']
);
}, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(),
ProcessManager: () => mockProcessManager,
FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
setUpMockXcodeBuildHandler('Release')
]),
Platform: () => macosPlatform,
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
});
@ -205,35 +196,22 @@ void main() {
final CommandRunner<void> runner = createTestCommandRunner(BuildCommand());
expect(() => runner.run(<String>['build', 'macos']),
throwsToolExit());
throwsToolExit());
}, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: false),
});
testUsingContext('hidden when not enabled on macOS host', () {
when(globals.platform.isMacOS).thenReturn(true);
expect(BuildMacosCommand().hidden, true);
}, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: false),
Platform: () => MockPlatform(),
Platform: () => macosPlatform,
});
testUsingContext('Not hidden when enabled and on macOS host', () {
when(globals.platform.isMacOS).thenReturn(true);
expect(BuildMacosCommand().hidden, false);
}, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
Platform: () => MockPlatform(),
Platform: () => macosPlatform,
});
}
class MockProcessManager extends Mock implements ProcessManager {}
class MockProcess extends Mock implements Process {}
class MockPlatform extends Mock implements Platform {
@override
Map<String, String> environment = <String, String>{
'FLUTTER_ROOT': '/',
};
}

View file

@ -3,6 +3,8 @@
// found in the LICENSE file.
import 'package:args/command_runner.dart';
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:platform/platform.dart';
import 'package:flutter_tools/src/build_info.dart';
@ -15,18 +17,22 @@ import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/build_runner/resident_web_runner.dart';
import 'package:flutter_tools/src/version.dart';
import 'package:flutter_tools/src/web/compile.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/mocks.dart';
import '../../src/testbed.dart';
void main() {
Testbed testbed;
MockPlatform mockPlatform;
FileSystem fileSystem;
final Platform fakePlatform = FakePlatform(
operatingSystem: 'linux',
environment: <String, String>{
'FLUTTER_ROOT': '/'
}
);
setUpAll(() {
Cache.flutterRoot = '';
@ -34,36 +40,36 @@ void main() {
});
setUp(() {
testbed = Testbed(setup: () {
globals.fs.file('pubspec.yaml')
..createSync()
..writeAsStringSync('name: foo\n');
globals.fs.file('.packages').createSync();
globals.fs.file(globals.fs.path.join('web', 'index.html')).createSync(recursive: true);
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true);
}, overrides: <Type, Generator>{
Platform: () => mockPlatform,
FlutterVersion: () => MockFlutterVersion(),
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
Pub: () => MockPub(),
});
fileSystem = MemoryFileSystem.test();
fileSystem.file('pubspec.yaml')
..createSync()
..writeAsStringSync('name: foo\n');
fileSystem.file('.packages').createSync();
fileSystem.file(fileSystem.path.join('web', 'index.html')).createSync(recursive: true);
fileSystem.file(fileSystem.path.join('lib', 'main.dart')).createSync(recursive: true);
});
test('Refuses to build for web when missing index.html', () => testbed.run(() async {
globals.fs.file(globals.fs.path.join('web', 'index.html')).deleteSync();
testUsingContext('Refuses to build for web when missing index.html', () async {
fileSystem.file(fileSystem.path.join('web', 'index.html')).deleteSync();
expect(buildWeb(
FlutterProject.current(),
globals.fs.path.join('lib', 'main.dart'),
fileSystem.path.join('lib', 'main.dart'),
BuildInfo.debug,
false,
const <String>[],
false,
), throwsToolExit());
}));
}, overrides: <Type, Generator>{
Platform: () => fakePlatform,
FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
Pub: () => MockPub(),
ProcessManager: () => FakeProcessManager.any(),
});
test('Refuses to build using runner when missing index.html', () => testbed.run(() async {
globals.fs.file(globals.fs.path.join('web', 'index.html')).deleteSync();
testUsingContext('Refuses to build using runner when missing index.html', () async {
fileSystem.file(fileSystem.path.join('web', 'index.html')).deleteSync();
final ResidentWebRunner runner = DwdsWebRunnerFactory().createWebRunner(
null,
@ -75,48 +81,64 @@ void main() {
urlTunneller: null,
) as ResidentWebRunner;
expect(await runner.run(), 1);
}));
}, overrides: <Type, Generator>{
Platform: () => fakePlatform,
FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
Pub: () => MockPub(),
ProcessManager: () => FakeProcessManager.any(),
});
test('Refuses to build a debug build for web', () => testbed.run(() async {
testUsingContext('Refuses to build a debug build for web', () async {
final CommandRunner<void> runner = createTestCommandRunner(BuildCommand());
expect(() => runner.run(<String>['build', 'web', '--debug']),
throwsA(isA<UsageException>()));
throwsA(isA<UsageException>()));
}, overrides: <Type, Generator>{
Platform: () => fakePlatform,
FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
}));
Pub: () => MockPub(),
ProcessManager: () => FakeProcessManager.any(),
});
test('Refuses to build for web when feature is disabled', () => testbed.run(() async {
testUsingContext('Refuses to build for web when feature is disabled', () async {
final CommandRunner<void> runner = createTestCommandRunner(BuildCommand());
expect(() => runner.run(<String>['build', 'web']),
throwsToolExit());
expect(
() => runner.run(<String>['build', 'web']),
throwsToolExit(),
);
}, overrides: <Type, Generator>{
Platform: () => fakePlatform,
FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: false),
}));
Pub: () => MockPub(),
ProcessManager: () => FakeProcessManager.any(),
});
test('Builds a web bundle - end to end', () => testbed.run(() async {
testUsingContext('Builds a web bundle - end to end', () async {
final BuildCommand buildCommand = BuildCommand();
applyMocksToCommand(buildCommand);
final CommandRunner<void> runner = createTestCommandRunner(buildCommand);
final List<String> dependencies = <String>[
globals.fs.path.join('packages', 'flutter_tools', 'lib', 'src', 'build_system', 'targets', 'web.dart'),
globals.fs.path.join('bin', 'cache', 'flutter_web_sdk'),
globals.fs.path.join('bin', 'cache', 'dart-sdk', 'bin', 'snapshots', 'dart2js.dart.snapshot'),
globals.fs.path.join('bin', 'cache', 'dart-sdk', 'bin', 'dart'),
globals.fs.path.join('bin', 'cache', 'dart-sdk '),
fileSystem.path.join('packages', 'flutter_tools', 'lib', 'src', 'build_system', 'targets', 'web.dart'),
fileSystem.path.join('bin', 'cache', 'flutter_web_sdk'),
fileSystem.path.join('bin', 'cache', 'dart-sdk', 'bin', 'snapshots', 'dart2js.dart.snapshot'),
fileSystem.path.join('bin', 'cache', 'dart-sdk', 'bin', 'dart'),
fileSystem.path.join('bin', 'cache', 'dart-sdk '),
];
for (final String dependency in dependencies) {
globals.fs.file(dependency).createSync(recursive: true);
fileSystem.file(dependency).createSync(recursive: true);
}
// Project files.
globals.fs.file('.packages')
fileSystem.file('.packages')
..writeAsStringSync('''
foo:lib/
fizz:bar/lib/
''');
globals.fs.file('pubspec.yaml')
fileSystem.file('pubspec.yaml')
..writeAsStringSync('''
name: foo
@ -127,7 +149,7 @@ dependencies:
path:
bar/
''');
globals.fs.file(globals.fs.path.join('bar', 'pubspec.yaml'))
fileSystem.file(fileSystem.path.join('bar', 'pubspec.yaml'))
..createSync(recursive: true)
..writeAsStringSync('''
name: bar
@ -139,12 +161,12 @@ flutter:
pluginClass: UrlLauncherPlugin
fileName: url_launcher_web.dart
''');
globals.fs.file(globals.fs.path.join('bar', 'lib', 'url_launcher_web.dart'))
fileSystem.file(fileSystem.path.join('bar', 'lib', 'url_launcher_web.dart'))
..createSync(recursive: true)
..writeAsStringSync('''
class UrlLauncherPlugin {}
''');
globals.fs.file(globals.fs.path.join('lib', 'main.dart'))
fileSystem.file(fileSystem.path.join('lib', 'main.dart'))
..writeAsStringSync('void main() { }');
// Process calls. We're not testing that these invocations are correct because
@ -154,35 +176,36 @@ class UrlLauncherPlugin {}
});
await runner.run(<String>['build', 'web']);
expect(globals.fs.file(globals.fs.path.join('lib', 'generated_plugin_registrant.dart')).existsSync(), true);
expect(fileSystem.file(fileSystem.path.join('lib', 'generated_plugin_registrant.dart')).existsSync(), true);
}, overrides: <Type, Generator>{
Platform: () => fakePlatform,
FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
Pub: () => MockPub(),
ProcessManager: () => FakeProcessManager.any(),
BuildSystem: () => MockBuildSystem(),
}));
});
test('hidden if feature flag is not enabled', () => testbed.run(() async {
testUsingContext('hidden if feature flag is not enabled', () async {
expect(BuildWebCommand().hidden, true);
}, overrides: <Type, Generator>{
Platform: () => fakePlatform,
FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: false),
}));
Pub: () => MockPub(),
ProcessManager: () => FakeProcessManager.any(),
});
test('not hidden if feature flag is enabled', () => testbed.run(() async {
testUsingContext('not hidden if feature flag is enabled', () async {
expect(BuildWebCommand().hidden, false);
}, overrides: <Type, Generator>{
Platform: () => fakePlatform,
FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
}));
Pub: () => MockPub(),
ProcessManager: () => FakeProcessManager.any(),
});
}
class MockBuildSystem extends Mock implements BuildSystem {}
class MockWebCompilationProxy extends Mock implements WebCompilationProxy {}
class MockPlatform extends Mock implements Platform {
@override
Map<String, String> environment = <String, String>{
'FLUTTER_ROOT': '/',
};
}
class MockFlutterVersion extends Mock implements FlutterVersion {
@override
bool get isMaster => true;
}
class MockPub extends Mock implements Pub {}

View file

@ -8,7 +8,6 @@ import 'dart:io' as io show ProcessSignal;
import 'package:flutter_tools/src/base/io.dart';
import 'package:meta/meta.dart';
import 'package:process/process.dart';
import 'common.dart';
export 'package:process/process.dart' show ProcessManager;