| // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| import 'dart:async'; | |
| import 'dart:convert'; | |
| import 'dart:io' as io; | |
| import 'package:process/process.dart'; | |
| import 'package:test/test.dart'; | |
| void main() { | |
| group('ProcessWrapper', () { | |
| late TestProcess delegate; | |
| late ProcessWrapper process; | |
| setUp(() { | |
| delegate = TestProcess(); | |
| process = ProcessWrapper(delegate); | |
| }); | |
| group('done', () { | |
| late bool done; | |
| setUp(() { | |
| done = false; | |
| // ignore: unawaited_futures | |
| process.done.then((int result) { | |
| done = true; | |
| }); | |
| }); | |
| test('completes only when all done', () async { | |
| expect(done, isFalse); | |
| delegate.exitCodeCompleter.complete(0); | |
| await Future<void>.value(); | |
| expect(done, isFalse); | |
| await delegate.stdoutController.close(); | |
| await Future<void>.value(); | |
| expect(done, isFalse); | |
| await delegate.stderrController.close(); | |
| await Future<void>.value(); | |
| expect(done, isTrue); | |
| expect(await process.exitCode, 0); | |
| }); | |
| test('works in conjunction with subscribers to stdio streams', () async { | |
| process.stdout | |
| .transform<String>(utf8.decoder) | |
| .transform<String>(const LineSplitter()) | |
| // ignore: avoid_print | |
| .listen(print); | |
| delegate.exitCodeCompleter.complete(0); | |
| await delegate.stdoutController.close(); | |
| await delegate.stderrController.close(); | |
| await Future<void>.value(); | |
| expect(done, isTrue); | |
| }); | |
| }); | |
| group('stdio', () { | |
| test('streams properly close', () async { | |
| Future<void> testStream( | |
| Stream<List<int>> stream, | |
| StreamController<List<int>> controller, | |
| String name, | |
| ) async { | |
| bool closed = false; | |
| stream.listen( | |
| (_) {}, | |
| onDone: () { | |
| closed = true; | |
| }, | |
| ); | |
| await controller.close(); | |
| await Future<void>.value(); | |
| expect(closed, isTrue, reason: 'for $name'); | |
| } | |
| await testStream(process.stdout, delegate.stdoutController, 'stdout'); | |
| await testStream(process.stderr, delegate.stderrController, 'stderr'); | |
| }); | |
| }); | |
| }); | |
| } | |
| class TestProcess implements io.Process { | |
| TestProcess([this.pid = 123]) | |
| : exitCodeCompleter = Completer<int>(), | |
| stdoutController = StreamController<List<int>>(), | |
| stderrController = StreamController<List<int>>(); | |
| @override | |
| final int pid; | |
| final Completer<int> exitCodeCompleter; | |
| final StreamController<List<int>> stdoutController; | |
| final StreamController<List<int>> stderrController; | |
| @override | |
| Future<int> get exitCode => exitCodeCompleter.future; | |
| @override | |
| bool kill([io.ProcessSignal signal = io.ProcessSignal.sigterm]) { | |
| exitCodeCompleter.complete(-1); | |
| return true; | |
| } | |
| @override | |
| Stream<List<int>> get stderr => stderrController.stream; | |
| @override | |
| io.IOSink get stdin => throw UnsupportedError('Not supported'); | |
| @override | |
| Stream<List<int>> get stdout => stdoutController.stream; | |
| } |