diff --git a/script/tool/lib/src/lint_podspecs_command.dart b/script/tool/lib/src/lint_podspecs_command.dart index 68fd4b61dd..b10031162f 100644 --- a/script/tool/lib/src/lint_podspecs_command.dart +++ b/script/tool/lib/src/lint_podspecs_command.dart @@ -14,8 +14,7 @@ import 'common.dart'; typedef void Print(Object object); -/// Lint the CocoaPod podspecs, run the static analyzer on iOS/macOS plugin -/// platform code, and run unit tests. +/// Lint the CocoaPod podspecs and run unit tests. /// /// See https://guides.cocoapods.org/terminal/commands.html#pod_lib_lint. class LintPodspecsCommand extends PluginCommand { @@ -35,10 +34,6 @@ class LintPodspecsCommand extends PluginCommand { help: 'Do not pass --allow-warnings flag to "pod lib lint" for podspecs with this basename (example: plugins with known warnings)', valueHelp: 'podspec_file_name'); - argParser.addMultiOption('no-analyze', - help: - 'Do not pass --analyze flag to "pod lib lint" for podspecs with this basename (example: plugins with known analyzer warnings)', - valueHelp: 'podspec_file_name'); } @override @@ -102,25 +97,17 @@ class LintPodspecsCommand extends PluginCommand { Future _lintPodspec(File podspec) async { // Do not run the static analyzer on plugins with known analyzer issues. final String podspecPath = podspec.path; - final bool runAnalyzer = !argResults['no-analyze'] - .contains(p.basenameWithoutExtension(podspecPath)); final String podspecBasename = p.basename(podspecPath); - if (runAnalyzer) { - _print('Linting and analyzing $podspecBasename'); - } else { - _print('Linting $podspecBasename'); - } + _print('Linting $podspecBasename'); // Lint plugin as framework (use_frameworks!). - final ProcessResult frameworkResult = await _runPodLint(podspecPath, - runAnalyzer: runAnalyzer, libraryLint: true); + final ProcessResult frameworkResult = await _runPodLint(podspecPath, libraryLint: true); _print(frameworkResult.stdout); _print(frameworkResult.stderr); // Lint plugin as library. - final ProcessResult libraryResult = await _runPodLint(podspecPath, - runAnalyzer: runAnalyzer, libraryLint: false); + final ProcessResult libraryResult = await _runPodLint(podspecPath, libraryLint: false); _print(libraryResult.stdout); _print(libraryResult.stderr); @@ -128,7 +115,7 @@ class LintPodspecsCommand extends PluginCommand { } Future _runPodLint(String podspecPath, - {bool runAnalyzer, bool libraryLint}) async { + {bool libraryLint}) async { final bool allowWarnings = argResults['ignore-warnings'] .contains(p.basenameWithoutExtension(podspecPath)); final List arguments = [ @@ -136,10 +123,10 @@ class LintPodspecsCommand extends PluginCommand { 'lint', podspecPath, if (allowWarnings) '--allow-warnings', - if (runAnalyzer) '--analyze', if (libraryLint) '--use-libraries' ]; + _print('Running "pod ${arguments.join(' ')}"'); return processRunner.run('pod', arguments, workingDir: packagesDir, stdoutEncoding: utf8, stderrEncoding: utf8); } diff --git a/script/tool/lib/src/xctest_command.dart b/script/tool/lib/src/xctest_command.dart index d90b7a8fbf..a4d03360b2 100644 --- a/script/tool/lib/src/xctest_command.dart +++ b/script/tool/lib/src/xctest_command.dart @@ -12,17 +12,15 @@ import 'package:path/path.dart' as p; import 'common.dart'; const String _kiOSDestination = 'ios-destination'; -const String _kTarget = 'target'; const String _kSkip = 'skip'; const String _kXcodeBuildCommand = 'xcodebuild'; const String _kXCRunCommand = 'xcrun'; const String _kFoundNoSimulatorsMessage = 'Cannot find any available simulators, tests failed'; -/// The command to run iOS' XCTests in plugins, this should work for both XCUnitTest and XCUITest targets. -/// The tests target have to be added to the xcode project of the example app. Usually at "example/ios/Runner.xcodeproj". -/// The command takes a "-target" argument which has to match the target of the test target. -/// For information on how to add test target in an xcode project, see https://developer.apple.com/library/archive/documentation/ToolsLanguages/Conceptual/Xcode_Overview/UnitTesting.html +/// The command to run iOS XCTests in plugins, this should work for both XCUnitTest and XCUITest targets. +/// The tests target have to be added to the xcode project of the example app. Usually at "example/ios/Runner.xcworkspace". +/// The static analyzer is also run. class XCTestCommand extends PluginCommand { XCTestCommand( Directory packagesDir, @@ -36,10 +34,6 @@ class XCTestCommand extends PluginCommand { 'this is passed to the `-destination` argument in xcodebuild command.\n' 'See https://developer.apple.com/library/archive/technotes/tn2339/_index.html#//apple_ref/doc/uid/DTS40014588-CH1-UNIT for details on how to specify the destination.', ); - argParser.addOption(_kTarget, - help: 'The test target.\n' - 'This is the xcode project test target. This is passed to the `-scheme` argument in the xcodebuild command. \n' - 'See https://developer.apple.com/library/archive/technotes/tn2339/_index.html#//apple_ref/doc/uid/DTS40014588-CH1-UNIT for details on how to specify the scheme'); argParser.addMultiOption(_kSkip, help: 'Plugins to skip while running this command. \n'); } @@ -49,17 +43,10 @@ class XCTestCommand extends PluginCommand { @override final String description = 'Runs the xctests in the iOS example apps.\n\n' - 'This command requires "flutter" to be in your path.'; + 'This command requires "flutter" and "xcrun" to be in your path.'; @override Future run() async { - if (argResults[_kTarget] == null) { - // TODO(cyanglaz): Automatically find all the available testing schemes if this argument is not specified. - // https://github.com/flutter/flutter/issues/68419 - print('--$_kTarget must be specified'); - throw ToolExit(1); - } - String destination = argResults[_kiOSDestination]; if (destination == null) { String simulatorId = await _findAvailableIphoneSimulator(); @@ -72,7 +59,6 @@ class XCTestCommand extends PluginCommand { checkSharding(); - final String target = argResults[_kTarget]; final List skipped = argResults[_kSkip]; List failingPackages = []; @@ -92,57 +78,14 @@ class XCTestCommand extends PluginCommand { continue; } for (Directory example in getExamplesForPlugin(plugin)) { - // Look for the test scheme in the example app. - print('Look for target named: $_kTarget ...'); - final List findSchemeArgs = [ - '-project', - 'ios/Runner.xcodeproj', - '-list', - '-json' - ]; - final String completeFindSchemeCommand = - '$_kXcodeBuildCommand ${findSchemeArgs.join(' ')}'; - print(completeFindSchemeCommand); - final io.ProcessResult xcodeprojListResult = await processRunner - .run(_kXcodeBuildCommand, findSchemeArgs, workingDir: example); - if (xcodeprojListResult.exitCode != 0) { - print('Error occurred while running "$completeFindSchemeCommand":\n' - '${xcodeprojListResult.stderr}'); - failingPackages.add(packageName); - print('\n\n'); - continue; + // Running tests and static analyzer. + print('Running tests and analyzer for $packageName ...'); + int exitCode = await _runTests(true, destination, example); + // 66 = there is no test target (this fails fast). Try again with just the analyzer. + if (exitCode == 66) { + print('Tests not found for $packageName, running analyzer only...'); + exitCode = await _runTests(false, destination, example); } - - final String xcodeprojListOutput = xcodeprojListResult.stdout; - Map xcodeprojListOutputJson = - jsonDecode(xcodeprojListOutput); - if (!xcodeprojListOutputJson['project']['targets'].contains(target)) { - failingPackages.add(packageName); - print('$target not configured for $packageName, test failed.'); - print( - 'Please check the scheme for the test target if it matches the name $target.\n' - 'If this plugin does not have an XCTest target, use the $_kSkip flag in the $name command to skip the plugin.'); - print('\n\n'); - continue; - } - // Found the scheme, running tests - print('Running XCTests:$target for $packageName ...'); - final List xctestArgs = [ - 'test', - '-workspace', - 'ios/Runner.xcworkspace', - '-scheme', - target, - '-destination', - destination, - 'CODE_SIGN_IDENTITY=""', - 'CODE_SIGNING_REQUIRED=NO' - ]; - final String completeTestCommand = - '$_kXcodeBuildCommand ${xctestArgs.join(' ')}'; - print(completeTestCommand); - final int exitCode = await processRunner - .runAndStream(_kXcodeBuildCommand, xctestArgs, workingDir: example); if (exitCode == 0) { print('Successfully ran xctest for $packageName'); } else { @@ -164,6 +107,31 @@ class XCTestCommand extends PluginCommand { } } + Future _runTests(bool runTests, String destination, Directory example) { + final List xctestArgs = [ + _kXcodeBuildCommand, + if (runTests) + 'test', + 'analyze', + '-workspace', + 'ios/Runner.xcworkspace', + '-configuration', + 'Debug', + '-scheme', + 'Runner', + '-destination', + destination, + 'CODE_SIGN_IDENTITY=""', + 'CODE_SIGNING_REQUIRED=NO', + 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', + ]; + final String completeTestCommand = + '$_kXCRunCommand ${xctestArgs.join(' ')}'; + print(completeTestCommand); + return processRunner + .runAndStream(_kXCRunCommand, xctestArgs, workingDir: example, exitOnError: false); + } + Future _findAvailableIphoneSimulator() async { // Find the first available destination if not specified. final List findSimulatorsArguments = [ diff --git a/script/tool/test/lint_podspecs_command_test.dart b/script/tool/test/lint_podspecs_command_test.dart index 49d6ad4d8e..1014dcd170 100644 --- a/script/tool/test/lint_podspecs_command_test.dart +++ b/script/tool/test/lint_podspecs_command_test.dart @@ -81,7 +81,6 @@ void main() { 'lib', 'lint', p.join(plugin1Dir.path, 'ios', 'plugin1.podspec'), - '--analyze', '--use-libraries' ], mockPackagesDir.path), @@ -91,14 +90,13 @@ void main() { 'lib', 'lint', p.join(plugin1Dir.path, 'ios', 'plugin1.podspec'), - '--analyze', ], mockPackagesDir.path), ]), ); expect( - printedMessages, contains('Linting and analyzing plugin1.podspec')); + printedMessages, contains('Linting plugin1.podspec')); expect(printedMessages, contains('Foo')); expect(printedMessages, contains('Bar')); }); @@ -122,41 +120,6 @@ void main() { ); }); - test('skips analyzer for podspecs with known warnings', () async { - Directory plugin1Dir = - createFakePlugin('plugin1', withExtraFiles: >[ - ['plugin1.podspec'], - ]); - - await runner.run(['podspecs', '--no-analyze=plugin1']); - - expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall('which', ['pod'], mockPackagesDir.path), - ProcessCall( - 'pod', - [ - 'lib', - 'lint', - p.join(plugin1Dir.path, 'plugin1.podspec'), - '--use-libraries' - ], - mockPackagesDir.path), - ProcessCall( - 'pod', - [ - 'lib', - 'lint', - p.join(plugin1Dir.path, 'plugin1.podspec'), - ], - mockPackagesDir.path), - ]), - ); - - expect(printedMessages, contains('Linting plugin1.podspec')); - }); - test('allow warnings for podspecs with known warnings', () async { Directory plugin1Dir = createFakePlugin('plugin1', withExtraFiles: >[ @@ -176,7 +139,6 @@ void main() { 'lint', p.join(plugin1Dir.path, 'plugin1.podspec'), '--allow-warnings', - '--analyze', '--use-libraries' ], mockPackagesDir.path), @@ -187,14 +149,13 @@ void main() { 'lint', p.join(plugin1Dir.path, 'plugin1.podspec'), '--allow-warnings', - '--analyze', ], mockPackagesDir.path), ]), ); expect( - printedMessages, contains('Linting and analyzing plugin1.podspec')); + printedMessages, contains('Linting plugin1.podspec')); }); }); } diff --git a/script/tool/test/xctest_command_test.dart b/script/tool/test/xctest_command_test.dart index 007c2e1218..2b75ccde42 100644 --- a/script/tool/test/xctest_command_test.dart +++ b/script/tool/test/xctest_command_test.dart @@ -8,7 +8,6 @@ import 'package:args/command_runner.dart'; import 'package:file/file.dart'; import 'package:flutter_plugin_tools/src/xctest_command.dart'; import 'package:test/test.dart'; -import 'package:flutter_plugin_tools/src/common.dart'; import 'mocks.dart'; import 'util.dart'; @@ -81,7 +80,6 @@ final _kDeviceListMap = { void main() { const String _kDestination = '--ios-destination'; - const String _kTarget = '--target'; const String _kSkip = '--skip'; group('test xctest_command', () { @@ -100,12 +98,6 @@ void main() { cleanupPackages(); }); - test('Not specifying --target throws', () async { - await expectLater( - () => runner.run(['xctest', _kDestination, 'a_destination']), - throwsA(const TypeMatcher())); - }); - test('skip if ios is not supported', () async { createFakePlugin('plugin', withExtraFiles: >[ @@ -123,8 +115,6 @@ void main() { processRunner.processToReturn = mockProcess; final List output = await runCapturingPrint(runner, [ 'xctest', - _kTarget, - 'foo_scheme', _kDestination, 'foo_destination' ]); @@ -134,106 +124,7 @@ void main() { cleanupPackages(); }); - test('running with correct scheme and destination, did not find scheme', - () async { - createFakePlugin('plugin', - withExtraFiles: >[ - ['example', 'test'], - ], - isIosPlugin: true); - - final Directory pluginExampleDirectory = - mockPackagesDir.childDirectory('plugin').childDirectory('example'); - - createFakePubspec(pluginExampleDirectory, isFlutter: true); - - final MockProcess mockProcess = MockProcess(); - mockProcess.exitCodeCompleter.complete(0); - processRunner.processToReturn = mockProcess; - processRunner.resultStdout = '{"project":{"targets":["bar_scheme"]}}'; - - await expectLater(() async { - final List output = await runCapturingPrint(runner, [ - 'xctest', - _kTarget, - 'foo_scheme', - _kDestination, - 'foo_destination' - ]); - expect(output, - contains('foo_scheme not configured for plugin, test failed.')); - expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall('xcrun', ['simctl', 'list', '--json'], null), - ProcessCall( - 'xcodebuild', - [ - '-project', - 'ios/Runner.xcodeproj', - '-list', - '-json' - ], - pluginExampleDirectory.path), - ])); - }, throwsA(const TypeMatcher())); - cleanupPackages(); - }); - - test('running with correct scheme and destination, found scheme', () async { - createFakePlugin('plugin', - withExtraFiles: >[ - ['example', 'test'], - ], - isIosPlugin: true); - - final Directory pluginExampleDirectory = - mockPackagesDir.childDirectory('plugin').childDirectory('example'); - - createFakePubspec(pluginExampleDirectory, isFlutter: true); - - final MockProcess mockProcess = MockProcess(); - mockProcess.exitCodeCompleter.complete(0); - processRunner.processToReturn = mockProcess; - processRunner.resultStdout = - '{"project":{"targets":["bar_scheme", "foo_scheme"]}}'; - List output = await runCapturingPrint(runner, [ - 'xctest', - _kTarget, - 'foo_scheme', - _kDestination, - 'foo_destination' - ]); - - expect(output, contains('Successfully ran xctest for plugin')); - - expect( - processRunner.recordedCalls, - orderedEquals([ - ProcessCall( - 'xcodebuild', - ['-project', 'ios/Runner.xcodeproj', '-list', '-json'], - pluginExampleDirectory.path), - ProcessCall( - 'xcodebuild', - [ - 'test', - '-workspace', - 'ios/Runner.xcworkspace', - '-scheme', - 'foo_scheme', - '-destination', - 'foo_destination', - 'CODE_SIGN_IDENTITY=""', - 'CODE_SIGNING_REQUIRED=NO' - ], - pluginExampleDirectory.path), - ])); - - cleanupPackages(); - }); - - test('running with correct scheme and destination, skip 1 plugin', + test('running with correct destination, skip 1 plugin', () async { createFakePlugin('plugin1', withExtraFiles: >[ @@ -260,8 +151,6 @@ void main() { '{"project":{"targets":["bar_scheme", "foo_scheme"]}}'; List output = await runCapturingPrint(runner, [ 'xctest', - _kTarget, - 'foo_scheme', _kDestination, 'foo_destination', _kSkip, @@ -275,21 +164,22 @@ void main() { processRunner.recordedCalls, orderedEquals([ ProcessCall( - 'xcodebuild', - ['-project', 'ios/Runner.xcodeproj', '-list', '-json'], - pluginExampleDirectory2.path), - ProcessCall( - 'xcodebuild', + 'xcrun', [ + 'xcodebuild', 'test', + 'analyze', '-workspace', 'ios/Runner.xcworkspace', + '-configuration', + 'Debug', '-scheme', - 'foo_scheme', + 'Runner', '-destination', 'foo_destination', 'CODE_SIGN_IDENTITY=""', - 'CODE_SIGNING_REQUIRED=NO' + 'CODE_SIGNING_REQUIRED=NO', + 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', ], pluginExampleDirectory2.path), ])); @@ -324,8 +214,6 @@ void main() { jsonEncode(schemeCommandResult..addAll(_kDeviceListMap)); await runner.run([ 'xctest', - _kTarget, - 'foo_scheme', ]); expect( @@ -333,21 +221,22 @@ void main() { orderedEquals([ ProcessCall('xcrun', ['simctl', 'list', '--json'], null), ProcessCall( - 'xcodebuild', - ['-project', 'ios/Runner.xcodeproj', '-list', '-json'], - pluginExampleDirectory.path), - ProcessCall( - 'xcodebuild', + 'xcrun', [ + 'xcodebuild', 'test', + 'analyze', '-workspace', 'ios/Runner.xcworkspace', + '-configuration', + 'Debug', '-scheme', - 'foo_scheme', + 'Runner', '-destination', 'id=1E76A0FD-38AC-4537-A989-EA639D7D012A', 'CODE_SIGN_IDENTITY=""', - 'CODE_SIGNING_REQUIRED=NO' + 'CODE_SIGNING_REQUIRED=NO', + 'GCC_TREAT_WARNINGS_AS_ERRORS=YES', ], pluginExampleDirectory.path), ]));