Index: pkg/mock/lib/src/mock.dart |
diff --git a/pkg/mock/lib/src/mock.dart b/pkg/mock/lib/src/mock.dart |
deleted file mode 100644 |
index bdbb8f3d4f831e7eadface56f5ec564a7a68fc84..0000000000000000000000000000000000000000 |
--- a/pkg/mock/lib/src/mock.dart |
+++ /dev/null |
@@ -1,280 +0,0 @@ |
-// 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. |
- |
-library mock.mock; |
- |
-// TOOD(kevmoo): just use `Map` |
-import 'dart:collection' show LinkedHashMap; |
-import 'dart:mirrors'; |
- |
-import 'package:matcher/matcher.dart'; |
- |
-import 'action.dart'; |
-import 'behavior.dart'; |
-import 'call_matcher.dart'; |
-import 'log_entry.dart'; |
-import 'log_entry_list.dart'; |
-import 'responder.dart'; |
-import 'util.dart'; |
- |
-/** The base class for all mocked objects. */ |
-@proxy |
-class Mock { |
- /** The mock name. Needed if the log is shared; optional otherwise. */ |
- final String name; |
- |
- /** The set of [Behavior]s supported. */ |
- final LinkedHashMap<String, Behavior> _behaviors; |
- |
- /** How to handle unknown method calls - swallow or throw. */ |
- final bool _throwIfNoBehavior; |
- |
- /** For spys, the real object that we are spying on. */ |
- final Object _realObject; |
- |
- /** The [log] of calls made. Only used if [name] is null. */ |
- LogEntryList log; |
- |
- /** Whether to create an audit log or not. */ |
- bool _logging; |
- |
- bool get logging => _logging; |
- set logging(bool value) { |
- if (value && log == null) { |
- log = new LogEntryList(); |
- } |
- _logging = value; |
- } |
- |
- /** |
- * Default constructor. Unknown method calls are allowed and logged, |
- * the mock has no name, and has its own log. |
- */ |
- Mock() : |
- _throwIfNoBehavior = false, log = null, name = null, _realObject = null, |
- _behaviors = new LinkedHashMap<String,Behavior>() { |
- logging = true; |
- } |
- |
- /** |
- * This constructor makes a mock that has a [name] and possibly uses |
- * a shared [log]. If [throwIfNoBehavior] is true, any calls to methods |
- * that have no defined behaviors will throw an exception; otherwise they |
- * will be allowed and logged (but will not do anything). |
- * If [enableLogging] is false, no logging will be done initially (whether |
- * or not a [log] is supplied), but [logging] can be set to true later. |
- */ |
- Mock.custom({this.name, |
- this.log, |
- throwIfNoBehavior: false, |
- enableLogging: true}) |
- : _throwIfNoBehavior = throwIfNoBehavior, _realObject = null, |
- _behaviors = new LinkedHashMap<String,Behavior>() { |
- if (log != null && name == null) { |
- throw new Exception("Mocks with shared logs must have a name."); |
- } |
- logging = enableLogging; |
- } |
- |
- /** |
- * This constructor creates a spy with no user-defined behavior. |
- * This is simply a proxy for a real object that passes calls |
- * through to that real object but captures an audit trail of |
- * calls made to the object that can be queried and validated |
- * later. |
- */ |
- Mock.spy(this._realObject, {this.name, this.log}) |
- : _behaviors = null, |
- _throwIfNoBehavior = true { |
- logging = true; |
- } |
- |
- /** |
- * [when] is used to create a new or extend an existing [Behavior]. |
- * A [CallMatcher] [filter] must be supplied, and the [Behavior]s for |
- * that signature are returned (being created first if needed). |
- * |
- * Typical use case: |
- * |
- * mock.when(callsTo(...)).alwaysReturn(...); |
- */ |
- Behavior when(CallMatcher logFilter) { |
- String key = logFilter.toString(); |
- if (!_behaviors.containsKey(key)) { |
- Behavior b = new Behavior(logFilter); |
- _behaviors[key] = b; |
- return b; |
- } else { |
- return _behaviors[key]; |
- } |
- } |
- |
- /** |
- * This is the handler for method calls. We loop through the list |
- * of [Behavior]s, and find the first match that still has return |
- * values available, and then do the action specified by that |
- * return value. If we find no [Behavior] to apply an exception is |
- * thrown. |
- */ |
- noSuchMethod(Invocation invocation) { |
- var method = MirrorSystem.getName(invocation.memberName); |
- var args = invocation.positionalArguments; |
- if (invocation.isGetter) { |
- method = 'get $method'; |
- } else if (invocation.isSetter) { |
- method = 'set $method'; |
- // Remove the trailing '='. |
- if (method[method.length - 1] == '=') { |
- method = method.substring(0, method.length - 1); |
- } |
- } |
- if (_behaviors == null) { // Spy. |
- var mirror = reflect(_realObject); |
- try { |
- var result = mirror.delegate(invocation); |
- log.add(new LogEntry(name, method, args, Action.PROXY, result)); |
- return result; |
- } catch (e) { |
- log.add(new LogEntry(name, method, args, Action.THROW, e)); |
- throw e; |
- } |
- } |
- bool matchedMethodName = false; |
- Map matchState = {}; |
- for (String k in _behaviors.keys) { |
- Behavior b = _behaviors[k]; |
- if (b.matcher.nameFilter.matches(method, matchState)) { |
- matchedMethodName = true; |
- } |
- if (b.matches(method, args)) { |
- List actions = b.actions; |
- if (actions == null || actions.length == 0) { |
- continue; // No return values left in this Behavior. |
- } |
- // Get the first response. |
- Responder response = actions[0]; |
- // If it is exhausted, remove it from the list. |
- // Note that for endlessly repeating values, we started the count at |
- // 0, so we get a potentially useful value here, which is the |
- // (negation of) the number of times we returned the value. |
- if (--response.count == 0) { |
- actions.removeRange(0, 1); |
- } |
- // Do the response. |
- Action action = response.action; |
- var value = response.value; |
- if (action == Action.RETURN) { |
- if (_logging && b.logging) { |
- log.add(new LogEntry(name, method, args, action, value)); |
- } |
- return value; |
- } else if (action == Action.THROW) { |
- if (_logging && b.logging) { |
- log.add(new LogEntry(name, method, args, action, value)); |
- } |
- throw value; |
- } else if (action == Action.PROXY) { |
- var mir = reflect(value) as ClosureMirror; |
- var rtn = mir.invoke(#call, invocation.positionalArguments, |
- invocation.namedArguments).reflectee; |
- if (_logging && b.logging) { |
- log.add(new LogEntry(name, method, args, action, rtn)); |
- } |
- return rtn; |
- } |
- } |
- } |
- if (matchedMethodName) { |
- // User did specify behavior for this method, but all the |
- // actions are exhausted. This is considered an error. |
- throw new Exception('No more actions for method ' |
- '${qualifiedName(name, method)}.'); |
- } else if (_throwIfNoBehavior) { |
- throw new Exception('No behavior specified for method ' |
- '${qualifiedName(name, method)}.'); |
- } |
- // Otherwise user hasn't specified behavior for this method; we don't throw |
- // so we can underspecify. |
- if (_logging) { |
- log.add(new LogEntry(name, method, args, Action.IGNORE)); |
- } |
- } |
- |
- /** [verifyZeroInteractions] returns true if no calls were made */ |
- bool verifyZeroInteractions() { |
- if (log == null) { |
- // This means we created the mock with logging off and have never turned |
- // it on, so it doesn't make sense to verify behavior on such a mock. |
- throw new |
- Exception("Can't verify behavior when logging was never enabled."); |
- } |
- return log.logs.length == 0; |
- } |
- |
- /** |
- * [getLogs] extracts all calls from the call log that match the |
- * [logFilter], and returns the matching list of [LogEntry]s. If |
- * [destructive] is false (the default) the matching calls are left |
- * in the log, else they are removed. Removal allows us to verify a |
- * set of interactions and then verify that there are no other |
- * interactions left. [actionMatcher] can be used to further |
- * restrict the returned logs based on the action the mock performed. |
- * [logFilter] can be a [CallMatcher] or a predicate function that |
- * takes a [LogEntry] and returns a bool. |
- * |
- * Typical usage: |
- * |
- * getLogs(callsTo(...)).verify(...); |
- */ |
- LogEntryList getLogs([CallMatcher logFilter, |
- Matcher actionMatcher, |
- bool destructive = false]) { |
- if (log == null) { |
- // This means we created the mock with logging off and have never turned |
- // it on, so it doesn't make sense to get logs from such a mock. |
- throw new |
- Exception("Can't retrieve logs when logging was never enabled."); |
- } else { |
- return log.getMatches(name, logFilter, actionMatcher, destructive); |
- } |
- } |
- |
- /** |
- * Useful shorthand method that creates a [CallMatcher] from its arguments |
- * and then calls [getLogs]. |
- */ |
- LogEntryList calls(method, |
- [arg0 = NO_ARG, |
- arg1 = NO_ARG, |
- arg2 = NO_ARG, |
- arg3 = NO_ARG, |
- arg4 = NO_ARG, |
- arg5 = NO_ARG, |
- arg6 = NO_ARG, |
- arg7 = NO_ARG, |
- arg8 = NO_ARG, |
- arg9 = NO_ARG]) => |
- getLogs(callsTo(method, arg0, arg1, arg2, arg3, arg4, |
- arg5, arg6, arg7, arg8, arg9)); |
- |
- /** Clear the behaviors for the Mock. */ |
- void resetBehavior() => _behaviors.clear(); |
- |
- /** Clear the logs for the Mock. */ |
- void clearLogs() { |
- if (log != null) { |
- if (name == null) { // This log is not shared. |
- log.logs.clear(); |
- } else { // This log may be shared. |
- log.logs = log.logs.where((e) => e.mockName != name).toList(); |
- } |
- } |
- } |
- |
- /** Clear both logs and behavior. */ |
- void reset() { |
- resetBehavior(); |
- clearLogs(); |
- } |
-} |