LCOV - code coverage report
Current view: top level - matcher-0.12.1+4/lib/src - iterable_matchers.dart (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 0 109 0.0 %
Date: 2017-10-10 20:17:03 Functions: 0 0 -

          Line data    Source code
       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
       3             : // BSD-style license that can be found in the LICENSE file.
       4             : 
       5             : import 'core_matchers.dart';
       6             : import 'description.dart';
       7             : import 'interfaces.dart';
       8             : import 'util.dart';
       9             : 
      10             : /// Returns a matcher which matches [Iterable]s in which all elements
      11             : /// match the given [matcher].
      12           0 : Matcher everyElement(matcher) => new _EveryElement(wrapMatcher(matcher));
      13             : 
      14             : class _EveryElement extends _IterableMatcher {
      15             :   final Matcher _matcher;
      16             : 
      17           0 :   _EveryElement(this._matcher);
      18             : 
      19             :   bool matches(item, Map matchState) {
      20           0 :     if (item is! Iterable) {
      21             :       return false;
      22             :     }
      23             :     var i = 0;
      24           0 :     for (var element in item) {
      25           0 :       if (!_matcher.matches(element, matchState)) {
      26           0 :         addStateInfo(matchState, {'index': i, 'element': element});
      27             :         return false;
      28             :       }
      29           0 :       ++i;
      30             :     }
      31             :     return true;
      32             :   }
      33             : 
      34             :   Description describe(Description description) =>
      35           0 :       description.add('every element(').addDescriptionOf(_matcher).add(')');
      36             : 
      37             :   Description describeMismatch(
      38             :       item, Description mismatchDescription, Map matchState, bool verbose) {
      39           0 :     if (matchState['index'] != null) {
      40           0 :       var index = matchState['index'];
      41           0 :       var element = matchState['element'];
      42             :       mismatchDescription
      43           0 :           .add('has value ')
      44           0 :           .addDescriptionOf(element)
      45           0 :           .add(' which ');
      46           0 :       var subDescription = new StringDescription();
      47           0 :       _matcher.describeMismatch(
      48           0 :           element, subDescription, matchState['state'], verbose);
      49           0 :       if (subDescription.length > 0) {
      50           0 :         mismatchDescription.add(subDescription.toString());
      51             :       } else {
      52           0 :         mismatchDescription.add("doesn't match ");
      53           0 :         _matcher.describe(mismatchDescription);
      54             :       }
      55           0 :       mismatchDescription.add(' at index $index');
      56             :       return mismatchDescription;
      57             :     }
      58             :     return super
      59           0 :         .describeMismatch(item, mismatchDescription, matchState, verbose);
      60             :   }
      61             : }
      62             : 
      63             : /// Returns a matcher which matches [Iterable]s in which at least one
      64             : /// element matches the given [matcher].
      65           0 : Matcher anyElement(matcher) => new _AnyElement(wrapMatcher(matcher));
      66             : 
      67             : class _AnyElement extends _IterableMatcher {
      68             :   final Matcher _matcher;
      69             : 
      70           0 :   _AnyElement(this._matcher);
      71             : 
      72             :   bool matches(item, Map matchState) {
      73           0 :     return item.any((e) => _matcher.matches(e, matchState));
      74             :   }
      75             : 
      76             :   Description describe(Description description) =>
      77           0 :       description.add('some element ').addDescriptionOf(_matcher);
      78             : }
      79             : 
      80             : /// Returns a matcher which matches [Iterable]s that have the same
      81             : /// length and the same elements as [expected], in the same order.
      82             : ///
      83             : /// This is equivalent to [equals] but does not recurse.
      84           0 : Matcher orderedEquals(Iterable expected) => new _OrderedEquals(expected);
      85             : 
      86             : class _OrderedEquals extends Matcher {
      87             :   final Iterable _expected;
      88             :   Matcher _matcher;
      89             : 
      90           0 :   _OrderedEquals(this._expected) {
      91           0 :     _matcher = equals(_expected, 1);
      92             :   }
      93             : 
      94             :   bool matches(item, Map matchState) =>
      95           0 :       (item is Iterable) && _matcher.matches(item, matchState);
      96             : 
      97             :   Description describe(Description description) =>
      98           0 :       description.add('equals ').addDescriptionOf(_expected).add(' ordered');
      99             : 
     100             :   Description describeMismatch(
     101             :       item, Description mismatchDescription, Map matchState, bool verbose) {
     102           0 :     if (item is! Iterable) {
     103           0 :       return mismatchDescription.add('is not an Iterable');
     104             :     } else {
     105           0 :       return _matcher.describeMismatch(
     106             :           item, mismatchDescription, matchState, verbose);
     107             :     }
     108             :   }
     109             : }
     110             : 
     111             : /// Returns a matcher which matches [Iterable]s that have the same length and
     112             : /// the same elements as [expected], but not necessarily in the same order.
     113             : ///
     114             : /// Note that this is O(n^2) so should only be used on small objects.
     115           0 : Matcher unorderedEquals(Iterable expected) => new _UnorderedEquals(expected);
     116             : 
     117             : class _UnorderedEquals extends _UnorderedMatches {
     118             :   final List _expectedValues;
     119             : 
     120             :   _UnorderedEquals(Iterable expected)
     121           0 :       : _expectedValues = expected.toList(),
     122           0 :         super(expected.map(equals));
     123             : 
     124             :   Description describe(Description description) => description
     125           0 :       .add('equals ')
     126           0 :       .addDescriptionOf(_expectedValues)
     127           0 :       .add(' unordered');
     128             : }
     129             : 
     130             : /// Iterable matchers match against [Iterable]s. We add this intermediate
     131             : /// class to give better mismatch error messages than the base Matcher class.
     132             : abstract class _IterableMatcher extends Matcher {
     133           0 :   const _IterableMatcher();
     134             :   Description describeMismatch(
     135             :       item, Description mismatchDescription, Map matchState, bool verbose) {
     136           0 :     if (item is! Iterable) {
     137           0 :       return mismatchDescription.addDescriptionOf(item).add(' not an Iterable');
     138             :     } else {
     139             :       return super
     140           0 :           .describeMismatch(item, mismatchDescription, matchState, verbose);
     141             :     }
     142             :   }
     143             : }
     144             : 
     145             : /// Returns a matcher which matches [Iterable]s whose elements match the
     146             : /// matchers in [expected], but not necessarily in the same order.
     147             : ///
     148             : ///  Note that this is `O(n^2)` and so should only be used on small objects.
     149           0 : Matcher unorderedMatches(Iterable expected) => new _UnorderedMatches(expected);
     150             : 
     151             : class _UnorderedMatches extends Matcher {
     152             :   final List<Matcher> _expected;
     153             : 
     154             :   _UnorderedMatches(Iterable expected)
     155           0 :       : _expected = expected.map(wrapMatcher).toList();
     156             : 
     157             :   String _test(item) {
     158           0 :     if (item is Iterable) {
     159           0 :       var list = item.toList();
     160             : 
     161             :       // Check the lengths are the same.
     162           0 :       if (_expected.length > list.length) {
     163           0 :         return 'has too few elements (${list.length} < ${_expected.length})';
     164           0 :       } else if (_expected.length < list.length) {
     165           0 :         return 'has too many elements (${list.length} > ${_expected.length})';
     166             :       }
     167             : 
     168           0 :       var matched = new List<bool>.filled(list.length, false);
     169             :       var expectedPosition = 0;
     170           0 :       for (var expectedMatcher in _expected) {
     171             :         var actualPosition = 0;
     172             :         var gotMatch = false;
     173           0 :         for (var actualElement in list) {
     174           0 :           if (!matched[actualPosition]) {
     175           0 :             if (expectedMatcher.matches(actualElement, {})) {
     176           0 :               matched[actualPosition] = gotMatch = true;
     177             :               break;
     178             :             }
     179             :           }
     180           0 :           ++actualPosition;
     181             :         }
     182             : 
     183             :         if (!gotMatch) {
     184           0 :           return new StringDescription()
     185           0 :               .add('has no match for ')
     186           0 :               .addDescriptionOf(expectedMatcher)
     187           0 :               .add(' at index $expectedPosition')
     188           0 :               .toString();
     189             :         }
     190             : 
     191           0 :         ++expectedPosition;
     192             :       }
     193             :       return null;
     194             :     } else {
     195             :       return 'not iterable';
     196             :     }
     197             :   }
     198             : 
     199           0 :   bool matches(item, Map mismatchState) => _test(item) == null;
     200             : 
     201             :   Description describe(Description description) => description
     202           0 :       .add('matches ')
     203           0 :       .addAll('[', ', ', ']', _expected)
     204           0 :       .add(' unordered');
     205             : 
     206             :   Description describeMismatch(item, Description mismatchDescription,
     207             :           Map matchState, bool verbose) =>
     208           0 :       mismatchDescription.add(_test(item));
     209             : }
     210             : 
     211             : /// A pairwise matcher for [Iterable]s.
     212             : ///
     213             : /// The [comparator] function, taking an expected and an actual argument, and
     214             : /// returning whether they match, will be applied to each pair in order.
     215             : /// [description] should be a meaningful name for the comparator.
     216             : Matcher pairwiseCompare<S, T>(
     217             :         Iterable<S> expected, bool comparator(S a, T b), String description) =>
     218           0 :     new _PairwiseCompare(expected, comparator, description);
     219             : 
     220             : typedef bool _Comparator<S, T>(S a, T b);
     221             : 
     222             : class _PairwiseCompare<S, T> extends _IterableMatcher {
     223             :   final Iterable<S> _expected;
     224             :   final _Comparator<S, T> _comparator;
     225             :   final String _description;
     226             : 
     227           0 :   _PairwiseCompare(this._expected, this._comparator, this._description);
     228             : 
     229             :   bool matches(item, Map matchState) {
     230           0 :     if (item is Iterable) {
     231           0 :       if (item.length != _expected.length) return false;
     232           0 :       var iterator = item.iterator;
     233             :       var i = 0;
     234           0 :       for (var e in _expected) {
     235           0 :         iterator.moveNext();
     236           0 :         if (!_comparator(e, iterator.current)) {
     237           0 :           addStateInfo(matchState,
     238           0 :               {'index': i, 'expected': e, 'actual': iterator.current});
     239             :           return false;
     240             :         }
     241           0 :         i++;
     242             :       }
     243             :       return true;
     244             :     } else {
     245             :       return false;
     246             :     }
     247             :   }
     248             : 
     249             :   Description describe(Description description) =>
     250           0 :       description.add('pairwise $_description ').addDescriptionOf(_expected);
     251             : 
     252             :   Description describeMismatch(
     253             :       item, Description mismatchDescription, Map matchState, bool verbose) {
     254           0 :     if (item is! Iterable) {
     255           0 :       return mismatchDescription.add('is not an Iterable');
     256           0 :     } else if (item.length != _expected.length) {
     257             :       return mismatchDescription
     258           0 :           .add('has length ${item.length} instead of ${_expected.length}');
     259             :     } else {
     260             :       return mismatchDescription
     261           0 :           .add('has ')
     262           0 :           .addDescriptionOf(matchState["actual"])
     263           0 :           .add(' which is not $_description ')
     264           0 :           .addDescriptionOf(matchState["expected"])
     265           0 :           .add(' at index ${matchState["index"]}');
     266             :     }
     267             :   }
     268             : }
     269             : 
     270             : /// Matches [Iterable]s which contain an element matching every value in
     271             : /// [expected] in the same order, but may contain additional values interleaved
     272             : /// throughout.
     273             : ///
     274             : /// For example: `[0, 1, 0, 2, 0]` matches `containsAllInOrder([1, 2])` but not
     275             : /// `containsAllInOrder([2, 1])` or `containsAllInOrder([1, 2, 3])`.
     276             : Matcher containsAllInOrder(Iterable expected) =>
     277           0 :     new _ContainsAllInOrder(expected);
     278             : 
     279             : class _ContainsAllInOrder implements Matcher {
     280             :   final Iterable _expected;
     281             : 
     282           0 :   _ContainsAllInOrder(this._expected);
     283             : 
     284             :   String _test(item, Map matchState) {
     285           0 :     if (item is! Iterable) return 'not an iterable';
     286           0 :     var matchers = _expected.map(wrapMatcher).toList();
     287             :     var matcherIndex = 0;
     288           0 :     for (var value in item) {
     289           0 :       if (matchers[matcherIndex].matches(value, matchState)) matcherIndex++;
     290           0 :       if (matcherIndex == matchers.length) return null;
     291             :     }
     292           0 :     return new StringDescription()
     293           0 :         .add('did not find a value matching ')
     294           0 :         .addDescriptionOf(matchers[matcherIndex])
     295           0 :         .add(' following expected prior values')
     296           0 :         .toString();
     297             :   }
     298             : 
     299             :   @override
     300           0 :   bool matches(item, Map matchState) => _test(item, matchState) == null;
     301             : 
     302             :   @override
     303             :   Description describe(Description description) => description
     304           0 :       .add('contains in order(')
     305           0 :       .addDescriptionOf(_expected)
     306           0 :       .add(')');
     307             : 
     308             :   @override
     309             :   Description describeMismatch(item, Description mismatchDescription,
     310             :           Map matchState, bool verbose) =>
     311           0 :       mismatchDescription.add(_test(item, matchState));
     312             : }

Generated by: LCOV version 1.13