Git Product home page Git Product logo

matcher's Introduction

Dart CI pub package package publisher

Support for specifying test expectations, such as for unit tests.

The matcher library provides a third-generation assertion mechanism, drawing inspiration from Hamcrest.

For more information on testing, see Unit Testing with Dart.

Using matcher

Expectations start with a call to expect() or expectAsync().

Any matchers package can be used with expect() to do complex validations:

import 'package:test/test.dart';

void main() {
  test('.split() splits the string on the delimiter', () {
    expect('foo,bar,baz', allOf([
      contains('foo'),
      isNot(startsWith('bar')),
      endsWith('baz')
    ]));
  });
}

If a non-matcher value is passed, it will be wrapped with equals().

Exception matchers

You can also test exceptions with the throwsA() function or a matcher such as throwsFormatException:

import 'package:test/test.dart';

void main() {
  test('.parse() fails on invalid input', () {
    expect(() => int.parse('X'), throwsFormatException);
  });
}

Future Matchers

There are a number of useful functions and matchers for more advanced asynchrony. The completion() matcher can be used to test Futures; it ensures that the test doesn't finish until the Future completes, and runs a matcher against that Future's value.

import 'dart:async';

import 'package:test/test.dart';

void main() {
  test('Future.value() returns the value', () {
    expect(Future.value(10), completion(equals(10)));
  });
}

The throwsA() matcher and the various throwsExceptionType matchers work with both synchronous callbacks and asynchronous Futures. They ensure that a particular type of exception is thrown:

import 'dart:async';

import 'package:test/test.dart';

void main() {
  test('Future.error() throws the error', () {
    expect(Future.error('oh no'), throwsA(equals('oh no')));
    expect(Future.error(StateError('bad state')), throwsStateError);
  });
}

The expectAsync() function wraps another function and has two jobs. First, it asserts that the wrapped function is called a certain number of times, and will cause the test to fail if it's called too often; second, it keeps the test from finishing until the function is called the requisite number of times.

import 'dart:async';

import 'package:test/test.dart';

void main() {
  test('Stream.fromIterable() emits the values in the iterable', () {
    var stream = Stream.fromIterable([1, 2, 3]);

    stream.listen(expectAsync1((number) {
      expect(number, inInclusiveRange(1, 3));
    }, count: 3));
  });
}

Stream Matchers

The test package provides a suite of powerful matchers for dealing with asynchronous streams. They're expressive and composable, and make it easy to write complex expectations about the values emitted by a stream. For example:

import 'dart:async';

import 'package:test/test.dart';

void main() {
  test('process emits status messages', () {
    // Dummy data to mimic something that might be emitted by a process.
    var stdoutLines = Stream.fromIterable([
      'Ready.',
      'Loading took 150ms.',
      'Succeeded!'
    ]);

    expect(stdoutLines, emitsInOrder([
      // Values match individual events.
      'Ready.',

      // Matchers also run against individual events.
      startsWith('Loading took'),

      // Stream matchers can be nested. This asserts that one of two events are
      // emitted after the "Loading took" line.
      emitsAnyOf(['Succeeded!', 'Failed!']),

      // By default, more events are allowed after the matcher finishes
      // matching. This asserts instead that the stream emits a done event and
      // nothing else.
      emitsDone
    ]));
  });
}

A stream matcher can also match the async package's StreamQueue class, which allows events to be requested from a stream rather than pushed to the consumer. The matcher will consume the matched events, but leave the rest of the queue alone so that it can still be used by the test, unlike a normal Stream which can only have one subscriber. For example:

import 'dart:async';

import 'package:async/async.dart';
import 'package:test/test.dart';

void main() {
  test('process emits a WebSocket URL', () async {
    // Wrap the Stream in a StreamQueue so that we can request events.
    var stdout = StreamQueue(Stream.fromIterable([
      'WebSocket URL:',
      'ws://localhost:1234/',
      'Waiting for connection...'
    ]));

    // Ignore lines from the process until it's about to emit the URL.
    await expectLater(stdout, emitsThrough('WebSocket URL:'));

    // Parse the next line as a URL.
    var url = Uri.parse(await stdout.next);
    expect(url.host, equals('localhost'));

    // You can match against the same StreamQueue multiple times.
    await expectLater(stdout, emits('Waiting for connection...'));
  });
}

The following built-in stream matchers are available:

  • emits() matches a single data event.
  • emitsError() matches a single error event.
  • emitsDone matches a single done event.
  • mayEmit() consumes events if they match an inner matcher, without requiring them to match.
  • mayEmitMultiple() works like mayEmit(), but it matches events against the matcher as many times as possible.
  • emitsAnyOf() consumes events matching one (or more) of several possible matchers.
  • emitsInOrder() consumes events matching multiple matchers in a row.
  • emitsInAnyOrder() works like emitsInOrder(), but it allows the matchers to match in any order.
  • neverEmits() matches a stream that finishes without matching an inner matcher.

You can also define your own custom stream matchers with StreamMatcher().

Best Practices

Prefer semantically meaningful matchers to comparing derived values

Matchers which have knowledge of the semantics that are tested are able to emit more meaningful messages which don't require reading test source to understand why the test failed. For instance compare the failures between expect(someList.length, 1), and expect(someList, hasLength(1)):

// expect(someList.length, 1);
  Expected: <1>
    Actual: <2>
// expect(someList, hasLength(1));
  Expected: an object with length of <1>
    Actual: ['expected value', 'unexpected value']
     Which: has length of <2>

Prefer TypeMatcher to predicate if the match can fail in multiple ways

The predicate utility is a convenient shortcut for testing an arbitrary (synchronous) property of a value, but it discards context and failures are opaque. Different failure modes cannot be distinguished in the output which is determined by a single "description" argument. Using isA<SomeType>() and the TypeMatcher.having API to extract and test derived properties in a structured way brings the context of that structure through to failure messages, so failures for different reasons will have distinguishable and actionable failure messages.

matcher's People

Contributors

aliak00 avatar bcko avatar blackhc avatar chalin avatar dependabot[bot] avatar devoncarew avatar ekupershlak avatar franklinyow avatar goderbauer avatar hixie avatar icmdaf avatar jakemac53 avatar jamesderlin avatar joeconwaystk avatar kevmoo avatar kriswuollett avatar kunzhao77 avatar leafpetersen avatar lrhn avatar natebosch avatar nex3 avatar pq avatar sigurdm avatar srawlins avatar stereotype441 avatar trinarytree avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

matcher's Issues

replace 'given' with 'actual' in error message

From @skybrian on August 16, 2015 20:23

In this error message, I found the word "given" to be a bit confusing:

  Expected: 'r\'\'\'\n'
    'single: \' double: " triples: \'\'\' "\'\'\'" r\'\'\' and """!\'\'\''
    Actual: 'r\'\'\'\n'
    'single: \' double: " triples: \'\'\' "\'\'\'" r\'\'\' and """!\'\'\'\n'
    ''
     Which: is different. Both strings start the same, but the given value also has the following trailing characters: \n

In retrospect it makes sense, but it seems like replacing the word "given" with "actual" would be more consistent and immediately obvious.

(Also, there's a redundant '' at the end of the Actual part.)

Copied from original issue: dart-lang/test#321

Matcher.matches should return a rich "match result" object

Currently Matcher.matches just returns bool, and the rest of the match result is recorded separately by mutating an untyped Map matchState object that must be initialized and passed in. That's pretty strange. Instead it should just return the whole match result as a single immutable object.

class Matcher {
  Description describe();

  /// Returns either [MatchResult] of [Future<MatchResult>].
  matches(item);
}

abstract class MatchResult {
  bool get isMatch;
}

class Match {
  Match();
  bool get isMatch => true;
}

abstract class Mismatch extends MatchResult {
  bool get isMatch => false;
  Description describeMismatch({bool verbose: false});
}

Subclasses of Mismatch can add typed (likely private) fields for use by describeMisMatch, and a constructor to initialize them.

In the case when Matcher.matches returns a Future, expect from the test package would also return a Future which could be awaited. Alternatively there could a separate predict method for the async case. The ability to return a Future would allow for matchers which provide nicer error messages for things like testing asynchronous things like http calls. Also some of the existing APIs like completes and completion could use this, which would then allow them to finish executing before the test continues on to the next expectation:

  await predict(future, completion(5));
  expect(foo, bar);

edit: Renamed Matched to Match since dart:core Match will automatically be shadowed anyways.

Deprecate isTrue, isFalse

These matchers, when used in expect calls, don't add value over literal boolean values.

If there aren't other places which is seeing value from these we should deprecate and eventually remove them so we don't have multiple ways of accomplishing the same thing.

Add option to print expected and actual strings with triple quotes

From @skybrian on May 27, 2016 2:31

For example, this is not terribly readable:

  Expected: '///\n'
    '//  Generated code. Do not modify.\n'
    '///\n'
    'library test;\n'
    '\n'
    'import \'dart:async\';\n'
    '\n'
    'import \'package:protobuf/protobuf.dart\';\n'
    '\n'
    ''
    Actual: '///\n'
    '//  Generated code. Do not modify.\n'
    '///\n'
    'library test;\n'
    '\n'
    'import \'dart:async\';\n'
    '\n'
    'import \'package:protobuf/protobuf.dart\';\n'
    '\n'
    'class Api {\n'
    '  RpcClient _client;\n'
    '  Api(this._client);\n'
    '\n'
    '}\n'
    '\n'
    ''
     Which: is different. Both strings start the same, but the given value also has the following trailing characters: class Api  ...

Since I use triple-quoted strings for expected data, updating the test is a bit tedious. It would be nicer if there were an option to print diffs using triple-quoted strings. It would also make the output easier to read.

Copied from original issue: dart-lang/test#435

'$' not escaped when printing a multi-line string

If the equality matcher fails for a string, in the "Actual" section where it prints each line as a single-quoted string, the dollar sign should be escaped.

Here is the output where I saw this: 'const M$json = const {\n'

CustomMatcher.describeMismatch can fail if featureValueOf throws

From dart-lang/test#257 (originally from dart-lang/sdk#20398).


What steps will reproduce the problem?

  1. Write code like:
    class BadCustomMatcher extends CustomMatcher
    {
      BadCustomMatcher(): super("feature", "description", {1: "a"});

  featureValueOf(actual) => throw new Exception("bang");
}

main () {
  test("test", () {
    expect("a", new BadCustomMatcher());
  });
}
2. run it
3. Get a traceback like:
ERROR: test
  Test failed: Caught The null object does not have a method '[]'.
  
  NoSuchMethodError: method not found: '[]'
  Receiver: null
  Arguments: ["reason"]
  dart:core-patch/object_patch.dart 45 Object.noSuchMethod
  package:matcher/src/core_matchers.dart 263:28 _DeepMatcher.describeMismatch
  package:matcher/src/core_matchers.dart 740:30 CustomMatcher.describeMismatch
  package:matcher/src/expect.dart 146:27 _defaultErrorFormatter
  package:matcher/src/expect.dart 113:31 DefaultFailureHandler.failMatch
  package:matcher/src/expect.dart 73:29 expect
  test.dart 129:11 main.<fn>

What is the expected output? What do you see instead?
I'd expect to get a description of the exception. Indeed looking at the code I think I would if the inner matcher didn't use the matchState in it's own describeMismatch

What version of the product are you using?

On what operating system?

What browser (if applicable)?

Please provide any additional information below.

Provide a way to customize pretty printing

When expect notices an error, it outputs an Expected: Actual: Which: block of text.

The Actual: line, however, wraps the value in angle brackets.

Sometimes, the value I want to print isn't a literal value, it's just an English-prose vague description of the value (the value itself being a gigantic tree that takes pages and pages to print and that isn't useful to print in this context).

This is a feature request to have a way to provide a pretty printer for values, e.g. by implementing a particular interface, or by having the matchers provide the pretty printer for the value, and allowing this API to omit the angle brackets.

CustomMatcher dartdoc example is invalid – no const ctor

///     class HasPrice extends CustomMatcher {
///       const HasPrice(matcher) :
///           super("Widget with price that is", "price", matcher);
///       featureValueOf(actual) => actual.price;
///     }

CustomMather has no const constructor. So HasPrice should not have a const constructor

Matcher should always call describeMismatch of a nested macther

Originally opened as dart-lang/sdk#14068

This issue was originally filed by [email protected]


What steps will reproduce the problem?

  1. Create a Matcher with has a describeMismatch method
  2. Create a falling unittest with the Matcher in the isNot-Matcher: isNot(myMatcher)

What is the expected output? What do you see instead?
Expected:


Expected: not <my description>
  Actual: <value>
   Which: <my mismatch description>

Actual:


Expected: not <my description>
  Actual: <value>

What version of the product are you using? On what operating system?
Dart VM version: 0.8.1.2_r28355 (Tue Oct 08 06:29:27 2013) on "windows_ia32"

Please provide any additional information below.
All matcher that contain other matcher should add the nested description. At least isNot is missing that.

Could Matcher be changed to be typed as Matcher<T>?

Specifically, this allows strongly-typed assurances when creating specialized matchers:

abstract class StringMatcher extends Matcher<String> {}

I don't think this is a breaking change, unless we specifically want to allow something like:

expect(5, isNot(equalsIgnoringCase('5')))

Added after the fact by @nex3

Blocking issues (see comments for details):

Matchers: ||, &&, and ! instead of anyOf, allOf, isNot

<img src="https://avatars.githubusercontent.com/u/444270?v=3" align="left" width="96" height="96"hspace="10"> Issue by seaneagan
Originally opened as dart-lang/sdk#3727


consider:

expect(v, !(isNull || isEmpty));
// vs.
expect(v, isNot(anyOf(isNull, isEmpty)));

expect(v, new isInstanceOf<num> && isPositive);
// vs.
expect(v, allOf(new isInstanceOf<num>, isPositive));

The operators are clearly shorter, but more importantly to me, they read more naturally, and I would think this would be especially true for non-native English speakers.

One small problem... the ! operator is not currently user-definable. Is there a reason for this ?

Could also potentially remove all the composite negation matchers:

isFalse // somewhat misleading since it matches more than just "false".
isNotNull
isNonZero
isNonNegative
isNonPositive

and just have the ! operator of the Matcher they are negating, lazily initialize them:

! isTrue
! isNull
! isZero
! isNegative
! isPositive

It would be unusual to want to override || or && operators, but for the ! operator, it would be useful to customize the negated message, for the description for:

! hasChildren

could be customized to:

"to not have any children"

instead of:

"not <to have children>"

which might be generated by:

isNot(hasChildren)

contains() should auto-wrap in a matcher

Use case:

expect(fontManifest, contains({
  'family': 'DummyFont',
  'fonts': [
    {'asset': 'fonts/dummy_font_regular'},
    {'asset': 'fonts/dummy_font_bold', 'weight': 600},
    {'asset': 'fonts/dummy_font_italic', 'style': 'italic'},
    {'asset': 'fonts/dummy_font_bold_italic', 'weight': 600, 'style': 'italic'},
  ],
}));

Right now, this doesn't work, and the user has to explicitly call wrapMatcher() to get the desired behavior:

expect(fontManifest, contains(wrapMatcher({
  'family': 'DummyFont',
  'fonts': [
    {'asset': 'fonts/dummy_font_regular'},
    {'asset': 'fonts/dummy_font_bold', 'weight': 600},
    {'asset': 'fonts/dummy_font_italic', 'style': 'italic'},
    {'asset': 'fonts/dummy_font_bold_italic', 'weight': 600, 'style': 'italic'},
  ],
})));

It'd be more elegant if contains() implicitly called wrapMatcher() if it were matching against a non-string value.

Make all descriptions use the subjunctive mood

The subjunctive mood (that is, "contain" as opposed to "contains") is a lot easier to compose grammatically than the indicative ("contains"). For example, there's no way to create a description for the negation matcher that works if its argument uses the nominative case; "not contains" isn't valid, nor is "doesn't contains". However, "doesn't contain" is valid. Any sentence that would otherwise require the indicative mood can take the subjunctive instead by adding "should" (or "does", but that reads as redundant in some places).

We may also want to change the expect() method's "Expected:" label to "Should:" in test.

Move Matcher implementations to separate package

This package (matcher) could simply define the interfaces and default implementation.
It would be very easy to get such a package to stabilize to 1.0.0 and keep it there.
The test package and other packages which want to define a Matcher based API, such as constrain, would depend on matcher.

The Matcher implementations currently in this package could be moved to a separate matchers package which contains all the Matcher implementations which are currently in matcher, and it would be what users of test and other Matcher-based APIs would import. That would give the freedom to continue making breaking changes to these implementations, without it being a big deal, since it's only depended on by essentially end users.

This package could re-export the matchers package for a period of time, but that re-export would be deprecated. Is it possible to mark an export as deprecated?

@deprecated
export package:matchers/matchers.dart;

Strong mode errors while pub upgrade

Hi.
At our project we did not use matcher directly but we depend on it from quiver and test packages.

Recently after pub upgrade unit tests at our project failed, because of strong mode errors. pub upgrade bring new version of matcher. Method signatures was changed at:
#61

Is it possible to use semver for such changes, because it can break external projects?

pkg/matcher: isEmpty should fail for null or non-collections.

Originally opened as dart-lang/sdk#21562

This issue was originally filed by [email protected]


As there is no isNotEmpty matcher, you are forced to use isNot(isEmpty). However, expect(null, isNot(isEmpty)) passes because isEmpty returns false for non-collections or null. So, likewise, any other non-collection object would also wrongly pass such an expect call.

My suggested solution would be for isEmpty to throw an exception for "wrong" types.

Alternatively, an isNotEmpty matcher could be added.

Thanks,
 Andreas

Add an "exactlyOneOf" matcher

Sometimes it's useful to say that exactly one of a set of matchers matches. We should have a matcher that supports this.

Matcher: extend a Predicate interface

<img src="https://avatars.githubusercontent.com/u/444270?v=3" align="left" width="96" height="96"hspace="10"> Issue by seaneagan
Originally opened as dart-lang/sdk#3722


If we had:

typedef bool Predicate<T>(T item);
interface Matcher<T> extends Predicate<T> {...}

instead of Matcher#matches, thus using "operator call", then the following would work:

collection.some(same(value));
collection.every(isNotNull);
collection.filter(isPositive);

Also, issue dart-lang/sdk#2949 could be solved with:

switch(x) {
  match (isNegative) ...
  case (0) ...
  match (lessThan(5)) ...
  // avoid full blown Matcher since don't need mismatch messages
  match ((i) => i.isEven()) ...
  default ...
}

misleading comment matchState param of Matcher.matches

it says "[matchState] can be supplied and may be used to add details about the mismatch that are too costly to determine in [describeMismatch]."
that makes it sound like matchState is optional and that we are allowed to pass in null.
but equals(1).matches(2, null) complains
"Unhandled exception: The null object does not have a method 'forEach'."
if matchState really were optional, it should be declared as

bool matches(item, [Map matchState]);

and every subclass ought to tolerate null. at any rate, can we get a more accurate doc string so that it's clear what should be passed?

dart2js pkg/matcher/test/matchers_test fails on ie9

<img src="https://avatars.githubusercontent.com/u/4905639?v=3" align="left" width="96" height="96"hspace="10"> Issue by whesse
Originally opened as dart-lang/sdk#17762


There is a failure in matchers_test in the cyclic initialization test:
      {
              type: print
              value: FAIL: exception/error matchers throwsCyclicInitializationError
                      Expected: throws CyclicInitializationError
                        Actual: <Closure>
                         Which: threw JsNoSuchMethodError:<NoSuchMethodError: Object doesn't support property or method '$add' (Error 438)>
              timestamp: 1.769
        },

This is only on ie9, in both checked and unchecked mode.
The test is now suppressed in pkg/pkg.status on ie9.

Make some built-in matchers delegatable

I'm writing a more complicated project-specific matcher that takes an AST from package:analyzer, and compares the source text interpretation (after running dartfmt on it) with another String. It is something like:

Matcher equalsSource(String source) => ...

void main() {
  test('should emit good Dart code', () {
    equalsSource(someMethodAst, 'void main() {}');
  });
}

One problem is that I'd like to use the same awesome string-comparison/diffing so when something fails the user is presented with a better error message. I have an option of copying and pasting existing code (ew), or delegating... But there is nothing specific to delegate to.

Today's implementation (works) but seems wrong:

class _EqualsSource extends Matcher {
    ...

    @override
    Description describeMismatch(
    item,
    Description mismatchDescription,
    Map matchState,
    bool verbose,
  ) {
    if (item is Ast) {
      return equals(_source).describeMismatch(
        _formatAst(item),
        mismatchDescription,
        matchState,
        verbose,
      );
    } else {
      return mismatchDescription.add('$item is not an Ast');
    }
  }
}

Thoughts?

pkg/matcher: add a superclass to Matcher that has an async matchesAsync method that returns a future

<img src="https://avatars.githubusercontent.com/u/17034?v=3" align="left" width="96" height="96"hspace="10"> Issue by kevmoo
Originally opened as dart-lang/sdk#20205


Matchers for Completes and Throws are inherently async, yet return a true/false value immediately and later throw an exception if the actual match occurs.

Suggestion:
add CoreMatcher class which has an async match method.
Matcher can extend this class and "add" the sync match method

Update unit test and similar to understand these differences

Allow failed matcher results to be tagged as errors

Some Matchers typecheck for specific types that they know how to handle. Currently, they return false if it is not one of the expected types. This leads to undesirable behavior. For example, the following passes:
expect(123, isNot(contains(2));

It would be better for contains to throw when it receives anything other than an expected type. From what I can find, the other matchers that have this behavior are

  • everyElement
  • everything in string_matchers.dart
  • everything in numeric_matchers.dart

Standardize matchers' descriptions

Currently different matchers do very different things with their descriptions, up to and including just completely deleting whatever description came before them and replacing it with their own. The expectations for what a matcher's description should be need to be clarified, and all the core matchers brought in line with those expectations. Something like "matchers' descriptions must fit in this phrase" would be nice, although it should be flexible enough to support various operators such as allOf or hasLength.

This will likely require some degree of modification of the Description, Matcher.describe, and Matcher.describeMismatch APIs to make it easy for matchers to follow the guidelines and hard to break them.

Match DartDoc says that the Map state is optional, but util expects non-null

The comment to the Matcher.matches seem to suggest that the matchState is optional "can be supplied." Yet if a null map is passed into the equals matcher specifically the _DeepMatcher the util.dart addStateInfo will throw a null pointer exception.

I believe either the comment should be changed on the interface to state that the map isn't optional or needs to be non-null, the interface should be changed to allow for an optional argument with a default, and/or the code should be changed to not addStateInfo when the match state is null.

Create containsAllIn matcher

One of the matchers I use often in Java's truth library is "containsAllIn". I've found myself needing something like this in Dart a few times now.

A comparison of matchers in Truth vs. this package (credit @natebosch):

containsExactlyElementsIn(...) -> unorderedEquals(...)
containsExactlyElementsIn(...).inOrder() -> orderedEquals(...)
containsAll(Iterable matchers) => allOf(matchers.map(contains).toList())
containsAllOf(...).inOrder() -> containsAllInOrder(...)
containsAllIn -> Does not exist

unittest: list and set matchers

Originally opened as dart-lang/sdk#16306

This issue was originally filed by [email protected]


Matchers which perform a test for equality of elements using == (eg. unorderedEquals, isIn) won't match when the elements of the iterable being tested are iterables themselves.

eg.

test("permutation of lists", () {
   expect([[0,1,2],[2,3,4]], unorderedEquals([[2,3,4],[0,1,2]]));
});

Will fail with
"No match for [0,1,2] in [[2,3,4],[0,1,2]]".

pkg/matcher: isEmpty etc should not do any type checks

Originally opened as dart-lang/sdk#21792

This issue was originally filed by [email protected]


There are custom collections (like ListMultimap in quiver or RigidMap) that implement interfaces which are unknown to matcher. The matchers would be more useful and more easily understandable by removing all type checks from them:

class _Empty extends Matcher {
  const _Empty();
  bool matches(item, Map matchState) {
    return item.isEmpty;
  }
  Description describe(Description description) => description.add('empty');
}

This would be also match initial expectations. Obviously, there is a change in semantics (if the object has no isEmpty property, an exception will be thrown), but this is useful:
This also fixes the other bug (https://code.google.com/p/dart/issues/detail?id=21562) because isNot(isEmpty) on a null object would also throw an exception and fail the expect call instead of passing.

I'm happy to provide a patch for isEmpty (and isNotEmpty as soon as it is submitted).

Thanks,
 Andreas

Rationalize contains matcher

Right now, contains works on Iterables, Strings, and Maps. For Iterables, I believe it is equivalent to the anyElement matcher. For String, I think it is equivalent to the matches matcher (in string_matchers). For Maps, it does containsKey (which is surprising on its own), and a new matcher would need to be created.

Maybe contains should be deprecated in favor of the equivalent matchers mentioned above? Or at least perhaps the behavior can be made more consistent. It takes a Matcher for Iterable, but not String or Maps.

Improve matcher isInstanceOf now that Dart has first class types.

Originally opened as dart-lang/sdk#15381

This issue was originally filed by [email protected]


Current: new isInstanceOf<T>(T t)

New: isInstanceOf2(Type t). // But with a better name.

Consider adding:
  throwsType(Type t)

Also worth updating these docs:

"As types are not first class objects in Dart we can only approximate this test by using a generic wrapper class."

"Note that this does not currently work in dart2js; it will match any type, and isNot(new isInstanceof<T>()) will always fail. This is because dart2js currently ignores template type parameters."

https://api.dartlang.org/docs/channels/stable/latest/matcher/isInstanceOf.html

https://www.dartlang.org/articles/writing-unit-tests-for-pub-packages/

[equals] matcher shouldn't compare set order

<img src="https://avatars.githubusercontent.com/u/188?v=3" align="left" width="96" height="96"hspace="10"> Issue by nex3
Originally opened as dart-lang/sdk#19376


Much like [equals] has special deep-equality logic for lists and maps, when comparing sets it shouldn't require them to be in the same order, since they're fundamentally unordered.

Here's a simple case demonstrating the issue:

    void main() {
      var numbers = [];
      for (var i = 0; i < 1000; i++) {
        numbers.add(i);
      }
      var set1 = numbers.toSet();
      numbers.shuffle();
      var set2 = numbers.toSet();

      expect(set1, equals(set2));
    }

isTrue and isFalse don't necessarily do what they say

Not sure if this WAI or not, but I noticed in passing that the isTrue and isFalse matchers call the equality on the matched item, rather than on the true and false literals. I believe the result is that they more properly are implementing equalsTrue and equalsFalse, since the matched item can define operator == arbitrarily.

Make it easier to define custom matchers

Currently it's a huge pain to define a custom matcher, enough so that even when it would be more expressive and provide nicer error messages I often just give up and write a function that just runs a bunch of expect()s in a row instead.

There are a two things that are important here. First, it shouldn't be necessary to define an entire class. The class syntax is cumbersome, and there's very little reason for it: the user never references these classes. One straw-man possibility would be the following:

final Matcher isNotEmpty =
    customMatcher((value) => value.isNotEmpty, "isn't empty");

Second, it should be easy to define new matchers in terms of existing ones. For example:

Matcher name(matcher) =>
    customMatcher((value) => matcher.match(value.name), "has a name that $matcher")

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.