Migrate xcodeproj to null safety (#80549)

This commit is contained in:
Jenn Magder 2021-04-16 17:22:46 -07:00 committed by GitHub
parent f6f59c58bc
commit 72976f552c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 76 additions and 134 deletions

View file

@ -21,6 +21,9 @@ class Version implements Comparable<Version> {
return Version._(major ?? 0, minor ?? 0, patch ?? 0, text);
}
/// Public constant constructor when all fields are non-null, without default value fallbacks.
const Version.withText(this.major, this.minor, this.patch, this._text);
Version._(this.major, this.minor, this.patch, this._text) {
if (major < 0) {
throw ArgumentError('Major version must be non-negative.');

View file

@ -14,7 +14,6 @@ import 'fuchsia/fuchsia_sdk.dart';
import 'globals_null_migrated.dart' as globals;
import 'ios/ios_workflow.dart';
import 'ios/simulators.dart';
import 'ios/xcodeproj.dart';
import 'macos/cocoapods.dart';
import 'macos/cocoapods_validator.dart';
import 'macos/xcdevice.dart';
@ -47,7 +46,6 @@ FuchsiaArtifacts get fuchsiaArtifacts => context.get<FuchsiaArtifacts>();
IOSSimulatorUtils get iosSimulatorUtils => context.get<IOSSimulatorUtils>();
IOSWorkflow get iosWorkflow => context.get<IOSWorkflow>();
Xcode get xcode => context.get<Xcode>();
XcodeProjectInterpreter get xcodeProjectInterpreter => context.get<XcodeProjectInterpreter>();
XCDevice get xcdevice => context.get<XCDevice>();

View file

@ -24,6 +24,7 @@ import 'base/time.dart';
import 'base/user_messages.dart';
import 'cache.dart';
import 'ios/plist_parser.dart';
import 'ios/xcodeproj.dart';
import 'persistent_tool_state.dart';
import 'reporting/reporting.dart';
import 'version.dart';
@ -38,6 +39,7 @@ AndroidStudio? get androidStudio => context.get<AndroidStudio>();
AndroidSdk? get androidSdk => context.get<AndroidSdk>();
FlutterVersion get flutterVersion => context.get<FlutterVersion>()!;
Usage get flutterUsage => context.get<Usage>()!;
XcodeProjectInterpreter? get xcodeProjectInterpreter => context.get<XcodeProjectInterpreter>();
PersistentToolState? get persistentToolState => PersistentToolState.instance;

View file

@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:file/memory.dart';
import 'package:meta/meta.dart';
import 'package:process/process.dart';
@ -17,6 +15,7 @@ import '../base/platform.dart';
import '../base/process.dart';
import '../base/terminal.dart';
import '../base/utils.dart';
import '../base/version.dart';
import '../build_info.dart';
import '../reporting/reporting.dart';
@ -26,11 +25,11 @@ final RegExp _varExpr = RegExp(r'\$\(([^)]*)\)');
/// Interpreter of Xcode projects.
class XcodeProjectInterpreter {
factory XcodeProjectInterpreter({
@required Platform platform,
@required ProcessManager processManager,
@required Logger logger,
@required FileSystem fileSystem,
@required Usage usage,
required Platform platform,
required ProcessManager processManager,
required Logger logger,
required FileSystem fileSystem,
required Usage usage,
}) {
return XcodeProjectInterpreter._(
platform: platform,
@ -42,14 +41,12 @@ class XcodeProjectInterpreter {
}
XcodeProjectInterpreter._({
@required Platform platform,
@required ProcessManager processManager,
@required Logger logger,
@required FileSystem fileSystem,
@required Usage usage,
int majorVersion,
int minorVersion,
int patchVersion,
required Platform platform,
required ProcessManager processManager,
required Logger logger,
required FileSystem fileSystem,
required Usage usage,
Version? version,
}) : _platform = platform,
_fileSystem = fileSystem,
_logger = logger,
@ -60,9 +57,7 @@ class XcodeProjectInterpreter {
platform: platform,
processManager: processManager,
),
_majorVersion = majorVersion,
_minorVersion = minorVersion,
_patchVersion = patchVersion,
_version = version,
_usage = usage;
/// Create an [XcodeProjectInterpreter] for testing.
@ -70,12 +65,10 @@ class XcodeProjectInterpreter {
/// Defaults to installed with sufficient version,
/// a memory file system, fake platform, buffer logger,
/// test [Usage], and test [Terminal].
/// Set [majorVersion] to null to simulate Xcode not being installed.
/// Set [version] to null to simulate Xcode not being installed.
factory XcodeProjectInterpreter.test({
@required ProcessManager processManager,
int majorVersion = 1000,
int minorVersion = 0,
int patchVersion = 0,
required ProcessManager processManager,
Version? version = const Version.withText(1000, 0, 0, '1000.0.0'),
}) {
final Platform platform = FakePlatform(
operatingSystem: 'macos',
@ -87,9 +80,7 @@ class XcodeProjectInterpreter {
processManager: processManager,
usage: TestUsage(),
logger: BufferLogger.test(),
majorVersion: majorVersion,
minorVersion: minorVersion,
patchVersion: patchVersion,
version: version,
);
}
@ -116,52 +107,37 @@ class XcodeProjectInterpreter {
}
_versionText = result.stdout.trim().replaceAll('\n', ', ');
}
final Match match = _versionRegex.firstMatch(versionText);
final Match? match = _versionRegex.firstMatch(versionText!);
if (match == null) {
return;
}
final String version = match.group(1);
final String version = match.group(1)!;
final List<String> components = version.split('.');
_majorVersion = int.parse(components[0]);
_minorVersion = components.length < 2 ? 0 : int.parse(components[1]);
_patchVersion = components.length < 3 ? 0 : int.parse(components[2]);
final int majorVersion = int.parse(components[0]);
final int minorVersion = components.length < 2 ? 0 : int.parse(components[1]);
final int patchVersion = components.length < 3 ? 0 : int.parse(components[2]);
_version = Version(majorVersion, minorVersion, patchVersion);
} on ProcessException {
// Ignored, leave values null.
}
}
bool get isInstalled => majorVersion != null;
bool get isInstalled => version != null;
String _versionText;
String get versionText {
String? _versionText;
String? get versionText {
if (_versionText == null) {
_updateVersion();
}
return _versionText;
}
int _majorVersion;
int get majorVersion {
if (_majorVersion == null) {
Version? _version;
Version? get version {
if (_version == null) {
_updateVersion();
}
return _majorVersion;
}
int _minorVersion;
int get minorVersion {
if (_minorVersion == null) {
_updateVersion();
}
return _minorVersion;
}
int _patchVersion;
int get patchVersion {
if (_patchVersion == null) {
_updateVersion();
}
return _patchVersion;
return _version;
}
/// The `xcrun` Xcode command to run or locate development
@ -190,7 +166,7 @@ class XcodeProjectInterpreter {
/// target (by default this is Runner).
Future<Map<String, String>> getBuildSettings(
String projectPath, {
String scheme,
String? scheme,
Duration timeout = const Duration(minutes: 1),
}) async {
final Status status = _logger.startSpinner();
@ -247,7 +223,7 @@ class XcodeProjectInterpreter {
], workingDirectory: _fileSystem.currentDirectory.path);
}
Future<XcodeProjectInfo> getInfo(String projectPath, {String projectFilename}) async {
Future<XcodeProjectInfo> getInfo(String projectPath, {String? projectFilename}) async {
// The exit code returned by 'xcodebuild -list' when either:
// * -project is passed and the given project isn't there, or
// * no -project is passed and there isn't a project.
@ -287,9 +263,9 @@ List<String> environmentVariablesAsXcodeBuildSettings(Platform platform) {
Map<String, String> parseXcodeBuildSettings(String showBuildSettingsOutput) {
final Map<String, String> settings = <String, String>{};
for (final Match match in showBuildSettingsOutput.split('\n').map<Match>(_settingExpr.firstMatch)) {
for (final Match? match in showBuildSettingsOutput.split('\n').map<Match?>(_settingExpr.firstMatch)) {
if (match != null) {
settings[match[1]] = match[2];
settings[match[1]!] = match[2]!;
}
}
return settings;
@ -303,7 +279,7 @@ String substituteXcodeVariables(String str, Map<String, String> xcodeBuildSettin
return str;
}
return str.replaceAllMapped(_varExpr, (Match m) => xcodeBuildSettings[m[1]] ?? m[0]);
return str.replaceAllMapped(_varExpr, (Match m) => xcodeBuildSettings[m[1]!] ?? m[0]!);
}
/// Information about an Xcode project.
@ -321,7 +297,7 @@ class XcodeProjectInfo {
final List<String> targets = <String>[];
final List<String> buildConfigurations = <String>[];
final List<String> schemes = <String>[];
List<String> collector;
List<String>? collector;
for (final String line in output.split('\n')) {
if (line.isEmpty) {
collector = null;
@ -353,7 +329,7 @@ class XcodeProjectInfo {
/// The expected scheme for [buildInfo].
@visibleForTesting
static String expectedSchemeFor(BuildInfo buildInfo) {
static String expectedSchemeFor(BuildInfo? buildInfo) {
return toTitleCase(buildInfo?.flavor ?? 'runner');
}
@ -379,7 +355,7 @@ class XcodeProjectInfo {
}
/// Returns unique scheme matching [buildInfo], or null, if there is no unique
/// best match.
String schemeFor(BuildInfo buildInfo) {
String? schemeFor(BuildInfo buildInfo) {
final String expectedScheme = expectedSchemeFor(buildInfo);
if (schemes.contains(expectedScheme)) {
return expectedScheme;
@ -401,7 +377,7 @@ class XcodeProjectInfo {
/// Returns unique build configuration matching [buildInfo] and [scheme], or
/// null, if there is no unique best match.
String buildConfigurationFor(BuildInfo buildInfo, String scheme) {
String? buildConfigurationFor(BuildInfo buildInfo, String scheme) {
final String expectedConfiguration = expectedBuildConfigurationFor(buildInfo, scheme);
if (hasBuildConfigurationForBuildMode(expectedConfiguration)) {
return expectedConfiguration;
@ -426,7 +402,7 @@ class XcodeProjectInfo {
return 'Release';
}
static String _uniqueMatch(Iterable<String> strings, bool Function(String s) matches) {
static String? _uniqueMatch(Iterable<String> strings, bool Function(String s) matches) {
final List<String> options = strings.where(matches).toList();
if (options.length == 1) {
return options.first;

View file

@ -13,7 +13,7 @@ import '../base/logger.dart';
import '../base/project_migrator.dart';
import '../build_info.dart';
import '../convert.dart';
import '../globals.dart' as globals;
import '../globals_null_migrated.dart' as globals;
import '../ios/xcode_build_settings.dart';
import '../ios/xcodeproj.dart';
import '../project.dart';

View file

@ -18,7 +18,7 @@ import '../base/process.dart';
import '../build_info.dart';
import '../cache.dart';
import '../convert.dart';
import '../globals.dart' as globals;
import '../globals_null_migrated.dart' as globals;
import '../ios/devices.dart';
import '../ios/ios_deploy.dart';
import '../ios/iproxy.dart';

View file

@ -101,13 +101,7 @@ class Xcode {
bool get isInstalled => _xcodeProjectInterpreter.isInstalled;
Version get currentVersion => Version(
_xcodeProjectInterpreter.majorVersion,
_xcodeProjectInterpreter.minorVersion,
_xcodeProjectInterpreter.patchVersion,
text:
'${_xcodeProjectInterpreter.majorVersion}.${_xcodeProjectInterpreter.minorVersion}.${_xcodeProjectInterpreter.patchVersion}',
);
Version get currentVersion => _xcodeProjectInterpreter.version;
String get versionText => _xcodeProjectInterpreter.versionText;

View file

@ -8,6 +8,7 @@ import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/version.dart';
import 'package:flutter_tools/src/commands/clean.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/macos/xcode.dart';
@ -73,7 +74,7 @@ void main() {
final FlutterProject projectUnderTest = setupProjectUnderTest(fs.currentDirectory);
// Xcode is installed and version satisfactory.
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(1000);
when(mockXcodeProjectInterpreter.version).thenReturn(Version(1000, 0, 0));
await CleanCommand().runCommand();
expect(buildDirectory.existsSync(), isFalse);
@ -108,7 +109,7 @@ void main() {
setupProjectUnderTest(fs.currentDirectory);
// Xcode is installed and version satisfactory.
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(1000);
when(mockXcodeProjectInterpreter.version).thenReturn(Version(1000, 0, 0));
await CleanCommand(verbose: true).runCommand();
verify(mockXcodeProjectInterpreter.cleanWorkspace(any, 'Runner', verbose: true)).called(2);

View file

@ -10,6 +10,7 @@ import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/version.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/device.dart';
@ -92,7 +93,7 @@ void main() {
mockXcodeProjectInterpreter = MockXcodeProjectInterpreter();
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(1000);
when(mockXcodeProjectInterpreter.version).thenReturn(Version(1000, 0, 0));
when(mockXcodeProjectInterpreter.xcrunCommand()).thenReturn(<String>['xcrun']);
when(mockXcodeProjectInterpreter.getInfo(any, projectFilename: anyNamed('projectFilename'))).thenAnswer(
(_) {

View file

@ -5,6 +5,7 @@
// @dart = 2.8
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/version.dart';
import 'package:flutter_tools/src/ios/ios_workflow.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/macos/xcode.dart';
@ -60,9 +61,7 @@ void main() {
processManager: FakeProcessManager.any(),
xcodeProjectInterpreter: XcodeProjectInterpreter.test(
processManager: FakeProcessManager.any(),
majorVersion: 1000,
minorVersion: 0,
patchVersion: 0,
version: Version(1000, 0, 0)
),
);

View file

@ -10,6 +10,7 @@ import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/version.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/ios/xcodeproj.dart';
import 'package:flutter_tools/src/ios/xcode_build_settings.dart';
@ -172,9 +173,7 @@ void main() {
),
]);
expect(xcodeProjectInterpreter.majorVersion, 11);
expect(xcodeProjectInterpreter.minorVersion, 4);
expect(xcodeProjectInterpreter.patchVersion, 1);
expect(xcodeProjectInterpreter.version, Version(11, 4, 1));
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
@ -188,9 +187,7 @@ void main() {
),
]);
expect(xcodeProjectInterpreter.majorVersion, 11);
expect(xcodeProjectInterpreter.minorVersion, 0);
expect(xcodeProjectInterpreter.patchVersion, 0);
expect(xcodeProjectInterpreter.version, Version(11, 0, 0));
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});
@ -203,9 +200,7 @@ void main() {
stdout: 'Xcode Ultra5000\nBuild version 8E3004b',
),
]);
expect(xcodeProjectInterpreter.majorVersion, isNull);
expect(xcodeProjectInterpreter.minorVersion, isNull);
expect(xcodeProjectInterpreter.patchVersion, isNull);
expect(xcodeProjectInterpreter.version, isNull);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
});

View file

@ -10,6 +10,7 @@ import 'package:flutter_tools/src/artifacts.dart';
import 'package:flutter_tools/src/base/io.dart' show ProcessException;
import 'package:flutter_tools/src/base/logger.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/base/version.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/ios/devices.dart';
@ -137,9 +138,7 @@ void main() {
testWithoutContext('xcodeVersionSatisfactory 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);
when(mockXcodeProjectInterpreter.version).thenReturn(Version(9, 0, 0));
expect(xcode.isRequiredVersionSatisfactory, isFalse);
});
@ -152,45 +151,35 @@ void main() {
testWithoutContext('xcodeVersionSatisfactory 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);
when(mockXcodeProjectInterpreter.version).thenReturn(Version(12, 0, 1));
expect(xcode.isRequiredVersionSatisfactory, isTrue);
});
testWithoutContext('xcodeVersionSatisfactory 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);
when(mockXcodeProjectInterpreter.version).thenReturn(Version(13, 0, 0));
expect(xcode.isRequiredVersionSatisfactory, isTrue);
});
testWithoutContext('xcodeVersionSatisfactory 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);
when(mockXcodeProjectInterpreter.version).thenReturn(Version(12, 3, 0));
expect(xcode.isRequiredVersionSatisfactory, isTrue);
});
testWithoutContext('xcodeVersionSatisfactory 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);
when(mockXcodeProjectInterpreter.version).thenReturn(Version(12, 0, 2));
expect(xcode.isRequiredVersionSatisfactory, isTrue);
});
testWithoutContext('isRecommendedVersionSatisfactory is false when version is less than minimum', () {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(11);
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0);
when(mockXcodeProjectInterpreter.version).thenReturn(Version(11, 0, 0));
expect(xcode.isRecommendedVersionSatisfactory, isFalse);
});
@ -203,36 +192,28 @@ void main() {
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);
when(mockXcodeProjectInterpreter.version).thenReturn(Version(12, 0, 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);
when(mockXcodeProjectInterpreter.version).thenReturn(Version(13, 0, 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);
when(mockXcodeProjectInterpreter.version).thenReturn(Version(12, 3, 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);
when(mockXcodeProjectInterpreter.version).thenReturn(Version(12, 0, 2));
expect(xcode.isRecommendedVersionSatisfactory, isTrue);
});
@ -246,9 +227,7 @@ void main() {
testWithoutContext('isInstalledAndMeetsVersionCheck is false when version not satisfied', () {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(10);
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(2);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(0);
when(mockXcodeProjectInterpreter.version).thenReturn(Version(10, 2, 0));
expect(xcode.isInstalledAndMeetsVersionCheck, isFalse);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
@ -256,9 +235,7 @@ void main() {
testWithoutContext('isInstalledAndMeetsVersionCheck is true when macOS and installed and version is satisfied', () {
when(mockXcodeProjectInterpreter.isInstalled).thenReturn(true);
when(mockXcodeProjectInterpreter.majorVersion).thenReturn(12);
when(mockXcodeProjectInterpreter.minorVersion).thenReturn(0);
when(mockXcodeProjectInterpreter.patchVersion).thenReturn(1);
when(mockXcodeProjectInterpreter.version).thenReturn(Version(12, 0, 1));
expect(xcode.isInstalledAndMeetsVersionCheck, isTrue);
expect(fakeProcessManager.hasRemainingExpectations, isFalse);
@ -346,7 +323,7 @@ void main() {
processManager: FakeProcessManager.any(),
xcodeProjectInterpreter: XcodeProjectInterpreter.test(
processManager: FakeProcessManager.any(),
majorVersion: null, // Not installed.
version: null, // Not installed.
),
);
xcdevice = XCDevice(

View file

@ -26,6 +26,7 @@ baz=qux
testWithoutContext('can parse and compare', () {
expect(Version.unknown.toString(), equals('unknown'));
expect(Version(null, null, null).toString(), equals('0'));
expect(const Version.withText(1, 2, 3, 'versionText').toString(), 'versionText');
final Version v1 = Version.parse('1')!;
expect(v1.major, equals(1));

View file

@ -18,6 +18,7 @@ import 'package:flutter_tools/src/base/process.dart';
import 'package:flutter_tools/src/base/signals.dart';
import 'package:flutter_tools/src/base/template.dart';
import 'package:flutter_tools/src/base/terminal.dart';
import 'package:flutter_tools/src/base/version.dart';
import 'package:flutter_tools/src/doctor_validator.dart';
import 'package:flutter_tools/src/isolated/mustache_template.dart';
import 'package:flutter_tools/src/cache.dart';
@ -342,13 +343,7 @@ class FakeXcodeProjectInterpreter implements XcodeProjectInterpreter {
String get versionText => 'Xcode 12.0.1';
@override
int get majorVersion => 12;
@override
int get minorVersion => 0;
@override
int get patchVersion => 1;
Version get version => Version(12, 0, 1);
@override
Future<Map<String, String>> getBuildSettings(