Xcode error message (#94747)
This commit is contained in:
parent
710502c420
commit
1c4128c703
@ -32,6 +32,7 @@ import 'migrations/remove_framework_link_and_embedding_migration.dart';
|
||||
import 'migrations/xcode_build_system_migration.dart';
|
||||
import 'xcode_build_settings.dart';
|
||||
import 'xcodeproj.dart';
|
||||
import 'xcresult.dart';
|
||||
|
||||
class IMobileDevice {
|
||||
IMobileDevice({
|
||||
@ -315,74 +316,97 @@ Future<XcodeBuildResult> buildXcodeProject({
|
||||
|
||||
Status? buildSubStatus;
|
||||
Status? initialBuildStatus;
|
||||
Directory? tempDir;
|
||||
|
||||
File? scriptOutputPipeFile;
|
||||
if (globals.logger.hasTerminal) {
|
||||
tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_build_log_pipe.');
|
||||
scriptOutputPipeFile = tempDir.childFile('pipe_to_stdout');
|
||||
globals.os.makePipe(scriptOutputPipeFile.path);
|
||||
RunResult? buildResult;
|
||||
XCResult? xcResult;
|
||||
|
||||
Future<void> listenToScriptOutputLine() async {
|
||||
final List<String> lines = await scriptOutputPipeFile!.readAsLines();
|
||||
for (final String line in lines) {
|
||||
if (line == 'done' || line == 'all done') {
|
||||
buildSubStatus?.stop();
|
||||
buildSubStatus = null;
|
||||
if (line == 'all done') {
|
||||
// Free pipe file.
|
||||
tempDir?.deleteSync(recursive: true);
|
||||
return;
|
||||
final Directory tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_ios_build_temp_dir');
|
||||
try {
|
||||
if (globals.logger.hasTerminal) {
|
||||
scriptOutputPipeFile = tempDir.childFile('pipe_to_stdout');
|
||||
globals.os.makePipe(scriptOutputPipeFile.path);
|
||||
|
||||
Future<void> listenToScriptOutputLine() async {
|
||||
final List<String> lines = await scriptOutputPipeFile!.readAsLines();
|
||||
for (final String line in lines) {
|
||||
if (line == 'done' || line == 'all done') {
|
||||
buildSubStatus?.stop();
|
||||
buildSubStatus = null;
|
||||
if (line == 'all done') {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
initialBuildStatus?.cancel();
|
||||
initialBuildStatus = null;
|
||||
buildSubStatus = globals.logger.startProgress(
|
||||
line,
|
||||
progressIndicatorPadding: kDefaultStatusPadding - 7,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
initialBuildStatus?.cancel();
|
||||
initialBuildStatus = null;
|
||||
buildSubStatus = globals.logger.startProgress(
|
||||
line,
|
||||
progressIndicatorPadding: kDefaultStatusPadding - 7,
|
||||
);
|
||||
}
|
||||
await listenToScriptOutputLine();
|
||||
}
|
||||
await listenToScriptOutputLine();
|
||||
|
||||
// Trigger the start of the pipe -> stdout loop. Ignore exceptions.
|
||||
unawaited(listenToScriptOutputLine());
|
||||
|
||||
buildCommands.add('SCRIPT_OUTPUT_STREAM_FILE=${scriptOutputPipeFile.absolute.path}');
|
||||
}
|
||||
|
||||
// Trigger the start of the pipe -> stdout loop. Ignore exceptions.
|
||||
unawaited(listenToScriptOutputLine());
|
||||
|
||||
buildCommands.add('SCRIPT_OUTPUT_STREAM_FILE=${scriptOutputPipeFile.absolute.path}');
|
||||
}
|
||||
|
||||
// Don't log analytics for downstream Flutter commands.
|
||||
// e.g. `flutter build bundle`.
|
||||
buildCommands.add('FLUTTER_SUPPRESS_ANALYTICS=true');
|
||||
buildCommands.add('COMPILER_INDEX_STORE_ENABLE=NO');
|
||||
buildCommands.addAll(environmentVariablesAsXcodeBuildSettings(globals.platform));
|
||||
|
||||
if (buildAction == XcodeBuildAction.archive) {
|
||||
buildCommands.addAll(<String>[
|
||||
'-archivePath',
|
||||
globals.fs.path.absolute(app.archiveBundlePath),
|
||||
'archive',
|
||||
'-resultBundlePath',
|
||||
tempDir.childFile(_kResultBundlePath).absolute.path,
|
||||
'-resultBundleVersion',
|
||||
_kResultBundleVersion
|
||||
]);
|
||||
|
||||
// Don't log analytics for downstream Flutter commands.
|
||||
// e.g. `flutter build bundle`.
|
||||
buildCommands.add('FLUTTER_SUPPRESS_ANALYTICS=true');
|
||||
buildCommands.add('COMPILER_INDEX_STORE_ENABLE=NO');
|
||||
buildCommands.addAll(environmentVariablesAsXcodeBuildSettings(globals.platform));
|
||||
|
||||
if (buildAction == XcodeBuildAction.archive) {
|
||||
buildCommands.addAll(<String>[
|
||||
'-archivePath',
|
||||
globals.fs.path.absolute(app.archiveBundlePath),
|
||||
'archive',
|
||||
]);
|
||||
}
|
||||
|
||||
final Stopwatch sw = Stopwatch()..start();
|
||||
initialBuildStatus = globals.logger.startProgress('Running Xcode build...');
|
||||
|
||||
buildResult = await _runBuildWithRetries(buildCommands, app);
|
||||
|
||||
// Notifies listener that no more output is coming.
|
||||
scriptOutputPipeFile?.writeAsStringSync('all done');
|
||||
buildSubStatus?.stop();
|
||||
buildSubStatus = null;
|
||||
initialBuildStatus?.cancel();
|
||||
initialBuildStatus = null;
|
||||
globals.printStatus(
|
||||
'Xcode ${xcodeBuildActionToString(buildAction)} done.'.padRight(kDefaultStatusPadding + 1)
|
||||
+ getElapsedAsSeconds(sw.elapsed).padLeft(5),
|
||||
);
|
||||
globals.flutterUsage.sendTiming(xcodeBuildActionToString(buildAction), 'xcode-ios', Duration(milliseconds: sw.elapsedMilliseconds));
|
||||
|
||||
if (tempDir.existsSync()) {
|
||||
// Display additional warning and error message from xcresult bundle.
|
||||
final Directory resultBundle = tempDir.childDirectory(_kResultBundlePath);
|
||||
if (!resultBundle.existsSync()) {
|
||||
globals.printTrace('The xcresult bundle are not generated. Displaying xcresult is disabled.');
|
||||
} else {
|
||||
// Discard unwanted errors. See: https://github.com/flutter/flutter/issues/95354
|
||||
final XCResultIssueDiscarder warningDiscarder = XCResultIssueDiscarder(typeMatcher: XCResultIssueType.warning);
|
||||
final XCResultIssueDiscarder dartBuildErrorDiscarder = XCResultIssueDiscarder(messageMatcher: RegExp(r'Command PhaseScriptExecution failed with a nonzero exit code'));
|
||||
final XCResultGenerator xcResultGenerator = XCResultGenerator(resultPath: resultBundle.absolute.path, xcode: globals.xcode!, processUtils: globals.processUtils);
|
||||
xcResult = await xcResultGenerator.generate(issueDiscarders: <XCResultIssueDiscarder>[warningDiscarder, dartBuildErrorDiscarder]);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
tempDir.deleteSync(recursive: true);
|
||||
}
|
||||
|
||||
final Stopwatch sw = Stopwatch()..start();
|
||||
initialBuildStatus = globals.logger.startProgress('Running Xcode build...');
|
||||
|
||||
final RunResult? buildResult = await _runBuildWithRetries(buildCommands, app);
|
||||
|
||||
// Notifies listener that no more output is coming.
|
||||
scriptOutputPipeFile?.writeAsStringSync('all done');
|
||||
buildSubStatus?.stop();
|
||||
buildSubStatus = null;
|
||||
initialBuildStatus?.cancel();
|
||||
initialBuildStatus = null;
|
||||
globals.printStatus(
|
||||
'Xcode ${xcodeBuildActionToString(buildAction)} done.'.padRight(kDefaultStatusPadding + 1)
|
||||
+ getElapsedAsSeconds(sw.elapsed).padLeft(5),
|
||||
);
|
||||
globals.flutterUsage.sendTiming(xcodeBuildActionToString(buildAction), 'xcode-ios', Duration(milliseconds: sw.elapsedMilliseconds));
|
||||
|
||||
if (buildResult != null && buildResult.exitCode != 0) {
|
||||
globals.printStatus('Failed to build iOS app');
|
||||
if (buildResult.stderr.isNotEmpty) {
|
||||
@ -403,6 +427,7 @@ Future<XcodeBuildResult> buildXcodeProject({
|
||||
environmentType: environmentType,
|
||||
buildSettings: buildSettings,
|
||||
),
|
||||
xcResult: xcResult,
|
||||
);
|
||||
} else {
|
||||
String? outputDir;
|
||||
@ -466,6 +491,7 @@ Future<XcodeBuildResult> buildXcodeProject({
|
||||
environmentType: environmentType,
|
||||
buildSettings: buildSettings,
|
||||
),
|
||||
xcResult: xcResult,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -585,16 +611,19 @@ Future<void> diagnoseXcodeBuildFailure(XcodeBuildResult result, Usage flutterUsa
|
||||
logger.printError(' open ios/Runner.xcworkspace');
|
||||
return;
|
||||
}
|
||||
if (result.stdout?.contains('Code Sign error') == true) {
|
||||
logger.printError('');
|
||||
logger.printError('It appears that there was a problem signing your application prior to installation on the device.');
|
||||
logger.printError('');
|
||||
logger.printError('Verify that the Bundle Identifier in your project is your signing id in Xcode');
|
||||
logger.printError(' open ios/Runner.xcworkspace');
|
||||
logger.printError('');
|
||||
logger.printError("Also try selecting 'Product > Build' to fix the problem:");
|
||||
|
||||
// Handle xcresult errors.
|
||||
final XCResult? xcResult = result.xcResult;
|
||||
if (xcResult == null) {
|
||||
return;
|
||||
}
|
||||
if (!xcResult.parseSuccess) {
|
||||
globals.printTrace('XCResult parsing error: ${xcResult.parsingErrorMessage}');
|
||||
return;
|
||||
}
|
||||
for (final XCResultIssue issue in xcResult.issues) {
|
||||
_handleXCResultIssue(issue: issue, logger: logger);
|
||||
}
|
||||
}
|
||||
|
||||
/// xcodebuild <buildaction> parameter (see man xcodebuild for details).
|
||||
@ -618,6 +647,7 @@ class XcodeBuildResult {
|
||||
this.stdout,
|
||||
this.stderr,
|
||||
this.xcodeBuildExecution,
|
||||
this.xcResult
|
||||
});
|
||||
|
||||
final bool success;
|
||||
@ -626,6 +656,10 @@ class XcodeBuildResult {
|
||||
final String? stderr;
|
||||
/// The invocation of the build that resulted in this result instance.
|
||||
final XcodeBuildExecution? xcodeBuildExecution;
|
||||
/// Parsed information in xcresult bundle.
|
||||
///
|
||||
/// Can be null if the bundle is not created during build.
|
||||
final XCResult? xcResult;
|
||||
}
|
||||
|
||||
/// Describes an invocation of a Xcode build command.
|
||||
@ -686,3 +720,38 @@ bool upgradePbxProjWithFlutterAssets(IosProject project, Logger logger) {
|
||||
xcodeProjectFile.writeAsStringSync(buffer.toString());
|
||||
return true;
|
||||
}
|
||||
|
||||
void _handleXCResultIssue({required XCResultIssue issue, required Logger logger}) {
|
||||
// Issue summary from xcresult.
|
||||
final StringBuffer issueSummaryBuffer = StringBuffer();
|
||||
issueSummaryBuffer.write(issue.subType ?? 'Unknown');
|
||||
issueSummaryBuffer.write(' (Xcode): ');
|
||||
issueSummaryBuffer.writeln(issue.message ?? '');
|
||||
if (issue.location != null ) {
|
||||
issueSummaryBuffer.writeln(issue.location);
|
||||
}
|
||||
final String issueSummary = issueSummaryBuffer.toString();
|
||||
|
||||
switch (issue.type) {
|
||||
case XCResultIssueType.error:
|
||||
logger.printError(issueSummary);
|
||||
break;
|
||||
case XCResultIssueType.warning:
|
||||
logger.printWarning(issueSummary);
|
||||
break;
|
||||
}
|
||||
|
||||
// Add more custom output for flutter users.
|
||||
if (issue.message != null && issue.message!.toLowerCase().contains('provisioning profile')) {
|
||||
logger.printError('');
|
||||
logger.printError('It appears that there was a problem signing your application prior to installation on the device.');
|
||||
logger.printError('');
|
||||
logger.printError('Verify that the Bundle Identifier in your project is your signing id in Xcode');
|
||||
logger.printError(' open ios/Runner.xcworkspace');
|
||||
logger.printError('');
|
||||
logger.printError("Also try selecting 'Product > Build' to fix the problem:");
|
||||
}
|
||||
}
|
||||
|
||||
const String _kResultBundlePath = 'temporary_xcresult_bundle';
|
||||
const String _kResultBundleVersion = '3';
|
||||
|
@ -545,6 +545,7 @@ class IOSSimulator extends Device {
|
||||
deviceID: id,
|
||||
);
|
||||
if (!buildResult.success) {
|
||||
await diagnoseXcodeBuildFailure(buildResult, globals.flutterUsage, globals.logger);
|
||||
throwToolExit('Could not build the application for the simulator.');
|
||||
}
|
||||
|
||||
|
@ -78,31 +78,8 @@ class XCResult {
|
||||
/// Parse the `resultJson` and stores useful informations in the returned `XCResult`.
|
||||
factory XCResult({required Map<String, Object?> resultJson, List<XCResultIssueDiscarder> issueDiscarders = const <XCResultIssueDiscarder>[]}) {
|
||||
final List<XCResultIssue> issues = <XCResultIssue>[];
|
||||
final Object? actionsMap = resultJson['actions'];
|
||||
if (actionsMap == null || actionsMap is! Map<String, Object?>) {
|
||||
return XCResult.failed(
|
||||
errorMessage: 'xcresult parser: Failed to parse the actions map.');
|
||||
}
|
||||
final Object? actionValueList = actionsMap['_values'];
|
||||
if (actionValueList == null ||
|
||||
actionValueList is! List<Object?> ||
|
||||
actionValueList.isEmpty) {
|
||||
return XCResult.failed(
|
||||
errorMessage: 'xcresult parser: Failed to parse the actions map.');
|
||||
}
|
||||
final Object? actionMap = actionValueList.first;
|
||||
if (actionMap == null || actionMap is! Map<String, Object?>) {
|
||||
return XCResult.failed(
|
||||
errorMessage:
|
||||
'xcresult parser: Failed to parse the first action map.');
|
||||
}
|
||||
final Object? buildResultMap = actionMap['buildResult'];
|
||||
if (buildResultMap == null || buildResultMap is! Map<String, Object?>) {
|
||||
return XCResult.failed(
|
||||
errorMessage:
|
||||
'xcresult parser: Failed to parse the buildResult map.');
|
||||
}
|
||||
final Object? issuesMap = buildResultMap['issues'];
|
||||
|
||||
final Object? issuesMap = resultJson['issues'];
|
||||
if (issuesMap == null || issuesMap is! Map<String, Object?>) {
|
||||
return XCResult.failed(
|
||||
errorMessage: 'xcresult parser: Failed to parse the issues map.');
|
||||
|
@ -14,6 +14,7 @@ import 'package:flutter_tools/src/commands/build_ios.dart';
|
||||
import 'package:flutter_tools/src/ios/xcodeproj.dart';
|
||||
import 'package:flutter_tools/src/reporting/reporting.dart';
|
||||
|
||||
import '../../general.shard/ios/xcresult_test_data.dart';
|
||||
import '../../src/common.dart';
|
||||
import '../../src/context.dart';
|
||||
import '../../src/test_flutter_command_runner.dart';
|
||||
@ -88,12 +89,29 @@ void main() {
|
||||
'build/ios/Release-iphoneos/Runner.app',
|
||||
'build/ios/iphoneos',
|
||||
],
|
||||
onRun: onRun);
|
||||
onRun: onRun,
|
||||
);
|
||||
}
|
||||
|
||||
FakeCommand _setUpXCResultCommand({String stdout = '', void Function() onRun}) {
|
||||
return FakeCommand(
|
||||
command: const <String>[
|
||||
'xcrun',
|
||||
'xcresulttool',
|
||||
'get',
|
||||
'--path',
|
||||
_xcBundleFilePath,
|
||||
'--format',
|
||||
'json',
|
||||
],
|
||||
stdout: stdout,
|
||||
onRun: onRun,
|
||||
);
|
||||
}
|
||||
|
||||
// Creates a FakeCommand for the xcodebuild call to build the app
|
||||
// in the given configuration.
|
||||
FakeCommand _setUpFakeXcodeBuildHandler({ bool verbose = false, bool simulator = false, void Function() onRun }) {
|
||||
FakeCommand _setUpFakeXcodeBuildHandler({ bool verbose = false, bool simulator = false, int exitCode = 0, void Function() onRun }) {
|
||||
return FakeCommand(
|
||||
command: <String>[
|
||||
'xcrun',
|
||||
@ -120,6 +138,8 @@ void main() {
|
||||
'-destination',
|
||||
'generic/platform=iOS',
|
||||
],
|
||||
'-resultBundlePath', _xcBundleFilePath,
|
||||
'-resultBundleVersion', '3',
|
||||
'FLUTTER_SUPPRESS_ANALYTICS=true',
|
||||
'COMPILER_INDEX_STORE_ENABLE=NO',
|
||||
],
|
||||
@ -127,6 +147,7 @@ void main() {
|
||||
TARGET_BUILD_DIR=build/ios/Release-iphoneos
|
||||
WRAPPER_NAME=Runner.app
|
||||
''',
|
||||
exitCode: exitCode,
|
||||
onRun: onRun,
|
||||
);
|
||||
}
|
||||
@ -281,4 +302,257 @@ void main() {
|
||||
Usage: () => usage,
|
||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||
});
|
||||
group('xcresults device', () {
|
||||
testUsingContext('Trace error if xcresult is empty.', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await expectLater(
|
||||
createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']),
|
||||
throwsToolExit(),
|
||||
);
|
||||
|
||||
expect(testLogger.traceText, contains('xcresult parser: Unrecognized top level json format.'));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||
xattrCommand,
|
||||
_setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
|
||||
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
|
||||
}),
|
||||
_setUpXCResultCommand(),
|
||||
_setUpRsyncCommand(),
|
||||
]),
|
||||
Platform: () => macosPlatform,
|
||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||
});
|
||||
|
||||
testUsingContext('Display xcresult issues on console if parsed.', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await expectLater(
|
||||
createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']),
|
||||
throwsToolExit(),
|
||||
);
|
||||
|
||||
expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'"));
|
||||
expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||
xattrCommand,
|
||||
_setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
|
||||
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
|
||||
}),
|
||||
_setUpXCResultCommand(stdout: kSampleResultJsonWithIssues),
|
||||
_setUpRsyncCommand(),
|
||||
]),
|
||||
Platform: () => macosPlatform,
|
||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||
});
|
||||
|
||||
testUsingContext('Do not display xcresult issues that needs to be discarded.', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await expectLater(
|
||||
createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']),
|
||||
throwsToolExit(),
|
||||
);
|
||||
|
||||
expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'"));
|
||||
expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'));
|
||||
expect(testLogger.errorText, isNot(contains('Command PhaseScriptExecution failed with a nonzero exit code')));
|
||||
expect(testLogger.warningText, isNot(contains("The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99.")));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||
xattrCommand,
|
||||
_setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
|
||||
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
|
||||
}),
|
||||
_setUpXCResultCommand(stdout: kSampleResultJsonWithIssuesToBeDiscarded),
|
||||
_setUpRsyncCommand(),
|
||||
]),
|
||||
Platform: () => macosPlatform,
|
||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||
});
|
||||
|
||||
testUsingContext('Trace if xcresult bundle does not exist.', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await expectLater(
|
||||
createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']),
|
||||
throwsToolExit(),
|
||||
);
|
||||
|
||||
expect(testLogger.traceText, contains('The xcresult bundle are not generated. Displaying xcresult is disabled.'));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||
xattrCommand,
|
||||
_setUpFakeXcodeBuildHandler(exitCode: 1),
|
||||
_setUpXCResultCommand(stdout: kSampleResultJsonWithIssues),
|
||||
_setUpRsyncCommand(),
|
||||
]),
|
||||
Platform: () => macosPlatform,
|
||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||
});
|
||||
|
||||
testUsingContext('Extra error message for provision profile issue in xcresulb bundle.', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await expectLater(
|
||||
createTestCommandRunner(command).run(const <String>['build', 'ios', '--no-pub']),
|
||||
throwsToolExit(),
|
||||
);
|
||||
|
||||
expect(testLogger.errorText, contains('Some Provisioning profile issue.'));
|
||||
expect(testLogger.errorText, contains('It appears that there was a problem signing your application prior to installation on the device.'));
|
||||
expect(testLogger.errorText, contains('Verify that the Bundle Identifier in your project is your signing id in Xcode'));
|
||||
expect(testLogger.errorText, contains('open ios/Runner.xcworkspace'));
|
||||
expect(testLogger.errorText, contains("Also try selecting 'Product > Build' to fix the problem:"));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||
xattrCommand,
|
||||
_setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
|
||||
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
|
||||
}),
|
||||
_setUpXCResultCommand(stdout: kSampleResultJsonWithProvisionIssue),
|
||||
_setUpRsyncCommand(),
|
||||
]),
|
||||
Platform: () => macosPlatform,
|
||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||
});
|
||||
});
|
||||
|
||||
group('xcresults simulator', () {
|
||||
testUsingContext('Trace error if xcresult is empty.', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await expectLater(
|
||||
createTestCommandRunner(command).run(const <String>['build', 'ios', '--simulator', '--no-pub']),
|
||||
throwsToolExit(),
|
||||
);
|
||||
|
||||
expect(testLogger.traceText, contains('xcresult parser: Unrecognized top level json format.'));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||
xattrCommand,
|
||||
_setUpFakeXcodeBuildHandler(
|
||||
simulator: true,
|
||||
exitCode: 1,
|
||||
onRun: () {
|
||||
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
|
||||
},
|
||||
),
|
||||
_setUpXCResultCommand(),
|
||||
_setUpRsyncCommand(),
|
||||
]),
|
||||
Platform: () => macosPlatform,
|
||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||
});
|
||||
|
||||
testUsingContext('Display xcresult issues on console if parsed.', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await expectLater(
|
||||
createTestCommandRunner(command).run(const <String>['build', 'ios', '--simulator', '--no-pub']),
|
||||
throwsToolExit(),
|
||||
);
|
||||
|
||||
expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'"));
|
||||
expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||
xattrCommand,
|
||||
_setUpFakeXcodeBuildHandler(
|
||||
simulator: true,
|
||||
exitCode: 1,
|
||||
onRun: () {
|
||||
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
|
||||
},
|
||||
),
|
||||
_setUpXCResultCommand(stdout: kSampleResultJsonWithIssues),
|
||||
_setUpRsyncCommand(),
|
||||
]),
|
||||
Platform: () => macosPlatform,
|
||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||
});
|
||||
|
||||
testUsingContext('Do not display xcresult issues that needs to be discarded.', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await expectLater(
|
||||
createTestCommandRunner(command).run(const <String>['build', 'ios', '--simulator', '--no-pub']),
|
||||
throwsToolExit(),
|
||||
);
|
||||
|
||||
expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'"));
|
||||
expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'));
|
||||
expect(testLogger.errorText, isNot(contains('Command PhaseScriptExecution failed with a nonzero exit code')));
|
||||
expect(testLogger.warningText, isNot(contains("The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99.")));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||
xattrCommand,
|
||||
_setUpFakeXcodeBuildHandler(
|
||||
simulator: true,
|
||||
exitCode: 1,
|
||||
onRun: () {
|
||||
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
|
||||
},
|
||||
),
|
||||
_setUpXCResultCommand(stdout: kSampleResultJsonWithIssuesToBeDiscarded),
|
||||
_setUpRsyncCommand(),
|
||||
]),
|
||||
Platform: () => macosPlatform,
|
||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||
});
|
||||
|
||||
testUsingContext('Trace if xcresult bundle does not exist.', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await expectLater(
|
||||
createTestCommandRunner(command).run(const <String>['build', 'ios', '--simulator', '--no-pub']),
|
||||
throwsToolExit(),
|
||||
);
|
||||
|
||||
expect(testLogger.traceText, contains('The xcresult bundle are not generated. Displaying xcresult is disabled.'));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||
xattrCommand,
|
||||
_setUpFakeXcodeBuildHandler(
|
||||
simulator: true,
|
||||
exitCode: 1,
|
||||
),
|
||||
_setUpXCResultCommand(stdout: kSampleResultJsonWithIssues),
|
||||
_setUpRsyncCommand(),
|
||||
]),
|
||||
Platform: () => macosPlatform,
|
||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const String _xcBundleFilePath = '/.tmp_rand0/flutter_ios_build_temp_dirrand0/temporary_xcresult_bundle';
|
||||
|
@ -15,6 +15,7 @@ import 'package:flutter_tools/src/commands/build_ios.dart';
|
||||
import 'package:flutter_tools/src/ios/xcodeproj.dart';
|
||||
import 'package:flutter_tools/src/reporting/reporting.dart';
|
||||
|
||||
import '../../general.shard/ios/xcresult_test_data.dart';
|
||||
import '../../src/common.dart';
|
||||
import '../../src/context.dart';
|
||||
import '../../src/test_flutter_command_runner.dart';
|
||||
@ -62,27 +63,43 @@ void main() {
|
||||
});
|
||||
|
||||
// Sets up the minimal mock project files necessary to look like a Flutter project.
|
||||
void createCoreMockProjectFiles() {
|
||||
void _createCoreMockProjectFiles() {
|
||||
fileSystem.file('pubspec.yaml').createSync();
|
||||
fileSystem.file('.packages').createSync();
|
||||
fileSystem.file(fileSystem.path.join('lib', 'main.dart')).createSync(recursive: true);
|
||||
}
|
||||
|
||||
// Sets up the minimal mock project files necessary for iOS builds to succeed.
|
||||
void createMinimalMockProjectFiles() {
|
||||
void _createMinimalMockProjectFiles() {
|
||||
fileSystem.directory(fileSystem.path.join('ios', 'Runner.xcodeproj')).createSync(recursive: true);
|
||||
fileSystem.directory(fileSystem.path.join('ios', 'Runner.xcworkspace')).createSync(recursive: true);
|
||||
fileSystem.file(fileSystem.path.join('ios', 'Runner.xcodeproj', 'project.pbxproj')).createSync();
|
||||
createCoreMockProjectFiles();
|
||||
_createCoreMockProjectFiles();
|
||||
}
|
||||
|
||||
const FakeCommand xattrCommand = FakeCommand(command: <String>[
|
||||
'xattr', '-r', '-d', 'com.apple.FinderInfo', '/'
|
||||
]);
|
||||
|
||||
FakeCommand _setUpXCResultCommand({String stdout = '', void Function() onRun}) {
|
||||
return FakeCommand(
|
||||
command: const <String>[
|
||||
'xcrun',
|
||||
'xcresulttool',
|
||||
'get',
|
||||
'--path',
|
||||
_xcBundleFilePath,
|
||||
'--format',
|
||||
'json',
|
||||
],
|
||||
stdout: stdout,
|
||||
onRun: onRun,
|
||||
);
|
||||
}
|
||||
|
||||
// Creates a FakeCommand for the xcodebuild call to build the app
|
||||
// in the given configuration.
|
||||
FakeCommand setUpFakeXcodeBuildHandler({ bool verbose = false, void Function() onRun }) {
|
||||
FakeCommand _setUpFakeXcodeBuildHandler({ bool verbose = false, int exitCode = 0, void Function() onRun }) {
|
||||
return FakeCommand(
|
||||
command: <String>[
|
||||
'xcrun',
|
||||
@ -97,12 +114,15 @@ void main() {
|
||||
'-sdk', 'iphoneos',
|
||||
'-destination',
|
||||
'generic/platform=iOS',
|
||||
'-resultBundlePath', '/.tmp_rand0/flutter_ios_build_temp_dirrand0/temporary_xcresult_bundle',
|
||||
'-resultBundleVersion', '3',
|
||||
'FLUTTER_SUPPRESS_ANALYTICS=true',
|
||||
'COMPILER_INDEX_STORE_ENABLE=NO',
|
||||
'-archivePath', '/build/ios/archive/Runner',
|
||||
'archive',
|
||||
],
|
||||
stdout: 'STDOUT STUFF',
|
||||
exitCode: exitCode,
|
||||
onRun: onRun,
|
||||
);
|
||||
}
|
||||
@ -125,7 +145,7 @@ void main() {
|
||||
|
||||
testUsingContext('ipa build fails when there is no ios project', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
createCoreMockProjectFiles();
|
||||
_createCoreMockProjectFiles();
|
||||
|
||||
expect(createTestCommandRunner(command).run(
|
||||
const <String>['build', 'ipa', '--no-pub']
|
||||
@ -139,7 +159,7 @@ void main() {
|
||||
|
||||
testUsingContext('ipa build fails in debug with code analysis', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
createCoreMockProjectFiles();
|
||||
_createCoreMockProjectFiles();
|
||||
|
||||
expect(createTestCommandRunner(command).run(
|
||||
const <String>['build', 'ipa', '--no-pub', '--debug', '--analyze-size']
|
||||
@ -172,7 +192,7 @@ void main() {
|
||||
testUsingContext('ipa build fails when export plist does not exist',
|
||||
() async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
createMinimalMockProjectFiles();
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await expectToolExitLater(
|
||||
createTestCommandRunner(command).run(<String>[
|
||||
@ -195,7 +215,7 @@ void main() {
|
||||
testUsingContext('ipa build fails when export plist is not a file', () async {
|
||||
final Directory bogus = fileSystem.directory('bogus')..createSync();
|
||||
final BuildCommand command = BuildCommand();
|
||||
createMinimalMockProjectFiles();
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await expectToolExitLater(
|
||||
createTestCommandRunner(command).run(<String>[
|
||||
@ -217,7 +237,7 @@ void main() {
|
||||
|
||||
testUsingContext('ipa build invokes xcode build', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
createMinimalMockProjectFiles();
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await createTestCommandRunner(command).run(
|
||||
const <String>['build', 'ipa', '--no-pub']
|
||||
@ -227,7 +247,7 @@ void main() {
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||
xattrCommand,
|
||||
setUpFakeXcodeBuildHandler(),
|
||||
_setUpFakeXcodeBuildHandler(),
|
||||
]),
|
||||
Platform: () => macosPlatform,
|
||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||
@ -235,7 +255,7 @@ void main() {
|
||||
|
||||
testUsingContext('ipa build invokes xcode build with verbosity', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
createMinimalMockProjectFiles();
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await createTestCommandRunner(command).run(
|
||||
const <String>['build', 'ipa', '--no-pub', '-v']
|
||||
@ -244,7 +264,7 @@ void main() {
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||
xattrCommand,
|
||||
setUpFakeXcodeBuildHandler(verbose: true),
|
||||
_setUpFakeXcodeBuildHandler(verbose: true),
|
||||
]),
|
||||
Platform: () => macosPlatform,
|
||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||
@ -252,7 +272,7 @@ void main() {
|
||||
|
||||
testUsingContext('code size analysis fails when app not found', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
createMinimalMockProjectFiles();
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await expectToolExitLater(
|
||||
createTestCommandRunner(command).run(
|
||||
@ -270,7 +290,7 @@ void main() {
|
||||
|
||||
testUsingContext('Performs code size analysis and sends analytics', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
createMinimalMockProjectFiles();
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
fileSystem.file('build/ios/archive/Runner.xcarchive/Products/Applications/Runner.app/Frameworks/App.framework/App')
|
||||
..createSync(recursive: true)
|
||||
@ -289,7 +309,7 @@ void main() {
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||
xattrCommand,
|
||||
setUpFakeXcodeBuildHandler(onRun: () {
|
||||
_setUpFakeXcodeBuildHandler(onRun: () {
|
||||
fileSystem.file('build/flutter_size_01/snapshot.arm64.json')
|
||||
..createSync(recursive: true)
|
||||
..writeAsStringSync('''
|
||||
@ -318,7 +338,7 @@ void main() {
|
||||
final File exportOptions = fileSystem.file('ExportOptions.plist')
|
||||
..createSync();
|
||||
final BuildCommand command = BuildCommand();
|
||||
createMinimalMockProjectFiles();
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await createTestCommandRunner(command).run(
|
||||
<String>[
|
||||
@ -335,7 +355,7 @@ void main() {
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||
xattrCommand,
|
||||
setUpFakeXcodeBuildHandler(),
|
||||
_setUpFakeXcodeBuildHandler(),
|
||||
exportArchiveCommand,
|
||||
]),
|
||||
Platform: () => macosPlatform,
|
||||
@ -343,4 +363,133 @@ void main() {
|
||||
XcodeProjectInterpreter: () =>
|
||||
FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||
});
|
||||
|
||||
testUsingContext('Trace error if xcresult is empty.', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await expectLater(
|
||||
createTestCommandRunner(command).run(const <String>['build', 'ipa', '--no-pub']),
|
||||
throwsToolExit(),
|
||||
);
|
||||
|
||||
expect(testLogger.traceText, contains('xcresult parser: Unrecognized top level json format.'));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||
xattrCommand,
|
||||
_setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
|
||||
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
|
||||
}),
|
||||
_setUpXCResultCommand(),
|
||||
]),
|
||||
Platform: () => macosPlatform,
|
||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||
});
|
||||
|
||||
testUsingContext('Display xcresult issues on console if parsed.', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await expectLater(
|
||||
createTestCommandRunner(command).run(const <String>['build', 'ipa', '--no-pub']),
|
||||
throwsToolExit(),
|
||||
);
|
||||
|
||||
expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'"));
|
||||
expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||
xattrCommand,
|
||||
_setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
|
||||
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
|
||||
}),
|
||||
_setUpXCResultCommand(stdout: kSampleResultJsonWithIssues),
|
||||
]),
|
||||
Platform: () => macosPlatform,
|
||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||
});
|
||||
|
||||
testUsingContext('Do not display xcresult issues that needs to be discarded.', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await expectLater(
|
||||
createTestCommandRunner(command).run(const <String>['build', 'ipa', '--no-pub']),
|
||||
throwsToolExit(),
|
||||
);
|
||||
|
||||
expect(testLogger.errorText, contains("Use of undeclared identifier 'asdas'"));
|
||||
expect(testLogger.errorText, contains('/Users/m/Projects/test_create/ios/Runner/AppDelegate.m:7:56'));
|
||||
expect(testLogger.errorText, isNot(contains('Command PhaseScriptExecution failed with a nonzero exit code')));
|
||||
expect(testLogger.warningText, isNot(contains("The iOS deployment target 'IPHONEOS_DEPLOYMENT_TARGET' is set to 8.0, but the range of supported deployment target versions is 9.0 to 14.0.99.")));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||
xattrCommand,
|
||||
_setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
|
||||
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
|
||||
}),
|
||||
_setUpXCResultCommand(stdout: kSampleResultJsonWithIssuesToBeDiscarded),
|
||||
]),
|
||||
Platform: () => macosPlatform,
|
||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||
});
|
||||
|
||||
testUsingContext('Trace if xcresult bundle does not exist.', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await expectLater(
|
||||
createTestCommandRunner(command).run(const <String>['build', 'ipa', '--no-pub']),
|
||||
throwsToolExit(),
|
||||
);
|
||||
|
||||
expect(testLogger.traceText, contains('The xcresult bundle are not generated. Displaying xcresult is disabled.'));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||
xattrCommand,
|
||||
_setUpFakeXcodeBuildHandler(exitCode: 1),
|
||||
_setUpXCResultCommand(stdout: kSampleResultJsonWithIssues),
|
||||
]),
|
||||
Platform: () => macosPlatform,
|
||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||
});
|
||||
|
||||
|
||||
testUsingContext('Extra error message for provision profile issue in xcresulb bundle.', () async {
|
||||
final BuildCommand command = BuildCommand();
|
||||
|
||||
_createMinimalMockProjectFiles();
|
||||
|
||||
await expectLater(
|
||||
createTestCommandRunner(command).run(const <String>['build', 'ipa', '--no-pub']),
|
||||
throwsToolExit(),
|
||||
);
|
||||
|
||||
expect(testLogger.errorText, contains('Some Provisioning profile issue.'));
|
||||
expect(testLogger.errorText, contains('It appears that there was a problem signing your application prior to installation on the device.'));
|
||||
expect(testLogger.errorText, contains('Verify that the Bundle Identifier in your project is your signing id in Xcode'));
|
||||
expect(testLogger.errorText, contains('open ios/Runner.xcworkspace'));
|
||||
expect(testLogger.errorText, contains("Also try selecting 'Product > Build' to fix the problem:"));
|
||||
}, overrides: <Type, Generator>{
|
||||
FileSystem: () => fileSystem,
|
||||
ProcessManager: () => FakeProcessManager.list(<FakeCommand>[
|
||||
xattrCommand,
|
||||
_setUpFakeXcodeBuildHandler(exitCode: 1, onRun: () {
|
||||
fileSystem.systemTempDirectory.childDirectory(_xcBundleFilePath).createSync();
|
||||
}),
|
||||
_setUpXCResultCommand(stdout: kSampleResultJsonWithProvisionIssue),
|
||||
]),
|
||||
Platform: () => macosPlatform,
|
||||
XcodeProjectInterpreter: () => FakeXcodeProjectInterpreterWithBuildSettings(),
|
||||
});
|
||||
}
|
||||
|
||||
const String _xcBundleFilePath = '/.tmp_rand0/flutter_ios_build_temp_dirrand0/temporary_xcresult_bundle';
|
||||
|
@ -58,6 +58,8 @@ const List<String> kRunReleaseArgs = <String>[
|
||||
'id=123',
|
||||
'ONLY_ACTIVE_ARCH=YES',
|
||||
'ARCHS=arm64',
|
||||
'-resultBundlePath', '/.tmp_rand0/flutter_ios_build_temp_dirrand0/temporary_xcresult_bundle',
|
||||
'-resultBundleVersion', '3',
|
||||
'FLUTTER_SUPPRESS_ANALYTICS=true',
|
||||
'COMPILER_INDEX_STORE_ENABLE=NO',
|
||||
];
|
||||
|
@ -240,58 +240,17 @@ void main() {
|
||||
'xcresult parser: Unrecognized top level json format.');
|
||||
});
|
||||
|
||||
testWithoutContext('error: fail to parse actions map', () async {
|
||||
testWithoutContext('error: fail to parse issue map', () async {
|
||||
final XCResultGenerator generator = _setupGenerator(resultJson: '{}');
|
||||
|
||||
final XCResult result = await generator.generate();
|
||||
expect(result.issues.length, 0);
|
||||
expect(result.parseSuccess, false);
|
||||
expect(result.parsingErrorMessage,
|
||||
'xcresult parser: Failed to parse the actions map.');
|
||||
'xcresult parser: Failed to parse the issues map.');
|
||||
});
|
||||
|
||||
testWithoutContext('error: empty actions map', () async {
|
||||
final XCResultGenerator generator =
|
||||
_setupGenerator(resultJson: kSampleResultJsonEmptyActionsMap);
|
||||
|
||||
final XCResult result = await generator.generate();
|
||||
expect(result.issues.length, 0);
|
||||
expect(result.parseSuccess, false);
|
||||
expect(result.parsingErrorMessage,
|
||||
'xcresult parser: Failed to parse the actions map.');
|
||||
});
|
||||
|
||||
testWithoutContext('error: empty actions map', () async {
|
||||
final XCResultGenerator generator = _setupGenerator(resultJson: kSampleResultJsonEmptyActionsMap);
|
||||
|
||||
final XCResult result = await generator.generate();
|
||||
expect(result.issues.length, 0);
|
||||
expect(result.parseSuccess, false);
|
||||
expect(result.parsingErrorMessage,
|
||||
'xcresult parser: Failed to parse the actions map.');
|
||||
});
|
||||
|
||||
testWithoutContext('error: empty actions map', () async {
|
||||
final XCResultGenerator generator = _setupGenerator(resultJson: kSampleResultJsonInvalidActionMap);
|
||||
|
||||
final XCResult result = await generator.generate();
|
||||
expect(result.issues.length, 0);
|
||||
expect(result.parseSuccess, false);
|
||||
expect(result.parsingErrorMessage,
|
||||
'xcresult parser: Failed to parse the first action map.');
|
||||
});
|
||||
|
||||
testWithoutContext('error: empty actions map', () async {
|
||||
final XCResultGenerator generator = _setupGenerator(resultJson: kSampleResultJsonInvalidBuildResultMap);
|
||||
|
||||
final XCResult result = await generator.generate();
|
||||
expect(result.issues.length, 0);
|
||||
expect(result.parseSuccess, false);
|
||||
expect(result.parsingErrorMessage,
|
||||
'xcresult parser: Failed to parse the buildResult map.');
|
||||
});
|
||||
|
||||
testWithoutContext('error: empty actions map', () async {
|
||||
testWithoutContext('error: invalid issue map', () async {
|
||||
final XCResultGenerator generator = _setupGenerator(resultJson: kSampleResultJsonInvalidIssuesMap);
|
||||
|
||||
final XCResult result = await generator.generate();
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user