Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit b37379a

Browse files
committed
Run static analyzer during xctest
1 parent 1e3a823 commit b37379a

7 files changed

+65
-259
lines changed

.cirrus.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ task:
179179
- name: build-ipas+drive-examples
180180
env:
181181
PATH: $PATH:/usr/local/bin
182-
PLUGINS_TO_SKIP_XCTESTS: "battery/battery,camera/camera,connectivity/connectivity,device_info/device_info,espresso,google_maps_flutter/google_maps_flutter,google_sign_in/google_sign_in,in_app_purchase,integration_test,ios_platform_images,local_auth,package_info,path_provider/path_provider,sensors,shared_preferences/shared_preferences,url_launcher/url_launcher,video_player/video_player,webview_flutter,wifi_info_flutter/wifi_info_flutter"
182+
PLUGINS_TO_SKIP_XCTESTS: "image_picker/image_picker,integration_test,webview_flutter"
183183
matrix:
184184
PLUGIN_SHARDING: "--shardIndex 0 --shardCount 4"
185185
PLUGIN_SHARDING: "--shardIndex 1 --shardCount 4"
@@ -197,7 +197,7 @@ task:
197197
- flutter channel $CHANNEL
198198
- flutter upgrade
199199
- ./script/incremental_build.sh build-examples --ipa
200-
- ./script/incremental_build.sh xctest --target RunnerUITests --skip $PLUGINS_TO_SKIP_XCTESTS --ios-destination "platform=iOS Simulator,name=iPhone 11,OS=14.3"
200+
- ./script/incremental_build.sh xctest --skip $PLUGINS_TO_SKIP_XCTESTS --ios-destination "platform=iOS Simulator,name=iPhone 11,OS=latest"
201201
# `drive-examples` contains integration tests, which changes the UI of the application.
202202
# This UI change sometimes affects `xctest`.
203203
# So we run `drive-examples` after `xctest`, changing the order will result ci failure.

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Pods/
1717
.symlinks/
1818
**/Flutter/App.framework/
1919
**/Flutter/ephemeral/
20+
**/Flutter/Flutter.podspec
2021
**/Flutter/Flutter.framework/
2122
**/Flutter/Generated.xcconfig
2223
**/Flutter/flutter_assets/

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ If XCUITests has not been set up for the plugin, follow these steps to set it up
6969
1. Open <path_to_plugin>/example/ios/Runner.xcworkspace using XCode.
7070
1. Create a new "UI Testing Bundle".
7171
1. In the target options window, populate details as following, then click on "Finish".
72-
* In the "product name" field, type in "RunnerUITests" (this is the test target name our CI looks for.).
72+
* In the "product name" field, type in "RunnerUITests".
7373
* In the "Team" field, select "None".
7474
* In the Organization Name field, type in "Flutter". This should usually be pre-populated.
7575
* In the organization identifer field, type in "com.google". This should usually be pre-populated.

script/tool/lib/src/lint_podspecs_command.dart

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ import 'common.dart';
1414

1515
typedef void Print(Object object);
1616

17-
/// Lint the CocoaPod podspecs, run the static analyzer on iOS/macOS plugin
18-
/// platform code, and run unit tests.
17+
/// Lint the CocoaPod podspecs and run unit tests.
1918
///
2019
/// See https://guides.cocoapods.org/terminal/commands.html#pod_lib_lint.
2120
class LintPodspecsCommand extends PluginCommand {
@@ -35,10 +34,6 @@ class LintPodspecsCommand extends PluginCommand {
3534
help:
3635
'Do not pass --allow-warnings flag to "pod lib lint" for podspecs with this basename (example: plugins with known warnings)',
3736
valueHelp: 'podspec_file_name');
38-
argParser.addMultiOption('no-analyze',
39-
help:
40-
'Do not pass --analyze flag to "pod lib lint" for podspecs with this basename (example: plugins with known analyzer warnings)',
41-
valueHelp: 'podspec_file_name');
4237
}
4338

4439
@override
@@ -102,44 +97,36 @@ class LintPodspecsCommand extends PluginCommand {
10297
Future<bool> _lintPodspec(File podspec) async {
10398
// Do not run the static analyzer on plugins with known analyzer issues.
10499
final String podspecPath = podspec.path;
105-
final bool runAnalyzer = !argResults['no-analyze']
106-
.contains(p.basenameWithoutExtension(podspecPath));
107100

108101
final String podspecBasename = p.basename(podspecPath);
109-
if (runAnalyzer) {
110-
_print('Linting and analyzing $podspecBasename');
111-
} else {
112-
_print('Linting $podspecBasename');
113-
}
102+
_print('Linting $podspecBasename');
114103

115104
// Lint plugin as framework (use_frameworks!).
116-
final ProcessResult frameworkResult = await _runPodLint(podspecPath,
117-
runAnalyzer: runAnalyzer, libraryLint: true);
105+
final ProcessResult frameworkResult = await _runPodLint(podspecPath, libraryLint: true);
118106
_print(frameworkResult.stdout);
119107
_print(frameworkResult.stderr);
120108

121109
// Lint plugin as library.
122-
final ProcessResult libraryResult = await _runPodLint(podspecPath,
123-
runAnalyzer: runAnalyzer, libraryLint: false);
110+
final ProcessResult libraryResult = await _runPodLint(podspecPath, libraryLint: false);
124111
_print(libraryResult.stdout);
125112
_print(libraryResult.stderr);
126113

127114
return frameworkResult.exitCode == 0 && libraryResult.exitCode == 0;
128115
}
129116

130117
Future<ProcessResult> _runPodLint(String podspecPath,
131-
{bool runAnalyzer, bool libraryLint}) async {
118+
{bool libraryLint}) async {
132119
final bool allowWarnings = argResults['ignore-warnings']
133120
.contains(p.basenameWithoutExtension(podspecPath));
134121
final List<String> arguments = <String>[
135122
'lib',
136123
'lint',
137124
podspecPath,
138125
if (allowWarnings) '--allow-warnings',
139-
if (runAnalyzer) '--analyze',
140126
if (libraryLint) '--use-libraries'
141127
];
142128

129+
_print('Running "pod ${arguments.join(' ')}"');
143130
return processRunner.run('pod', arguments,
144131
workingDir: packagesDir, stdoutEncoding: utf8, stderrEncoding: utf8);
145132
}

script/tool/lib/src/xctest_command.dart

Lines changed: 36 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,15 @@ import 'package:path/path.dart' as p;
1212
import 'common.dart';
1313

1414
const String _kiOSDestination = 'ios-destination';
15-
const String _kTarget = 'target';
1615
const String _kSkip = 'skip';
1716
const String _kXcodeBuildCommand = 'xcodebuild';
1817
const String _kXCRunCommand = 'xcrun';
1918
const String _kFoundNoSimulatorsMessage =
2019
'Cannot find any available simulators, tests failed';
2120

22-
/// The command to run iOS' XCTests in plugins, this should work for both XCUnitTest and XCUITest targets.
23-
/// The tests target have to be added to the xcode project of the example app. Usually at "example/ios/Runner.xcodeproj".
24-
/// The command takes a "-target" argument which has to match the target of the test target.
25-
/// 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
21+
/// The command to run iOS XCTests in plugins, this should work for both XCUnitTest and XCUITest targets.
22+
/// The tests target have to be added to the xcode project of the example app. Usually at "example/ios/Runner.xcworkspace".
23+
/// The static analyzer is also run.
2624
class XCTestCommand extends PluginCommand {
2725
XCTestCommand(
2826
Directory packagesDir,
@@ -36,10 +34,6 @@ class XCTestCommand extends PluginCommand {
3634
'this is passed to the `-destination` argument in xcodebuild command.\n'
3735
'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.',
3836
);
39-
argParser.addOption(_kTarget,
40-
help: 'The test target.\n'
41-
'This is the xcode project test target. This is passed to the `-scheme` argument in the xcodebuild command. \n'
42-
'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');
4337
argParser.addMultiOption(_kSkip,
4438
help: 'Plugins to skip while running this command. \n');
4539
}
@@ -49,17 +43,10 @@ class XCTestCommand extends PluginCommand {
4943

5044
@override
5145
final String description = 'Runs the xctests in the iOS example apps.\n\n'
52-
'This command requires "flutter" to be in your path.';
46+
'This command requires "flutter" and "xcrun" to be in your path.';
5347

5448
@override
5549
Future<Null> run() async {
56-
if (argResults[_kTarget] == null) {
57-
// TODO(cyanglaz): Automatically find all the available testing schemes if this argument is not specified.
58-
// https://github.com/flutter/flutter/issues/68419
59-
print('--$_kTarget must be specified');
60-
throw ToolExit(1);
61-
}
62-
6350
String destination = argResults[_kiOSDestination];
6451
if (destination == null) {
6552
String simulatorId = await _findAvailableIphoneSimulator();
@@ -72,7 +59,6 @@ class XCTestCommand extends PluginCommand {
7259

7360
checkSharding();
7461

75-
final String target = argResults[_kTarget];
7662
final List<String> skipped = argResults[_kSkip];
7763

7864
List<String> failingPackages = <String>[];
@@ -92,57 +78,14 @@ class XCTestCommand extends PluginCommand {
9278
continue;
9379
}
9480
for (Directory example in getExamplesForPlugin(plugin)) {
95-
// Look for the test scheme in the example app.
96-
print('Look for target named: $_kTarget ...');
97-
final List<String> findSchemeArgs = <String>[
98-
'-project',
99-
'ios/Runner.xcodeproj',
100-
'-list',
101-
'-json'
102-
];
103-
final String completeFindSchemeCommand =
104-
'$_kXcodeBuildCommand ${findSchemeArgs.join(' ')}';
105-
print(completeFindSchemeCommand);
106-
final io.ProcessResult xcodeprojListResult = await processRunner
107-
.run(_kXcodeBuildCommand, findSchemeArgs, workingDir: example);
108-
if (xcodeprojListResult.exitCode != 0) {
109-
print('Error occurred while running "$completeFindSchemeCommand":\n'
110-
'${xcodeprojListResult.stderr}');
111-
failingPackages.add(packageName);
112-
print('\n\n');
113-
continue;
114-
}
115-
116-
final String xcodeprojListOutput = xcodeprojListResult.stdout;
117-
Map<String, dynamic> xcodeprojListOutputJson =
118-
jsonDecode(xcodeprojListOutput);
119-
if (!xcodeprojListOutputJson['project']['targets'].contains(target)) {
120-
failingPackages.add(packageName);
121-
print('$target not configured for $packageName, test failed.');
122-
print(
123-
'Please check the scheme for the test target if it matches the name $target.\n'
124-
'If this plugin does not have an XCTest target, use the $_kSkip flag in the $name command to skip the plugin.');
125-
print('\n\n');
126-
continue;
81+
// Running tests and static analyzer.
82+
print('Running tests and analyzer for $packageName ...');
83+
int exitCode = await _runTests(true, destination, example);
84+
// 66 = there is no test target (this fails fast). Try again with just the analyzer.
85+
if (exitCode == 66) {
86+
print('Tests not found for $packageName, running analyzer only...');
87+
exitCode = await _runTests(false, destination, example);
12788
}
128-
// Found the scheme, running tests
129-
print('Running XCTests:$target for $packageName ...');
130-
final List<String> xctestArgs = <String>[
131-
'test',
132-
'-workspace',
133-
'ios/Runner.xcworkspace',
134-
'-scheme',
135-
target,
136-
'-destination',
137-
destination,
138-
'CODE_SIGN_IDENTITY=""',
139-
'CODE_SIGNING_REQUIRED=NO'
140-
];
141-
final String completeTestCommand =
142-
'$_kXcodeBuildCommand ${xctestArgs.join(' ')}';
143-
print(completeTestCommand);
144-
final int exitCode = await processRunner
145-
.runAndStream(_kXcodeBuildCommand, xctestArgs, workingDir: example);
14689
if (exitCode == 0) {
14790
print('Successfully ran xctest for $packageName');
14891
} else {
@@ -164,6 +107,31 @@ class XCTestCommand extends PluginCommand {
164107
}
165108
}
166109

110+
Future<int> _runTests(bool runTests, String destination, Directory example) {
111+
final List<String> xctestArgs = <String>[
112+
_kXcodeBuildCommand,
113+
if (runTests)
114+
'test',
115+
'analyze',
116+
'-workspace',
117+
'ios/Runner.xcworkspace',
118+
'-configuration',
119+
'Debug',
120+
'-scheme',
121+
'Runner',
122+
'-destination',
123+
destination,
124+
'CODE_SIGN_IDENTITY=""',
125+
'CODE_SIGNING_REQUIRED=NO',
126+
'GCC_TREAT_WARNINGS_AS_ERRORS=YES',
127+
];
128+
final String completeTestCommand =
129+
'$_kXCRunCommand ${xctestArgs.join(' ')}';
130+
print(completeTestCommand);
131+
return processRunner
132+
.runAndStream(_kXCRunCommand, xctestArgs, workingDir: example, exitOnError: false);
133+
}
134+
167135
Future<String> _findAvailableIphoneSimulator() async {
168136
// Find the first available destination if not specified.
169137
final List<String> findSimulatorsArguments = <String>[

script/tool/test/lint_podspecs_command_test.dart

Lines changed: 2 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ void main() {
8181
'lib',
8282
'lint',
8383
p.join(plugin1Dir.path, 'ios', 'plugin1.podspec'),
84-
'--analyze',
8584
'--use-libraries'
8685
],
8786
mockPackagesDir.path),
@@ -91,14 +90,13 @@ void main() {
9190
'lib',
9291
'lint',
9392
p.join(plugin1Dir.path, 'ios', 'plugin1.podspec'),
94-
'--analyze',
9593
],
9694
mockPackagesDir.path),
9795
]),
9896
);
9997

10098
expect(
101-
printedMessages, contains('Linting and analyzing plugin1.podspec'));
99+
printedMessages, contains('Linting plugin1.podspec'));
102100
expect(printedMessages, contains('Foo'));
103101
expect(printedMessages, contains('Bar'));
104102
});
@@ -122,41 +120,6 @@ void main() {
122120
);
123121
});
124122

125-
test('skips analyzer for podspecs with known warnings', () async {
126-
Directory plugin1Dir =
127-
createFakePlugin('plugin1', withExtraFiles: <List<String>>[
128-
<String>['plugin1.podspec'],
129-
]);
130-
131-
await runner.run(<String>['podspecs', '--no-analyze=plugin1']);
132-
133-
expect(
134-
processRunner.recordedCalls,
135-
orderedEquals(<ProcessCall>[
136-
ProcessCall('which', <String>['pod'], mockPackagesDir.path),
137-
ProcessCall(
138-
'pod',
139-
<String>[
140-
'lib',
141-
'lint',
142-
p.join(plugin1Dir.path, 'plugin1.podspec'),
143-
'--use-libraries'
144-
],
145-
mockPackagesDir.path),
146-
ProcessCall(
147-
'pod',
148-
<String>[
149-
'lib',
150-
'lint',
151-
p.join(plugin1Dir.path, 'plugin1.podspec'),
152-
],
153-
mockPackagesDir.path),
154-
]),
155-
);
156-
157-
expect(printedMessages, contains('Linting plugin1.podspec'));
158-
});
159-
160123
test('allow warnings for podspecs with known warnings', () async {
161124
Directory plugin1Dir =
162125
createFakePlugin('plugin1', withExtraFiles: <List<String>>[
@@ -176,7 +139,6 @@ void main() {
176139
'lint',
177140
p.join(plugin1Dir.path, 'plugin1.podspec'),
178141
'--allow-warnings',
179-
'--analyze',
180142
'--use-libraries'
181143
],
182144
mockPackagesDir.path),
@@ -187,14 +149,13 @@ void main() {
187149
'lint',
188150
p.join(plugin1Dir.path, 'plugin1.podspec'),
189151
'--allow-warnings',
190-
'--analyze',
191152
],
192153
mockPackagesDir.path),
193154
]),
194155
);
195156

196157
expect(
197-
printedMessages, contains('Linting and analyzing plugin1.podspec'));
158+
printedMessages, contains('Linting plugin1.podspec'));
198159
});
199160
});
200161
}

0 commit comments

Comments
 (0)