Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(714)

Side by Side Diff: pkg/unittest/lib/mock.dart

Issue 13851022: Make mock behaviors be ordered. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/unittest/test/mock_test.dart » ('j') | pkg/unittest/test/mock_test.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /** 5 /**
6 * A simple mocking/spy library. 6 * A simple mocking/spy library.
7 * 7 *
8 * ## Installing ## 8 * ## Installing ##
9 * 9 *
10 * Use [pub][] to install this package. Add the following to your `pubspec.yaml` 10 * Use [pub][] to install this package. Add the following to your `pubspec.yaml`
(...skipping 1218 matching lines...) Expand 10 before | Expand all | Expand 10 after
1229 new _ResultSetMatcher(Action.THROW, wrapMatcher(value), _Frequency.NONE); 1229 new _ResultSetMatcher(Action.THROW, wrapMatcher(value), _Frequency.NONE);
1230 1230
1231 /** The shared log used for named mocks. */ 1231 /** The shared log used for named mocks. */
1232 LogEntryList sharedLog = null; 1232 LogEntryList sharedLog = null;
1233 1233
1234 /** The base class for all mocked objects. */ 1234 /** The base class for all mocked objects. */
1235 class Mock { 1235 class Mock {
1236 /** The mock name. Needed if the log is shared; optional otherwise. */ 1236 /** The mock name. Needed if the log is shared; optional otherwise. */
1237 final String name; 1237 final String name;
1238 1238
1239 /** The set of [Behavior]s supported. */ 1239 /**
1240 Map<String,Behavior> _behaviors; 1240 * The set of [Behavior]s supported. Behaviors are ordered, but are
1241 * also keyed, so we keep a hash table of indices pointing to a List.
1242 */
1243 Map<String,int> _behaviorIndices;
1244 List<Behavior> _behaviors;
1241 1245
1242 /** The [log] of calls made. Only used if [name] is null. */ 1246 /** The [log] of calls made. Only used if [name] is null. */
1243 LogEntryList log; 1247 LogEntryList log;
1244 1248
1245 /** How to handle unknown method calls - swallow or throw. */ 1249 /** How to handle unknown method calls - swallow or throw. */
1246 final bool _throwIfNoBehavior; 1250 final bool _throwIfNoBehavior;
1247 1251
1248 /** Whether to create an audit log or not. */ 1252 /** Whether to create an audit log or not. */
1249 bool _logging; 1253 bool _logging;
1250 1254
1251 bool get logging => _logging; 1255 bool get logging => _logging;
1252 set logging(bool value) { 1256 set logging(bool value) {
1253 if (value && log == null) { 1257 if (value && log == null) {
1254 log = new LogEntryList(); 1258 log = new LogEntryList();
1255 } 1259 }
1256 _logging = value; 1260 _logging = value;
1257 } 1261 }
1258 1262
1259 /** 1263 /**
1260 * Default constructor. Unknown method calls are allowed and logged, 1264 * Default constructor. Unknown method calls are allowed and logged,
1261 * the mock has no name, and has its own log. 1265 * the mock has no name, and has its own log.
1262 */ 1266 */
1263 Mock() : _throwIfNoBehavior = false, log = null, name = null { 1267 Mock() : _throwIfNoBehavior = false, log = null, name = null {
1264 logging = true; 1268 logging = true;
1265 _behaviors = new Map<String,Behavior>(); 1269 _behaviorIndices = new Map<String,int>();
Siggi Cherem (dart-lang) 2013/04/30 03:25:31 what about using LinkedHashMap instead of Map? Th
gram 2013/04/30 16:53:39 Done.
1270 _behaviors = new List<Behavior>();
1266 } 1271 }
1267 1272
1268 /** 1273 /**
1269 * This constructor makes a mock that has a [name] and possibly uses 1274 * This constructor makes a mock that has a [name] and possibly uses
1270 * a shared [log]. If [throwIfNoBehavior] is true, any calls to methods 1275 * a shared [log]. If [throwIfNoBehavior] is true, any calls to methods
1271 * that have no defined behaviors will throw an exception; otherwise they 1276 * that have no defined behaviors will throw an exception; otherwise they
1272 * will be allowed and logged (but will not do anything). 1277 * will be allowed and logged (but will not do anything).
1273 * If [enableLogging] is false, no logging will be done initially (whether 1278 * If [enableLogging] is false, no logging will be done initially (whether
1274 * or not a [log] is supplied), but [logging] can be set to true later. 1279 * or not a [log] is supplied), but [logging] can be set to true later.
1275 */ 1280 */
1276 Mock.custom({this.name, 1281 Mock.custom({this.name,
1277 this.log, 1282 this.log,
1278 throwIfNoBehavior: false, 1283 throwIfNoBehavior: false,
1279 enableLogging: true}) : _throwIfNoBehavior = throwIfNoBehavior { 1284 enableLogging: true}) : _throwIfNoBehavior = throwIfNoBehavior {
1280 if (log != null && name == null) { 1285 if (log != null && name == null) {
1281 throw new Exception("Mocks with shared logs must have a name."); 1286 throw new Exception("Mocks with shared logs must have a name.");
1282 } 1287 }
1283 logging = enableLogging; 1288 logging = enableLogging;
1284 _behaviors = new Map<String,Behavior>(); 1289 _behaviorIndices = new Map<String,int>();
1290 _behaviors = new List<Behavior>();
1285 } 1291 }
1286 1292
1287 /** 1293 /**
1288 * [when] is used to create a new or extend an existing [Behavior]. 1294 * [when] is used to create a new or extend an existing [Behavior].
1289 * A [CallMatcher] [filter] must be supplied, and the [Behavior]s for 1295 * A [CallMatcher] [filter] must be supplied, and the [Behavior]s for
1290 * that signature are returned (being created first if needed). 1296 * that signature are returned (being created first if needed).
1291 * 1297 *
1292 * Typical use case: 1298 * Typical use case:
1293 * 1299 *
1294 * mock.when(callsTo(...)).alwaysReturn(...); 1300 * mock.when(callsTo(...)).alwaysReturn(...);
1295 */ 1301 */
1296 Behavior when(CallMatcher logFilter) { 1302 Behavior when(CallMatcher logFilter) {
1297 String key = logFilter.toString(); 1303 String key = logFilter.toString();
1298 if (!_behaviors.containsKey(key)) { 1304 if (!_behaviorIndices.containsKey(key)) {
1299 Behavior b = new Behavior(logFilter); 1305 Behavior b = new Behavior(logFilter);
1300 _behaviors[key] = b; 1306 _behaviorIndices[key] = _behaviors.length;
1307 _behaviors.add(b);
1301 return b; 1308 return b;
1302 } else { 1309 } else {
1303 return _behaviors[key]; 1310 return _behaviors[_behaviorIndices[key]];
1304 } 1311 }
1305 } 1312 }
1306 1313
1307 /** 1314 /**
1308 * This is the handler for method calls. We loop through the list 1315 * This is the handler for method calls. We loop through the list
1309 * of [Behavior]s, and find the first match that still has return 1316 * of [Behavior]s, and find the first match that still has return
1310 * values available, and then do the action specified by that 1317 * values available, and then do the action specified by that
1311 * return value. If we find no [Behavior] to apply an exception is 1318 * return value. If we find no [Behavior] to apply an exception is
1312 * thrown. 1319 * thrown.
1313 */ 1320 */
1314 noSuchMethod(Invocation invocation) { 1321 noSuchMethod(Invocation invocation) {
1315 var method = MirrorSystem.getName(invocation.memberName); 1322 var method = MirrorSystem.getName(invocation.memberName);
1316 var args = invocation.positionalArguments; 1323 var args = invocation.positionalArguments;
1317 if (invocation.isGetter) { 1324 if (invocation.isGetter) {
1318 method = 'get $method'; 1325 method = 'get $method';
1319 } else if (invocation.isSetter) { 1326 } else if (invocation.isSetter) {
1320 method = 'set $method'; 1327 method = 'set $method';
1321 // Remove the trailing '='. 1328 // Remove the trailing '='.
1322 if (method[method.length-1] == '=') { 1329 if (method[method.length-1] == '=') {
1323 method = method.substring(0, method.length - 1); 1330 method = method.substring(0, method.length - 1);
1324 } 1331 }
1325 } 1332 }
1326 bool matchedMethodName = false; 1333 bool matchedMethodName = false;
1327 MatchState matchState = new MatchState(); 1334 MatchState matchState = new MatchState();
1328 for (String k in _behaviors.keys) { 1335 for (var i = 0; i < _behaviors.length; i++) {
1329 Behavior b = _behaviors[k]; 1336 Behavior b = _behaviors[i];
1330 if (b.matcher.nameFilter.matches(method, matchState)) { 1337 if (b.matcher.nameFilter.matches(method, matchState)) {
1331 matchedMethodName = true; 1338 matchedMethodName = true;
1332 } 1339 }
1333 if (b.matches(method, args)) { 1340 if (b.matches(method, args)) {
1334 List actions = b.actions; 1341 List actions = b.actions;
1335 if (actions == null || actions.length == 0) { 1342 if (actions == null || actions.length == 0) {
1336 continue; // No return values left in this Behavior. 1343 continue; // No return values left in this Behavior.
1337 } 1344 }
1338 // Get the first response. 1345 // Get the first response.
1339 Responder response = actions[0]; 1346 Responder response = actions[0];
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
1479 arg4 = _noArg, 1486 arg4 = _noArg,
1480 arg5 = _noArg, 1487 arg5 = _noArg,
1481 arg6 = _noArg, 1488 arg6 = _noArg,
1482 arg7 = _noArg, 1489 arg7 = _noArg,
1483 arg8 = _noArg, 1490 arg8 = _noArg,
1484 arg9 = _noArg]) => 1491 arg9 = _noArg]) =>
1485 getLogs(callsTo(method, arg0, arg1, arg2, arg3, arg4, 1492 getLogs(callsTo(method, arg0, arg1, arg2, arg3, arg4,
1486 arg5, arg6, arg7, arg8, arg9)); 1493 arg5, arg6, arg7, arg8, arg9));
1487 1494
1488 /** Clear the behaviors for the Mock. */ 1495 /** Clear the behaviors for the Mock. */
1489 void resetBehavior() => _behaviors.clear(); 1496 void resetBehavior() {
1497 _behaviorIndices.clear();
1498 _behaviors.clear();
1499 }
1490 1500
1491 /** Clear the logs for the Mock. */ 1501 /** Clear the logs for the Mock. */
1492 void clearLogs() { 1502 void clearLogs() {
1493 if (log != null) { 1503 if (log != null) {
1494 if (name == null) { // This log is not shared. 1504 if (name == null) { // This log is not shared.
1495 log.logs.clear(); 1505 log.logs.clear();
1496 } else { // This log may be shared. 1506 } else { // This log may be shared.
1497 log.logs = log.logs.where((e) => e.mockName != name).toList(); 1507 log.logs = log.logs.where((e) => e.mockName != name).toList();
1498 } 1508 }
1499 } 1509 }
1500 } 1510 }
1501 1511
1502 /** Clear both logs and behavior. */ 1512 /** Clear both logs and behavior. */
1503 void reset() { 1513 void reset() {
1504 resetBehavior(); 1514 resetBehavior();
1505 clearLogs(); 1515 clearLogs();
1506 } 1516 }
1507 } 1517 }
OLDNEW
« no previous file with comments | « no previous file | pkg/unittest/test/mock_test.dart » ('j') | pkg/unittest/test/mock_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698