| Index: pkg/mock/lib/src/log_entry_list.dart
|
| diff --git a/pkg/mock/lib/src/log_entry_list.dart b/pkg/mock/lib/src/log_entry_list.dart
|
| deleted file mode 100644
|
| index b96baab2e6e94858728e7e727216cfa200d1bdb0..0000000000000000000000000000000000000000
|
| --- a/pkg/mock/lib/src/log_entry_list.dart
|
| +++ /dev/null
|
| @@ -1,564 +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.log_entry_list;
|
| -
|
| -import 'package:matcher/matcher.dart';
|
| -
|
| -import 'call_matcher.dart';
|
| -import 'log_entry.dart';
|
| -import 'util.dart';
|
| -
|
| -/**
|
| -* [StepValidator]s are used by [stepwiseValidate] in [LogEntryList], which
|
| -* iterates through the list and call the [StepValidator] function with the
|
| -* log [List] and position. The [StepValidator] should return the number of
|
| -* positions to advance upon success, or zero upon failure. When zero is
|
| -* returned an error is reported.
|
| -*/
|
| -typedef int StepValidator(List<LogEntry> logs, int pos);
|
| -
|
| -/**
|
| - * We do verification on a list of [LogEntry]s. To allow chaining
|
| - * of calls to verify, we encapsulate such a list in the [LogEntryList]
|
| - * class.
|
| - */
|
| -class LogEntryList {
|
| - String filter;
|
| - List<LogEntry> logs;
|
| - LogEntryList([this.filter]) {
|
| - logs = new List<LogEntry>();
|
| - }
|
| -
|
| - /** Add a [LogEntry] to the log. */
|
| - add(LogEntry entry) => logs.add(entry);
|
| -
|
| - /** Get the first entry, or null if no entries. */
|
| - get first => (logs == null || logs.length == 0) ? null : logs[0];
|
| -
|
| - /** Get the last entry, or null if no entries. */
|
| - get last => (logs == null || logs.length == 0) ? null : logs.last;
|
| -
|
| - /** Creates a LogEntry predicate function from the argument. */
|
| - Function _makePredicate(arg) {
|
| - if (arg == null) {
|
| - return (e) => true;
|
| - } else if (arg is CallMatcher) {
|
| - return (e) => arg.matches(e.methodName, e.args);
|
| - } else if (arg is Function) {
|
| - return arg;
|
| - } else {
|
| - throw new Exception("Invalid argument to _makePredicate.");
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Create a new [LogEntryList] consisting of [LogEntry]s from
|
| - * this list that match the specified [mockNameFilter] and [logFilter].
|
| - * [mockNameFilter] can be null, a [String], a predicate [Function],
|
| - * or a [Matcher]. If [mockNameFilter] is null, this is the same as
|
| - * [anything].
|
| - * If [logFilter] is null, all entries in the log will be returned.
|
| - * Otherwise [logFilter] should be a [CallMatcher] or predicate function
|
| - * that takes a [LogEntry] and returns a bool.
|
| - * If [destructive] is true, the log entries are removed from the
|
| - * original list.
|
| - */
|
| - LogEntryList getMatches([mockNameFilter,
|
| - logFilter,
|
| - Matcher actionMatcher,
|
| - bool destructive = false]) {
|
| - if (mockNameFilter == null) {
|
| - mockNameFilter = anything;
|
| - } else {
|
| - mockNameFilter = wrapMatcher(mockNameFilter);
|
| - }
|
| - Function entryFilter = _makePredicate(logFilter);
|
| - String filterName = qualifiedName(mockNameFilter, logFilter.toString());
|
| - LogEntryList rtn = new LogEntryList(filterName);
|
| - var matchState = {};
|
| - for (var i = 0; i < logs.length; i++) {
|
| - LogEntry entry = logs[i];
|
| - if (mockNameFilter.matches(entry.mockName, matchState) &&
|
| - entryFilter(entry)) {
|
| - if (actionMatcher == null ||
|
| - actionMatcher.matches(entry, matchState)) {
|
| - rtn.add(entry);
|
| - if (destructive) {
|
| - int startIndex = i--;
|
| - logs.removeRange(startIndex, startIndex + 1);
|
| - }
|
| - }
|
| - }
|
| - }
|
| - return rtn;
|
| - }
|
| -
|
| - /** Apply a unit test [Matcher] to the [LogEntryList]. */
|
| - LogEntryList verify(Matcher matcher) {
|
| - if (_mockFailureHandler == null) {
|
| - _mockFailureHandler =
|
| - new _MockFailureHandler(getOrCreateExpectFailureHandler());
|
| - }
|
| - expect(logs, matcher, reason: filter, failureHandler: _mockFailureHandler);
|
| - return this;
|
| - }
|
| -
|
| - /**
|
| - * Iterate through the list and call the [validator] function with the
|
| - * log [List] and position. The [validator] should return the number of
|
| - * positions to advance upon success, or zero upon failure. When zero is
|
| - * returned an error is reported. [reason] can be used to provide a
|
| - * more descriptive failure message. If a failure occurred false will be
|
| - * returned (unless the failure handler itself threw an exception);
|
| - * otherwise true is returned.
|
| - * The use case here is to perform more complex validations; for example
|
| - * we may want to assert that the return value from some function is
|
| - * later used as a parameter to a following function. If we filter the logs
|
| - * to include just these two functions we can write a simple validator to
|
| - * do this check.
|
| - */
|
| - bool stepwiseValidate(StepValidator validator, [String reason = '']) {
|
| - if (_mockFailureHandler == null) {
|
| - _mockFailureHandler =
|
| - new _MockFailureHandler(getOrCreateExpectFailureHandler());
|
| - }
|
| - var i = 0;
|
| - while (i < logs.length) {
|
| - var n = validator(logs, i);
|
| - if (n == 0) {
|
| - if (reason.length > 0) {
|
| - reason = ': $reason';
|
| - }
|
| - _mockFailureHandler.fail("Stepwise validation failed at $filter "
|
| - "position $i$reason");
|
| - return false;
|
| - } else {
|
| - i += n;
|
| - }
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - /**
|
| - * Turn the logs into human-readable text. If [baseTime] is specified
|
| - * then each entry is prefixed with the offset from that time in
|
| - * milliseconds; otherwise the time of day is used.
|
| - */
|
| - String toString([DateTime baseTime]) {
|
| - String s = '';
|
| - for (var e in logs) {
|
| - s = '$s${e.toString(baseTime)}\n';
|
| - }
|
| - return s;
|
| - }
|
| -
|
| - /**
|
| - * Find the first log entry that satisfies [logFilter] and
|
| - * return its position. A search [start] position can be provided
|
| - * to allow for repeated searches. [logFilter] can be a [CallMatcher],
|
| - * or a predicate function that takes a [LogEntry] argument and returns
|
| - * a bool. If [logFilter] is null, it will match any [LogEntry].
|
| - * If no entry is found, then [failureReturnValue] is returned.
|
| - * After each check the position is updated by [skip], so using
|
| - * [skip] of -1 allows backward searches, using a [skip] of 2 can
|
| - * be used to check pairs of adjacent entries, and so on.
|
| - */
|
| - int findLogEntry(logFilter, [int start = 0, int failureReturnValue = -1,
|
| - skip = 1]) {
|
| - logFilter = _makePredicate(logFilter);
|
| - int pos = start;
|
| - while (pos >= 0 && pos < logs.length) {
|
| - if (logFilter(logs[pos])) {
|
| - return pos;
|
| - }
|
| - pos += skip;
|
| - }
|
| - return failureReturnValue;
|
| - }
|
| -
|
| - /**
|
| - * Returns log events that happened up to the first one that
|
| - * satisfies [logFilter]. If [inPlace] is true, then returns
|
| - * this LogEntryList after removing the from the first satisfier;
|
| - * onwards otherwise a new list is created. [description]
|
| - * is used to create a new name for the resulting list.
|
| - * [defaultPosition] is used as the index of the matching item in
|
| - * the case that no match is found.
|
| - */
|
| - LogEntryList _head(logFilter, bool inPlace,
|
| - String description, int defaultPosition) {
|
| - if (filter != null) {
|
| - description = '$filter $description';
|
| - }
|
| - int pos = findLogEntry(logFilter, 0, defaultPosition);
|
| - if (inPlace) {
|
| - if (pos < logs.length) {
|
| - logs.removeRange(pos, logs.length);
|
| - }
|
| - filter = description;
|
| - return this;
|
| - } else {
|
| - LogEntryList newList = new LogEntryList(description);
|
| - for (var i = 0; i < pos; i++) {
|
| - newList.logs.add(logs[i]);
|
| - }
|
| - return newList;
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Returns log events that happened from the first one that
|
| - * satisfies [logFilter]. If [inPlace] is true, then returns
|
| - * this LogEntryList after removing the entries up to the first
|
| - * satisfier; otherwise a new list is created. [description]
|
| - * is used to create a new name for the resulting list.
|
| - * [defaultPosition] is used as the index of the matching item in
|
| - * the case that no match is found.
|
| - */
|
| - LogEntryList _tail(logFilter, bool inPlace,
|
| - String description, int defaultPosition) {
|
| - if (filter != null) {
|
| - description = '$filter $description';
|
| - }
|
| - int pos = findLogEntry(logFilter, 0, defaultPosition);
|
| - if (inPlace) {
|
| - if (pos > 0) {
|
| - logs.removeRange(0, pos);
|
| - }
|
| - filter = description;
|
| - return this;
|
| - } else {
|
| - LogEntryList newList = new LogEntryList(description);
|
| - while (pos < logs.length) {
|
| - newList.logs.add(logs[pos++]);
|
| - }
|
| - return newList;
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Returns log events that happened after [when]. If [inPlace]
|
| - * is true, then it returns this LogEntryList after removing
|
| - * the entries that happened up to [when]; otherwise a new
|
| - * list is created.
|
| - */
|
| - LogEntryList after(DateTime when, [bool inPlace = false]) =>
|
| - _tail((e) => e.time.isAfter(when), inPlace, 'after $when', logs.length);
|
| -
|
| - /**
|
| - * Returns log events that happened from [when] onwards. If
|
| - * [inPlace] is true, then it returns this LogEntryList after
|
| - * removing the entries that happened before [when]; otherwise
|
| - * a new list is created.
|
| - */
|
| - LogEntryList from(DateTime when, [bool inPlace = false]) =>
|
| - _tail((e) => !e.time.isBefore(when), inPlace, 'from $when', logs.length);
|
| -
|
| - /**
|
| - * Returns log events that happened until [when]. If [inPlace]
|
| - * is true, then it returns this LogEntryList after removing
|
| - * the entries that happened after [when]; otherwise a new
|
| - * list is created.
|
| - */
|
| - LogEntryList until(DateTime when, [bool inPlace = false]) =>
|
| - _head((e) => e.time.isAfter(when), inPlace, 'until $when', logs.length);
|
| -
|
| - /**
|
| - * Returns log events that happened before [when]. If [inPlace]
|
| - * is true, then it returns this LogEntryList after removing
|
| - * the entries that happened from [when] onwards; otherwise a new
|
| - * list is created.
|
| - */
|
| - LogEntryList before(DateTime when, [bool inPlace = false]) =>
|
| - _head((e) => !e.time.isBefore(when),
|
| - inPlace,
|
| - 'before $when',
|
| - logs.length);
|
| -
|
| - /**
|
| - * Returns log events that happened after [logEntry]'s time.
|
| - * If [inPlace] is true, then it returns this LogEntryList after
|
| - * removing the entries that happened up to [when]; otherwise a new
|
| - * list is created. If [logEntry] is null the current time is used.
|
| - */
|
| - LogEntryList afterEntry(LogEntry logEntry, [bool inPlace = false]) =>
|
| - after(logEntry == null ? new DateTime.now() : logEntry.time);
|
| -
|
| - /**
|
| - * Returns log events that happened from [logEntry]'s time onwards.
|
| - * If [inPlace] is true, then it returns this LogEntryList after
|
| - * removing the entries that happened before [when]; otherwise
|
| - * a new list is created. If [logEntry] is null the current time is used.
|
| - */
|
| - LogEntryList fromEntry(LogEntry logEntry, [bool inPlace = false]) =>
|
| - from(logEntry == null ? new DateTime.now() : logEntry.time);
|
| -
|
| - /**
|
| - * Returns log events that happened until [logEntry]'s time. If
|
| - * [inPlace] is true, then it returns this LogEntryList after removing
|
| - * the entries that happened after [when]; otherwise a new
|
| - * list is created. If [logEntry] is null the epoch time is used.
|
| - */
|
| - LogEntryList untilEntry(LogEntry logEntry, [bool inPlace = false]) =>
|
| - until(logEntry == null ?
|
| - new DateTime.fromMillisecondsSinceEpoch(0) : logEntry.time);
|
| -
|
| - /**
|
| - * Returns log events that happened before [logEntry]'s time. If
|
| - * [inPlace] is true, then it returns this LogEntryList after removing
|
| - * the entries that happened from [when] onwards; otherwise a new
|
| - * list is created. If [logEntry] is null the epoch time is used.
|
| - */
|
| - LogEntryList beforeEntry(LogEntry logEntry, [bool inPlace = false]) =>
|
| - before(logEntry == null ?
|
| - new DateTime.fromMillisecondsSinceEpoch(0) : logEntry.time);
|
| -
|
| - /**
|
| - * Returns log events that happened after the first event in [segment].
|
| - * If [inPlace] is true, then it returns this LogEntryList after removing
|
| - * the entries that happened earlier; otherwise a new list is created.
|
| - */
|
| - LogEntryList afterFirst(LogEntryList segment, [bool inPlace = false]) =>
|
| - afterEntry(segment.first, inPlace);
|
| -
|
| - /**
|
| - * Returns log events that happened after the last event in [segment].
|
| - * If [inPlace] is true, then it returns this LogEntryList after removing
|
| - * the entries that happened earlier; otherwise a new list is created.
|
| - */
|
| - LogEntryList afterLast(LogEntryList segment, [bool inPlace = false]) =>
|
| - afterEntry(segment.last, inPlace);
|
| -
|
| - /**
|
| - * Returns log events that happened from the time of the first event in
|
| - * [segment] onwards. If [inPlace] is true, then it returns this
|
| - * LogEntryList after removing the earlier entries; otherwise a new list
|
| - * is created.
|
| - */
|
| - LogEntryList fromFirst(LogEntryList segment, [bool inPlace = false]) =>
|
| - fromEntry(segment.first, inPlace);
|
| -
|
| - /**
|
| - * Returns log events that happened from the time of the last event in
|
| - * [segment] onwards. If [inPlace] is true, then it returns this
|
| - * LogEntryList after removing the earlier entries; otherwise a new list
|
| - * is created.
|
| - */
|
| - LogEntryList fromLast(LogEntryList segment, [bool inPlace = false]) =>
|
| - fromEntry(segment.last, inPlace);
|
| -
|
| - /**
|
| - * Returns log events that happened until the first event in [segment].
|
| - * If [inPlace] is true, then it returns this LogEntryList after removing
|
| - * the entries that happened later; otherwise a new list is created.
|
| - */
|
| - LogEntryList untilFirst(LogEntryList segment, [bool inPlace = false]) =>
|
| - untilEntry(segment.first, inPlace);
|
| -
|
| - /**
|
| - * Returns log events that happened until the last event in [segment].
|
| - * If [inPlace] is true, then it returns this LogEntryList after removing
|
| - * the entries that happened later; otherwise a new list is created.
|
| - */
|
| - LogEntryList untilLast(LogEntryList segment, [bool inPlace = false]) =>
|
| - untilEntry(segment.last, inPlace);
|
| -
|
| - /**
|
| - * Returns log events that happened before the first event in [segment].
|
| - * If [inPlace] is true, then it returns this LogEntryList after removing
|
| - * the entries that happened later; otherwise a new list is created.
|
| - */
|
| - LogEntryList beforeFirst(LogEntryList segment, [bool inPlace = false]) =>
|
| - beforeEntry(segment.first, inPlace);
|
| -
|
| - /**
|
| - * Returns log events that happened before the last event in [segment].
|
| - * If [inPlace] is true, then it returns this LogEntryList after removing
|
| - * the entries that happened later; otherwise a new list is created.
|
| - */
|
| - LogEntryList beforeLast(LogEntryList segment, [bool inPlace = false]) =>
|
| - beforeEntry(segment.last, inPlace);
|
| -
|
| - /**
|
| - * Iterate through the LogEntryList looking for matches to the entries
|
| - * in [keys]; for each match found the closest [distance] neighboring log
|
| - * entries that match [mockNameFilter] and [logFilter] will be included in
|
| - * the result. If [isPreceding] is true we use the neighbors that precede
|
| - * the matched entry; else we use the neighbors that followed.
|
| - * If [includeKeys] is true then the entries in [keys] that resulted in
|
| - * entries in the output list are themselves included in the output list. If
|
| - * [distance] is zero then all matches are included.
|
| - */
|
| - LogEntryList _neighboring(bool isPreceding,
|
| - LogEntryList keys,
|
| - mockNameFilter,
|
| - logFilter,
|
| - int distance,
|
| - bool includeKeys) {
|
| - String filterName = 'Calls to '
|
| - '${qualifiedName(mockNameFilter, logFilter.toString())} '
|
| - '${isPreceding?"preceding":"following"} ${keys.filter}';
|
| -
|
| - LogEntryList rtn = new LogEntryList(filterName);
|
| -
|
| - // Deal with the trivial case.
|
| - if (logs.length == 0 || keys.logs.length == 0) {
|
| - return rtn;
|
| - }
|
| -
|
| - // Normalize the mockNameFilter and logFilter values.
|
| - if (mockNameFilter == null) {
|
| - mockNameFilter = anything;
|
| - } else {
|
| - mockNameFilter = wrapMatcher(mockNameFilter);
|
| - }
|
| - logFilter = _makePredicate(logFilter);
|
| -
|
| - // The scratch list is used to hold matching entries when we
|
| - // are doing preceding neighbors. The remainingCount is used to
|
| - // keep track of how many matching entries we can still add in the
|
| - // current segment (0 if we are doing doing following neighbors, until
|
| - // we get our first key match).
|
| - List scratch = null;
|
| - int remainingCount = 0;
|
| - if (isPreceding) {
|
| - scratch = new List();
|
| - remainingCount = logs.length;
|
| - }
|
| -
|
| - var keyIterator = keys.logs.iterator;
|
| - keyIterator.moveNext();
|
| - LogEntry keyEntry = keyIterator.current;
|
| - Map matchState = {};
|
| -
|
| - for (LogEntry logEntry in logs) {
|
| - // If we have a log entry match, copy the saved matches from the
|
| - // scratch buffer into the return list, as well as the matching entry,
|
| - // if appropriate, and reset the scratch buffer. Continue processing
|
| - // from the next key entry.
|
| - if (keyEntry == logEntry) {
|
| - if (scratch != null) {
|
| - int numToCopy = scratch.length;
|
| - if (distance > 0 && distance < numToCopy) {
|
| - numToCopy = distance;
|
| - }
|
| - for (var i = scratch.length - numToCopy; i < scratch.length; i++) {
|
| - rtn.logs.add(scratch[i]);
|
| - }
|
| - scratch.clear();
|
| - } else {
|
| - remainingCount = distance > 0 ? distance : logs.length;
|
| - }
|
| - if (includeKeys) {
|
| - rtn.logs.add(keyEntry);
|
| - }
|
| - if (keyIterator.moveNext()) {
|
| - keyEntry = keyIterator.current;
|
| - } else if (isPreceding) { // We're done.
|
| - break;
|
| - }
|
| - } else if (remainingCount > 0 &&
|
| - mockNameFilter.matches(logEntry.mockName, matchState) &&
|
| - logFilter(logEntry)) {
|
| - if (scratch != null) {
|
| - scratch.add(logEntry);
|
| - } else {
|
| - rtn.logs.add(logEntry);
|
| - --remainingCount;
|
| - }
|
| - }
|
| - }
|
| - return rtn;
|
| - }
|
| -
|
| - /**
|
| - * Iterate through the LogEntryList looking for matches to the entries
|
| - * in [keys]; for each match found the closest [distance] prior log entries
|
| - * that match [mocknameFilter] and [logFilter] will be included in the result.
|
| - * If [includeKeys] is true then the entries in [keys] that resulted in
|
| - * entries in the output list are themselves included in the output list. If
|
| - * [distance] is zero then all matches are included.
|
| - *
|
| - * The idea here is that you could find log entries that are related to
|
| - * other logs entries in some temporal sense. For example, say we have a
|
| - * method commit() that returns -1 on failure. Before commit() gets called
|
| - * the value being committed is created by process(). We may want to find
|
| - * the calls to process() that preceded calls to commit() that failed.
|
| - * We could do this with:
|
| - *
|
| - * print(log.preceding(log.getLogs(callsTo('commit'), returning(-1)),
|
| - * logFilter: callsTo('process')).toString());
|
| - *
|
| - * We might want to include the details of the failing calls to commit()
|
| - * to see what parameters were passed in, in which case we would set
|
| - * [includeKeys].
|
| - *
|
| - * As another simple example, say we wanted to know the three method
|
| - * calls that immediately preceded each failing call to commit():
|
| - *
|
| - * print(log.preceding(log.getLogs(callsTo('commit'), returning(-1)),
|
| - * distance: 3).toString());
|
| - */
|
| - LogEntryList preceding(LogEntryList keys,
|
| - {mockNameFilter: null,
|
| - logFilter: null,
|
| - int distance: 1,
|
| - bool includeKeys: false}) =>
|
| - _neighboring(true, keys, mockNameFilter, logFilter,
|
| - distance, includeKeys);
|
| -
|
| - /**
|
| - * Iterate through the LogEntryList looking for matches to the entries
|
| - * in [keys]; for each match found the closest [distance] subsequent log
|
| - * entries that match [mocknameFilter] and [logFilter] will be included in
|
| - * the result. If [includeKeys] is true then the entries in [keys] that
|
| - * resulted in entries in the output list are themselves included in the
|
| - * output list. If [distance] is zero then all matches are included.
|
| - * See [preceding] for a usage example.
|
| - */
|
| - LogEntryList following(LogEntryList keys,
|
| - {mockNameFilter: null,
|
| - logFilter: null,
|
| - int distance: 1,
|
| - bool includeKeys: false}) =>
|
| - _neighboring(false, keys, mockNameFilter, logFilter,
|
| - distance, includeKeys);
|
| -}
|
| -
|
| -_MockFailureHandler _mockFailureHandler = null;
|
| -
|
| -/**
|
| - * The failure handler for the [expect()] calls that occur in [verify()]
|
| - * methods in the mock objects. This calls the real failure handler used
|
| - * by the unit test library after formatting the error message with
|
| - * the custom formatter.
|
| - */
|
| -class _MockFailureHandler implements FailureHandler {
|
| - FailureHandler proxy;
|
| - _MockFailureHandler(this.proxy);
|
| - void fail(String reason) {
|
| - proxy.fail(reason);
|
| - }
|
| - void failMatch(actual, Matcher matcher, String reason,
|
| - Map matchState, bool verbose) {
|
| - proxy.fail(_mockingErrorFormatter(actual, matcher, reason,
|
| - matchState, verbose));
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * The error formatter for mocking is a bit different from the default one
|
| - * for unit testing; instead of the third argument being a 'reason'
|
| - * it is instead a [signature] describing the method signature filter
|
| - * that was used to select the logs that were verified.
|
| - */
|
| -String _mockingErrorFormatter(actual, Matcher matcher, String signature,
|
| - Map matchState, bool verbose) {
|
| - var description = new StringDescription();
|
| - description.add('Expected ${signature} ').addDescriptionOf(matcher).
|
| - add('\n but: ');
|
| - matcher.describeMismatch(actual, description, matchState, verbose).add('.');
|
| - return description.toString();
|
| -}
|
|
|