mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

* First step in Flutter Doctor refactor. Assigns categories to all validators.
* Revert "Roll engine e54bc4ea1832..a84b210b3d26 (6 commits) (#20453)"
This reverts commit 05c2880a17
.
* Split iOS and Android workflows into workflow and validator classes.
* Change ValidatorCategory to handle standalone validators that share a
category (e.g. IntelliJ).
Also make Android Studio and Android toolchain use separate categories.
At this stage, flutter doctor output matches what it was previously.
(The summary() method itself has not yet been changed )
* Change doctor summary code to support validator categories.
Output is still unchanged.
* Handle small formatting issues.
* Flip Flutter category's isGroup field to false until it's actually
needed.
* Revert auto-generated formatting changes to keep those lines from
muddying the pull.
* Small fixes pointed out by analyzer.
* Properly fix analyzer issues around const constructors.
* Small changes to address comments.
* Add tests to verify grouped validator behavior and validationtype
merging.
* Update doctor.dart
* Add comments for clarification.
333 lines
13 KiB
Dart
333 lines
13 KiB
Dart
// Copyright 2017 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import 'dart:async';
|
|
|
|
import 'package:file/memory.dart';
|
|
import 'package:flutter_tools/src/base/common.dart';
|
|
import 'package:flutter_tools/src/base/file_system.dart';
|
|
import 'package:flutter_tools/src/base/io.dart';
|
|
import 'package:flutter_tools/src/doctor.dart';
|
|
import 'package:flutter_tools/src/ios/cocoapods.dart';
|
|
import 'package:flutter_tools/src/ios/ios_workflow.dart';
|
|
import 'package:flutter_tools/src/ios/mac.dart';
|
|
import 'package:mockito/mockito.dart';
|
|
import 'package:process/process.dart';
|
|
|
|
import '../src/common.dart';
|
|
import '../src/context.dart';
|
|
|
|
void main() {
|
|
group('iOS Workflow validation', () {
|
|
MockIMobileDevice iMobileDevice;
|
|
MockXcode xcode;
|
|
MockProcessManager processManager;
|
|
MockCocoaPods cocoaPods;
|
|
FileSystem fs;
|
|
|
|
setUp(() {
|
|
iMobileDevice = new MockIMobileDevice();
|
|
xcode = new MockXcode();
|
|
processManager = new MockProcessManager();
|
|
cocoaPods = new MockCocoaPods();
|
|
fs = new MemoryFileSystem();
|
|
|
|
when(cocoaPods.evaluateCocoaPodsInstallation)
|
|
.thenAnswer((_) async => CocoaPodsStatus.recommended);
|
|
when(cocoaPods.isCocoaPodsInitialized).thenAnswer((_) async => true);
|
|
when(cocoaPods.cocoaPodsVersionText).thenAnswer((_) async => '1.8.0');
|
|
});
|
|
|
|
testUsingContext('Emit missing status when nothing is installed', () async {
|
|
when(xcode.isInstalled).thenReturn(false);
|
|
when(xcode.xcodeSelectPath).thenReturn(null);
|
|
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(
|
|
hasHomebrew: false,
|
|
hasIosDeploy: false,
|
|
);
|
|
final ValidationResult result = await workflow.validate();
|
|
expect(result.type, ValidationType.missing);
|
|
}, overrides: <Type, Generator>{
|
|
IMobileDevice: () => iMobileDevice,
|
|
Xcode: () => xcode,
|
|
CocoaPods: () => cocoaPods,
|
|
});
|
|
|
|
testUsingContext('Emits partial status when Xcode is not installed', () async {
|
|
when(xcode.isInstalled).thenReturn(false);
|
|
when(xcode.xcodeSelectPath).thenReturn(null);
|
|
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
|
|
final ValidationResult result = await workflow.validate();
|
|
expect(result.type, ValidationType.partial);
|
|
}, overrides: <Type, Generator>{
|
|
IMobileDevice: () => iMobileDevice,
|
|
Xcode: () => xcode,
|
|
CocoaPods: () => cocoaPods,
|
|
});
|
|
|
|
testUsingContext('Emits partial status when Xcode is partially installed', () async {
|
|
when(xcode.isInstalled).thenReturn(false);
|
|
when(xcode.xcodeSelectPath).thenReturn('/Library/Developer/CommandLineTools');
|
|
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
|
|
final ValidationResult result = await workflow.validate();
|
|
expect(result.type, ValidationType.partial);
|
|
}, overrides: <Type, Generator>{
|
|
IMobileDevice: () => iMobileDevice,
|
|
Xcode: () => xcode,
|
|
CocoaPods: () => cocoaPods,
|
|
});
|
|
|
|
testUsingContext('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);
|
|
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
|
|
final ValidationResult result = await workflow.validate();
|
|
expect(result.type, ValidationType.partial);
|
|
}, overrides: <Type, Generator>{
|
|
IMobileDevice: () => iMobileDevice,
|
|
Xcode: () => xcode,
|
|
CocoaPods: () => cocoaPods,
|
|
});
|
|
|
|
testUsingContext('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);
|
|
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
|
|
final ValidationResult result = await workflow.validate();
|
|
expect(result.type, ValidationType.partial);
|
|
}, overrides: <Type, Generator>{
|
|
IMobileDevice: () => iMobileDevice,
|
|
Xcode: () => xcode,
|
|
CocoaPods: () => cocoaPods,
|
|
});
|
|
|
|
testUsingContext('Emits partial status when homebrew 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(true);
|
|
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(hasHomebrew: false);
|
|
final ValidationResult result = await workflow.validate();
|
|
expect(result.type, ValidationType.partial);
|
|
}, overrides: <Type, Generator>{
|
|
IMobileDevice: () => iMobileDevice,
|
|
Xcode: () => xcode,
|
|
CocoaPods: () => cocoaPods,
|
|
});
|
|
|
|
testUsingContext('Emits partial status when libimobiledevice 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(true);
|
|
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
|
|
final ValidationResult result = await workflow.validate();
|
|
expect(result.type, ValidationType.partial);
|
|
}, overrides: <Type, Generator>{
|
|
IMobileDevice: () => new MockIMobileDevice(isInstalled: false, isWorking: false),
|
|
Xcode: () => xcode,
|
|
CocoaPods: () => cocoaPods,
|
|
});
|
|
|
|
testUsingContext('Emits partial status when libimobiledevice is installed but not working', () 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);
|
|
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
|
|
final ValidationResult result = await workflow.validate();
|
|
expect(result.type, ValidationType.partial);
|
|
}, overrides: <Type, Generator>{
|
|
IMobileDevice: () => new MockIMobileDevice(isWorking: false),
|
|
Xcode: () => xcode,
|
|
CocoaPods: () => cocoaPods,
|
|
});
|
|
|
|
testUsingContext('Emits partial status when ios-deploy 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.isSimctlInstalled).thenReturn(true);
|
|
when(xcode.eulaSigned).thenReturn(true);
|
|
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(hasIosDeploy: false);
|
|
final ValidationResult result = await workflow.validate();
|
|
expect(result.type, ValidationType.partial);
|
|
}, overrides: <Type, Generator>{
|
|
IMobileDevice: () => iMobileDevice,
|
|
Xcode: () => xcode,
|
|
CocoaPods: () => cocoaPods,
|
|
});
|
|
|
|
testUsingContext('Emits partial status when ios-deploy version is too low', () 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);
|
|
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(iosDeployVersionText: '1.8.0');
|
|
final ValidationResult result = await workflow.validate();
|
|
expect(result.type, ValidationType.partial);
|
|
}, overrides: <Type, Generator>{
|
|
IMobileDevice: () => iMobileDevice,
|
|
Xcode: () => xcode,
|
|
CocoaPods: () => cocoaPods,
|
|
});
|
|
|
|
testUsingContext('Emits partial status when CocoaPods 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(cocoaPods.evaluateCocoaPodsInstallation)
|
|
.thenAnswer((_) async => CocoaPodsStatus.notInstalled);
|
|
when(xcode.isSimctlInstalled).thenReturn(true);
|
|
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
|
|
final ValidationResult result = await workflow.validate();
|
|
expect(result.type, ValidationType.partial);
|
|
}, overrides: <Type, Generator>{
|
|
IMobileDevice: () => iMobileDevice,
|
|
Xcode: () => xcode,
|
|
CocoaPods: () => cocoaPods,
|
|
});
|
|
|
|
testUsingContext('Emits partial status when CocoaPods version is too low', () 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(cocoaPods.evaluateCocoaPodsInstallation)
|
|
.thenAnswer((_) async => CocoaPodsStatus.belowRecommendedVersion);
|
|
when(xcode.isSimctlInstalled).thenReturn(true);
|
|
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
|
|
final ValidationResult result = await workflow.validate();
|
|
expect(result.type, ValidationType.partial);
|
|
}, overrides: <Type, Generator>{
|
|
IMobileDevice: () => iMobileDevice,
|
|
Xcode: () => xcode,
|
|
CocoaPods: () => cocoaPods,
|
|
});
|
|
|
|
testUsingContext('Emits partial status when CocoaPods is not initialized', () 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(cocoaPods.isCocoaPodsInitialized).thenAnswer((_) async => false);
|
|
when(xcode.isSimctlInstalled).thenReturn(true);
|
|
|
|
final ValidationResult result = await new IOSWorkflowTestTarget().validate();
|
|
expect(result.type, ValidationType.partial);
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => fs,
|
|
IMobileDevice: () => iMobileDevice,
|
|
Xcode: () => xcode,
|
|
CocoaPods: () => cocoaPods,
|
|
ProcessManager: () => processManager,
|
|
});
|
|
|
|
testUsingContext('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);
|
|
final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
|
|
final ValidationResult result = await workflow.validate();
|
|
expect(result.type, ValidationType.partial);
|
|
}, overrides: <Type, Generator>{
|
|
IMobileDevice: () => iMobileDevice,
|
|
Xcode: () => xcode,
|
|
CocoaPods: () => cocoaPods,
|
|
});
|
|
|
|
|
|
testUsingContext('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);
|
|
|
|
ensureDirectoryExists(fs.path.join(homeDirPath, '.cocoapods', 'repos', 'master', 'README.md'));
|
|
|
|
final ValidationResult result = await new IOSWorkflowTestTarget().validate();
|
|
expect(result.type, ValidationType.installed);
|
|
}, overrides: <Type, Generator>{
|
|
FileSystem: () => fs,
|
|
IMobileDevice: () => iMobileDevice,
|
|
Xcode: () => xcode,
|
|
CocoaPods: () => cocoaPods,
|
|
ProcessManager: () => processManager,
|
|
});
|
|
});
|
|
}
|
|
|
|
final ProcessResult exitsHappy = new ProcessResult(
|
|
1, // pid
|
|
0, // exitCode
|
|
'', // stdout
|
|
'', // stderr
|
|
);
|
|
|
|
class MockIMobileDevice extends IMobileDevice {
|
|
MockIMobileDevice({
|
|
this.isInstalled = true,
|
|
bool isWorking = true,
|
|
}) : isWorking = new Future<bool>.value(isWorking);
|
|
|
|
@override
|
|
final bool isInstalled;
|
|
|
|
@override
|
|
final Future<bool> isWorking;
|
|
}
|
|
|
|
class MockXcode extends Mock implements Xcode {}
|
|
class MockProcessManager extends Mock implements ProcessManager {}
|
|
class MockCocoaPods extends Mock implements CocoaPods {}
|
|
|
|
class IOSWorkflowTestTarget extends IOSValidator {
|
|
IOSWorkflowTestTarget({
|
|
this.hasHomebrew = true,
|
|
bool hasIosDeploy = true,
|
|
String iosDeployVersionText = '1.9.2',
|
|
bool hasIDeviceInstaller = true,
|
|
}) : hasIosDeploy = new Future<bool>.value(hasIosDeploy),
|
|
iosDeployVersionText = new Future<String>.value(iosDeployVersionText),
|
|
hasIDeviceInstaller = new Future<bool>.value(hasIDeviceInstaller);
|
|
|
|
@override
|
|
final bool hasHomebrew;
|
|
|
|
@override
|
|
final Future<bool> hasIosDeploy;
|
|
|
|
@override
|
|
final Future<String> iosDeployVersionText;
|
|
|
|
@override
|
|
final Future<bool> hasIDeviceInstaller;
|
|
}
|