process_test.dart 12.7 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 6
// @dart = 2.8

7
import 'package:flutter_tools/src/base/io.dart';
8
import 'package:flutter_tools/src/base/logger.dart';
9
import 'package:flutter_tools/src/base/platform.dart';
10
import 'package:flutter_tools/src/base/process.dart';
11
import 'package:flutter_tools/src/base/terminal.dart';
12

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

17
void main() {
18
  group('process exceptions', () {
19
    FakeProcessManager fakeProcessManager;
20
    ProcessUtils processUtils;
21 22

    setUp(() {
23
      fakeProcessManager = FakeProcessManager.empty();
24
      processUtils = ProcessUtils(
25
        processManager: fakeProcessManager,
26
        logger: BufferLogger.test(),
27
      );
28 29
    });

30
    testWithoutContext('runAsync throwOnError: exceptions should be ProcessException objects', () async {
31 32 33 34 35 36 37
      fakeProcessManager.addCommand(const FakeCommand(
        command: <String>[
          'false',
        ],
        exitCode: 1,
      ));

38
      expect(() async => processUtils.run(<String>['false'], throwOnError: true), throwsProcessException());
39
    });
40
  });
41

42
  group('shutdownHooks', () {
43
    testWithoutContext('runInExpectedOrder', () async {
44 45 46
      int i = 1;
      int cleanup;

47
      final ShutdownHooks shutdownHooks = ShutdownHooks(logger: BufferLogger.test());
48 49

      shutdownHooks.addShutdownHook(() async {
50
        cleanup = i++;
51
      });
52

53
      await shutdownHooks.runShutdownHooks();
54

55
      expect(cleanup, 1);
56 57
    });
  });
58

59
  group('output formatting', () {
60
    FakeProcessManager processManager;
61
    ProcessUtils processUtils;
62
    BufferLogger logger;
63 64

    setUp(() {
65 66
      processManager = FakeProcessManager.empty();
      logger = BufferLogger.test();
67
      processUtils = ProcessUtils(
68 69
        processManager: processManager,
        logger: logger,
70
      );
71 72
    });

73
    testWithoutContext('Command output is not wrapped.', () async {
74
      final List<String> testString = <String>['0123456789' * 10];
75 76 77 78 79 80
      processManager.addCommand(FakeCommand(
        command: const <String>['command'],
        stdout: testString.join(''),
        stderr: testString.join(''),
      ));

81
      await processUtils.stream(<String>['command']);
82 83 84

      expect(logger.statusText, equals('${testString[0]}\n'));
      expect(logger.errorText, equals('${testString[0]}\n'));
85
    });
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103

    testWithoutContext('Command output is filtered by mapFunction', () async {
      processManager.addCommand(const FakeCommand(
        command: <String>['command'],
        stdout: 'match\nno match',
        stderr: 'match\nno match',
      ));

      await processUtils.stream(<String>['command'], mapFunction: (String line) {
        if (line == 'match') {
          return line;
        }
        return null;
      });

      expect(logger.statusText, equals('match\n'));
      expect(logger.errorText, equals('match\n'));
    });
104
  });
105

106
  group('run', () {
107
    FakeProcessManager fakeProcessManager;
108
    ProcessUtils processUtils;
109 110

    setUp(() {
111
      fakeProcessManager = FakeProcessManager.empty();
112
      processUtils = ProcessUtils(
113
        processManager: fakeProcessManager,
114
        logger: BufferLogger.test(),
115
      );
116 117
    });

118
    testWithoutContext(' succeeds on success', () async {
119 120 121 122 123
      fakeProcessManager.addCommand(const FakeCommand(
        command: <String>[
          'whoohoo',
        ],
      ));
124 125 126
      expect((await processUtils.run(<String>['whoohoo'])).exitCode, 0);
    });

127
    testWithoutContext(' fails on failure', () async {
128 129 130 131 132 133
      fakeProcessManager.addCommand(const FakeCommand(
        command: <String>[
          'boohoo',
        ],
        exitCode: 1,
      ));
134 135 136
      expect((await processUtils.run(<String>['boohoo'])).exitCode, 1);
    });

137
    testWithoutContext(' throws on failure with throwOnError', () async {
138 139 140 141 142 143
      fakeProcessManager.addCommand(const FakeCommand(
        command: <String>[
          'kaboom',
        ],
        exitCode: 1,
      ));
144
      expect(() => processUtils.run(<String>['kaboom'], throwOnError: true), throwsProcessException());
145 146
    });

147
    testWithoutContext(' does not throw on allowed Failures', () async {
148 149 150 151 152 153
      fakeProcessManager.addCommand(const FakeCommand(
        command: <String>[
          'kaboom',
        ],
        exitCode: 1,
      ));
154 155 156 157
      expect(
        (await processUtils.run(
          <String>['kaboom'],
          throwOnError: true,
158
          allowedFailures: (int c) => c == 1,
159
        )).exitCode,
160 161
        1,
      );
162 163
    });

164
    testWithoutContext(' throws on disallowed failure', () async {
165 166 167 168 169 170
      fakeProcessManager.addCommand(const FakeCommand(
        command: <String>[
          'kaboom',
        ],
        exitCode: 2,
      ));
171 172 173 174
      expect(
        () => processUtils.run(
          <String>['kaboom'],
          throwOnError: true,
175
          allowedFailures: (int c) => c == 1,
176
        ),
177
        throwsProcessException(),
178
      );
179
    });
180
  });
181 182

  group('runSync', () {
183
    FakeProcessManager fakeProcessManager;
184 185
    ProcessUtils processUtils;
    BufferLogger testLogger;
186 187

    setUp(() {
188
      fakeProcessManager = FakeProcessManager.empty();
189 190
      testLogger = BufferLogger(
        terminal: AnsiTerminal(
191
          stdio: FakeStdio(),
192
          platform: FakePlatform(stdinSupportsAnsi: false),
193 194 195 196
        ),
        outputPreferences: OutputPreferences(wrapText: true, wrapColumn: 40),
      );
      processUtils = ProcessUtils(
197
        processManager: fakeProcessManager,
198 199
        logger: testLogger,
      );
200 201
    });

202
    testWithoutContext(' succeeds on success', () async {
203 204 205 206 207
      fakeProcessManager.addCommand(const FakeCommand(
        command: <String>[
          'whoohoo',
        ],
      ));
208 209 210
      expect(processUtils.runSync(<String>['whoohoo']).exitCode, 0);
    });

211
    testWithoutContext(' fails on failure', () async {
212 213 214 215 216 217
      fakeProcessManager.addCommand(const FakeCommand(
        command: <String>[
          'boohoo',
        ],
        exitCode: 1,
      ));
218 219 220
      expect(processUtils.runSync(<String>['boohoo']).exitCode, 1);
    });

221 222
    testWithoutContext('throws on failure with throwOnError', () async {
      const String stderr = 'Something went wrong.';
223 224 225 226 227 228 229
      fakeProcessManager.addCommand(const FakeCommand(
        command: <String>[
          'kaboom',
        ],
        exitCode: 1,
        stderr: stderr,
      ));
230 231 232 233 234 235 236 237
      expect(
        () => processUtils.runSync(<String>['kaboom'], throwOnError: true),
        throwsA(isA<ProcessException>().having(
          (ProcessException error) => error.message,
          'message',
          isNot(contains(stderr)),
        )),
      );
238 239 240 241
    });

    testWithoutContext('throws with stderr in exception on failure with verboseExceptions', () async {
      const String stderr = 'Something went wrong.';
242 243 244 245 246 247 248
      fakeProcessManager.addCommand(const FakeCommand(
        command: <String>[
          'verybad',
        ],
        exitCode: 1,
        stderr: stderr,
      ));
249 250 251 252 253 254 255
      expect(
        () => processUtils.runSync(
          <String>['verybad'],
          throwOnError: true,
          verboseExceptions: true,
        ),
        throwsProcessException(message: stderr),
256 257 258
      );
    });

259
    testWithoutContext(' does not throw on allowed Failures', () async {
260 261 262 263 264 265
      fakeProcessManager.addCommand(const FakeCommand(
        command: <String>[
          'kaboom',
        ],
        exitCode: 1,
      ));
266 267 268 269
      expect(
        processUtils.runSync(
          <String>['kaboom'],
          throwOnError: true,
270
          allowedFailures: (int c) => c == 1,
271 272 273 274
        ).exitCode,
        1);
    });

275
    testWithoutContext(' throws on disallowed failure', () async {
276 277 278 279 280 281
      fakeProcessManager.addCommand(const FakeCommand(
        command: <String>[
          'kaboom',
        ],
        exitCode: 2,
      ));
282 283 284 285
      expect(
        () => processUtils.runSync(
          <String>['kaboom'],
          throwOnError: true,
286
          allowedFailures: (int c) => c == 1,
287
        ),
288 289
        throwsProcessException(),
      );
290 291
    });

292
    testWithoutContext(' prints stdout and stderr to trace on success', () async {
293 294 295 296 297 298 299
      fakeProcessManager.addCommand(const FakeCommand(
        command: <String>[
          'whoohoo',
        ],
        stdout: 'stdout',
        stderr: 'stderr',
      ));
300 301 302 303 304
      expect(processUtils.runSync(<String>['whoohoo']).exitCode, 0);
      expect(testLogger.traceText, contains('stdout'));
      expect(testLogger.traceText, contains('stderr'));
    });

305
    testWithoutContext(' prints stdout to status and stderr to error on failure with throwOnError', () async {
306 307 308 309 310 311 312 313
      fakeProcessManager.addCommand(const FakeCommand(
        command: <String>[
          'kaboom',
        ],
        exitCode: 1,
        stdout: 'stdout',
        stderr: 'stderr',
      ));
314
      expect(() => processUtils.runSync(<String>['kaboom'], throwOnError: true), throwsProcessException());
315 316 317 318
      expect(testLogger.statusText, contains('stdout'));
      expect(testLogger.errorText, contains('stderr'));
    });

319
    testWithoutContext(' does not print stdout with hideStdout', () async {
320 321 322 323 324 325 326
      fakeProcessManager.addCommand(const FakeCommand(
        command: <String>[
          'whoohoo',
        ],
        stdout: 'stdout',
        stderr: 'stderr',
      ));
327 328 329 330 331 332 333
      expect(processUtils.runSync(<String>['whoohoo'], hideStdout: true).exitCode, 0);
      expect(testLogger.traceText.contains('stdout'), isFalse);
      expect(testLogger.traceText, contains('stderr'));
    });
  });

  group('exitsHappySync', () {
334
    FakeProcessManager processManager;
335
    ProcessUtils processUtils;
336 337

    setUp(() {
338
      processManager = FakeProcessManager.empty();
339
      processUtils = ProcessUtils(
340
        processManager: processManager,
341
        logger: BufferLogger.test(),
342
      );
343 344
    });

345 346 347 348 349
    testWithoutContext('succeeds on success', () async {
      processManager.addCommand(const FakeCommand(
        command: <String>['whoohoo'],
      ));

350 351 352
      expect(processUtils.exitsHappySync(<String>['whoohoo']), isTrue);
    });

353 354 355 356 357 358
    testWithoutContext('fails on failure', () async {
      processManager.addCommand(const FakeCommand(
        command: <String>['boohoo'],
        exitCode: 1,
      ));

359 360
      expect(processUtils.exitsHappySync(<String>['boohoo']), isFalse);
    });
361 362

    testWithoutContext('catches Exception and returns false', () {
363 364 365 366 367
      processManager.addCommand(const FakeCommand(
        command: <String>['boohoo'],
        exception: ProcessException('Process failed', <String>[]),
      ));

368 369 370
      expect(processUtils.exitsHappySync(<String>['boohoo']), isFalse);
    });

371
    testWithoutContext('does not throw Exception and returns false if binary cannot run', () {
372 373
      processManager.excludedExecutables.add('nonesuch');

374
      expect(processUtils.exitsHappySync(<String>['nonesuch']), isFalse);
375 376 377
    });

    testWithoutContext('does not catch ArgumentError', () async {
378 379 380 381 382
      processManager.addCommand(FakeCommand(
        command: const <String>['invalid'],
        exception: ArgumentError('Bad input'),
      ));

383 384 385 386
      expect(
        () => processUtils.exitsHappySync(<String>['invalid']),
        throwsArgumentError,
      );
387
    });
388 389 390
  });

  group('exitsHappy', () {
391
    FakeProcessManager processManager;
392
    ProcessUtils processUtils;
393 394

    setUp(() {
395
      processManager = FakeProcessManager.empty();
396
      processUtils = ProcessUtils(
397
        processManager: processManager,
398
        logger: BufferLogger.test(),
399
      );
400 401
    });

402
    testWithoutContext('succeeds on success', () async {
403 404 405 406
      processManager.addCommand(const FakeCommand(
        command: <String>['whoohoo']
      ));

407 408 409
      expect(await processUtils.exitsHappy(<String>['whoohoo']), isTrue);
    });

410
    testWithoutContext('fails on failure', () async {
411 412 413 414 415
      processManager.addCommand(const FakeCommand(
        command: <String>['boohoo'],
        exitCode: 1,
      ));

416 417
      expect(await processUtils.exitsHappy(<String>['boohoo']), isFalse);
    });
418 419

    testWithoutContext('catches Exception and returns false', () async {
420 421 422 423 424
      processManager.addCommand(const FakeCommand(
        command: <String>['boohoo'],
        exception: ProcessException('Process failed', <String>[])
      ));

425 426 427
      expect(await processUtils.exitsHappy(<String>['boohoo']), isFalse);
    });

428
    testWithoutContext('does not throw Exception and returns false if binary cannot run', () async {
429 430
      processManager.excludedExecutables.add('nonesuch');

431
      expect(await processUtils.exitsHappy(<String>['nonesuch']), isFalse);
432 433 434
    });

    testWithoutContext('does not catch ArgumentError', () async {
435 436 437 438 439
      processManager.addCommand(FakeCommand(
        command: const <String>['invalid'],
        exception: ArgumentError('Bad input')
      ));

440
      expect(
441
        () async => processUtils.exitsHappy(<String>['invalid']),
442 443
        throwsArgumentError,
      );
444
    });
445
  });
446
}