blob: 8ff2532747e013f2c8cb0b50502c1c903b2b8169 [file] [log] [blame]
// Copyright (c) 2012, 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.
import 'interfaces.dart';
import 'util.dart';
/// Returns a matcher that inverts [valueOrMatcher] to its logical negation.
Matcher isNot(Object? valueOrMatcher) => _IsNot(wrapMatcher(valueOrMatcher));
class _IsNot extends Matcher {
final Matcher _matcher;
const _IsNot(this._matcher);
@override
bool matches(dynamic item, Map matchState) =>
!_matcher.matches(item, matchState);
@override
Description describe(Description description) =>
description.add('not ').addDescriptionOf(_matcher);
}
/// This returns a matcher that matches if all of the matchers passed as
/// arguments (up to 7) match.
///
/// Instead of passing the matchers separately they can be passed as a single
/// List argument. Any argument that is not a matcher is implicitly wrapped in a
/// Matcher to check for equality.
Matcher allOf(
Object? arg0, [
Object? arg1,
Object? arg2,
Object? arg3,
Object? arg4,
Object? arg5,
Object? arg6,
]) {
return _AllOf(_wrapArgs(arg0, arg1, arg2, arg3, arg4, arg5, arg6));
}
class _AllOf extends Matcher {
final List<Matcher> _matchers;
const _AllOf(this._matchers);
@override
bool matches(dynamic item, Map matchState) {
for (var matcher in _matchers) {
if (!matcher.matches(item, matchState)) {
addStateInfo(matchState, {'matcher': matcher});
return false;
}
}
return true;
}
@override
Description describeMismatch(
dynamic item,
Description mismatchDescription,
Map matchState,
bool verbose,
) {
var matcher = matchState['matcher'] as Matcher;
matcher.describeMismatch(
item,
mismatchDescription,
matchState['state'] as Map,
verbose,
);
return mismatchDescription;
}
@override
Description describe(Description description) =>
description.addAll('(', ' and ', ')', _matchers);
}
/// Matches if any of the given matchers evaluate to true.
///
/// The arguments can be a set of matchers as separate parameters
/// (up to 7), or a List of matchers.
///
/// The matchers are evaluated from left to right using short-circuit
/// evaluation, so evaluation stops as soon as a matcher returns true.
///
/// Any argument that is not a matcher is implicitly wrapped in a
/// Matcher to check for equality.
Matcher anyOf(
Object? arg0, [
Object? arg1,
Object? arg2,
Object? arg3,
Object? arg4,
Object? arg5,
Object? arg6,
]) {
return _AnyOf(_wrapArgs(arg0, arg1, arg2, arg3, arg4, arg5, arg6));
}
class _AnyOf extends Matcher {
final List<Matcher> _matchers;
const _AnyOf(this._matchers);
@override
bool matches(dynamic item, Map matchState) {
for (var matcher in _matchers) {
if (matcher.matches(item, matchState)) {
return true;
}
}
return false;
}
@override
Description describe(Description description) =>
description.addAll('(', ' or ', ')', _matchers);
}
List<Matcher> _wrapArgs(
Object? arg0,
Object? arg1,
Object? arg2,
Object? arg3,
Object? arg4,
Object? arg5,
Object? arg6,
) {
Iterable args;
if (arg0 is List) {
if (arg1 != null ||
arg2 != null ||
arg3 != null ||
arg4 != null ||
arg5 != null ||
arg6 != null) {
throw ArgumentError(
'If arg0 is a List, all other arguments must be'
' null.',
);
}
args = arg0;
} else {
args = [arg0, arg1, arg2, arg3, arg4, arg5, arg6].where((e) => e != null);
}
return args.map(wrapMatcher).toList();
}