Chromium Code Reviews| Index: pkg/analysis_server/test/typed_mock.dart |
| diff --git a/pkg/analysis_server/test/typed_mock.dart b/pkg/analysis_server/test/typed_mock.dart |
| index 740f54c7ec211a5559398ec147c010e6d784fdc5..48673fda0ddf137e00814722cfb14d0e6917d79e 100644 |
| --- a/pkg/analysis_server/test/typed_mock.dart |
| +++ b/pkg/analysis_server/test/typed_mock.dart |
| @@ -1,8 +1,10 @@ |
| library typed_mock; |
| -import 'dart:collection' show Queue; |
| +import 'package:collection/collection.dart'; |
| -Behavior _lastBehavior; |
| +InvocationMatcher _lastMatcher; |
| + |
| +ListEquality LIST_EQUALITY = new ListEquality(); |
| /// Enables stubbing methods. |
| @@ -10,16 +12,54 @@ Behavior _lastBehavior; |
| /// method is called. |
| Behavior when(_ignored) { |
| try { |
| - return _lastBehavior; |
| + var behavior = new Behavior(_lastMatcher); |
| + _lastMatcher._behavior = behavior; |
| + return behavior; |
| } finally { |
| // clear to prevent memory leak |
| - _lastBehavior = null; |
| + _lastMatcher = null; |
| } |
| } |
| +class InvocationMatcher { |
| + List<ArgumentMatcher> _matchers = []; |
| + |
| + Behavior _behavior; |
| + |
| + InvocationMatcher(Invocation invocation) { |
| + invocation.positionalArguments.forEach((argument) { |
| + ArgumentMatcher matcher; |
| + if (argument is ArgumentMatcher) { |
| + matcher = argument; |
| + } else { |
| + matcher = equals(argument); |
| + } |
| + _matchers.add(matcher); |
| + }); |
| + } |
| + |
| + bool operator ==(other) => LIST_EQUALITY.equals(other._matchers, |
| + _matchers); |
| + |
| + bool _match(Invocation invocation) { |
| + var arguments = invocation.positionalArguments; |
| + if (arguments.length != _matchers.length) { |
| + return false; |
| + } |
| + for (int i = 0; i < _matchers.length; i++) { |
| + var matcher = _matchers[i]; |
| + var argument = arguments[i]; |
| + if (!matcher.match(argument)) { |
| + return false; |
| + } |
| + } |
| + return true; |
| + } |
| +} |
| + |
| class Behavior { |
| - final Symbol _member; |
| + final InvocationMatcher _matcher; |
| bool _thenFunctionEnabled = false; |
| Function _thenFunction; |
| @@ -30,7 +70,7 @@ class Behavior { |
| bool _throwExceptionEnabled = false; |
| var _throwException; |
| - Behavior(this._member); |
| + Behavior(InvocationMatcher this._matcher); |
| Behavior thenInvoke(Function function) { |
| _reset(); |
| @@ -80,16 +120,88 @@ class Behavior { |
| class TypedMock { |
| - final Map<Symbol, Behavior> _behaviors = {}; |
| + final Map<Symbol, List<InvocationMatcher>> _invocationMatchersMap = {}; |
| noSuchMethod(Invocation invocation) { |
| var member = invocation.memberName; |
| - Behavior behavior = _behaviors[member]; |
| - if (behavior == null) { |
| - behavior = new Behavior(member); |
| - _behaviors[member] = behavior; |
| + // prepare invocation matchers |
| + var matchers = _invocationMatchersMap[member]; |
| + if (matchers == null) { |
| + matchers = []; |
| + _invocationMatchersMap[member] = matchers; |
| } |
| - _lastBehavior = behavior; |
| - return behavior.getReturnValue(invocation); |
| + // check if there is a matcher |
| + for (var matcher in matchers) { |
| + if (matcher._match(invocation)) { |
| + _lastMatcher = matcher; |
| + return matcher._behavior.getReturnValue(invocation); |
| + } |
| + } |
| + // add a new matcher |
| + InvocationMatcher matcher = new InvocationMatcher(invocation); |
| + matchers.remove(matcher); |
|
Paul Berry
2014/04/24 22:13:50
This means that the semantic effect of calling whe
scheglov
2014/04/24 23:48:44
As discussed offline, I'm going to reintroduce the
|
| + matchers.add(matcher); |
| + _lastMatcher = matcher; |
| } |
| } |
| + |
| + |
| +abstract class ArgumentMatcher { |
| + bool match(val); |
| +} |
| + |
| + |
| +class _ArgumentMatcher_equals extends ArgumentMatcher { |
| + final expected; |
| + |
| + _ArgumentMatcher_equals(this.expected); |
| + |
| + @override |
| + bool match(val) { |
| + return val == expected; |
| + } |
| +} |
| + |
| +equals(expected) { |
| + return new _ArgumentMatcher_equals(expected); |
| +} |
| + |
| + |
| +class _ArgumentMatcher_anyBool extends ArgumentMatcher { |
| + @override |
| + bool match(val) { |
| + return val is bool; |
| + } |
| +} |
| + |
| +final anyBool = new _ArgumentMatcher_anyBool(); |
| + |
| + |
| +class _ArgumentMatcher_anyInt extends ArgumentMatcher { |
| + @override |
| + bool match(val) { |
| + return val is int; |
| + } |
| +} |
| + |
| +final anyInt = new _ArgumentMatcher_anyInt(); |
| + |
| + |
| +class _ArgumentMatcher_anyObject extends ArgumentMatcher { |
| + @override |
| + bool match(val) { |
| + return true; |
| + } |
| +} |
| + |
| +final anyObject = new _ArgumentMatcher_anyObject(); |
| + |
| + |
| +class _ArgumentMatcher_anyString extends ArgumentMatcher { |
| + @override |
| + bool match(val) { |
| + return val is String; |
| + } |
| +} |
| + |
| +final anyString = new _ArgumentMatcher_anyString(); |