Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions packages/flutter_tools/lib/src/context_runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import 'macos/cocoapods.dart';
import 'macos/cocoapods_validator.dart';
import 'macos/macos_workflow.dart';
import 'macos/xcode.dart';
import 'macos/xcode_validator.dart';
import 'mdns_discovery.dart';
import 'persistent_tool_state.dart';
import 'reporting/reporting.dart';
Expand Down Expand Up @@ -226,7 +225,6 @@ Future<T> runInContext<T>(
fileSystem: globals.fs,
terminal: globals.terminal,
),
XcodeValidator: () => const XcodeValidator(),
},
);
}
2 changes: 1 addition & 1 deletion packages/flutter_tools/lib/src/doctor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ class _DefaultDoctorValidatorsProvider implements DoctorValidatorsProvider {
if (androidWorkflow.appliesToHostPlatform)
GroupedValidator(<DoctorValidator>[androidValidator, androidLicenseValidator]),
if (globals.iosWorkflow.appliesToHostPlatform || macOSWorkflow.appliesToHostPlatform)
GroupedValidator(<DoctorValidator>[xcodeValidator, cocoapodsValidator]),
GroupedValidator(<DoctorValidator>[XcodeValidator(xcode: globals.xcode, userMessages: userMessages), cocoapodsValidator]),
if (webWorkflow.appliesToHostPlatform)
WebValidator(
chromeLauncher: globals.chromeLauncher,
Expand Down
42 changes: 24 additions & 18 deletions packages/flutter_tools/lib/src/macos/xcode_validator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,56 +2,62 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import '../base/context.dart';
import 'package:meta/meta.dart';

import '../base/user_messages.dart';
import '../doctor.dart';
import '../globals.dart' as globals;
import 'xcode.dart';

XcodeValidator get xcodeValidator => context.get<XcodeValidator>();

class XcodeValidator extends DoctorValidator {
const XcodeValidator() : super('Xcode - develop for iOS and macOS');
XcodeValidator({
@required Xcode xcode,
@required UserMessages userMessages,
}) : _xcode = xcode,
_userMessages = userMessages,
super('Xcode - develop for iOS and macOS');

final Xcode _xcode;
final UserMessages _userMessages;

@override
Future<ValidationResult> validate() async {
final List<ValidationMessage> messages = <ValidationMessage>[];
ValidationType xcodeStatus = ValidationType.missing;
String xcodeVersionInfo;

if (globals.xcode.isInstalled) {
if (_xcode.isInstalled) {
xcodeStatus = ValidationType.installed;

messages.add(ValidationMessage(userMessages.xcodeLocation(globals.xcode.xcodeSelectPath)));
messages.add(ValidationMessage(_userMessages.xcodeLocation(_xcode.xcodeSelectPath)));

xcodeVersionInfo = globals.xcode.versionText;
xcodeVersionInfo = _xcode.versionText;
if (xcodeVersionInfo.contains(',')) {
xcodeVersionInfo = xcodeVersionInfo.substring(0, xcodeVersionInfo.indexOf(','));
}
messages.add(ValidationMessage(globals.xcode.versionText));
messages.add(ValidationMessage(_xcode.versionText));

if (!globals.xcode.isInstalledAndMeetsVersionCheck) {
if (!_xcode.isInstalledAndMeetsVersionCheck) {
xcodeStatus = ValidationType.partial;
messages.add(ValidationMessage.error(
userMessages.xcodeOutdated(kXcodeRequiredVersionMajor, kXcodeRequiredVersionMinor)
_userMessages.xcodeOutdated(kXcodeRequiredVersionMajor, kXcodeRequiredVersionMinor)
));
}

if (!globals.xcode.eulaSigned) {
if (!_xcode.eulaSigned) {
xcodeStatus = ValidationType.partial;
messages.add(ValidationMessage.error(userMessages.xcodeEula));
messages.add(ValidationMessage.error(_userMessages.xcodeEula));
}
if (!globals.xcode.isSimctlInstalled) {
if (!_xcode.isSimctlInstalled) {
xcodeStatus = ValidationType.partial;
messages.add(ValidationMessage.error(userMessages.xcodeMissingSimct));
messages.add(ValidationMessage.error(_userMessages.xcodeMissingSimct));
}

} else {
xcodeStatus = ValidationType.missing;
if (globals.xcode.xcodeSelectPath == null || globals.xcode.xcodeSelectPath.isEmpty) {
messages.add(ValidationMessage.error(userMessages.xcodeMissing));
if (_xcode.xcodeSelectPath == null || _xcode.xcodeSelectPath.isEmpty) {
messages.add(ValidationMessage.error(_userMessages.xcodeMissing));
} else {
messages.add(ValidationMessage.error(userMessages.xcodeIncomplete));
messages.add(ValidationMessage.error(_userMessages.xcodeIncomplete));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter_tools/src/base/user_messages.dart';
import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/macos/xcode.dart';
import 'package:flutter_tools/src/macos/xcode_validator.dart';
Expand All @@ -17,89 +18,74 @@ class MockXcode extends Mock implements Xcode {}
void main() {
group('Xcode validation', () {
MockXcode xcode;
MockProcessManager processManager;

setUp(() {
xcode = MockXcode();
processManager = MockProcessManager();
});

testUsingContext('Emits missing status when Xcode is not installed', () async {
testWithoutContext('Emits missing status when Xcode is not installed', () async {
when(xcode.isInstalled).thenReturn(false);
when(xcode.xcodeSelectPath).thenReturn(null);
const XcodeValidator validator = XcodeValidator();
final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages());
final ValidationResult result = await validator.validate();
expect(result.type, ValidationType.missing);
}, overrides: <Type, Generator>{
Xcode: () => xcode,
});

testUsingContext('Emits missing status when Xcode installation is incomplete', () async {
testWithoutContext('Emits missing status when Xcode installation is incomplete', () async {
when(xcode.isInstalled).thenReturn(false);
when(xcode.xcodeSelectPath).thenReturn('/Library/Developer/CommandLineTools');
const XcodeValidator validator = XcodeValidator();
final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages());
final ValidationResult result = await validator.validate();
expect(result.type, ValidationType.missing);
}, overrides: <Type, Generator>{
Xcode: () => xcode,
});

testUsingContext('Emits partial status when Xcode version too low', () async {
testWithoutContext('Emits partial status when Xcode version too low', () async {
when(xcode.isInstalled).thenReturn(true);
when(xcode.versionText)
.thenReturn('Xcode 7.0.1\nBuild version 7C1002\n');
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(false);
when(xcode.eulaSigned).thenReturn(true);
when(xcode.isSimctlInstalled).thenReturn(true);
const XcodeValidator validator = XcodeValidator();
final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages());
final ValidationResult result = await validator.validate();
expect(result.type, ValidationType.partial);
}, overrides: <Type, Generator>{
Xcode: () => xcode,
});

testUsingContext('Emits partial status when Xcode EULA not signed', () async {
testWithoutContext('Emits partial status when Xcode EULA not signed', () async {
when(xcode.isInstalled).thenReturn(true);
when(xcode.versionText)
.thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(xcode.eulaSigned).thenReturn(false);
when(xcode.isSimctlInstalled).thenReturn(true);
const XcodeValidator validator = XcodeValidator();
final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages());
final ValidationResult result = await validator.validate();
expect(result.type, ValidationType.partial);
}, overrides: <Type, Generator>{
Xcode: () => xcode,
});

testUsingContext('Emits partial status when simctl is not installed', () async {
testWithoutContext('Emits partial status when simctl is not installed', () async {
when(xcode.isInstalled).thenReturn(true);
when(xcode.versionText)
.thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(xcode.eulaSigned).thenReturn(true);
when(xcode.isSimctlInstalled).thenReturn(false);
const XcodeValidator validator = XcodeValidator();
final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages());
final ValidationResult result = await validator.validate();
expect(result.type, ValidationType.partial);
}, overrides: <Type, Generator>{
Xcode: () => xcode,
});


testUsingContext('Succeeds when all checks pass', () async {
testWithoutContext('Succeeds when all checks pass', () async {
when(xcode.isInstalled).thenReturn(true);
when(xcode.versionText)
.thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(xcode.eulaSigned).thenReturn(true);
when(xcode.isSimctlInstalled).thenReturn(true);
const XcodeValidator validator = XcodeValidator();
final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages());
final ValidationResult result = await validator.validate();
expect(result.type, ValidationType.installed);
}, overrides: <Type, Generator>{
Xcode: () => xcode,
ProcessManager: () => processManager,
});
});
}