linux_doctor_test.dart 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/doctor_validator.dart';
7 8
import 'package:flutter_tools/src/linux/linux_doctor.dart';

9
import '../../src/common.dart';
10
import '../../src/fake_process_manager.dart';
11

12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
// A command that will return typical-looking 'clang++ --version' output with
// the given version number.
FakeCommand _clangPresentCommand(String version) {
  return FakeCommand(
    command: const <String>['clang++', '--version'],
    stdout: '''
clang version $version-6+build1
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
''',
  );
}

// A command that will return typical-looking 'cmake --version' output with the
// given version number.
FakeCommand _cmakePresentCommand(String version) {
  return FakeCommand(
    command: const <String>['cmake', '--version'],
    stdout: '''
cmake version $version

CMake suite maintained and supported by Kitware (kitware.com/cmake).
''',
  );
}

// A command that will return typical-looking 'ninja --version' output with the
// given version number.
FakeCommand _ninjaPresentCommand(String version) {
  return FakeCommand(
    command: const <String>['ninja', '--version'],
    stdout: version,
  );
}

Taha Tesser's avatar
Taha Tesser committed
48
// A command that will return typical-looking 'pkg-config --version' output with
49 50 51 52 53 54 55 56
// the given version number.
FakeCommand _pkgConfigPresentCommand(String version) {
  return FakeCommand(
    command: const <String>['pkg-config', '--version'],
    stdout: version,
  );
}

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
/// A command that returns either success or failure for a pkg-config query
/// for [library], depending on [exists].
FakeCommand _libraryCheckCommand(String library, {bool exists = true}) {
  return FakeCommand(
    command: <String>['pkg-config', '--exists', library],
    exitCode: exists ? 0 : 1,
  );
}

// Commands that give positive replies for all the GTK library pkg-config queries.
List<FakeCommand> _gtkLibrariesPresentCommands() {
  return <FakeCommand>[
    _libraryCheckCommand('gtk+-3.0'),
    _libraryCheckCommand('glib-2.0'),
    _libraryCheckCommand('gio-2.0'),
72 73 74
  ];
}

75 76 77 78 79 80 81
// Commands that give some failures for the GTK library pkg-config queries.
List<FakeCommand> _gtkLibrariesMissingCommands() {
  return <FakeCommand>[
    _libraryCheckCommand('gtk+-3.0'),
    _libraryCheckCommand('glib-2.0', exists: false),
    // No more entries, since the first missing GTK library stops the
    // checks.
82 83 84
  ];
}

85 86 87 88 89 90 91 92
// A command that will failure when running '[binary] --version'.
FakeCommand _missingBinaryCommand(String binary) {
  return FakeCommand(
    command: <String>[binary, '--version'],
    exitCode: 1,
  );
}

93
void main() {
94
  testWithoutContext('Full validation when everything is available at the necessary version',() async {
95
    final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
96 97 98
      _clangPresentCommand('4.0.1'),
      _cmakePresentCommand('3.16.3'),
      _ninjaPresentCommand('1.10.0'),
99
      _pkgConfigPresentCommand('0.29'),
100
      ..._gtkLibrariesPresentCommands(),
101 102 103
    ]);
    final DoctorValidator linuxDoctorValidator = LinuxDoctorValidator(
      processManager: processManager,
104
      userMessages: UserMessages(),
105 106 107 108
    );
    final ValidationResult result = await linuxDoctorValidator.validate();

    expect(result.type, ValidationType.installed);
109
    expect(result.messages, const <ValidationMessage>[
110 111 112
      ValidationMessage('clang version 4.0.1-6+build1'),
      ValidationMessage('cmake version 3.16.3'),
      ValidationMessage('ninja version 1.10.0'),
113
      ValidationMessage('pkg-config version 0.29'),
114 115
    ]);
  });
116

117 118
  testWithoutContext('Partial validation when clang++ version is too old', () async {
    final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
119 120 121
      _clangPresentCommand('2.0.1'),
      _cmakePresentCommand('3.16.3'),
      _ninjaPresentCommand('1.10.0'),
122
      _pkgConfigPresentCommand('0.29'),
123
      ..._gtkLibrariesPresentCommands(),
124 125 126
    ]);
    final DoctorValidator linuxDoctorValidator = LinuxDoctorValidator(
      processManager: processManager,
127
      userMessages: UserMessages(),
128 129 130 131
    );
    final ValidationResult result = await linuxDoctorValidator.validate();

    expect(result.type, ValidationType.partial);
132
    expect(result.messages, const <ValidationMessage>[
133 134 135 136
      ValidationMessage('clang version 2.0.1-6+build1'),
      ValidationMessage.error('clang++ 3.4.0 or later is required.'),
      ValidationMessage('cmake version 3.16.3'),
      ValidationMessage('ninja version 1.10.0'),
137
      ValidationMessage('pkg-config version 0.29'),
138 139
    ]);
  });
140

141
  testWithoutContext('Partial validation when CMake version is too old', () async {
142
    final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
143 144 145
      _clangPresentCommand('4.0.1'),
      _cmakePresentCommand('3.2.0'),
      _ninjaPresentCommand('1.10.0'),
146
      _pkgConfigPresentCommand('0.29'),
147
      ..._gtkLibrariesPresentCommands(),
148 149 150
    ]);
    final DoctorValidator linuxDoctorValidator = LinuxDoctorValidator(
      processManager: processManager,
151
      userMessages: UserMessages(),
152 153 154
    );
    final ValidationResult result = await linuxDoctorValidator.validate();

155 156 157 158 159 160
    expect(result.type, ValidationType.partial);
    expect(result.messages, const <ValidationMessage>[
      ValidationMessage('clang version 4.0.1-6+build1'),
      ValidationMessage('cmake version 3.2.0'),
      ValidationMessage.error('cmake 3.10.0 or later is required.'),
      ValidationMessage('ninja version 1.10.0'),
161
      ValidationMessage('pkg-config version 0.29'),
162 163 164 165 166 167 168 169
    ]);
  });

  testWithoutContext('Partial validation when ninja version is too old', () async {
    final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
      _clangPresentCommand('4.0.1'),
      _cmakePresentCommand('3.16.3'),
      _ninjaPresentCommand('0.8.1'),
170
      _pkgConfigPresentCommand('0.29'),
171
      ..._gtkLibrariesPresentCommands(),
172 173 174 175 176 177 178 179
    ]);
    final DoctorValidator linuxDoctorValidator = LinuxDoctorValidator(
      processManager: processManager,
      userMessages: UserMessages(),
    );
    final ValidationResult result = await linuxDoctorValidator.validate();

    expect(result.type, ValidationType.partial);
180
    expect(result.messages, const <ValidationMessage>[
181 182 183 184
      ValidationMessage('clang version 4.0.1-6+build1'),
      ValidationMessage('cmake version 3.16.3'),
      ValidationMessage('ninja version 0.8.1'),
      ValidationMessage.error('ninja 1.8.0 or later is required.'),
185 186 187 188 189 190 191 192 193 194
      ValidationMessage('pkg-config version 0.29'),
    ]);
  });

  testWithoutContext('Partial validation when pkg-config version is too old', () async {
    final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
      _clangPresentCommand('4.0.1'),
      _cmakePresentCommand('3.16.3'),
      _ninjaPresentCommand('1.10.0'),
      _pkgConfigPresentCommand('0.27.0'),
195
      ..._gtkLibrariesPresentCommands(),
196 197 198 199 200 201 202 203 204 205 206 207 208 209
    ]);
    final DoctorValidator linuxDoctorValidator = LinuxDoctorValidator(
      processManager: processManager,
      userMessages: UserMessages(),
    );
    final ValidationResult result = await linuxDoctorValidator.validate();

    expect(result.type, ValidationType.partial);
    expect(result.messages, const <ValidationMessage>[
      ValidationMessage('clang version 4.0.1-6+build1'),
      ValidationMessage('cmake version 3.16.3'),
      ValidationMessage('ninja version 1.10.0'),
      ValidationMessage('pkg-config version 0.27.0'),
      ValidationMessage.error('pkg-config 0.29.0 or later is required.'),
210 211 212 213 214 215 216 217
    ]);
  });

  testWithoutContext('Missing validation when CMake is not available', () async {
    final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
      _clangPresentCommand('4.0.1'),
      _missingBinaryCommand('cmake'),
      _ninjaPresentCommand('1.10.0'),
218
      _pkgConfigPresentCommand('0.29'),
219
      ..._gtkLibrariesPresentCommands(),
220 221 222 223 224 225 226 227 228 229 230 231 232
    ]);
    final UserMessages userMessages = UserMessages();
    final DoctorValidator linuxDoctorValidator = LinuxDoctorValidator(
      processManager: processManager,
      userMessages: userMessages,
    );
    final ValidationResult result = await linuxDoctorValidator.validate();

    expect(result.type, ValidationType.missing);
    expect(result.messages, <ValidationMessage>[
      const ValidationMessage('clang version 4.0.1-6+build1'),
      ValidationMessage.error(userMessages.cmakeMissing),
      const ValidationMessage('ninja version 1.10.0'),
233
      const ValidationMessage('pkg-config version 0.29'),
234 235
    ]);
  });
236

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
  testWithoutContext('Missing validation when CMake version is unparsable', () async {
    final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
      _clangPresentCommand('4.0.1'),
      _cmakePresentCommand('bogus'),
      _ninjaPresentCommand('1.10.0'),
      _pkgConfigPresentCommand('0.29'),
      ..._gtkLibrariesPresentCommands(),
    ]);
    final UserMessages userMessages = UserMessages();
    final DoctorValidator linuxDoctorValidator = LinuxDoctorValidator(
      processManager: processManager,
      userMessages: userMessages,
    );
    final ValidationResult result = await linuxDoctorValidator.validate();

    expect(result.type, ValidationType.missing);
    expect(result.messages, <ValidationMessage>[
      const ValidationMessage('clang version 4.0.1-6+build1'),
      ValidationMessage.error(userMessages.cmakeMissing),
      const ValidationMessage('ninja version 1.10.0'),
      const ValidationMessage('pkg-config version 0.29'),
    ]);
  });

261 262
  testWithoutContext('Missing validation when clang++ is not available', () async {
    final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
263 264 265
      _missingBinaryCommand('clang++'),
      _cmakePresentCommand('3.16.3'),
      _ninjaPresentCommand('1.10.0'),
266
      _pkgConfigPresentCommand('0.29'),
267
      ..._gtkLibrariesPresentCommands(),
268
    ]);
269
    final UserMessages userMessages = UserMessages();
270 271
    final DoctorValidator linuxDoctorValidator = LinuxDoctorValidator(
      processManager: processManager,
272
      userMessages: userMessages,
273 274 275 276
    );
    final ValidationResult result = await linuxDoctorValidator.validate();

    expect(result.type, ValidationType.missing);
277 278 279 280
    expect(result.messages, <ValidationMessage>[
      ValidationMessage.error(userMessages.clangMissing),
      const ValidationMessage('cmake version 3.16.3'),
      const ValidationMessage('ninja version 1.10.0'),
281
      const ValidationMessage('pkg-config version 0.29'),
282 283 284
    ]);
  });

285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
  testWithoutContext('Missing validation when clang++ version is unparsable', () async {
    final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
      _clangPresentCommand('bogus'),
      _cmakePresentCommand('3.16.3'),
      _ninjaPresentCommand('1.10.0'),
      _pkgConfigPresentCommand('0.29'),
      ..._gtkLibrariesPresentCommands(),
    ]);
    final UserMessages userMessages = UserMessages();
    final DoctorValidator linuxDoctorValidator = LinuxDoctorValidator(
      processManager: processManager,
      userMessages: userMessages,
    );
    final ValidationResult result = await linuxDoctorValidator.validate();

    expect(result.type, ValidationType.missing);
    expect(result.messages, <ValidationMessage>[
      ValidationMessage.error(userMessages.clangMissing),
      const ValidationMessage('cmake version 3.16.3'),
      const ValidationMessage('ninja version 1.10.0'),
      const ValidationMessage('pkg-config version 0.29'),
    ]);
  });

309 310 311 312 313
  testWithoutContext('Missing validation when ninja is not available', () async {
    final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
      _clangPresentCommand('4.0.1'),
      _cmakePresentCommand('3.16.3'),
      _missingBinaryCommand('ninja'),
314
      _pkgConfigPresentCommand('0.29'),
315
      ..._gtkLibrariesPresentCommands(),
316 317 318 319 320 321 322 323 324 325 326 327 328
    ]);
    final UserMessages userMessages = UserMessages();
    final DoctorValidator linuxDoctorValidator = LinuxDoctorValidator(
      processManager: processManager,
      userMessages: userMessages,
    );
    final ValidationResult result = await linuxDoctorValidator.validate();

    expect(result.type, ValidationType.missing);
    expect(result.messages, <ValidationMessage>[
      const ValidationMessage('clang version 4.0.1-6+build1'),
      const ValidationMessage('cmake version 3.16.3'),
      ValidationMessage.error(userMessages.ninjaMissing),
329 330 331 332
      const ValidationMessage('pkg-config version 0.29'),
    ]);
  });

333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
  testWithoutContext('Missing validation when ninja version is unparsable', () async {
    final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
      _clangPresentCommand('4.0.1'),
      _cmakePresentCommand('3.16.3'),
      _ninjaPresentCommand('bogus'),
      _pkgConfigPresentCommand('0.29'),
      ..._gtkLibrariesPresentCommands(),
    ]);
    final UserMessages userMessages = UserMessages();
    final DoctorValidator linuxDoctorValidator = LinuxDoctorValidator(
      processManager: processManager,
      userMessages: userMessages,
    );
    final ValidationResult result = await linuxDoctorValidator.validate();

    expect(result.type, ValidationType.missing);
    expect(result.messages, <ValidationMessage>[
      const ValidationMessage('clang version 4.0.1-6+build1'),
      const ValidationMessage('cmake version 3.16.3'),
      ValidationMessage.error(userMessages.ninjaMissing),
      const ValidationMessage('pkg-config version 0.29'),
    ]);
  });

357 358 359 360 361 362
  testWithoutContext('Missing validation when pkg-config is not available', () async {
    final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
      _clangPresentCommand('4.0.1'),
      _cmakePresentCommand('3.16.3'),
      _ninjaPresentCommand('1.10.0'),
      _missingBinaryCommand('pkg-config'),
363
      ..._gtkLibrariesPresentCommands(),
364 365 366 367 368 369 370 371 372
    ]);
    final UserMessages userMessages = UserMessages();
    final DoctorValidator linuxDoctorValidator = LinuxDoctorValidator(
      processManager: processManager,
      userMessages: userMessages,
    );
    final ValidationResult result = await linuxDoctorValidator.validate();

    expect(result.type, ValidationType.missing);
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
    expect(result.messages, <ValidationMessage>[
      const ValidationMessage('clang version 4.0.1-6+build1'),
      const ValidationMessage('cmake version 3.16.3'),
      const ValidationMessage('ninja version 1.10.0'),
      ValidationMessage.error(userMessages.pkgConfigMissing),
    ]);
  });

  testWithoutContext('Missing validation when pkg-config version is unparsable', () async {
    final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
      _clangPresentCommand('4.0.1'),
      _cmakePresentCommand('3.16.3'),
      _ninjaPresentCommand('1.10.0'),
      _pkgConfigPresentCommand('bogus'),
      ..._gtkLibrariesPresentCommands(),
    ]);
    final UserMessages userMessages = UserMessages();
    final DoctorValidator linuxDoctorValidator = LinuxDoctorValidator(
      processManager: processManager,
      userMessages: userMessages,
    );
    final ValidationResult result = await linuxDoctorValidator.validate();

    expect(result.type, ValidationType.missing);
397 398 399 400 401 402 403 404
    expect(result.messages, <ValidationMessage>[
      const ValidationMessage('clang version 4.0.1-6+build1'),
      const ValidationMessage('cmake version 3.16.3'),
      const ValidationMessage('ninja version 1.10.0'),
      ValidationMessage.error(userMessages.pkgConfigMissing),
    ]);
  });

405
  testWithoutContext('Missing validation when GTK libraries are not available', () async {
406 407 408 409 410
    final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
      _clangPresentCommand('4.0.1'),
      _cmakePresentCommand('3.16.3'),
      _ninjaPresentCommand('1.10.0'),
      _pkgConfigPresentCommand('0.29'),
411
      ..._gtkLibrariesMissingCommands(),
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426
    ]);
    final UserMessages userMessages = UserMessages();
    final DoctorValidator linuxDoctorValidator = LinuxDoctorValidator(
      processManager: processManager,
      userMessages: userMessages,
    );
    final ValidationResult result = await linuxDoctorValidator.validate();

    expect(result.type, ValidationType.missing);
    expect(result.messages, <ValidationMessage>[
      const ValidationMessage('clang version 4.0.1-6+build1'),
      const ValidationMessage('cmake version 3.16.3'),
      const ValidationMessage('ninja version 1.10.0'),
      const ValidationMessage('pkg-config version 0.29'),
      ValidationMessage.error(userMessages.gtkLibrariesMissing),
427 428
    ]);
  });
429

430
  testWithoutContext('Missing validation when multiple dependencies are not available', () async {
431
    final ProcessManager processManager = FakeProcessManager.list(<FakeCommand>[
432 433 434
      _missingBinaryCommand('clang++'),
      _missingBinaryCommand('cmake'),
      _ninjaPresentCommand('1.10.0'),
435
      _pkgConfigPresentCommand('0.29'),
436
      ..._gtkLibrariesPresentCommands(),
437 438 439
    ]);
    final DoctorValidator linuxDoctorValidator = LinuxDoctorValidator(
      processManager: processManager,
440
      userMessages: UserMessages(),
441 442 443 444
    );

    final ValidationResult result = await linuxDoctorValidator.validate();
    expect(result.type, ValidationType.missing);
445 446
  });
}