Move plugin injection to just after pub get (#14743)
diff --git a/packages/flutter_tools/test/commands/packages_test.dart b/packages/flutter_tools/test/commands/packages_test.dart
index 86bbc28..34f6fb8 100644
--- a/packages/flutter_tools/test/commands/packages_test.dart
+++ b/packages/flutter_tools/test/commands/packages_test.dart
@@ -29,9 +29,19 @@
temp.deleteSync(recursive: true);
});
- Future<String> runCommand(String verb, { List<String> args }) async {
+ Future<String> createProjectWithPlugin(String plugin) async {
final String projectPath = await createProject(temp);
+ final File pubspec = fs.file(fs.path.join(projectPath, 'pubspec.yaml'));
+ String content = await pubspec.readAsString();
+ content = content.replaceFirst(
+ '\ndependencies:\n',
+ '\ndependencies:\n $plugin:\n',
+ );
+ await pubspec.writeAsString(content, flush: true);
+ return projectPath;
+ }
+ Future<Null> runCommandIn(String projectPath, String verb, { List<String> args }) async {
final PackagesCommand command = new PackagesCommand();
final CommandRunner<Null> runner = createTestCommandRunner(command);
@@ -41,31 +51,148 @@
commandArgs.add(projectPath);
await runner.run(commandArgs);
-
- return projectPath;
}
void expectExists(String projectPath, String relPath) {
- expect(fs.isFileSync(fs.path.join(projectPath, relPath)), true);
+ expect(
+ fs.isFileSync(fs.path.join(projectPath, relPath)),
+ true,
+ reason: '$projectPath/$relPath should exist, but does not',
+ );
}
- // Verify that we create a project that is well-formed.
- testUsingContext('get', () async {
- final String projectPath = await runCommand('get');
- expectExists(projectPath, 'lib/main.dart');
- expectExists(projectPath, '.packages');
+ void expectContains(String projectPath, String relPath, String substring) {
+ expectExists(projectPath, relPath);
+ expect(
+ fs.file(fs.path.join(projectPath, relPath)).readAsStringSync(),
+ contains(substring),
+ reason: '$projectPath/$relPath has unexpected content'
+ );
+ }
+
+ void expectNotExists(String projectPath, String relPath) {
+ expect(
+ fs.isFileSync(fs.path.join(projectPath, relPath)),
+ false,
+ reason: '$projectPath/$relPath should not exist, but does',
+ );
+ }
+
+ void expectNotContains(String projectPath, String relPath, String substring) {
+ expectExists(projectPath, relPath);
+ expect(
+ fs.file(fs.path.join(projectPath, relPath)).readAsStringSync(),
+ isNot(contains(substring)),
+ reason: '$projectPath/$relPath has unexpected content',
+ );
+ }
+
+ const List<String> pubOutput = const <String>[
+ '.packages',
+ 'pubspec.lock',
+ ];
+
+ const List<String> pluginRegistrants = const <String>[
+ 'ios/Runner/GeneratedPluginRegistrant.h',
+ 'ios/Runner/GeneratedPluginRegistrant.m',
+ 'android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java',
+ ];
+
+ const List<String> pluginWitnesses = const <String>[
+ '.flutter-plugins',
+ 'ios/Podfile',
+ ];
+
+ const Map<String, String> pluginContentWitnesses = const <String, String>{
+ 'ios/Flutter/Debug.xcconfig': '#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"',
+ 'ios/Flutter/Release.xcconfig': '#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"',
+ };
+
+ void expectDependenciesResolved(String projectPath) {
+ for (String output in pubOutput) {
+ expectExists(projectPath, output);
+ }
+ }
+
+ void expectZeroPluginsInjected(String projectPath) {
+ for (final String registrant in pluginRegistrants) {
+ expectExists(projectPath, registrant);
+ }
+ for (final String witness in pluginWitnesses) {
+ expectNotExists(projectPath, witness);
+ }
+ pluginContentWitnesses.forEach((String witness, String content) {
+ expectNotContains(projectPath, witness, content);
+ });
+ }
+
+ void expectPluginInjected(String projectPath) {
+ for (final String registrant in pluginRegistrants) {
+ expectExists(projectPath, registrant);
+ }
+ for (final String witness in pluginWitnesses) {
+ expectExists(projectPath, witness);
+ }
+ pluginContentWitnesses.forEach((String witness, String content) {
+ expectContains(projectPath, witness, content);
+ });
+ }
+
+ void removeGeneratedFiles(String projectPath) {
+ final Iterable<String> allFiles = <List<String>>[
+ pubOutput,
+ pluginRegistrants,
+ pluginWitnesses,
+ ].expand((List<String> list) => list);
+ for (String path in allFiles) {
+ final File file = fs.file(fs.path.join(projectPath, path));
+ if (file.existsSync())
+ file.deleteSync();
+ }
+ }
+
+ testUsingContext('get fetches packages', () async {
+ final String projectPath = await createProject(temp);
+
+ removeGeneratedFiles(projectPath);
+
+ await runCommandIn(projectPath, 'get');
+
+ expectDependenciesResolved(projectPath);
+ expectZeroPluginsInjected(projectPath);
}, timeout: allowForRemotePubInvocation);
- testUsingContext('get --offline', () async {
- final String projectPath = await runCommand('get', args: <String>['--offline']);
- expectExists(projectPath, 'lib/main.dart');
- expectExists(projectPath, '.packages');
- });
+ testUsingContext('get --offline fetches packages', () async {
+ final String projectPath = await createProject(temp);
- testUsingContext('upgrade', () async {
- final String projectPath = await runCommand('upgrade');
- expectExists(projectPath, 'lib/main.dart');
- expectExists(projectPath, '.packages');
+ removeGeneratedFiles(projectPath);
+
+ await runCommandIn(projectPath, 'get', args: <String>['--offline']);
+
+ expectDependenciesResolved(projectPath);
+ expectZeroPluginsInjected(projectPath);
+ }, timeout: allowForCreateFlutterProject);
+
+ testUsingContext('upgrade fetches packages', () async {
+ final String projectPath = await createProject(temp);
+
+ removeGeneratedFiles(projectPath);
+
+ await runCommandIn(projectPath, 'upgrade');
+
+ expectDependenciesResolved(projectPath);
+ expectZeroPluginsInjected(projectPath);
+ }, timeout: allowForRemotePubInvocation);
+
+ testUsingContext('get fetches packages and injects plugin', () async {
+ final String projectPath = await createProjectWithPlugin('path_provider');
+
+ removeGeneratedFiles(projectPath);
+
+ await runCommandIn(projectPath, 'get');
+
+ expectDependenciesResolved(projectPath);
+ expectPluginInjected(projectPath);
}, timeout: allowForRemotePubInvocation);
});
diff --git a/packages/flutter_tools/test/ios/cocoapods_test.dart b/packages/flutter_tools/test/ios/cocoapods_test.dart
index 531c8ab..77c1e6d 100644
--- a/packages/flutter_tools/test/ios/cocoapods_test.dart
+++ b/packages/flutter_tools/test/ios/cocoapods_test.dart
@@ -6,9 +6,11 @@
import 'package:file/file.dart';
import 'package:file/memory.dart';
+import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/io.dart';
-import 'package:flutter_tools/src/ios/cocoapods.dart';
import 'package:flutter_tools/src/cache.dart';
+import 'package:flutter_tools/src/ios/cocoapods.dart';
+import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:mockito/mockito.dart';
import 'package:process/process.dart';
import 'package:test/test.dart';
@@ -18,6 +20,7 @@
void main() {
FileSystem fs;
ProcessManager mockProcessManager;
+ MockXcodeProjectInterpreter mockXcodeProjectInterpreter;
Directory projectUnderTest;
CocoaPods cocoaPodsUnderTest;
@@ -25,7 +28,9 @@
Cache.flutterRoot = 'flutter';
fs = new MemoryFileSystem();
mockProcessManager = new MockProcessManager();
+ mockXcodeProjectInterpreter = new MockXcodeProjectInterpreter();
projectUnderTest = fs.directory(fs.path.join('project', 'ios'))..createSync(recursive: true);
+
fs.file(fs.path.join(
Cache.flutterRoot, 'packages', 'flutter_tools', 'templates', 'cocoapods', 'Podfile-objc'
))
@@ -45,97 +50,122 @@
)).thenReturn(exitsHappy);
});
- testUsingContext(
- 'create objective-c Podfile when not present',
- () async {
- await cocoaPodsUnderTest.processPods(
- appIosDir: projectUnderTest,
- iosEngineDir: 'engine/path',
- );
- expect(fs.file(fs.path.join('project', 'ios', 'Podfile')).readAsStringSync() , 'Objective-C podfile template');
- verify(mockProcessManager.run(
- <String>['pod', 'install', '--verbose'],
- workingDirectory: 'project/ios',
- environment: <String, String>{'FLUTTER_FRAMEWORK_DIR': 'engine/path', 'COCOAPODS_DISABLE_STATS': 'true'},
- ));
- },
- overrides: <Type, Generator>{
- FileSystem: () => fs,
- ProcessManager: () => mockProcessManager,
- },
- );
+ group('Setup Podfile', () {
+ File podfile;
+ File debugConfigFile;
+ File releaseConfigFile;
- testUsingContext(
- 'create swift Podfile if swift',
- () async {
- await cocoaPodsUnderTest.processPods(
- appIosDir: projectUnderTest,
- iosEngineDir: 'engine/path',
- isSwift: true,
- );
- expect(fs.file(fs.path.join('project', 'ios', 'Podfile')).readAsStringSync() , 'Swift podfile template');
- verify(mockProcessManager.run(
- <String>['pod', 'install', '--verbose'],
- workingDirectory: 'project/ios',
- environment: <String, String>{'FLUTTER_FRAMEWORK_DIR': 'engine/path', 'COCOAPODS_DISABLE_STATS': 'true'},
- ));
- },
- overrides: <Type, Generator>{
- FileSystem: () => fs,
- ProcessManager: () => mockProcessManager,
- },
- );
+ setUp(() {
+ debugConfigFile = fs.file(fs.path.join('project', 'ios', 'Flutter', 'Debug.xcconfig'));
+ releaseConfigFile = fs.file(fs.path.join('project', 'ios', 'Flutter', 'Release.xcconfig'));
+ podfile = fs.file(fs.path.join('project', 'ios', 'Podfile'));
+ });
- testUsingContext(
- 'do not recreate Podfile when present',
- () async {
- fs.file(fs.path.join('project', 'ios', 'Podfile'))
- ..createSync()
- ..writeAsString('Existing Podfile');
- await cocoaPodsUnderTest.processPods(
- appIosDir: projectUnderTest,
- iosEngineDir: 'engine/path',
- );
- expect(fs.file(fs.path.join('project', 'ios', 'Podfile')).readAsStringSync() , 'Existing Podfile');
- verify(mockProcessManager.run(
- <String>['pod', 'install', '--verbose'],
- workingDirectory: 'project/ios',
- environment: <String, String>{'FLUTTER_FRAMEWORK_DIR': 'engine/path', 'COCOAPODS_DISABLE_STATS': 'true'},
- ));
- },
- overrides: <Type, Generator>{
- FileSystem: () => fs,
- ProcessManager: () => mockProcessManager,
- },
- );
+ testUsingContext('creates objective-c Podfile when not present', () {
+ cocoaPodsUnderTest.setupPodfile('project');
- testUsingContext(
- 'missing CocoaPods throws',
- () async {
+ expect(podfile.readAsStringSync(), 'Objective-C podfile template');
+ }, overrides: <Type, Generator>{
+ FileSystem: () => fs,
+ });
+
+ testUsingContext('creates swift Podfile if swift', () {
+ when(mockXcodeProjectInterpreter.canInterpretXcodeProjects).thenReturn(true);
+ when(mockXcodeProjectInterpreter.getBuildSettings(any, any)).thenReturn(<String, String>{
+ 'SWIFT_VERSION': '4.0',
+ });
+
+ cocoaPodsUnderTest.setupPodfile('project');
+
+ expect(podfile.readAsStringSync(), 'Swift podfile template');
+ }, overrides: <Type, Generator>{
+ FileSystem: () => fs,
+ XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
+ });
+
+ testUsingContext('does not recreate Podfile when already present', () {
+ podfile..createSync()..writeAsStringSync('Existing Podfile');
+
+ cocoaPodsUnderTest.setupPodfile('project');
+
+ expect(podfile.readAsStringSync(), 'Existing Podfile');
+ }, overrides: <Type, Generator>{
+ FileSystem: () => fs,
+ });
+
+ testUsingContext('does not create Podfile when we cannot interpret Xcode projects', () {
+ when(mockXcodeProjectInterpreter.canInterpretXcodeProjects).thenReturn(false);
+
+ cocoaPodsUnderTest.setupPodfile('project');
+
+ expect(podfile.existsSync(), false);
+ }, overrides: <Type, Generator>{
+ FileSystem: () => fs,
+ XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
+ });
+
+ testUsingContext('includes Pod config in xcconfig files, if not present', () {
+ podfile..createSync()..writeAsStringSync('Existing Podfile');
+ debugConfigFile..createSync(recursive: true)..writeAsStringSync('Existing debug config');
+ releaseConfigFile..createSync(recursive: true)..writeAsStringSync('Existing release config');
+
+ cocoaPodsUnderTest.setupPodfile('project');
+
+ final String debugContents = debugConfigFile.readAsStringSync();
+ expect(debugContents, contains(
+ '#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"\n'));
+ expect(debugContents, contains('Existing debug config'));
+ final String releaseContents = releaseConfigFile.readAsStringSync();
+ expect(releaseContents, contains(
+ '#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"\n'));
+ expect(releaseContents, contains('Existing release config'));
+ }, overrides: <Type, Generator>{
+ FileSystem: () => fs,
+ });
+ });
+
+ group('Process pods', () {
+ testUsingContext('prints error, if CocoaPods is not installed', () async {
+ projectUnderTest.childFile('Podfile').createSync();
cocoaPodsUnderTest = const TestCocoaPods(false);
+ await cocoaPodsUnderTest.processPods(
+ appIosDir: projectUnderTest,
+ iosEngineDir: 'engine/path',
+ );
+ verifyNever(mockProcessManager.run(
+ typed<List<String>>(any),
+ workingDirectory: any,
+ environment: typed<Map<String, String>>(any, named: 'environment'),
+ ));
+ expect(testLogger.errorText, contains('not installed'));
+ expect(testLogger.errorText, contains('Skipping pod install'));
+ }, overrides: <Type, Generator>{
+ FileSystem: () => fs,
+ ProcessManager: () => mockProcessManager,
+ });
+
+ testUsingContext('throws, if Podfile is missing.', () async {
+ cocoaPodsUnderTest = const TestCocoaPods(true);
try {
await cocoaPodsUnderTest.processPods(
appIosDir: projectUnderTest,
iosEngineDir: 'engine/path',
);
- fail('Expected tool error');
- } catch (ToolExit) {
+ fail('ToolExit expected');
+ } catch(e) {
+ expect(e, const isInstanceOf<ToolExit>());
verifyNever(mockProcessManager.run(
- <String>['pod', 'install', '--verbose'],
- workingDirectory: 'project/ios',
- environment: <String, String>{'FLUTTER_FRAMEWORK_DIR': 'engine/path', 'COCOAPODS_DISABLE_STATS': 'true'},
+ typed<List<String>>(any),
+ workingDirectory: any,
+ environment: typed<Map<String, String>>(any, named: 'environment'),
));
}
- },
- overrides: <Type, Generator>{
+ }, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
- },
- );
+ });
- testUsingContext(
- 'outdated specs repo should print error',
- () async {
+ testUsingContext('throws, if specs repo is outdated.', () async {
fs.file(fs.path.join('project', 'ios', 'Podfile'))
..createSync()
..writeAsString('Existing Podfile');
@@ -143,7 +173,10 @@
when(mockProcessManager.run(
<String>['pod', 'install', '--verbose'],
workingDirectory: 'project/ios',
- environment: <String, String>{'FLUTTER_FRAMEWORK_DIR': 'engine/path', 'COCOAPODS_DISABLE_STATS': 'true'},
+ environment: <String, String>{
+ 'FLUTTER_FRAMEWORK_DIR': 'engine/path',
+ 'COCOAPODS_DISABLE_STATS': 'true',
+ },
)).thenReturn(new ProcessResult(
1,
1,
@@ -167,78 +200,152 @@
await cocoaPodsUnderTest.processPods(
appIosDir: projectUnderTest,
iosEngineDir: 'engine/path',
- ); expect(fs.file(fs.path.join('project', 'ios', 'Podfile')).readAsStringSync() , 'Existing Podfile');
- fail('Exception expected');
- } catch (ToolExit) {
- expect(testLogger.errorText, contains("CocoaPods's specs repository is too out-of-date to satisfy dependencies"));
+ );
+ fail('ToolExit expected');
+ } catch (e) {
+ expect(e, const isInstanceOf<ToolExit>());
+ expect(
+ testLogger.errorText,
+ contains("CocoaPods's specs repository is too out-of-date to satisfy dependencies"),
+ );
}
- },
- overrides: <Type, Generator>{
+ }, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
- },
- );
+ });
- testUsingContext(
- 'Run pod install if plugins or flutter framework have changes.',
- () async {
- fs.file(fs.path.join('project', 'ios', 'Podfile'))
+ testUsingContext('run pod install, if Podfile.lock is missing', () async {
+ projectUnderTest.childFile('Podfile')
..createSync()
..writeAsString('Existing Podfile');
- fs.file(fs.path.join('project', 'ios', 'Podfile.lock'))
- ..createSync()
- ..writeAsString('Existing lock files.');
- fs.file(fs.path.join('project', 'ios', 'Pods','Manifest.lock'))
+ projectUnderTest.childFile('Pods/Manifest.lock')
..createSync(recursive: true)
- ..writeAsString('Existing lock files.');
+ ..writeAsString('Existing lock file.');
await cocoaPodsUnderTest.processPods(
- appIosDir: projectUnderTest,
- iosEngineDir: 'engine/path',
- pluginOrFlutterPodChanged: true
+ appIosDir: projectUnderTest,
+ iosEngineDir: 'engine/path',
+ flutterPodChanged: false,
);
verify(mockProcessManager.run(
<String>['pod', 'install', '--verbose'],
workingDirectory: 'project/ios',
environment: <String, String>{'FLUTTER_FRAMEWORK_DIR': 'engine/path', 'COCOAPODS_DISABLE_STATS': 'true'},
));
- },
- overrides: <Type, Generator>{
+ }, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
- },
- );
+ });
- testUsingContext(
- 'Skip pod install if plugins and flutter framework remain unchanged.',
- () async {
- fs.file(fs.path.join('project', 'ios', 'Podfile'))
+ testUsingContext('runs pod install, if Manifest.lock is missing', () async {
+ projectUnderTest.childFile('Podfile')
..createSync()
..writeAsString('Existing Podfile');
- fs.file(fs.path.join('project', 'ios', 'Podfile.lock'))
+ projectUnderTest.childFile('Podfile.lock')
..createSync()
- ..writeAsString('Existing lock files.');
- fs.file(fs.path.join('project', 'ios', 'Pods','Manifest.lock'))
- ..createSync(recursive: true)
- ..writeAsString('Existing lock files.');
+ ..writeAsString('Existing lock file.');
await cocoaPodsUnderTest.processPods(
- appIosDir: projectUnderTest,
- iosEngineDir: 'engine/path',
- pluginOrFlutterPodChanged: false
+ appIosDir: projectUnderTest,
+ iosEngineDir: 'engine/path',
+ flutterPodChanged: false,
);
- verifyNever(mockProcessManager.run(
+ verify(mockProcessManager.run(
<String>['pod', 'install', '--verbose'],
workingDirectory: 'project/ios',
- environment: <String, String>{'FLUTTER_FRAMEWORK_DIR': 'engine/path', 'COCOAPODS_DISABLE_STATS': 'true'},
+ environment: <String, String>{
+ 'FLUTTER_FRAMEWORK_DIR': 'engine/path',
+ 'COCOAPODS_DISABLE_STATS': 'true',
+ },
));
- },
- overrides: <Type, Generator>{
+ }, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
- },
- );
+ });
+
+ testUsingContext('runs pod install, if Manifest.lock different from Podspec.lock', () async {
+ projectUnderTest.childFile('Podfile')
+ ..createSync()
+ ..writeAsString('Existing Podfile');
+ projectUnderTest.childFile('Podfile.lock')
+ ..createSync()
+ ..writeAsString('Existing lock file.');
+ projectUnderTest.childFile('Pods/Manifest.lock')
+ ..createSync(recursive: true)
+ ..writeAsString('Different lock file.');
+ await cocoaPodsUnderTest.processPods(
+ appIosDir: projectUnderTest,
+ iosEngineDir: 'engine/path',
+ flutterPodChanged: false,
+ );
+ verify(mockProcessManager.run(
+ <String>['pod', 'install', '--verbose'],
+ workingDirectory: 'project/ios',
+ environment: <String, String>{
+ 'FLUTTER_FRAMEWORK_DIR': 'engine/path',
+ 'COCOAPODS_DISABLE_STATS': 'true',
+ },
+ ));
+ }, overrides: <Type, Generator>{
+ FileSystem: () => fs,
+ ProcessManager: () => mockProcessManager,
+ });
+
+ testUsingContext('runs pod install, if flutter framework changed', () async {
+ projectUnderTest.childFile('Podfile')
+ ..createSync()
+ ..writeAsString('Existing Podfile');
+ projectUnderTest.childFile('Podfile.lock')
+ ..createSync()
+ ..writeAsString('Existing lock file.');
+ projectUnderTest.childFile('Pods/Manifest.lock')
+ ..createSync(recursive: true)
+ ..writeAsString('Existing lock file.');
+ await cocoaPodsUnderTest.processPods(
+ appIosDir: projectUnderTest,
+ iosEngineDir: 'engine/path',
+ flutterPodChanged: true,
+ );
+ verify(mockProcessManager.run(
+ <String>['pod', 'install', '--verbose'],
+ workingDirectory: 'project/ios',
+ environment: <String, String>{
+ 'FLUTTER_FRAMEWORK_DIR': 'engine/path',
+ 'COCOAPODS_DISABLE_STATS': 'true',
+ },
+ ));
+ }, overrides: <Type, Generator>{
+ FileSystem: () => fs,
+ ProcessManager: () => mockProcessManager,
+ });
+
+ testUsingContext('skips pod install, if nothing changed', () async {
+ projectUnderTest.childFile('Podfile')
+ ..createSync()
+ ..writeAsString('Existing Podfile');
+ projectUnderTest.childFile('Podfile.lock')
+ ..createSync()
+ ..writeAsString('Existing lock file.');
+ projectUnderTest.childFile('Pods/Manifest.lock')
+ ..createSync(recursive: true)
+ ..writeAsString('Existing lock file.');
+ await cocoaPodsUnderTest.processPods(
+ appIosDir: projectUnderTest,
+ iosEngineDir: 'engine/path',
+ flutterPodChanged: false,
+ );
+ verifyNever(mockProcessManager.run(
+ typed<List<String>>(any),
+ workingDirectory: any,
+ environment: typed<Map<String, String>>(any, named: 'environment'),
+ ));
+ }, overrides: <Type, Generator>{
+ FileSystem: () => fs,
+ ProcessManager: () => mockProcessManager,
+ });
+ });
}
class MockProcessManager extends Mock implements ProcessManager {}
+class MockXcodeProjectInterpreter extends Mock implements XcodeProjectInterpreter {}
class TestCocoaPods extends CocoaPods {
const TestCocoaPods([this._hasCocoaPods = true]);
diff --git a/packages/flutter_tools/test/project_test.dart b/packages/flutter_tools/test/project_test.dart
index 2f1a3ff..6ef5bbb 100644
--- a/packages/flutter_tools/test/project_test.dart
+++ b/packages/flutter_tools/test/project_test.dart
@@ -17,6 +17,29 @@
final Directory directory = fs.directory('myproject');
expect(new FlutterProject(directory).directory, directory);
});
+ group('ensure ready for platform-specific tooling', () {
+ testInMemory('does nothing, if project is not created', () async {
+ final FlutterProject project = someProject();
+ project.ensureReadyForPlatformSpecificTooling();
+ expect(project.directory.existsSync(), isFalse);
+ });
+ testInMemory('injects plugins', () async {
+ final FlutterProject project = aProjectWithIos();
+ project.ensureReadyForPlatformSpecificTooling();
+ expect(project.ios.directory.childFile('Runner/GeneratedPluginRegistrant.h').existsSync(), isTrue);
+ });
+ testInMemory('generates Xcode configuration', () async {
+ final FlutterProject project = aProjectWithIos();
+ project.ensureReadyForPlatformSpecificTooling();
+ expect(project.ios.directory.childFile('Flutter/Generated.xcconfig').existsSync(), isTrue);
+ });
+ testInMemory('generates files in plugin example project', () async {
+ final FlutterProject project = aPluginProject();
+ project.ensureReadyForPlatformSpecificTooling();
+ expect(project.example.ios.directory.childFile('Runner/GeneratedPluginRegistrant.h').existsSync(), isTrue);
+ expect(project.example.ios.directory.childFile('Flutter/Generated.xcconfig').existsSync(), isTrue);
+ });
+ });
group('organization names set', () {
testInMemory('is empty, if project not created', () async {
final FlutterProject project = someProject();
@@ -71,8 +94,23 @@
});
}
-FlutterProject someProject() =>
- new FlutterProject(fs.directory('some_project'));
+FlutterProject someProject() => new FlutterProject(fs.directory('some_project'));
+
+FlutterProject aProjectWithIos() {
+ final Directory directory = fs.directory('ios_project');
+ directory.childFile('pubspec.yaml').createSync(recursive: true);
+ directory.childFile('.packages').createSync(recursive: true);
+ directory.childDirectory('ios').createSync(recursive: true);
+ return new FlutterProject(directory);
+}
+
+FlutterProject aPluginProject() {
+ final Directory directory = fs.directory('plugin_project/example');
+ directory.childFile('pubspec.yaml').createSync(recursive: true);
+ directory.childFile('.packages').createSync(recursive: true);
+ directory.childDirectory('ios').createSync(recursive: true);
+ return new FlutterProject(directory.parent);
+}
void testInMemory(String description, Future<Null> testMethod()) {
testUsingContext(
@@ -84,6 +122,13 @@
);
}
+void addPubPackages(Directory directory) {
+ directory.childFile('pubspec.yaml')
+ ..createSync(recursive: true);
+ directory.childFile('.packages')
+ ..createSync(recursive: true);
+}
+
void addIosWithBundleId(Directory directory, String id) {
directory
.childDirectory('ios')
diff --git a/packages/flutter_tools/test/src/context.dart b/packages/flutter_tools/test/src/context.dart
index 3c5fe1b..dbe5188 100644
--- a/packages/flutter_tools/test/src/context.dart
+++ b/packages/flutter_tools/test/src/context.dart
@@ -19,6 +19,7 @@
import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/ios/mac.dart';
import 'package:flutter_tools/src/ios/simulators.dart';
+import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/run_hot.dart';
import 'package:flutter_tools/src/usage.dart';
import 'package:flutter_tools/src/version.dart';
@@ -50,6 +51,7 @@
..putIfAbsent(OperatingSystemUtils, () => new MockOperatingSystemUtils())
..putIfAbsent(PortScanner, () => new MockPortScanner())
..putIfAbsent(Xcode, () => new Xcode())
+ ..putIfAbsent(XcodeProjectInterpreter, () => new MockXcodeProjectInterpreter())
..putIfAbsent(IOSSimulatorUtils, () {
final MockIOSSimulatorUtils mock = new MockIOSSimulatorUtils();
when(mock.getAttachedDevices()).thenReturn(<IOSSimulator>[]);
@@ -262,6 +264,25 @@
void printWelcome() { }
}
+class MockXcodeProjectInterpreter implements XcodeProjectInterpreter {
+ @override
+ bool get canInterpretXcodeProjects => true;
+
+ @override
+ Map<String, String> getBuildSettings(String projectPath, String target) {
+ return <String, String>{};
+ }
+
+ @override
+ XcodeProjectInfo getInfo(String projectPath) {
+ return new XcodeProjectInfo(
+ <String>['Runner'],
+ <String>['Debug', 'Release'],
+ <String>['Runner'],
+ );
+ }
+}
+
class MockFlutterVersion extends Mock implements FlutterVersion {}
class MockClock extends Mock implements Clock {}