xcode_validator_test.dart 8.29 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'package:flutter_tools/src/base/user_messages.dart';
6
import 'package:flutter_tools/src/base/version.dart';
7
import 'package:flutter_tools/src/doctor_validator.dart';
8
import 'package:flutter_tools/src/ios/xcodeproj.dart';
9 10 11
import 'package:flutter_tools/src/macos/xcode.dart';
import 'package:flutter_tools/src/macos/xcode_validator.dart';

12
import '../../src/common.dart';
13
import '../../src/fake_process_manager.dart';
14 15 16

void main() {
  group('Xcode validation', () {
17
    testWithoutContext('Emits missing status when Xcode is not installed', () async {
18 19 20 21 22
      final ProcessManager processManager = FakeProcessManager.any();
      final Xcode xcode = Xcode.test(
        processManager: processManager,
        xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager, version: null),
      );
23
      final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages());
24 25
      final ValidationResult result = await validator.validate();
      expect(result.type, ValidationType.missing);
26
      expect(result.statusInfo, isNull);
27 28
      expect(result.messages.last.type, ValidationMessageType.error);
      expect(result.messages.last.message, contains('Xcode not installed'));
29 30
    });

31
    testWithoutContext('Emits missing status when Xcode installation is incomplete', () async {
32 33 34 35 36 37 38 39 40 41
      final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
        const FakeCommand(
          command: <String>['/usr/bin/xcode-select', '--print-path'],
          stdout: '/Library/Developer/CommandLineTools',
        ),
      ]);
      final Xcode xcode = Xcode.test(
      processManager: processManager,
        xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager, version: null),
      );
42
      final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages());
43 44
      final ValidationResult result = await validator.validate();
      expect(result.type, ValidationType.missing);
45 46
      expect(result.messages.last.type, ValidationMessageType.error);
      expect(result.messages.last.message, contains('Xcode installation is incomplete'));
47 48
    });

49
    testWithoutContext('Emits partial status when Xcode version too low', () async {
50 51 52 53 54
      final ProcessManager processManager = FakeProcessManager.any();
      final Xcode xcode = Xcode.test(
        processManager: processManager,
        xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager, version: Version(7, 0, 1)),
      );
55
      final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages());
56 57
      final ValidationResult result = await validator.validate();
      expect(result.type, ValidationType.partial);
58
      expect(result.messages.last.type, ValidationMessageType.error);
59
      expect(result.messages.last.message, contains('Flutter requires Xcode 13 or higher'));
60 61 62
    });

    testWithoutContext('Emits partial status when Xcode below recommended version', () async {
63 64 65
      final ProcessManager processManager = FakeProcessManager.any();
      final Xcode xcode = Xcode.test(
        processManager: processManager,
66
        xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager, version: Version(12, 4, null)),
67
      );
68 69 70 71
      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);
72
      expect(result.messages.last.message, contains('Flutter recommends a minimum Xcode version of 13'));
73
    }, skip: true); // [intended] Unskip and update when minimum and required check versions diverge.
74

75
    testWithoutContext('Emits partial status when Xcode EULA not signed', () async {
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
      final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
        const FakeCommand(
          command: <String>['/usr/bin/xcode-select', '--print-path'],
          stdout: '/Library/Developer/CommandLineTools',
        ),
        const FakeCommand(
          command: <String>[
            'which',
            'sysctl',
          ],
        ),
        const FakeCommand(
          command: <String>[
            'sysctl',
            'hw.optional.arm64',
          ],
          exitCode: 1,
        ),
        const FakeCommand(
          command: <String>['xcrun', 'clang'],
          exitCode: 1,
          stderr:
          'Xcode EULA has not been accepted.\nLaunch Xcode and accept the license.',
        ),
        const FakeCommand(
101
          command: <String>['xcrun', 'simctl', 'list', 'devices', 'booted'],
102 103 104 105 106 107
        ),
      ]);
      final Xcode xcode = Xcode.test(
        processManager: processManager,
        xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager),
      );
108
      final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages());
109 110
      final ValidationResult result = await validator.validate();
      expect(result.type, ValidationType.partial);
111 112
      expect(result.messages.last.type, ValidationMessageType.error);
      expect(result.messages.last.message, contains('code end user license agreement not signed'));
113 114
    });

115
    testWithoutContext('Emits partial status when simctl is not installed', () async {
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
      final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
        const FakeCommand(
          command: <String>['/usr/bin/xcode-select', '--print-path'],
          stdout: '/Library/Developer/CommandLineTools',
        ),
        const FakeCommand(
          command: <String>[
            'which',
            'sysctl',
          ],
        ),
        const FakeCommand(
          command: <String>[
            'sysctl',
            'hw.optional.arm64',
          ],
          exitCode: 1,
        ),
        const FakeCommand(
          command: <String>['xcrun', 'clang'],
        ),
        const FakeCommand(
138
          command: <String>['xcrun', 'simctl', 'list', 'devices', 'booted'],
139 140 141 142 143 144 145
          exitCode: 1,
        ),
      ]);
      final Xcode xcode = Xcode.test(
        processManager: processManager,
        xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager),
      );
146
      final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages());
147 148
      final ValidationResult result = await validator.validate();
      expect(result.type, ValidationType.partial);
149 150
      expect(result.messages.last.type, ValidationMessageType.error);
      expect(result.messages.last.message, contains('Xcode requires additional components'));
151 152
    });

153
    testWithoutContext('Succeeds when all checks pass', () async {
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
      final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
        const FakeCommand(
          command: <String>['/usr/bin/xcode-select', '--print-path'],
          stdout: '/Library/Developer/CommandLineTools',
        ),
        const FakeCommand(
          command: <String>[
            'which',
            'sysctl',
          ],
        ),
        const FakeCommand(
          command: <String>[
            'sysctl',
            'hw.optional.arm64',
          ],
          exitCode: 1,
        ),
        const FakeCommand(
          command: <String>['xcrun', 'clang'],
        ),
        const FakeCommand(
176
          command: <String>['xcrun', 'simctl', 'list', 'devices', 'booted'],
177 178 179 180 181 182
        ),
      ]);
      final Xcode xcode = Xcode.test(
        processManager: processManager,
        xcodeProjectInterpreter: XcodeProjectInterpreter.test(processManager: processManager),
      );
183
      final XcodeValidator validator = XcodeValidator(xcode: xcode, userMessages: UserMessages());
184 185
      final ValidationResult result = await validator.validate();
      expect(result.type, ValidationType.installed);
186
      expect(result.messages.length, 2);
187 188 189 190
      final ValidationMessage firstMessage = result.messages.first;
      expect(firstMessage.type, ValidationMessageType.information);
      expect(firstMessage.message, 'Xcode at /Library/Developer/CommandLineTools');
      expect(result.statusInfo, '1000.0.0');
191
      expect(result.messages[1].message, 'Build 13C100');
192 193 194
    });
  });
}