| // Copyright (c) 2014, 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 '../description.dart'; | |
| import '../interfaces.dart'; | |
| import '../util.dart'; | |
| import 'async_matcher.dart'; | |
| import 'expect.dart'; | |
| import 'util/pretty_print.dart'; | |
| /// Matches a [Function] that prints text that matches [matcher]. | |
| /// | |
| /// [matcher] may be a String or a [Matcher]. | |
| /// | |
| /// If the function this runs against returns a [Future], all text printed by | |
| /// the function (using [Zone] scoping) until that Future completes is matched. | |
| /// | |
| /// This only tracks text printed using the [print] function. | |
| /// | |
| /// This returns an [AsyncMatcher], so [expect] won't complete until the matched | |
| /// function does. | |
| Matcher prints(Object? matcher) => _Prints(wrapMatcher(matcher)); | |
| class _Prints extends AsyncMatcher { | |
| final Matcher _matcher; | |
| _Prints(this._matcher); | |
| // Avoid async/await so we synchronously fail if the function is | |
| // synchronous. | |
| @override | |
| dynamic /*FutureOr<String>*/ matchAsync(Object? item) { | |
| if (item is! Object? Function()) return 'was not a unary Function'; | |
| var buffer = StringBuffer(); | |
| var result = runZoned( | |
| item, | |
| zoneSpecification: ZoneSpecification( | |
| print: (_, _, _, line) { | |
| buffer.writeln(line); | |
| }, | |
| ), | |
| ); | |
| return result is Future | |
| ? result.then((_) => _check(buffer.toString())) | |
| : _check(buffer.toString()); | |
| } | |
| @override | |
| Description describe(Description description) => | |
| description.add('prints ').addDescriptionOf(_matcher); | |
| /// Verifies that [actual] matches [_matcher] and returns a [String] | |
| /// description of the failure if it doesn't. | |
| String? _check(String actual) { | |
| var matchState = <Object?, Object?>{}; | |
| if (_matcher.matches(actual, matchState)) return null; | |
| var result = _matcher | |
| .describeMismatch(actual, StringDescription(), matchState, false) | |
| .toString(); | |
| var buffer = StringBuffer(); | |
| if (actual.isEmpty) { | |
| buffer.writeln('printed nothing'); | |
| } else { | |
| buffer.writeln(indent(prettyPrint(actual), first: 'printed ')); | |
| } | |
| if (result.isNotEmpty) buffer.writeln(indent(result, first: ' which ')); | |
| return buffer.toString().trimRight(); | |
| } | |
| } |