xcode_validator_test.dart 8.17 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 101 102 103 104 105 106 107
      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(
          command: <String>['xcrun', 'simctl', 'list'],
        ),
      ]);
      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 138 139 140 141 142 143 144 145
      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(
          command: <String>['xcrun', 'simctl', 'list'],
          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 176 177 178 179 180 181 182
      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(
          command: <String>['xcrun', 'simctl', 'list'],
        ),
      ]);
      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 187 188 189 190
      expect(result.messages.length, 1);
      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 192 193
    });
  });
}