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 /// The mirror matchers library provides some additional matchers that | |
6 /// make use of `dart:mirrors`. | |
7 library matcher.mirror_matchers; | |
8 | |
9 import 'dart:mirrors'; | |
10 | |
11 import 'matcher.dart'; | |
12 | |
13 /// Returns a matcher that checks if a class instance has a property | |
14 /// with name [name], and optionally, if that property in turn satisfies | |
15 /// a [matcher]. | |
16 Matcher hasProperty(String name, [matcher]) => | |
17 new _HasProperty(name, matcher == null ? null : wrapMatcher(matcher)); | |
18 | |
19 class _HasProperty extends Matcher { | |
20 final String _name; | |
21 final Matcher _matcher; | |
22 | |
23 const _HasProperty(this._name, [this._matcher]); | |
24 | |
25 bool matches(item, Map matchState) { | |
26 var mirror = reflect(item); | |
27 var classMirror = mirror.type; | |
28 var symbol = new Symbol(_name); | |
29 var candidate = classMirror.declarations[symbol]; | |
30 if (candidate == null) { | |
31 addStateInfo(matchState, {'reason': 'has no property named "$_name"'}); | |
32 return false; | |
33 } | |
34 bool isInstanceField = candidate is VariableMirror && !candidate.isStatic; | |
35 bool isInstanceGetter = | |
36 candidate is MethodMirror && candidate.isGetter && !candidate.isStatic; | |
37 if (!(isInstanceField || isInstanceGetter)) { | |
38 addStateInfo(matchState, { | |
39 'reason': | |
40 'has a member named "$_name", but it is not an instance property' | |
41 }); | |
42 return false; | |
43 } | |
44 if (_matcher == null) return true; | |
45 var result = mirror.getField(symbol); | |
46 var resultMatches = _matcher.matches(result.reflectee, matchState); | |
47 if (!resultMatches) { | |
48 addStateInfo(matchState, {'value': result.reflectee}); | |
49 } | |
50 return resultMatches; | |
51 } | |
52 | |
53 Description describe(Description description) { | |
54 description.add('has property "$_name"'); | |
55 if (_matcher != null) { | |
56 description.add(' which matches ').addDescriptionOf(_matcher); | |
57 } | |
58 return description; | |
59 } | |
60 | |
61 Description describeMismatch( | |
62 item, Description mismatchDescription, Map matchState, bool verbose) { | |
63 var reason = matchState == null ? null : matchState['reason']; | |
64 if (reason != null) { | |
65 mismatchDescription.add(reason); | |
66 } else { | |
67 mismatchDescription | |
68 .add('has property "$_name" with value ') | |
69 .addDescriptionOf(matchState['value']); | |
70 var innerDescription = new StringDescription(); | |
71 _matcher.describeMismatch( | |
72 matchState['value'], innerDescription, matchState['state'], verbose); | |
73 if (innerDescription.length > 0) { | |
74 mismatchDescription.add(' which ').add(innerDescription.toString()); | |
75 } | |
76 } | |
77 return mismatchDescription; | |
78 } | |
79 } | |
OLD | NEW |