Unverified Commit 7c75c01f authored by Jenn Magder's avatar Jenn Magder Committed by GitHub

Add recommended Xcode version to doctor (#73808)

parent c65304bb
...@@ -139,8 +139,9 @@ class UserMessages { ...@@ -139,8 +139,9 @@ class UserMessages {
// Messages used in XcodeValidator // Messages used in XcodeValidator
String xcodeLocation(String location) => 'Xcode at $location'; String xcodeLocation(String location) => 'Xcode at $location';
String xcodeOutdated(int versionMajor, int versionMinor, int versionPatch) =>
'Flutter requires a minimum Xcode version of $versionMajor.$versionMinor.$versionPatch.\n' String xcodeOutdated(String currentVersion, String recommendedVersion) =>
'Xcode $currentVersion out of date ($recommendedVersion is recommended).\n'
'Download the latest version or update via the Mac App Store.'; 'Download the latest version or update via the Mac App Store.';
String get xcodeEula => "Xcode end user license agreement not signed; open Xcode or run the command 'sudo xcodebuild -license'."; String get xcodeEula => "Xcode end user license agreement not signed; open Xcode or run the command 'sudo xcodebuild -license'.";
String get xcodeMissingSimct => String get xcodeMissingSimct =>
......
...@@ -637,7 +637,7 @@ class XcodeBuildExecution { ...@@ -637,7 +637,7 @@ class XcodeBuildExecution {
final Map<String, String> buildSettings; final Map<String, String> buildSettings;
} }
const String _xcodeRequirement = 'Xcode $kXcodeRequiredVersionMajor.$kXcodeRequiredVersionMinor.$kXcodeRequiredVersionPatch or greater is required to develop for iOS.'; final String _xcodeRequirement = 'Xcode $xcodeRequiredVersion or greater is required to develop for iOS.';
bool _checkXcodeVersion() { bool _checkXcodeVersion() {
if (!globals.platform.isMacOS) { if (!globals.platform.isMacOS) {
...@@ -647,7 +647,7 @@ bool _checkXcodeVersion() { ...@@ -647,7 +647,7 @@ bool _checkXcodeVersion() {
globals.printError('Cannot find "xcodebuild". $_xcodeRequirement'); globals.printError('Cannot find "xcodebuild". $_xcodeRequirement');
return false; return false;
} }
if (!globals.xcode.isVersionSatisfactory) { if (!globals.xcode.isRequiredVersionSatisfactory) {
globals.printError('Found "${globals.xcodeProjectInterpreter.versionText}". $_xcodeRequirement'); globals.printError('Found "${globals.xcodeProjectInterpreter.versionText}". $_xcodeRequirement');
return false; return false;
} }
......
...@@ -6,6 +6,7 @@ import '../../base/common.dart'; ...@@ -6,6 +6,7 @@ import '../../base/common.dart';
import '../../base/file_system.dart'; import '../../base/file_system.dart';
import '../../base/logger.dart'; import '../../base/logger.dart';
import '../../base/project_migrator.dart'; import '../../base/project_migrator.dart';
import '../../base/version.dart';
import '../../macos/xcode.dart'; import '../../macos/xcode.dart';
import '../../project.dart'; import '../../project.dart';
import '../../reporting/reporting.dart'; import '../../reporting/reporting.dart';
...@@ -99,7 +100,7 @@ class RemoveFrameworkLinkAndEmbeddingMigration extends ProjectMigrator { ...@@ -99,7 +100,7 @@ class RemoveFrameworkLinkAndEmbeddingMigration extends ProjectMigrator {
if (line.contains('/* App.framework ') || line.contains('/* Flutter.framework ')) { if (line.contains('/* App.framework ') || line.contains('/* Flutter.framework ')) {
// Print scary message if the user is on Xcode 11.4 or greater, or if Xcode isn't installed. // Print scary message if the user is on Xcode 11.4 or greater, or if Xcode isn't installed.
final bool xcodeIsInstalled = _xcode.isInstalled; final bool xcodeIsInstalled = _xcode.isInstalled;
if(!xcodeIsInstalled || (_xcode.majorVersion > 11 || (_xcode.majorVersion == 11 && _xcode.minorVersion >= 4))) { if(!xcodeIsInstalled || _xcode.currentVersion >= Version(11, 4, 0)) {
UsageEvent('ios-migration', 'remove-frameworks', label: 'failure', flutterUsage: _usage).send(); UsageEvent('ios-migration', 'remove-frameworks', label: 'failure', flutterUsage: _usage).send();
throwToolExit('Your Xcode project requires migration. See https://flutter.dev/docs/development/ios-project-migration for details.'); throwToolExit('Your Xcode project requires migration. See https://flutter.dev/docs/development/ios-project-migration for details.');
} }
......
...@@ -73,7 +73,6 @@ class IOSSimulatorUtils { ...@@ -73,7 +73,6 @@ class IOSSimulatorUtils {
name: device.name, name: device.name,
simControl: _simControl, simControl: _simControl,
simulatorCategory: device.category, simulatorCategory: device.category,
xcode: _xcode,
); );
}).toList(); }).toList();
} }
...@@ -309,9 +308,7 @@ class IOSSimulator extends Device { ...@@ -309,9 +308,7 @@ class IOSSimulator extends Device {
this.name, this.name,
this.simulatorCategory, this.simulatorCategory,
@required SimControl simControl, @required SimControl simControl,
@required Xcode xcode,
}) : _simControl = simControl, }) : _simControl = simControl,
_xcode = xcode,
super( super(
id, id,
category: Category.mobile, category: Category.mobile,
...@@ -325,7 +322,6 @@ class IOSSimulator extends Device { ...@@ -325,7 +322,6 @@ class IOSSimulator extends Device {
final String simulatorCategory; final String simulatorCategory;
final SimControl _simControl; final SimControl _simControl;
final Xcode _xcode;
@override @override
DevFSWriter createDevFSWriter(covariant ApplicationPackage app, String userIdentifier) { DevFSWriter createDevFSWriter(covariant ApplicationPackage app, String userIdentifier) {
...@@ -610,12 +606,8 @@ class IOSSimulator extends Device { ...@@ -610,12 +606,8 @@ class IOSSimulator extends Device {
} }
} }
bool get _xcodeVersionSupportsScreenshot {
return _xcode.majorVersion > 8 || (_xcode.majorVersion == 8 && _xcode.minorVersion >= 2);
}
@override @override
bool get supportsScreenshot => _xcodeVersionSupportsScreenshot; bool get supportsScreenshot => true;
@override @override
Future<void> takeScreenshot(File outputFile) { Future<void> takeScreenshot(File outputFile) {
......
...@@ -14,6 +14,7 @@ import '../base/io.dart'; ...@@ -14,6 +14,7 @@ import '../base/io.dart';
import '../base/logger.dart'; import '../base/logger.dart';
import '../base/platform.dart'; import '../base/platform.dart';
import '../base/process.dart'; import '../base/process.dart';
import '../base/version.dart';
import '../build_info.dart'; import '../build_info.dart';
import '../cache.dart'; import '../cache.dart';
import '../convert.dart'; import '../convert.dart';
...@@ -25,9 +26,8 @@ import '../ios/mac.dart'; ...@@ -25,9 +26,8 @@ import '../ios/mac.dart';
import '../ios/xcodeproj.dart'; import '../ios/xcodeproj.dart';
import '../reporting/reporting.dart'; import '../reporting/reporting.dart';
const int kXcodeRequiredVersionMajor = 11; Version get xcodeRequiredVersion => Version(11, 0, 0, text: '11.0');
const int kXcodeRequiredVersionMinor = 0; Version get xcodeRecommendedVersion => Version(12, 0, 1, text: '12.0.1');
const int kXcodeRequiredVersionPatch = 0;
/// SDK name passed to `xcrun --sdk`. Corresponds to undocumented Xcode /// SDK name passed to `xcrun --sdk`. Corresponds to undocumented Xcode
/// SUPPORTED_PLATFORMS values. /// SUPPORTED_PLATFORMS values.
...@@ -60,7 +60,7 @@ class Xcode { ...@@ -60,7 +60,7 @@ class Xcode {
final FileSystem _fileSystem; final FileSystem _fileSystem;
final XcodeProjectInterpreter _xcodeProjectInterpreter; final XcodeProjectInterpreter _xcodeProjectInterpreter;
bool get isInstalledAndMeetsVersionCheck => _platform.isMacOS && isInstalled && isVersionSatisfactory; bool get isInstalledAndMeetsVersionCheck => _platform.isMacOS && isInstalled && isRequiredVersionSatisfactory;
String _xcodeSelectPath; String _xcodeSelectPath;
String get xcodeSelectPath { String get xcodeSelectPath {
...@@ -85,9 +85,13 @@ class Xcode { ...@@ -85,9 +85,13 @@ class Xcode {
return _xcodeProjectInterpreter.isInstalled; return _xcodeProjectInterpreter.isInstalled;
} }
int get majorVersion => _xcodeProjectInterpreter.majorVersion; Version get currentVersion => Version(
int get minorVersion => _xcodeProjectInterpreter.minorVersion; _xcodeProjectInterpreter.majorVersion,
int get patchVersion => _xcodeProjectInterpreter.patchVersion; _xcodeProjectInterpreter.minorVersion,
_xcodeProjectInterpreter.patchVersion,
text:
'${_xcodeProjectInterpreter.majorVersion}.${_xcodeProjectInterpreter.minorVersion}.${_xcodeProjectInterpreter.patchVersion}',
);
String get versionText => _xcodeProjectInterpreter.versionText; String get versionText => _xcodeProjectInterpreter.versionText;
...@@ -132,20 +136,18 @@ class Xcode { ...@@ -132,20 +136,18 @@ class Xcode {
return _isSimctlInstalled; return _isSimctlInstalled;
} }
bool get isVersionSatisfactory { bool get isRequiredVersionSatisfactory {
if (!_xcodeProjectInterpreter.isInstalled) { if (!_xcodeProjectInterpreter.isInstalled) {
return false; return false;
} }
if (majorVersion > kXcodeRequiredVersionMajor) { return currentVersion >= xcodeRequiredVersion;
return true; }
}
if (majorVersion == kXcodeRequiredVersionMajor) { bool get isRecommendedVersionSatisfactory {
if (minorVersion == kXcodeRequiredVersionMinor) { if (!_xcodeProjectInterpreter.isInstalled) {
return patchVersion >= kXcodeRequiredVersionPatch; return false;
}
return minorVersion >= kXcodeRequiredVersionMinor;
} }
return false; return currentVersion >= xcodeRecommendedVersion;
} }
/// See [XcodeProjectInterpreter.xcrunCommand]. /// See [XcodeProjectInterpreter.xcrunCommand].
......
...@@ -29,18 +29,20 @@ class XcodeValidator extends DoctorValidator { ...@@ -29,18 +29,20 @@ class XcodeValidator extends DoctorValidator {
xcodeStatus = ValidationType.installed; xcodeStatus = ValidationType.installed;
messages.add(ValidationMessage(_userMessages.xcodeLocation(_xcode.xcodeSelectPath))); messages.add(ValidationMessage(_userMessages.xcodeLocation(_xcode.xcodeSelectPath)));
xcodeVersionInfo = _xcode.versionText;
if (xcodeVersionInfo.contains(',')) {
xcodeVersionInfo = xcodeVersionInfo.substring(0, xcodeVersionInfo.indexOf(','));
}
messages.add(ValidationMessage(_xcode.versionText)); messages.add(ValidationMessage(_xcode.versionText));
if (!_xcode.isInstalledAndMeetsVersionCheck) { if (!_xcode.isInstalledAndMeetsVersionCheck) {
xcodeStatus = ValidationType.partial; xcodeStatus = ValidationType.partial;
messages.add(ValidationMessage.error( messages.add(ValidationMessage.error(_userMessages.xcodeOutdated(
_userMessages.xcodeOutdated(kXcodeRequiredVersionMajor, kXcodeRequiredVersionMinor, kXcodeRequiredVersionPatch) _xcode.currentVersion.toString(),
)); xcodeRecommendedVersion.toString(),
)));
} else if (!_xcode.isRecommendedVersionSatisfactory) {
xcodeStatus = ValidationType.partial;
messages.add(ValidationMessage.hint(_userMessages.xcodeOutdated(
_xcode.currentVersion.toString(),
xcodeRecommendedVersion.toString(),
)));
} }
if (!_xcode.eulaSigned) { if (!_xcode.eulaSigned) {
......
...@@ -101,7 +101,7 @@ void main() { ...@@ -101,7 +101,7 @@ void main() {
} }
); );
mockXcode = MockXcode(); mockXcode = MockXcode();
when(mockXcode.isVersionSatisfactory).thenReturn(true); when(mockXcode.isRequiredVersionSatisfactory).thenReturn(true);
when(mockXcode.xcrunCommand()).thenReturn(<String>['xcrun']); when(mockXcode.xcrunCommand()).thenReturn(<String>['xcrun']);
fileSystem.file('foo/.packages') fileSystem.file('foo/.packages')
..createSync(recursive: true) ..createSync(recursive: true)
......
...@@ -6,6 +6,7 @@ import 'package:file/file.dart'; ...@@ -6,6 +6,7 @@ import 'package:file/file.dart';
import 'package:file/memory.dart'; import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/project_migrator.dart'; import 'package:flutter_tools/src/base/project_migrator.dart';
import 'package:flutter_tools/src/base/version.dart';
import 'package:flutter_tools/src/ios/migrations/project_base_configuration_migration.dart'; import 'package:flutter_tools/src/ios/migrations/project_base_configuration_migration.dart';
import 'package:flutter_tools/src/ios/migrations/project_build_location_migration.dart'; import 'package:flutter_tools/src/ios/migrations/project_build_location_migration.dart';
import 'package:flutter_tools/src/ios/migrations/remove_framework_link_and_embedding_migration.dart'; import 'package:flutter_tools/src/ios/migrations/remove_framework_link_and_embedding_migration.dart';
...@@ -145,8 +146,7 @@ keep this 2 ...@@ -145,8 +146,7 @@ keep this 2
746232531E83B71900CC1A5E /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 746232521E83B71900CC1A5E /* App.framework */; }; 746232531E83B71900CC1A5E /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 746232521E83B71900CC1A5E /* App.framework */; };
'''); ''');
when(mockXcode.isInstalled).thenReturn(true); when(mockXcode.isInstalled).thenReturn(true);
when(mockXcode.majorVersion).thenReturn(11); when(mockXcode.currentVersion).thenReturn(Version(11, 4, 0));
when(mockXcode.minorVersion).thenReturn(4);
final RemoveFrameworkLinkAndEmbeddingMigration iosProjectMigration = RemoveFrameworkLinkAndEmbeddingMigration( final RemoveFrameworkLinkAndEmbeddingMigration iosProjectMigration = RemoveFrameworkLinkAndEmbeddingMigration(
mockIosProject, mockIosProject,
...@@ -164,8 +164,7 @@ keep this 2 ...@@ -164,8 +164,7 @@ keep this 2
9705A1C71CF904A300538480 /* Flutter.framework in Embed Frameworks */, 9705A1C71CF904A300538480 /* Flutter.framework in Embed Frameworks */,
'''); ''');
when(mockXcode.isInstalled).thenReturn(true); when(mockXcode.isInstalled).thenReturn(true);
when(mockXcode.majorVersion).thenReturn(11); when(mockXcode.currentVersion).thenReturn(Version(11, 4, 0));
when(mockXcode.minorVersion).thenReturn(4);
final RemoveFrameworkLinkAndEmbeddingMigration iosProjectMigration = RemoveFrameworkLinkAndEmbeddingMigration( final RemoveFrameworkLinkAndEmbeddingMigration iosProjectMigration = RemoveFrameworkLinkAndEmbeddingMigration(
mockIosProject, mockIosProject,
...@@ -198,8 +197,7 @@ keep this 2 ...@@ -198,8 +197,7 @@ keep this 2
746232531E83B71900CC1A5E /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 746232521E83B71900CC1A5E /* App.framework */; }; 746232531E83B71900CC1A5E /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 746232521E83B71900CC1A5E /* App.framework */; };
'''); ''');
when(mockXcode.isInstalled).thenReturn(true); when(mockXcode.isInstalled).thenReturn(true);
when(mockXcode.majorVersion).thenReturn(11); when(mockXcode.currentVersion).thenReturn(Version(11, 3, 0));
when(mockXcode.minorVersion).thenReturn(3);
final RemoveFrameworkLinkAndEmbeddingMigration iosProjectMigration = RemoveFrameworkLinkAndEmbeddingMigration( final RemoveFrameworkLinkAndEmbeddingMigration iosProjectMigration = RemoveFrameworkLinkAndEmbeddingMigration(
mockIosProject, mockIosProject,
...@@ -217,8 +215,7 @@ keep this 2 ...@@ -217,8 +215,7 @@ keep this 2
746232531E83B71900CC1A5E /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 746232521E83B71900CC1A5E /* App.framework */; }; 746232531E83B71900CC1A5E /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 746232521E83B71900CC1A5E /* App.framework */; };
'''); ''');
when(mockXcode.isInstalled).thenReturn(true); when(mockXcode.isInstalled).thenReturn(true);
when(mockXcode.majorVersion).thenReturn(11); when(mockXcode.currentVersion).thenReturn(Version(11, 4, 0));
when(mockXcode.minorVersion).thenReturn(4);
final RemoveFrameworkLinkAndEmbeddingMigration iosProjectMigration = RemoveFrameworkLinkAndEmbeddingMigration( final RemoveFrameworkLinkAndEmbeddingMigration iosProjectMigration = RemoveFrameworkLinkAndEmbeddingMigration(
mockIosProject, mockIosProject,
...@@ -235,8 +232,7 @@ keep this 2 ...@@ -235,8 +232,7 @@ keep this 2
746232531E83B71900CC1A5E /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 746232521E83B71900CC1A5E /* App.framework */; }; 746232531E83B71900CC1A5E /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 746232521E83B71900CC1A5E /* App.framework */; };
'''); ''');
when(mockXcode.isInstalled).thenReturn(true); when(mockXcode.isInstalled).thenReturn(true);
when(mockXcode.majorVersion).thenReturn(12); when(mockXcode.currentVersion).thenReturn(Version(12, 0, 0));
when(mockXcode.minorVersion).thenReturn(0);
final RemoveFrameworkLinkAndEmbeddingMigration iosProjectMigration = RemoveFrameworkLinkAndEmbeddingMigration( final RemoveFrameworkLinkAndEmbeddingMigration iosProjectMigration = RemoveFrameworkLinkAndEmbeddingMigration(
mockIosProject, mockIosProject,
......
...@@ -221,13 +221,13 @@ void main() { ...@@ -221,13 +221,13 @@ void main() {
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0); when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0); when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0);
expect(xcode.isVersionSatisfactory, isFalse); expect(xcode.isRequiredVersionSatisfactory, isFalse);
}); });
testWithoutContext('xcodeVersionSatisfactory is false when xcodebuild tools are not installed', () { testWithoutContext('xcodeVersionSatisfactory is false when xcodebuild tools are not installed', () {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(false); when(mockXcodeProjectInterpreter.isInstalled).thenReturn(false);
expect(xcode.isVersionSatisfactory, isFalse); expect(xcode.isRequiredVersionSatisfactory, isFalse);
}); });
testWithoutContext('xcodeVersionSatisfactory is true when version meets minimum', () { testWithoutContext('xcodeVersionSatisfactory is true when version meets minimum', () {
...@@ -236,7 +236,7 @@ void main() { ...@@ -236,7 +236,7 @@ void main() {
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0); when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0); when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0);
expect(xcode.isVersionSatisfactory, isTrue); expect(xcode.isRequiredVersionSatisfactory, isTrue);
}); });
testWithoutContext('xcodeVersionSatisfactory is true when major version exceeds minimum', () { testWithoutContext('xcodeVersionSatisfactory is true when major version exceeds minimum', () {
...@@ -245,7 +245,7 @@ void main() { ...@@ -245,7 +245,7 @@ void main() {
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0); when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0); when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0);
expect(xcode.isVersionSatisfactory, isTrue); expect(xcode.isRequiredVersionSatisfactory, isTrue);
}); });
testWithoutContext('xcodeVersionSatisfactory is true when minor version exceeds minimum', () { testWithoutContext('xcodeVersionSatisfactory is true when minor version exceeds minimum', () {
...@@ -254,7 +254,7 @@ void main() { ...@@ -254,7 +254,7 @@ void main() {
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(3); when(mockXcodeProjectInterpreter.minorVersion).thenReturn(3);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0); when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0);
expect(xcode.isVersionSatisfactory, isTrue); expect(xcode.isRequiredVersionSatisfactory, isTrue);
}); });
testWithoutContext('xcodeVersionSatisfactory is true when patch version exceeds minimum', () { testWithoutContext('xcodeVersionSatisfactory is true when patch version exceeds minimum', () {
...@@ -263,7 +263,58 @@ void main() { ...@@ -263,7 +263,58 @@ void main() {
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0); when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(1); when(mockXcodeProjectInterpreter.patchVersion).thenReturn(1);
expect(xcode.isVersionSatisfactory, isTrue); expect(xcode.isRequiredVersionSatisfactory, isTrue);
});
testWithoutContext('isRecommendedVersionSatisfactory is false when version is less than minimum', () {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(9);
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0);
expect(xcode.isRecommendedVersionSatisfactory, isFalse);
});
testWithoutContext('isRecommendedVersionSatisfactory is false when xcodebuild tools are not installed', () {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(false);
expect(xcode.isRecommendedVersionSatisfactory, isFalse);
});
testWithoutContext('isRecommendedVersionSatisfactory is true when version meets minimum', () {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(12);
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(1);
expect(xcode.isRecommendedVersionSatisfactory, isTrue);
});
testWithoutContext('isRecommendedVersionSatisfactory is true when major version exceeds minimum', () {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(13);
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0);
expect(xcode.isRecommendedVersionSatisfactory, isTrue);
});
testWithoutContext('isRecommendedVersionSatisfactory is true when minor version exceeds minimum', () {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(12);
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(3);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0);
expect(xcode.isRecommendedVersionSatisfactory, isTrue);
});
testWithoutContext('isRecommendedVersionSatisfactory is true when patch version exceeds minimum', () {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(12);
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(2);
expect(xcode.isRecommendedVersionSatisfactory, isTrue);
}); });
testWithoutContext('isInstalledAndMeetsVersionCheck is false when not installed', () { testWithoutContext('isInstalledAndMeetsVersionCheck is false when not installed', () {
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/base/user_messages.dart';
import 'package:flutter_tools/src/base/version.dart';
import 'package:flutter_tools/src/doctor.dart'; import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/macos/xcode.dart'; import 'package:flutter_tools/src/macos/xcode.dart';
import 'package:flutter_tools/src/macos/xcode_validator.dart'; import 'package:flutter_tools/src/macos/xcode_validator.dart';
...@@ -40,12 +41,32 @@ void main() { ...@@ -40,12 +41,32 @@ void main() {
when(xcode.isInstalled).thenReturn(true); when(xcode.isInstalled).thenReturn(true);
when(xcode.versionText) when(xcode.versionText)
.thenReturn('Xcode 7.0.1\nBuild version 7C1002\n'); .thenReturn('Xcode 7.0.1\nBuild version 7C1002\n');
when(xcode.currentVersion).thenReturn(Version(7, 0, 1));
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(false); when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(false);
when(xcode.isRecommendedVersionSatisfactory).thenReturn(false);
when(xcode.eulaSigned).thenReturn(true); when(xcode.eulaSigned).thenReturn(true);
when(xcode.isSimctlInstalled).thenReturn(true); when(xcode.isSimctlInstalled).thenReturn(true);
final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages()); final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages());
final ValidationResult result = await validator.validate(); final ValidationResult result = await validator.validate();
expect(result.type, ValidationType.partial); expect(result.type, ValidationType.partial);
expect(result.messages.last.type, ValidationMessageType.error);
expect(result.messages.last.message, contains('Xcode 7.0.1 out of date (12.0.1 is recommended)'));
});
testWithoutContext('Emits partial status when Xcode below recommended version', () async {
when(xcode.isInstalled).thenReturn(true);
when(xcode.versionText)
.thenReturn('Xcode 11.0\nBuild version 11A420a\n');
when(xcode.currentVersion).thenReturn(Version(11, 0, 0));
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(xcode.isRecommendedVersionSatisfactory).thenReturn(false);
when(xcode.eulaSigned).thenReturn(true);
when(xcode.isSimctlInstalled).thenReturn(true);
final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages());
final ValidationResult result = await validator.validate();
expect(result.type, ValidationType.partial);
expect(result.messages.last.type, ValidationMessageType.hint);
expect(result.messages.last.message, contains('Xcode 11.0.0 out of date (12.0.1 is recommended)'));
}); });
testWithoutContext('Emits partial status when Xcode EULA not signed', () async { testWithoutContext('Emits partial status when Xcode EULA not signed', () async {
...@@ -53,6 +74,7 @@ void main() { ...@@ -53,6 +74,7 @@ void main() {
when(xcode.versionText) when(xcode.versionText)
.thenReturn('Xcode 8.2.1\nBuild version 8C1002\n'); .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true); when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(xcode.isRecommendedVersionSatisfactory).thenReturn(true);
when(xcode.eulaSigned).thenReturn(false); when(xcode.eulaSigned).thenReturn(false);
when(xcode.isSimctlInstalled).thenReturn(true); when(xcode.isSimctlInstalled).thenReturn(true);
final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages()); final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages());
...@@ -65,6 +87,7 @@ void main() { ...@@ -65,6 +87,7 @@ void main() {
when(xcode.versionText) when(xcode.versionText)
.thenReturn('Xcode 8.2.1\nBuild version 8C1002\n'); .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true); when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(xcode.isRecommendedVersionSatisfactory).thenReturn(true);
when(xcode.eulaSigned).thenReturn(true); when(xcode.eulaSigned).thenReturn(true);
when(xcode.isSimctlInstalled).thenReturn(false); when(xcode.isSimctlInstalled).thenReturn(false);
final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages()); final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages());
...@@ -78,6 +101,7 @@ void main() { ...@@ -78,6 +101,7 @@ void main() {
when(xcode.versionText) when(xcode.versionText)
.thenReturn('Xcode 8.2.1\nBuild version 8C1002\n'); .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true); when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(xcode.isRecommendedVersionSatisfactory).thenReturn(true);
when(xcode.eulaSigned).thenReturn(true); when(xcode.eulaSigned).thenReturn(true);
when(xcode.isSimctlInstalled).thenReturn(true); when(xcode.isSimctlInstalled).thenReturn(true);
final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages()); final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment