ios_workflow_test.dart 11 KB
Newer Older
1 2 3 4
// 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.

5 6
import 'dart:async';

7 8 9
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/common.dart';
import 'package:flutter_tools/src/base/file_system.dart';
10
import 'package:flutter_tools/src/base/io.dart';
11 12 13
import 'package:flutter_tools/src/doctor.dart';
import 'package:flutter_tools/src/ios/ios_workflow.dart';
import 'package:flutter_tools/src/ios/mac.dart';
14
import 'package:mockito/mockito.dart';
15
import 'package:process/process.dart';
16 17
import 'package:test/test.dart';

18
import '../src/context.dart';
19 20 21

void main() {
  group('iOS Workflow validation', () {
22
    MockXcode xcode;
23
    MockProcessManager processManager;
24
    FileSystem fs;
25

26
    setUp(() {
27
      xcode = new MockXcode();
28
      processManager = new MockProcessManager();
29
      fs = new MemoryFileSystem();
30 31 32 33
    });

    testUsingContext('Emit missing status when nothing is installed', () async {
      when(xcode.isInstalled).thenReturn(false);
34
      when(xcode.xcodeSelectPath).thenReturn(null);
35 36 37 38 39
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(
        hasPythonSixModule: false,
        hasHomebrew: false,
        hasIosDeploy: false,
      );
40
      final ValidationResult result = await workflow.validate();
41
      expect(result.type, ValidationType.missing);
42
    }, overrides: <Type, Generator>{ Xcode: () => xcode });
43 44 45

    testUsingContext('Emits partial status when Xcode is not installed', () async {
      when(xcode.isInstalled).thenReturn(false);
46
      when(xcode.xcodeSelectPath).thenReturn(null);
47 48
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
      final ValidationResult result = await workflow.validate();
49 50 51 52 53 54
      expect(result.type, ValidationType.partial);
    }, overrides: <Type, Generator>{ Xcode: () => xcode });

    testUsingContext('Emits partial status when Xcode is partially installed', () async {
      when(xcode.isInstalled).thenReturn(false);
      when(xcode.xcodeSelectPath).thenReturn('/Library/Developer/CommandLineTools');
55 56
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
      final ValidationResult result = await workflow.validate();
57
      expect(result.type, ValidationType.partial);
58
    }, overrides: <Type, Generator>{ Xcode: () => xcode });
59 60 61 62 63 64 65

    testUsingContext('Emits partial status when Xcode version too low', () async {
      when(xcode.isInstalled).thenReturn(true);
      when(xcode.xcodeVersionText)
          .thenReturn('Xcode 7.0.1\nBuild version 7C1002\n');
      when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(false);
      when(xcode.eulaSigned).thenReturn(true);
66 67
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
      final ValidationResult result = await workflow.validate();
68
      expect(result.type, ValidationType.partial);
69
    }, overrides: <Type, Generator>{ Xcode: () => xcode });
70 71 72 73 74 75 76

    testUsingContext('Emits partial status when Xcode EULA not signed', () async {
      when(xcode.isInstalled).thenReturn(true);
      when(xcode.xcodeVersionText)
          .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
      when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
      when(xcode.eulaSigned).thenReturn(false);
77 78
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
      final ValidationResult result = await workflow.validate();
79
      expect(result.type, ValidationType.partial);
80
    }, overrides: <Type, Generator>{ Xcode: () => xcode });
81

82 83 84 85 86 87
    testUsingContext('Emits partial status when python six not installed', () async {
      when(xcode.isInstalled).thenReturn(true);
      when(xcode.xcodeVersionText)
          .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
      when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
      when(xcode.eulaSigned).thenReturn(true);
88
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(hasPythonSixModule: false);
89
      final ValidationResult result = await workflow.validate();
90 91 92
      expect(result.type, ValidationType.partial);
    }, overrides: <Type, Generator>{ Xcode: () => xcode });

93 94 95 96 97 98
    testUsingContext('Emits partial status when homebrew not installed', () async {
      when(xcode.isInstalled).thenReturn(true);
      when(xcode.xcodeVersionText)
          .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
      when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
      when(xcode.eulaSigned).thenReturn(true);
99
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(hasHomebrew: false);
100
      final ValidationResult result = await workflow.validate();
101
      expect(result.type, ValidationType.partial);
102
    }, overrides: <Type, Generator>{ Xcode: () => xcode });
103

104 105 106 107 108 109
    testUsingContext('Emits partial status when libimobiledevice is not installed', () async {
      when(xcode.isInstalled).thenReturn(true);
      when(xcode.xcodeVersionText)
          .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
      when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
      when(xcode.eulaSigned).thenReturn(true);
110
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(hasWorkingLibimobiledevice: false);
111 112 113 114
      final ValidationResult result = await workflow.validate();
      expect(result.type, ValidationType.partial);
    }, overrides: <Type, Generator>{ Xcode: () => xcode });

115 116 117 118 119 120
    testUsingContext('Emits partial status when ios-deploy is not installed', () async {
      when(xcode.isInstalled).thenReturn(true);
      when(xcode.xcodeVersionText)
          .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
      when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
      when(xcode.eulaSigned).thenReturn(true);
121
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(hasIosDeploy: false);
122
      final ValidationResult result = await workflow.validate();
123
      expect(result.type, ValidationType.partial);
124
    }, overrides: <Type, Generator>{ Xcode: () => xcode });
125 126 127 128 129 130 131

    testUsingContext('Emits partial status when ios-deploy version is too low', () async {
      when(xcode.isInstalled).thenReturn(true);
      when(xcode.xcodeVersionText)
          .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
      when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
      when(xcode.eulaSigned).thenReturn(true);
132
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(iosDeployVersionText: '1.8.0');
133
      final ValidationResult result = await workflow.validate();
134
      expect(result.type, ValidationType.partial);
135
    }, overrides: <Type, Generator>{ Xcode: () => xcode });
136

137 138 139 140 141 142
    testUsingContext('Emits partial status when CocoaPods is not installed', () async {
      when(xcode.isInstalled).thenReturn(true);
      when(xcode.xcodeVersionText)
          .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
      when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
      when(xcode.eulaSigned).thenReturn(true);
143
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(hasCocoaPods: false);
144 145 146 147 148 149 150 151 152 153
      final ValidationResult result = await workflow.validate();
      expect(result.type, ValidationType.partial);
    }, overrides: <Type, Generator>{ Xcode: () => xcode });

    testUsingContext('Emits partial status when CocoaPods version is too low', () async {
      when(xcode.isInstalled).thenReturn(true);
      when(xcode.xcodeVersionText)
          .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
      when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
      when(xcode.eulaSigned).thenReturn(true);
154
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(cocoaPodsVersionText: '0.39.0');
155 156 157 158
      final ValidationResult result = await workflow.validate();
      expect(result.type, ValidationType.partial);
    }, overrides: <Type, Generator>{ Xcode: () => xcode });

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
    testUsingContext('Emits partial status when CocoaPods is not initialized', () async {
      when(xcode.isInstalled).thenReturn(true);
      when(xcode.xcodeVersionText)
          .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
      when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
      when(xcode.eulaSigned).thenReturn(true);

      when(processManager.runSync(argThat(contains('idevice_id'))))
          .thenReturn(exitsHappy);
      when(processManager.run(argThat(contains('idevice_id')), workingDirectory: any, environment: any))
          .thenReturn(exitsHappy);

      final ValidationResult result = await new IOSWorkflowTestTarget().validate();
      expect(result.type, ValidationType.partial);
    }, overrides: <Type, Generator>{
      FileSystem: () => fs,
      Xcode: () => xcode,
      ProcessManager: () => processManager,
    });

179 180 181 182 183 184
    testUsingContext('Succeeds when all checks pass', () async {
      when(xcode.isInstalled).thenReturn(true);
      when(xcode.xcodeVersionText)
          .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
      when(xcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
      when(xcode.eulaSigned).thenReturn(true);
185 186 187 188 189 190

      when(processManager.runSync(argThat(contains('idevice_id'))))
          .thenReturn(exitsHappy);
      when(processManager.run(argThat(contains('idevice_id')), workingDirectory: any, environment: any))
          .thenReturn(exitsHappy);

191 192
      ensureDirectoryExists(fs.path.join(homeDirPath, '.cocoapods', 'repos', 'master', 'README.md'));

193
      final ValidationResult result = await new IOSWorkflowTestTarget().validate();
194
      expect(result.type, ValidationType.installed);
195
    }, overrides: <Type, Generator>{
196
      FileSystem: () => fs,
197 198 199
      Xcode: () => xcode,
      ProcessManager: () => processManager,
    });
200 201 202
  });
}

203 204 205 206 207 208 209
final ProcessResult exitsHappy = new ProcessResult(
  1,     // pid
  0,     // exitCode
  '',    // stdout
  '',    // stderr
);

210
class MockXcode extends Mock implements Xcode {}
211
class MockProcessManager extends Mock implements ProcessManager {}
212 213

class IOSWorkflowTestTarget extends IOSWorkflow {
214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
  IOSWorkflowTestTarget({
    this.hasPythonSixModule: true,
    this.hasHomebrew: true,
    bool hasWorkingLibimobiledevice: true,
    bool hasIosDeploy: true,
    String iosDeployVersionText: '1.9.0',
    bool hasIDeviceInstaller: true,
    bool hasCocoaPods: true,
    String cocoaPodsVersionText: '1.2.0',
  }) : hasWorkingLibimobiledevice = new Future<bool>.value(hasWorkingLibimobiledevice),
       hasIosDeploy = new Future<bool>.value(hasIosDeploy),
       iosDeployVersionText = new Future<String>.value(iosDeployVersionText),
       hasIDeviceInstaller = new Future<bool>.value(hasIDeviceInstaller),
       hasCocoaPods = new Future<bool>.value(hasCocoaPods),
       cocoaPodsVersionText = new Future<String>.value(cocoaPodsVersionText);

230
  @override
231
  final bool hasPythonSixModule;
232

233
  @override
234
  final bool hasHomebrew;
235

236
  @override
237
  final Future<bool> hasWorkingLibimobiledevice;
238

239
  @override
240
  final Future<bool> hasIosDeploy;
241 242

  @override
243
  final Future<String> iosDeployVersionText;
244 245

  @override
246
  final Future<bool> hasIDeviceInstaller;
247 248

  @override
249
  final Future<bool> hasCocoaPods;
250 251

  @override
252
  final Future<String> cocoaPodsVersionText;
253
}