ios_workflow_test.dart 13.1 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
import 'package:flutter_tools/src/doctor.dart';
12
import 'package:flutter_tools/src/ios/cocoapods.dart';
13 14
import 'package:flutter_tools/src/ios/ios_workflow.dart';
import 'package:flutter_tools/src/ios/mac.dart';
15
import 'package:mockito/mockito.dart';
16
import 'package:process/process.dart';
17 18
import 'package:test/test.dart';

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

void main() {
  group('iOS Workflow validation', () {
23
    MockIMobileDevice iMobileDevice;
24
    MockXcode xcode;
25
    MockProcessManager processManager;
26
    MockCocoaPods cocoaPods;
27
    FileSystem fs;
28

29
    setUp(() {
30
      iMobileDevice = new MockIMobileDevice();
31
      xcode = new MockXcode();
32
      processManager = new MockProcessManager();
33
      cocoaPods = new MockCocoaPods();
34
      fs = new MemoryFileSystem();
35 36 37

      when(cocoaPods.isCocoaPodsInstalledAndMeetsVersionCheck).thenReturn(true);
      when(cocoaPods.isCocoaPodsInitialized).thenReturn(true);
38 39 40 41
    });

    testUsingContext('Emit missing status when nothing is installed', () async {
      when(xcode.isInstalled).thenReturn(false);
42
      when(xcode.xcodeSelectPath).thenReturn(null);
43 44 45 46 47
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(
        hasPythonSixModule: false,
        hasHomebrew: false,
        hasIosDeploy: false,
      );
48
      final ValidationResult result = await workflow.validate();
49
      expect(result.type, ValidationType.missing);
50 51 52
    }, overrides: <Type, Generator>{
      IMobileDevice: () => iMobileDevice,
      Xcode: () => xcode,
53
      CocoaPods: () => cocoaPods,
54
    });
55 56 57

    testUsingContext('Emits partial status when Xcode is not installed', () async {
      when(xcode.isInstalled).thenReturn(false);
58
      when(xcode.xcodeSelectPath).thenReturn(null);
59 60
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
      final ValidationResult result = await workflow.validate();
61
      expect(result.type, ValidationType.partial);
62 63 64
    }, overrides: <Type, Generator>{
      IMobileDevice: () => iMobileDevice,
      Xcode: () => xcode,
65
      CocoaPods: () => cocoaPods,
66
    });
67 68 69 70

    testUsingContext('Emits partial status when Xcode is partially installed', () async {
      when(xcode.isInstalled).thenReturn(false);
      when(xcode.xcodeSelectPath).thenReturn('/Library/Developer/CommandLineTools');
71 72
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
      final ValidationResult result = await workflow.validate();
73
      expect(result.type, ValidationType.partial);
74 75 76
    }, overrides: <Type, Generator>{
      IMobileDevice: () => iMobileDevice,
      Xcode: () => xcode,
77
      CocoaPods: () => cocoaPods,
78
    });
79 80 81 82 83 84 85

    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);
86 87
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
      final ValidationResult result = await workflow.validate();
88
      expect(result.type, ValidationType.partial);
89 90 91
    }, overrides: <Type, Generator>{
      IMobileDevice: () => iMobileDevice,
      Xcode: () => xcode,
92
      CocoaPods: () => cocoaPods,
93
    });
94 95 96 97 98 99 100

    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);
101 102
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
      final ValidationResult result = await workflow.validate();
103
      expect(result.type, ValidationType.partial);
104 105 106
    }, overrides: <Type, Generator>{
      IMobileDevice: () => iMobileDevice,
      Xcode: () => xcode,
107
      CocoaPods: () => cocoaPods,
108
    });
109

110 111 112 113 114 115 116 117 118 119 120 121
    testUsingContext('Emits partial status when Mac dev mode was never enabled', () 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);
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(macDevMode: 'Developer mode is currently disabled.');
      final ValidationResult result = await workflow.validate();
      expect(result.type, ValidationType.partial);
    }, overrides: <Type, Generator>{
      IMobileDevice: () => iMobileDevice,
      Xcode: () => xcode,
122
      CocoaPods: () => cocoaPods,
123 124
    });

125 126 127 128 129 130
    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);
131
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(hasPythonSixModule: false);
132
      final ValidationResult result = await workflow.validate();
133
      expect(result.type, ValidationType.partial);
134 135 136
    }, overrides: <Type, Generator>{
      IMobileDevice: () => iMobileDevice,
      Xcode: () => xcode,
137
      CocoaPods: () => cocoaPods,
138
    });
139

140 141 142 143 144 145
    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);
146
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(hasHomebrew: false);
147
      final ValidationResult result = await workflow.validate();
148
      expect(result.type, ValidationType.partial);
149 150 151
    }, overrides: <Type, Generator>{
      IMobileDevice: () => iMobileDevice,
      Xcode: () => xcode,
152
      CocoaPods: () => cocoaPods,
153
    });
154

155 156 157 158 159 160
    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);
161
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
162 163
      final ValidationResult result = await workflow.validate();
      expect(result.type, ValidationType.partial);
164 165 166
    }, overrides: <Type, Generator>{
      IMobileDevice: () => new MockIMobileDevice(isWorking: false),
      Xcode: () => xcode,
167
      CocoaPods: () => cocoaPods,
168
    });
169

170 171 172 173 174 175
    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);
176
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(hasIosDeploy: false);
177
      final ValidationResult result = await workflow.validate();
178
      expect(result.type, ValidationType.partial);
179 180 181
    }, overrides: <Type, Generator>{
      IMobileDevice: () => iMobileDevice,
      Xcode: () => xcode,
182
      CocoaPods: () => cocoaPods,
183
    });
184 185 186 187 188 189 190

    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);
191
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget(iosDeployVersionText: '1.8.0');
192
      final ValidationResult result = await workflow.validate();
193
      expect(result.type, ValidationType.partial);
194 195 196
    }, overrides: <Type, Generator>{
      IMobileDevice: () => iMobileDevice,
      Xcode: () => xcode,
197
      CocoaPods: () => cocoaPods,
198
    });
199

200 201 202 203 204 205
    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);
206 207 208
      when(cocoaPods.isCocoaPodsInstalledAndMeetsVersionCheck).thenReturn(false);
      when(cocoaPods.hasCocoaPods).thenReturn(false);
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
209 210
      final ValidationResult result = await workflow.validate();
      expect(result.type, ValidationType.partial);
211 212 213
    }, overrides: <Type, Generator>{
      IMobileDevice: () => iMobileDevice,
      Xcode: () => xcode,
214
      CocoaPods: () => cocoaPods,
215
    });
216 217 218 219 220 221 222

    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);
223 224 225 226
      when(cocoaPods.isCocoaPodsInstalledAndMeetsVersionCheck).thenReturn(false);
      when(cocoaPods.hasCocoaPods).thenReturn(true);
      when(cocoaPods.cocoaPodsVersionText).thenReturn('0.39.0');
      final IOSWorkflowTestTarget workflow = new IOSWorkflowTestTarget();
227 228
      final ValidationResult result = await workflow.validate();
      expect(result.type, ValidationType.partial);
229 230 231
    }, overrides: <Type, Generator>{
      IMobileDevice: () => iMobileDevice,
      Xcode: () => xcode,
232
      CocoaPods: () => cocoaPods,
233
    });
234

235 236 237 238 239 240
    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);
241 242 243
      when(cocoaPods.isCocoaPodsInstalledAndMeetsVersionCheck).thenReturn(false);
      when(cocoaPods.hasCocoaPods).thenReturn(true);
      when(cocoaPods.isCocoaPodsInitialized).thenReturn(false);
244 245 246 247 248

      final ValidationResult result = await new IOSWorkflowTestTarget().validate();
      expect(result.type, ValidationType.partial);
    }, overrides: <Type, Generator>{
      FileSystem: () => fs,
249
      IMobileDevice: () => iMobileDevice,
250
      Xcode: () => xcode,
251
      CocoaPods: () => cocoaPods,
252 253 254
      ProcessManager: () => processManager,
    });

255 256 257 258 259 260
    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);
261

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

264
      final ValidationResult result = await new IOSWorkflowTestTarget().validate();
265
      expect(result.type, ValidationType.installed);
266
    }, overrides: <Type, Generator>{
267
      FileSystem: () => fs,
268
      IMobileDevice: () => iMobileDevice,
269
      Xcode: () => xcode,
270
      CocoaPods: () => cocoaPods,
271 272
      ProcessManager: () => processManager,
    });
273 274 275
  });
}

276 277 278 279 280 281 282
final ProcessResult exitsHappy = new ProcessResult(
  1,     // pid
  0,     // exitCode
  '',    // stdout
  '',    // stderr
);

283 284 285 286 287 288 289
class MockIMobileDevice extends IMobileDevice {
  MockIMobileDevice({bool isWorking: true}) : isWorking = new Future<bool>.value(isWorking);

  @override
  final Future<bool> isWorking;
}

290
class MockXcode extends Mock implements Xcode {}
291
class MockProcessManager extends Mock implements ProcessManager {}
292
class MockCocoaPods extends Mock implements CocoaPods {}
293 294

class IOSWorkflowTestTarget extends IOSWorkflow {
295 296 297 298
  IOSWorkflowTestTarget({
    this.hasPythonSixModule: true,
    this.hasHomebrew: true,
    bool hasIosDeploy: true,
299
    String iosDeployVersionText: '1.9.2',
300
    bool hasIDeviceInstaller: true,
301
    String macDevMode: 'Developer mode is already enabled.',
302
  }) : hasIosDeploy = new Future<bool>.value(hasIosDeploy),
303 304
       iosDeployVersionText = new Future<String>.value(iosDeployVersionText),
       hasIDeviceInstaller = new Future<bool>.value(hasIDeviceInstaller),
305
       macDevMode = new Future<String>.value(macDevMode);
306

307
  @override
308
  final bool hasPythonSixModule;
309

310
  @override
311
  final bool hasHomebrew;
312 313

  @override
314
  final Future<bool> hasIosDeploy;
315 316

  @override
317
  final Future<String> iosDeployVersionText;
318 319

  @override
320
  final Future<bool> hasIDeviceInstaller;
321

322 323
  @override
  final Future<String> macDevMode;
324
}