OLD | NEW |
| (Empty) |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library unittest.prints_matcher; | |
6 | |
7 import 'dart:async'; | |
8 | |
9 import 'package:matcher/matcher.dart' hide completes, expect; | |
10 | |
11 import 'future_matchers.dart'; | |
12 import 'expect.dart'; | |
13 | |
14 /// Matches a [Function] that prints text that matches [matcher]. | |
15 /// | |
16 /// [matcher] may be a String or a [Matcher]. | |
17 /// | |
18 /// If the function this runs against returns a [Future], all text printed by | |
19 /// the function (using [Zone] scoping) until that Future completes is matched. | |
20 /// | |
21 /// This only tracks text printed using the [print] function. | |
22 Matcher prints(matcher) => new _Prints(wrapMatcher(matcher)); | |
23 | |
24 class _Prints extends Matcher { | |
25 final Matcher _matcher; | |
26 | |
27 _Prints(this._matcher); | |
28 | |
29 bool matches(item, Map matchState) { | |
30 if (item is! Function) return false; | |
31 | |
32 var buffer = new StringBuffer(); | |
33 var result = runZoned(item, | |
34 zoneSpecification: new ZoneSpecification(print: (_, __, ____, line) { | |
35 buffer.writeln(line); | |
36 })); | |
37 | |
38 if (result is! Future) { | |
39 var actual = buffer.toString(); | |
40 matchState['prints.actual'] = actual; | |
41 return _matcher.matches(actual, matchState); | |
42 } | |
43 | |
44 return completes.matches(result.then((_) { | |
45 // Re-run expect() so we get the same formatting as we would without being | |
46 // asynchronous. | |
47 expect(() { | |
48 var actual = buffer.toString(); | |
49 if (actual.isEmpty) return; | |
50 | |
51 // Strip off the final newline because [print] will re-add it. | |
52 actual = actual.substring(0, actual.length - 1); | |
53 print(actual); | |
54 }, this); | |
55 }), matchState); | |
56 } | |
57 | |
58 Description describe(Description description) => | |
59 description.add('prints ').addDescriptionOf(_matcher); | |
60 | |
61 Description describeMismatch( | |
62 item, Description description, Map matchState, bool verbose) { | |
63 var actual = matchState.remove('prints.actual'); | |
64 if (actual == null) return description; | |
65 if (actual.isEmpty) return description.add("printed nothing."); | |
66 | |
67 description.add('printed ').addDescriptionOf(actual); | |
68 | |
69 // Create a new description for the matcher because at least | |
70 // [_StringEqualsMatcher] replaces the previous contents of the description. | |
71 var innerMismatch = _matcher | |
72 .describeMismatch(actual, new StringDescription(), matchState, verbose) | |
73 .toString(); | |
74 | |
75 if (innerMismatch.isNotEmpty) { | |
76 description.add('\n Which: ').add(innerMismatch.toString()); | |
77 } | |
78 | |
79 return description; | |
80 } | |
81 } | |
OLD | NEW |