_Mismatch? _recursiveMatch()

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);
    }
  }