Unverified Commit 9295b348 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

cleanup of tool build tests (#50904)

parent 1793108b
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart';
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/file_system.dart';
...@@ -16,104 +17,106 @@ import 'package:flutter_tools/src/project.dart'; ...@@ -16,104 +17,106 @@ import 'package:flutter_tools/src/project.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart'; import '../../src/context.dart';
import '../../src/mocks.dart'; import '../../src/mocks.dart';
// Defined globally for mocks to use.
FileSystem fileSystem;
void main() { void main() {
Cache.disableLocking(); Cache.disableLocking();
MockPlatform linuxPlatform; final Platform linuxPlatform = FakePlatform(
MockPlatform windowsPlatform; operatingSystem: 'linux',
environment: const <String, String>{
'FLUTTER_ROOT': '/',
},
);
final Platform windowsPlatform = FakePlatform(
operatingSystem: 'windows',
environment: const <String, String>{
'FLUTTER_ROOT': '/'
},
);
MockFuchsiaSdk fuchsiaSdk; MockFuchsiaSdk fuchsiaSdk;
setUp(() { setUp(() {
linuxPlatform = MockPlatform();
windowsPlatform = MockPlatform();
fuchsiaSdk = MockFuchsiaSdk(); fuchsiaSdk = MockFuchsiaSdk();
fileSystem = MemoryFileSystem.test();
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);
}); });
group('Fuchsia build fails gracefully when', () { group('Fuchsia build fails gracefully when', () {
testUsingContext('there is no Fuchsia project', () async { testUsingContext('there is no Fuchsia project', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
expect( expect(
createTestCommandRunner(command) createTestCommandRunner(command).run(const <String>['build', 'fuchsia']),
.run(const <String>['build', 'fuchsia']), throwsToolExit(),
throwsToolExit()); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => linuxPlatform, Platform: () => linuxPlatform,
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
}); });
testUsingContext('there is no cmx file', () async { testUsingContext('there is no cmx file', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command); fileSystem.directory('fuchsia').createSync(recursive: true);
globals.fs.directory('fuchsia').createSync(recursive: true); fileSystem.file('.packages').createSync();
globals.fs.file('.packages').createSync(); fileSystem.file('pubspec.yaml').createSync();
globals.fs.file('pubspec.yaml').createSync();
expect( expect(
createTestCommandRunner(command) createTestCommandRunner(command).run(const <String>['build', 'fuchsia']),
.run(const <String>['build', 'fuchsia']), throwsToolExit(),
throwsToolExit()); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => linuxPlatform, Platform: () => linuxPlatform,
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
}); });
testUsingContext('on Windows platform', () async { testUsingContext('on Windows platform', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
const String appName = 'app_name'; const String appName = 'app_name';
globals.fs fileSystem
.file(globals.fs.path.join('fuchsia', 'meta', '$appName.cmx')) .file(fileSystem.path.join('fuchsia', 'meta', '$appName.cmx'))
..createSync(recursive: true) ..createSync(recursive: true)
..writeAsStringSync('{}'); ..writeAsStringSync('{}');
globals.fs.file('.packages').createSync(); fileSystem.file('.packages').createSync();
final File pubspecFile = globals.fs.file('pubspec.yaml')..createSync(); final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync();
pubspecFile.writeAsStringSync('name: $appName'); pubspecFile.writeAsStringSync('name: $appName');
expect( expect(
createTestCommandRunner(command) createTestCommandRunner(command).run(const <String>['build', 'fuchsia']),
.run(const <String>['build', 'fuchsia']), throwsToolExit(),
throwsToolExit()); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => windowsPlatform, Platform: () => windowsPlatform,
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
}); });
testUsingContext('there is no Fuchsia kernel compiler', () async { testUsingContext('there is no Fuchsia kernel compiler', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
const String appName = 'app_name'; const String appName = 'app_name';
globals.fs fileSystem
.file(globals.fs.path.join('fuchsia', 'meta', '$appName.cmx')) .file(fileSystem.path.join('fuchsia', 'meta', '$appName.cmx'))
..createSync(recursive: true) ..createSync(recursive: true)
..writeAsStringSync('{}'); ..writeAsStringSync('{}');
globals.fs.file('.packages').createSync(); fileSystem.file('.packages').createSync();
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true); fileSystem.file(fileSystem.path.join('lib', 'main.dart')).createSync(recursive: true);
final File pubspecFile = globals.fs.file('pubspec.yaml')..createSync(); final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync();
pubspecFile.writeAsStringSync('name: $appName'); pubspecFile.writeAsStringSync('name: $appName');
expect( expect(
createTestCommandRunner(command) createTestCommandRunner(command).run(const <String>['build', 'fuchsia']),
.run(const <String>['build', 'fuchsia']), throwsToolExit(),
throwsToolExit()); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => linuxPlatform, Platform: () => linuxPlatform,
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
}); });
}); });
...@@ -122,45 +125,40 @@ void main() { ...@@ -122,45 +125,40 @@ void main() {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command); applyMocksToCommand(command);
const String appName = 'app_name'; const String appName = 'app_name';
globals.fs fileSystem
.file(globals.fs.path.join('fuchsia', 'meta', '$appName.cmx')) .file(fileSystem.path.join('fuchsia', 'meta', '$appName.cmx'))
..createSync(recursive: true) ..createSync(recursive: true)
..writeAsStringSync('{}'); ..writeAsStringSync('{}');
globals.fs.file('.packages').createSync(); fileSystem.file('.packages').createSync();
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true); fileSystem.file(fileSystem.path.join('lib', 'main.dart')).createSync(recursive: true);
final File pubspecFile = globals.fs.file('pubspec.yaml')..createSync(); final File pubspecFile = fileSystem.file('pubspec.yaml')..createSync();
pubspecFile.writeAsStringSync('name: $appName'); pubspecFile.writeAsStringSync('name: $appName');
await createTestCommandRunner(command) await createTestCommandRunner(command)
.run(const <String>['build', 'fuchsia']); .run(const <String>['build', 'fuchsia']);
final String farPath = final String farPath = fileSystem.path.join(
globals.fs.path.join(getFuchsiaBuildDirectory(), 'pkg', 'app_name-0.far'); getFuchsiaBuildDirectory(), 'pkg', 'app_name-0.far',
expect(globals.fs.file(farPath).existsSync(), isTrue); );
expect(fileSystem.file(farPath), exists);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => linuxPlatform, Platform: () => linuxPlatform,
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
FuchsiaSdk: () => fuchsiaSdk, FuchsiaSdk: () => fuchsiaSdk,
}); });
} }
class MockPlatform extends Mock implements Platform {
@override
Map<String, String> environment = <String, String>{
'FLUTTER_ROOT': '/',
};
}
class MockFuchsiaPM extends Mock implements FuchsiaPM { class MockFuchsiaPM extends Mock implements FuchsiaPM {
String _appName; String _appName;
@override @override
Future<bool> init(String buildPath, String appName) async { Future<bool> init(String buildPath, String appName) async {
if (!globals.fs.directory(buildPath).existsSync()) { if (!fileSystem.directory(buildPath).existsSync()) {
return false; return false;
} }
globals.fs fileSystem
.file(globals.fs.path.join(buildPath, 'meta', 'package')) .file(fileSystem.path.join(buildPath, 'meta', 'package'))
.createSync(recursive: true); .createSync(recursive: true);
_appName = appName; _appName = appName;
return true; return true;
...@@ -168,36 +166,36 @@ class MockFuchsiaPM extends Mock implements FuchsiaPM { ...@@ -168,36 +166,36 @@ class MockFuchsiaPM extends Mock implements FuchsiaPM {
@override @override
Future<bool> genkey(String buildPath, String outKeyPath) async { 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; return false;
} }
globals.fs.file(outKeyPath).createSync(recursive: true); fileSystem.file(outKeyPath).createSync(recursive: true);
return true; return true;
} }
@override @override
Future<bool> build(String buildPath, String keyPath, String manifestPath) async { Future<bool> build(String buildPath, String keyPath, String manifestPath) async {
if (!globals.fs.file(globals.fs.path.join(buildPath, 'meta', 'package')).existsSync() || if (!fileSystem.file(fileSystem.path.join(buildPath, 'meta', 'package')).existsSync() ||
!globals.fs.file(keyPath).existsSync() || !fileSystem.file(keyPath).existsSync() ||
!globals.fs.file(manifestPath).existsSync()) { !fileSystem.file(manifestPath).existsSync()) {
return false; 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; return true;
} }
@override @override
Future<bool> archive(String buildPath, String keyPath, String manifestPath) async { Future<bool> archive(String buildPath, String keyPath, String manifestPath) async {
if (!globals.fs.file(globals.fs.path.join(buildPath, 'meta', 'package')).existsSync() || if (!fileSystem.file(fileSystem.path.join(buildPath, 'meta', 'package')).existsSync() ||
!globals.fs.file(keyPath).existsSync() || !fileSystem.file(keyPath).existsSync() ||
!globals.fs.file(manifestPath).existsSync()) { !fileSystem.file(manifestPath).existsSync()) {
return false; return false;
} }
if (_appName == null) { if (_appName == null) {
return false; return false;
} }
globals.fs fileSystem
.file(globals.fs.path.join(buildPath, '$_appName-0.far')) .file(fileSystem.path.join(buildPath, '$_appName-0.far'))
.createSync(recursive: true); .createSync(recursive: true);
return true; return true;
} }
...@@ -212,8 +210,8 @@ class MockFuchsiaKernelCompiler extends Mock implements FuchsiaKernelCompiler { ...@@ -212,8 +210,8 @@ class MockFuchsiaKernelCompiler extends Mock implements FuchsiaKernelCompiler {
}) async { }) async {
final String outDir = getFuchsiaBuildDirectory(); final String outDir = getFuchsiaBuildDirectory();
final String appName = fuchsiaProject.project.manifest.appName; final String appName = fuchsiaProject.project.manifest.appName;
final String manifestPath = globals.fs.path.join(outDir, '$appName.dilpmanifest'); final String manifestPath = fileSystem.path.join(outDir, '$appName.dilpmanifest');
globals.fs.file(manifestPath).createSync(recursive: true); fileSystem.file(manifestPath).createSync(recursive: true);
} }
} }
......
...@@ -4,98 +4,77 @@ ...@@ -4,98 +4,77 @@
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:file_testing/file_testing.dart';
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
import 'package:flutter_tools/src/base/file_system.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/cache.dart';
import 'package:flutter_tools/src/commands/build.dart'; import 'package:flutter_tools/src/commands/build.dart';
import 'package:flutter_tools/src/commands/build_linux.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/features.dart';
import 'package:flutter_tools/src/linux/makefile.dart'; import 'package:flutter_tools/src/linux/makefile.dart';
import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart'; import '../../src/context.dart';
import '../../src/mocks.dart';
import '../../src/testbed.dart'; import '../../src/testbed.dart';
void main() { final Platform linuxPlatform = FakePlatform(
MockProcessManager mockProcessManager; operatingSystem: 'linux',
MockProcess mockProcess; environment: <String, String>{
MockPlatform linuxPlatform; 'FLUTTER_ROOT': '/',
MockPlatform notLinuxPlatform; }
);
final Platform notLinuxPlatform = FakePlatform(
operatingSystem: 'macos',
environment: <String, String>{
'FLUTTER_ROOT': '/',
}
);
void main() {
setUpAll(() { setUpAll(() {
Cache.disableLocking(); Cache.disableLocking();
}); });
FileSystem fileSystem;
ProcessManager processManager;
setUp(() { setUp(() {
mockProcessManager = MockProcessManager(); fileSystem = MemoryFileSystem.test();
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);
}); });
// Creates the mock files necessary to look like a Flutter project. // Creates the mock files necessary to look like a Flutter project.
void setUpMockCoreProjectFiles() { void setUpMockCoreProjectFiles() {
globals.fs.file('pubspec.yaml').createSync(); fileSystem.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync(); fileSystem.file('.packages').createSync();
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true); fileSystem.file(fileSystem.path.join('lib', 'main.dart')).createSync(recursive: true);
} }
// Creates the mock files necessary to run a build. // Creates the mock files necessary to run a build.
void setUpMockProjectFilesForBuild() { 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(); 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 { testUsingContext('Linux build fails when there is no linux project', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
setUpMockCoreProjectFiles(); setUpMockCoreProjectFiles();
expect(createTestCommandRunner(command).run( expect(createTestCommandRunner(command).run(
const <String>['build', 'linux'] const <String>['build', 'linux']
), throwsToolExit(message: 'No Linux desktop project configured')); ), throwsToolExit(message: 'No Linux desktop project configured'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => linuxPlatform, Platform: () => linuxPlatform,
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true), FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
}); });
testUsingContext('Linux build fails on non-linux platform', () async { testUsingContext('Linux build fails on non-linux platform', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
expect(createTestCommandRunner(command).run( expect(createTestCommandRunner(command).run(
...@@ -103,54 +82,72 @@ void main() { ...@@ -103,54 +82,72 @@ void main() {
), throwsToolExit()); ), throwsToolExit());
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => notLinuxPlatform, Platform: () => notLinuxPlatform,
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true), FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
}); });
testUsingContext('Linux build invokes make and writes temporary files', () async { testUsingContext('Linux build invokes make and writes temporary files', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command); processManager = FakeProcessManager.list(<FakeCommand>[
FakeCommand(command: const <String>[
'make',
'-C',
'/linux',
'BUILD=release',
], onRun: () {
})
]);
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
expectMakeInvocationWithMode('release');
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
const <String>['build', 'linux'] 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>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => processManager,
Platform: () => linuxPlatform, Platform: () => linuxPlatform,
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true), FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
}); });
testUsingContext('Handles argument error from missing make', () async { testUsingContext('Handles argument error from missing make', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
when(mockProcessManager.start(<String>[ processManager = FakeProcessManager.list(<FakeCommand>[
'make', FakeCommand(command: const <String>[
'-C', 'make',
'/linux', '-C',
'BUILD=release', '/linux',
])).thenThrow(ArgumentError()); 'BUILD=release',
], onRun: () {
throw ArgumentError();
}),
]);
expect(createTestCommandRunner(command).run( expect(createTestCommandRunner(command).run(
const <String>['build', 'linux'] const <String>['build', 'linux']
), throwsToolExit(message: "make not found. Run 'flutter doctor' for more information.")); ), throwsToolExit(message: "make not found. Run 'flutter doctor' for more information."));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => processManager,
Platform: () => linuxPlatform, Platform: () => linuxPlatform,
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true), FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
}); });
testUsingContext('Linux build does not spew stdout to status logger', () async { testUsingContext('Linux build does not spew stdout to status logger', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
expectMakeInvocationWithMode('debug'); processManager = FakeProcessManager.list(<FakeCommand>[
const FakeCommand(command: <String>[
'make',
'-C',
'/linux',
'BUILD=debug',
], stdout: 'STDOUT STUFF'),
]);
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
const <String>['build', 'linux', '--debug'] const <String>['build', 'linux', '--debug']
...@@ -158,59 +155,72 @@ void main() { ...@@ -158,59 +155,72 @@ void main() {
expect(testLogger.statusText, isNot(contains('STDOUT STUFF'))); expect(testLogger.statusText, isNot(contains('STDOUT STUFF')));
expect(testLogger.traceText, contains('STDOUT STUFF')); expect(testLogger.traceText, contains('STDOUT STUFF'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => processManager,
Platform: () => linuxPlatform, Platform: () => linuxPlatform,
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true), FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
}); });
testUsingContext('Linux build --debug passes debug mode to make', () async { testUsingContext('Linux build --debug passes debug mode to make', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
expectMakeInvocationWithMode('debug'); processManager = FakeProcessManager.list(<FakeCommand>[
const FakeCommand(command: <String>[
'make',
'-C',
'/linux',
'BUILD=debug',
]),
]);
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
const <String>['build', 'linux', '--debug'] const <String>['build', 'linux', '--debug']
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => processManager,
Platform: () => linuxPlatform, Platform: () => linuxPlatform,
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true), FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
}); });
testUsingContext('Linux build --profile passes profile mode to make', () async { testUsingContext('Linux build --profile passes profile mode to make', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
expectMakeInvocationWithMode('profile'); processManager = FakeProcessManager.list(<FakeCommand>[
const FakeCommand(command: <String>[
'make',
'-C',
'/linux',
'BUILD=profile',
]),
]);
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
const <String>['build', 'linux', '--profile'] const <String>['build', 'linux', '--profile']
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => processManager,
Platform: () => linuxPlatform, Platform: () => linuxPlatform,
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true), FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
}); });
testUsingContext('linux can extract binary name from Makefile', () async { testUsingContext('linux can extract binary name from Makefile', () async {
globals.fs.file('linux/Makefile') fileSystem.file('linux/Makefile')
..createSync(recursive: true) ..createSync(recursive: true)
..writeAsStringSync(r''' ..writeAsStringSync(r'''
# Comment # Comment
SOMETHING_ELSE=FOO SOMETHING_ELSE=FOO
BINARY_NAME=fizz_bar BINARY_NAME=fizz_bar
'''); ''');
globals.fs.file('pubspec.yaml').createSync(); fileSystem.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync(); fileSystem.file('.packages').createSync();
final FlutterProject flutterProject = FlutterProject.current(); final FlutterProject flutterProject = FlutterProject.current();
expect(makefileExecutableName(flutterProject.linux), 'fizz_bar'); expect(makefileExecutableName(flutterProject.linux), 'fizz_bar');
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true), FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
}); });
...@@ -219,53 +229,45 @@ BINARY_NAME=fizz_bar ...@@ -219,53 +229,45 @@ BINARY_NAME=fizz_bar
final CommandRunner<void> runner = createTestCommandRunner(BuildCommand()); final CommandRunner<void> runner = createTestCommandRunner(BuildCommand());
expect(() => runner.run(<String>['build', 'linux']), expect(() => runner.run(<String>['build', 'linux']),
throwsToolExit()); throwsToolExit());
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: false), FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: false),
}); });
testUsingContext('Release build prints an under-construction warning', () async { testUsingContext('Release build prints an under-construction warning', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
setUpMockProjectFilesForBuild(); setUpMockProjectFilesForBuild();
expectMakeInvocationWithMode('release'); processManager = FakeProcessManager.list(<FakeCommand>[
const FakeCommand(command: <String>[
'make',
'-C',
'/linux',
'BUILD=release',
]),
]);
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
const <String>['build', 'linux'] const <String>['build', 'linux']
); );
expect(testLogger.statusText, contains('🚧')); expect(testLogger.statusText, contains('🚧'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => processManager,
Platform: () => linuxPlatform, Platform: () => linuxPlatform,
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true), FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true),
}); });
testUsingContext('hidden when not enabled on Linux host', () { testUsingContext('hidden when not enabled on Linux host', () {
when(globals.platform.isLinux).thenReturn(true);
expect(BuildLinuxCommand().hidden, true); expect(BuildLinuxCommand().hidden, true);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: false), FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: false),
Platform: () => MockPlatform(), Platform: () => notLinuxPlatform,
}); });
testUsingContext('Not hidden when enabled and on Linux host', () { testUsingContext('Not hidden when enabled and on Linux host', () {
when(globals.platform.isLinux).thenReturn(true);
expect(BuildLinuxCommand().hidden, false); expect(BuildLinuxCommand().hidden, false);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isLinuxEnabled: true), 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': '/',
};
}
...@@ -5,24 +5,18 @@ ...@@ -5,24 +5,18 @@
import 'package:args/command_runner.dart'; import 'package:args/command_runner.dart';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:platform/platform.dart'; import 'package:platform/platform.dart';
import 'package:flutter_tools/src/base/file_system.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/build_info.dart';
import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/commands/build.dart'; import 'package:flutter_tools/src/commands/build.dart';
import 'package:flutter_tools/src/commands/build_macos.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/features.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart'; import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/project.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart'; import '../../src/context.dart';
import '../../src/mocks.dart';
import '../../src/testbed.dart'; import '../../src/testbed.dart';
class FakeXcodeProjectInterpreterWithProfile extends FakeXcodeProjectInterpreter { class FakeXcodeProjectInterpreterWithProfile extends FakeXcodeProjectInterpreter {
...@@ -36,109 +30,104 @@ 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() { void main() {
MockProcessManager mockProcessManager; FileSystem fileSystem;
MockProcess mockProcess;
MockPlatform macosPlatform;
MockPlatform notMacosPlatform;
setUpAll(() { setUpAll(() {
Cache.disableLocking(); Cache.disableLocking();
}); });
setUp(() { setUp(() {
mockProcessManager = MockProcessManager(); fileSystem = MemoryFileSystem.test();
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);
}); });
// Sets up the minimal mock project files necessary to look like a Flutter project. // Sets up the minimal mock project files necessary to look like a Flutter project.
void createCoreMockProjectFiles() { void createCoreMockProjectFiles() {
globals.fs.file('pubspec.yaml').createSync(); fileSystem.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync(); fileSystem.file('.packages').createSync();
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true); fileSystem.file(fileSystem.path.join('lib', 'main.dart')).createSync(recursive: true);
} }
// Sets up the minimal mock project files necessary for macOS builds to succeed. // Sets up the minimal mock project files necessary for macOS builds to succeed.
void createMinimalMockProjectFiles() { 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(); 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. // in the given configuration.
void setUpMockXcodeBuildHandler(String configuration) { FakeCommand setUpMockXcodeBuildHandler(String configuration) {
final FlutterProject flutterProject = FlutterProject.fromDirectory(globals.fs.currentDirectory); final FlutterProject flutterProject = FlutterProject.fromDirectory(fileSystem.currentDirectory);
final Directory flutterBuildDir = globals.fs.directory(getMacOSBuildDirectory()); final Directory flutterBuildDir = fileSystem.directory(getMacOSBuildDirectory());
when(mockProcessManager.start(<String>[ return FakeCommand(
'/usr/bin/env', command: <String>[
'xcrun', '/usr/bin/env',
'xcodebuild', 'xcrun',
'-workspace', flutterProject.macos.xcodeWorkspace.path, 'xcodebuild',
'-configuration', configuration, '-workspace', flutterProject.macos.xcodeWorkspace.path,
'-scheme', 'Runner', '-configuration', configuration,
'-derivedDataPath', flutterBuildDir.absolute.path, '-scheme', 'Runner',
'OBJROOT=${globals.fs.path.join(flutterBuildDir.absolute.path, 'Build', 'Intermediates.noindex')}', '-derivedDataPath', flutterBuildDir.absolute.path,
'SYMROOT=${globals.fs.path.join(flutterBuildDir.absolute.path, 'Build', 'Products')}', 'OBJROOT=${fileSystem.path.join(flutterBuildDir.absolute.path, 'Build', 'Intermediates.noindex')}',
'COMPILER_INDEX_STORE_ENABLE=NO', 'SYMROOT=${fileSystem.path.join(flutterBuildDir.absolute.path, 'Build', 'Products')}',
])).thenAnswer((Invocation invocation) async { 'COMPILER_INDEX_STORE_ENABLE=NO',
globals.fs.file(globals.fs.path.join('macos', 'Flutter', 'ephemeral', '.app_filename')) ],
..createSync(recursive: true) stdout: 'STDOUT STUFF',
..writeAsStringSync('example.app'); onRun: () {
return mockProcess; 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 { testUsingContext('macOS build fails when there is no macos project', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
createCoreMockProjectFiles(); createCoreMockProjectFiles();
expect(createTestCommandRunner(command).run( expect(createTestCommandRunner(command).run(
const <String>['build', 'macos'] const <String>['build', 'macos']
), throwsToolExit(message: 'No macOS desktop project configured')); ), throwsToolExit(message: 'No macOS desktop project configured'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => macosPlatform, Platform: () => macosPlatform,
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true), FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
}); });
testUsingContext('macOS build fails on non-macOS platform', () async { testUsingContext('macOS build fails on non-macOS platform', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command); fileSystem.file('pubspec.yaml').createSync();
globals.fs.file('pubspec.yaml').createSync(); fileSystem.file('.packages').createSync();
globals.fs.file('.packages').createSync(); fileSystem.file(fileSystem.path.join('lib', 'main.dart'))
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true); .createSync(recursive: true);
expect(createTestCommandRunner(command).run( expect(createTestCommandRunner(command).run(
const <String>['build', 'macos'] const <String>['build', 'macos']
), throwsToolExit()); ), throwsToolExit());
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => notMacosPlatform, Platform: () => notMacosPlatform,
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => FakeProcessManager.any(), ProcessManager: () => FakeProcessManager.any(),
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true), FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
}); });
testUsingContext('macOS build does not spew stdout to status logger', () async { testUsingContext('macOS build does not spew stdout to status logger', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
setUpMockXcodeBuildHandler('Debug');
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
const <String>['build', 'macos', '--debug'] const <String>['build', 'macos', '--debug']
...@@ -146,40 +135,42 @@ void main() { ...@@ -146,40 +135,42 @@ void main() {
expect(testLogger.statusText, isNot(contains('STDOUT STUFF'))); expect(testLogger.statusText, isNot(contains('STDOUT STUFF')));
expect(testLogger.traceText, contains('STDOUT STUFF')); expect(testLogger.traceText, contains('STDOUT STUFF'));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
setUpMockXcodeBuildHandler('Debug')
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true), FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
}); });
testUsingContext('macOS build invokes xcode build (debug)', () async { testUsingContext('macOS build invokes xcode build (debug)', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
setUpMockXcodeBuildHandler('Debug');
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
const <String>['build', 'macos', '--debug'] const <String>['build', 'macos', '--debug']
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
setUpMockXcodeBuildHandler('Debug')
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true), FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
}); });
testUsingContext('macOS build invokes xcode build (profile)', () async { testUsingContext('macOS build invokes xcode build (profile)', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
setUpMockXcodeBuildHandler('Profile');
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
const <String>['build', 'macos', '--profile'] const <String>['build', 'macos', '--profile']
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
setUpMockXcodeBuildHandler('Profile')
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithProfile(), XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithProfile(),
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true), FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
...@@ -187,16 +178,16 @@ void main() { ...@@ -187,16 +178,16 @@ void main() {
testUsingContext('macOS build invokes xcode build (release)', () async { testUsingContext('macOS build invokes xcode build (release)', () async {
final BuildCommand command = BuildCommand(); final BuildCommand command = BuildCommand();
applyMocksToCommand(command);
createMinimalMockProjectFiles(); createMinimalMockProjectFiles();
setUpMockXcodeBuildHandler('Release');
await createTestCommandRunner(command).run( await createTestCommandRunner(command).run(
const <String>['build', 'macos', '--release'] const <String>['build', 'macos', '--release']
); );
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FileSystem: () => MemoryFileSystem(), FileSystem: () => fileSystem,
ProcessManager: () => mockProcessManager, ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
setUpMockXcodeBuildHandler('Release')
]),
Platform: () => macosPlatform, Platform: () => macosPlatform,
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true), FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
}); });
...@@ -205,35 +196,22 @@ void main() { ...@@ -205,35 +196,22 @@ void main() {
final CommandRunner<void> runner = createTestCommandRunner(BuildCommand()); final CommandRunner<void> runner = createTestCommandRunner(BuildCommand());
expect(() => runner.run(<String>['build', 'macos']), expect(() => runner.run(<String>['build', 'macos']),
throwsToolExit()); throwsToolExit());
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: false), FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: false),
}); });
testUsingContext('hidden when not enabled on macOS host', () { testUsingContext('hidden when not enabled on macOS host', () {
when(globals.platform.isMacOS).thenReturn(true);
expect(BuildMacosCommand().hidden, true); expect(BuildMacosCommand().hidden, true);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: false), FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: false),
Platform: () => MockPlatform(), Platform: () => macosPlatform,
}); });
testUsingContext('Not hidden when enabled and on macOS host', () { testUsingContext('Not hidden when enabled and on macOS host', () {
when(globals.platform.isMacOS).thenReturn(true);
expect(BuildMacosCommand().hidden, false); expect(BuildMacosCommand().hidden, false);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true), 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': '/',
};
}
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:args/command_runner.dart'; 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:platform/platform.dart';
import 'package:flutter_tools/src/build_info.dart'; import 'package:flutter_tools/src/build_info.dart';
...@@ -15,18 +17,22 @@ import 'package:flutter_tools/src/device.dart'; ...@@ -15,18 +17,22 @@ import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/build_runner/resident_web_runner.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:flutter_tools/src/web/compile.dart';
import 'package:mockito/mockito.dart'; import 'package:mockito/mockito.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import '../../src/common.dart'; import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/mocks.dart'; import '../../src/mocks.dart';
import '../../src/testbed.dart'; import '../../src/testbed.dart';
void main() { void main() {
Testbed testbed; FileSystem fileSystem;
MockPlatform mockPlatform; final Platform fakePlatform = FakePlatform(
operatingSystem: 'linux',
environment: <String, String>{
'FLUTTER_ROOT': '/'
}
);
setUpAll(() { setUpAll(() {
Cache.flutterRoot = ''; Cache.flutterRoot = '';
...@@ -34,36 +40,36 @@ void main() { ...@@ -34,36 +40,36 @@ void main() {
}); });
setUp(() { setUp(() {
testbed = Testbed(setup: () { fileSystem = MemoryFileSystem.test();
globals.fs.file('pubspec.yaml') fileSystem.file('pubspec.yaml')
..createSync() ..createSync()
..writeAsStringSync('name: foo\n'); ..writeAsStringSync('name: foo\n');
globals.fs.file('.packages').createSync(); fileSystem.file('.packages').createSync();
globals.fs.file(globals.fs.path.join('web', 'index.html')).createSync(recursive: true); fileSystem.file(fileSystem.path.join('web', 'index.html')).createSync(recursive: true);
globals.fs.file(globals.fs.path.join('lib', 'main.dart')).createSync(recursive: true); fileSystem.file(fileSystem.path.join('lib', 'main.dart')).createSync(recursive: true);
}, overrides: <Type, Generator>{
Platform: () => mockPlatform,
FlutterVersion: () => MockFlutterVersion(),
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
Pub: () => MockPub(),
});
}); });
test('Refuses to build for web when missing index.html', () => testbed.run(() async { testUsingContext('Refuses to build for web when missing index.html', () async {
globals.fs.file(globals.fs.path.join('web', 'index.html')).deleteSync(); fileSystem.file(fileSystem.path.join('web', 'index.html')).deleteSync();
expect(buildWeb( expect(buildWeb(
FlutterProject.current(), FlutterProject.current(),
globals.fs.path.join('lib', 'main.dart'), fileSystem.path.join('lib', 'main.dart'),
BuildInfo.debug, BuildInfo.debug,
false, false,
const <String>[], const <String>[],
false, false,
), throwsToolExit()); ), 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 { testUsingContext('Refuses to build using runner when missing index.html', () async {
globals.fs.file(globals.fs.path.join('web', 'index.html')).deleteSync(); fileSystem.file(fileSystem.path.join('web', 'index.html')).deleteSync();
final ResidentWebRunner runner = DwdsWebRunnerFactory().createWebRunner( final ResidentWebRunner runner = DwdsWebRunnerFactory().createWebRunner(
null, null,
...@@ -75,48 +81,64 @@ void main() { ...@@ -75,48 +81,64 @@ void main() {
urlTunneller: null, urlTunneller: null,
) as ResidentWebRunner; ) as ResidentWebRunner;
expect(await runner.run(), 1); 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()); final CommandRunner<void> runner = createTestCommandRunner(BuildCommand());
expect(() => runner.run(<String>['build', 'web', '--debug']), expect(() => runner.run(<String>['build', 'web', '--debug']),
throwsA(isA<UsageException>())); throwsA(isA<UsageException>()));
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => fakePlatform,
FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), 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()); final CommandRunner<void> runner = createTestCommandRunner(BuildCommand());
expect(() => runner.run(<String>['build', 'web']), expect(
throwsToolExit()); () => runner.run(<String>['build', 'web']),
throwsToolExit(),
);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => fakePlatform,
FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: false), 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(); final BuildCommand buildCommand = BuildCommand();
applyMocksToCommand(buildCommand); applyMocksToCommand(buildCommand);
final CommandRunner<void> runner = createTestCommandRunner(buildCommand); final CommandRunner<void> runner = createTestCommandRunner(buildCommand);
final List<String> dependencies = <String>[ final List<String> dependencies = <String>[
globals.fs.path.join('packages', 'flutter_tools', 'lib', 'src', 'build_system', 'targets', 'web.dart'), fileSystem.path.join('packages', 'flutter_tools', 'lib', 'src', 'build_system', 'targets', 'web.dart'),
globals.fs.path.join('bin', 'cache', 'flutter_web_sdk'), fileSystem.path.join('bin', 'cache', 'flutter_web_sdk'),
globals.fs.path.join('bin', 'cache', 'dart-sdk', 'bin', 'snapshots', 'dart2js.dart.snapshot'), fileSystem.path.join('bin', 'cache', 'dart-sdk', 'bin', 'snapshots', 'dart2js.dart.snapshot'),
globals.fs.path.join('bin', 'cache', 'dart-sdk', 'bin', 'dart'), fileSystem.path.join('bin', 'cache', 'dart-sdk', 'bin', 'dart'),
globals.fs.path.join('bin', 'cache', 'dart-sdk '), fileSystem.path.join('bin', 'cache', 'dart-sdk '),
]; ];
for (final String dependency in dependencies) { for (final String dependency in dependencies) {
globals.fs.file(dependency).createSync(recursive: true); fileSystem.file(dependency).createSync(recursive: true);
} }
// Project files. // Project files.
globals.fs.file('.packages') fileSystem.file('.packages')
..writeAsStringSync(''' ..writeAsStringSync('''
foo:lib/ foo:lib/
fizz:bar/lib/ fizz:bar/lib/
'''); ''');
globals.fs.file('pubspec.yaml') fileSystem.file('pubspec.yaml')
..writeAsStringSync(''' ..writeAsStringSync('''
name: foo name: foo
...@@ -127,7 +149,7 @@ dependencies: ...@@ -127,7 +149,7 @@ dependencies:
path: path:
bar/ bar/
'''); ''');
globals.fs.file(globals.fs.path.join('bar', 'pubspec.yaml')) fileSystem.file(fileSystem.path.join('bar', 'pubspec.yaml'))
..createSync(recursive: true) ..createSync(recursive: true)
..writeAsStringSync(''' ..writeAsStringSync('''
name: bar name: bar
...@@ -139,12 +161,12 @@ flutter: ...@@ -139,12 +161,12 @@ flutter:
pluginClass: UrlLauncherPlugin pluginClass: UrlLauncherPlugin
fileName: url_launcher_web.dart 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) ..createSync(recursive: true)
..writeAsStringSync(''' ..writeAsStringSync('''
class UrlLauncherPlugin {} class UrlLauncherPlugin {}
'''); ''');
globals.fs.file(globals.fs.path.join('lib', 'main.dart')) fileSystem.file(fileSystem.path.join('lib', 'main.dart'))
..writeAsStringSync('void main() { }'); ..writeAsStringSync('void main() { }');
// Process calls. We're not testing that these invocations are correct because // Process calls. We're not testing that these invocations are correct because
...@@ -154,35 +176,36 @@ class UrlLauncherPlugin {} ...@@ -154,35 +176,36 @@ class UrlLauncherPlugin {}
}); });
await runner.run(<String>['build', 'web']); 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>{ }, overrides: <Type, Generator>{
Platform: () => fakePlatform,
FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
Pub: () => MockPub(),
ProcessManager: () => FakeProcessManager.any(),
BuildSystem: () => MockBuildSystem(), 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); expect(BuildWebCommand().hidden, true);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => fakePlatform,
FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: false), 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); expect(BuildWebCommand().hidden, false);
}, overrides: <Type, Generator>{ }, overrides: <Type, Generator>{
Platform: () => fakePlatform,
FileSystem: () => fileSystem,
FeatureFlags: () => TestFeatureFlags(isWebEnabled: true), FeatureFlags: () => TestFeatureFlags(isWebEnabled: true),
})); Pub: () => MockPub(),
ProcessManager: () => FakeProcessManager.any(),
});
} }
class MockBuildSystem extends Mock implements BuildSystem {} 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 {} class MockPub extends Mock implements Pub {}
...@@ -8,7 +8,6 @@ import 'dart:io' as io show ProcessSignal; ...@@ -8,7 +8,6 @@ import 'dart:io' as io show ProcessSignal;
import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/io.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
import 'package:process/process.dart'; import 'package:process/process.dart';
import 'common.dart'; import 'common.dart';
export 'package:process/process.dart' show ProcessManager; export 'package:process/process.dart' show ProcessManager;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment