in lib/src/equals_matcher.dart [166:255]
_Mismatch? _recursiveMatch(
Object? expected, Object? actual, String location, int depth) {
// If the expected value is a matcher, try to match it.
if (expected is Matcher) {
var matchState = {};
if (expected.matches(actual, matchState)) return null;
return _Mismatch(location, actual, (description, verbose) {
var oldLength = description.length;
expected.describeMismatch(actual, description, matchState, verbose);
if (depth > 0 && description.length == oldLength) {
description.add('does not match ');
expected.describe(description);
}
});
} else {
// Otherwise, test for equality.
try {
if (expected == actual) return null;
} catch (e) {
// TODO(gram): Add a test for this case.
return _Mismatch(
location,
actual,
(description, verbose) =>
description.add('== threw ').addDescriptionOf(e));
}
}
if (depth > _limit) {
return _Mismatch.simple(
location, actual, 'recursion depth limit exceeded');
}
// If _limit is 1 we can only recurse one level into object.
if (depth == 0 || _limit > 1) {
if (expected is Set) {
return _compareSets(
expected, actual, _recursiveMatch, depth + 1, location);
} else if (expected is Iterable) {
return _compareIterables(
expected, actual, _recursiveMatch, depth + 1, location);
} else if (expected is Map) {
if (actual is! Map) {
return _Mismatch.simple(location, actual, 'expected a map');
}
var err = (expected.length == actual.length)
? ''
: 'has different length and ';
for (var key in expected.keys) {
if (!actual.containsKey(key)) {
return _Mismatch(
location,
actual,
(description, verbose) => description
.add('${err}is missing map key ')
.addDescriptionOf(key));
}
}
for (var key in actual.keys) {
if (!expected.containsKey(key)) {
return _Mismatch(
location,
actual,
(description, verbose) => description
.add('${err}has extra map key ')
.addDescriptionOf(key));
}
}
for (var key in expected.keys) {
var rp = _recursiveMatch(
expected[key], actual[key], "$location['$key']", depth + 1);
if (rp != null) return rp;
}
return null;
}
}
// If we have recursed, show the expected value too; if not, expect() will
// show it for us.
if (depth > 0) {
return _Mismatch(location, actual,
(description, verbose) => description.addDescriptionOf(expected),
instead: true);
} else {
return _Mismatch(location, actual, null);
}
}