diff --git a/packages/flutter_tools/lib/src/plugins.dart b/packages/flutter_tools/lib/src/plugins.dart index 0e42bcd3e6b..38af093a7f4 100644 --- a/packages/flutter_tools/lib/src/plugins.dart +++ b/packages/flutter_tools/lib/src/plugins.dart @@ -502,10 +502,14 @@ void refreshPluginsList(FlutterProject project, {bool checkProjects = false}) { final List plugins = findPlugins(project); final bool changed = _writeFlutterPluginsList(project, plugins); if (changed) { - if (checkProjects && !project.ios.existsSync()) { - return; + if (!checkProjects || project.ios.existsSync()) { + cocoaPods.invalidatePodInstallOutput(project.ios); + } + // TODO(stuartmorgan): Potentially add checkProjects once a decision has + // made about how to handle macOS in existing projects. + if (project.macos.existsSync()) { + cocoaPods.invalidatePodInstallOutput(project.macos); } - cocoaPods.invalidatePodInstallOutput(project.ios); } } diff --git a/packages/flutter_tools/test/general.shard/plugins_test.dart b/packages/flutter_tools/test/general.shard/plugins_test.dart new file mode 100644 index 00000000000..f119fc80ab7 --- /dev/null +++ b/packages/flutter_tools/test/general.shard/plugins_test.dart @@ -0,0 +1,106 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:file/file.dart'; +import 'package:file/memory.dart'; +import 'package:flutter_tools/src/dart/package_map.dart'; +import 'package:flutter_tools/src/plugins.dart'; +import 'package:flutter_tools/src/project.dart'; +import 'package:mockito/mockito.dart'; + +import '../src/common.dart'; +import '../src/context.dart'; + +class MockFlutterProject extends Mock implements FlutterProject {} +class MockIosProject extends Mock implements IosProject {} +class MockMacOSProject extends Mock implements MacOSProject {} + +void main() { + FileSystem fs; + MockFlutterProject flutterProject; + MockIosProject iosProject; + MockMacOSProject macosProject; + File packagesFile; + Directory dummyPackageDirectory; + + setUp(() async { + fs = MemoryFileSystem(); + + // Add basic properties to the Flutter project and subprojects + flutterProject = MockFlutterProject(); + when(flutterProject.directory).thenReturn(fs.directory('/')); + when(flutterProject.flutterPluginsFile).thenReturn(flutterProject.directory.childFile('.plugins')); + iosProject = MockIosProject(); + when(flutterProject.ios).thenReturn(iosProject); + when(iosProject.podManifestLock).thenReturn(flutterProject.directory.childDirectory('ios').childFile('Podfile.lock')); + macosProject = MockMacOSProject(); + when(flutterProject.macos).thenReturn(macosProject); + when(macosProject.podManifestLock).thenReturn(flutterProject.directory.childDirectory('macos').childFile('Podfile.lock')); + + // Set up a simple .packages file for all the tests to use, pointing to one package. + dummyPackageDirectory = fs.directory('/pubcache/apackage/lib/'); + packagesFile = fs.file(fs.path.join(flutterProject.directory.path, PackageMap.globalPackagesPath)); + packagesFile..createSync(recursive: true) + ..writeAsStringSync('apackage:file://${dummyPackageDirectory.path}'); + }); + + // Makes the dummy package pointed to by packagesFile look like a plugin. + void configureDummyPackageAsPlugin() { + dummyPackageDirectory.parent.childFile('pubspec.yaml')..createSync(recursive: true)..writeAsStringSync(''' +flutter: + plugin: + platforms: + ios: + pluginClass: FLESomePlugin +'''); + } + + // Creates the files that would indicate that pod install has run for the + // given project. + void simulatePodInstallRun(XcodeBasedProject project) { + project.podManifestLock.createSync(recursive: true); + } + + group('refreshPlugins', () { + testUsingContext('Refreshing the plugin list is a no-op when the plugins list stays empty', () { + refreshPluginsList(flutterProject); + expect(flutterProject.flutterPluginsFile.existsSync(), false); + }, overrides: { + FileSystem: () => fs, + }); + + testUsingContext('Refreshing the plugin list deletes the plugin file when there were plugins but no longer are', () { + flutterProject.flutterPluginsFile.createSync(); + when(iosProject.existsSync()).thenReturn(false); + when(macosProject.existsSync()).thenReturn(false); + refreshPluginsList(flutterProject); + expect(flutterProject.flutterPluginsFile.existsSync(), false); + }, overrides: { + FileSystem: () => fs, + }); + + testUsingContext('Refreshing the plugin list creates a plugin directory when there are plugins', () { + configureDummyPackageAsPlugin(); + when(iosProject.existsSync()).thenReturn(false); + when(macosProject.existsSync()).thenReturn(false); + refreshPluginsList(flutterProject); + expect(flutterProject.flutterPluginsFile.existsSync(), true); + }, overrides: { + FileSystem: () => fs, + }); + + testUsingContext('Changes to the plugin list invalidates the Cocoapod lockfiles', () { + simulatePodInstallRun(iosProject); + simulatePodInstallRun(macosProject); + configureDummyPackageAsPlugin(); + when(iosProject.existsSync()).thenReturn(true); + when(macosProject.existsSync()).thenReturn(true); + refreshPluginsList(flutterProject); + expect(iosProject.podManifestLock.existsSync(), false); + expect(macosProject.podManifestLock.existsSync(), false); + }, overrides: { + FileSystem: () => fs, + }); + }); +}