chromium/third_party/blink/web_tests/resources/testharness-helpers.js

/**
 * testharness-helpers contains userful extensions to testharness.js
 * to allow them to be used across multiple tests.
 */


// Asserts that two objects |actual| and |expected| are weakly equal under the
// following definition:
//
// |a| and |b| are weakly equal if any of the following are true:
//   1. If |a| is not an 'object', and |a| === |b|.
//   2. If |a| is an 'object', and all of the following are true:
//     2.1 |a.p| is weakly equal to |b.p| for all enumerable properties |p| of
//     |a|, including inherited properties.
//     2.2 |b.p| is weakly equal to |a.p| for all enumerable properties |p| of
//     |b|, including inherited properties.
//
// This is a replacement for the the version of assert_object_equals() in
// testharness.js. The latter doesn't handle own properties correctly. I.e. if
// |a.p| is not an own property, it still requires that |b.p| be an own
// property.
//
// Note that |actual| must not contain cyclic references.
function assert_weak_equals(actual, expected, description) {
  var object_stack = [];

  function _is_equal(actual, expected, prefix) {
    if (typeof actual !== 'object' || actual === null) {
      assert_equals(actual, expected, prefix);
      return;
    }
    assert_true(typeof expected === 'object', prefix);
    assert_equals(object_stack.indexOf(actual), -1,
                  prefix + ' must not contain cyclic references.');

    object_stack.push(actual);

    let checked_set = new Set();
    for(var property in expected) {
      assert_true(property in actual, prefix);
      _is_equal(actual[property], expected[property], prefix + '.' + property);
      checked_set.add(actual[property]);
    }
    for(var property in actual) {
      assert_true(property in expected, prefix);
      if(!checked_set.has(actual[property])){
        _is_equal(actual[property], expected[property], prefix + '.' + property);
      }
    }

    object_stack.pop();
  }

  function _brand(object) {
    return Object.prototype.toString.call(object).match(/^\[object (.*)\]$/)[1];
  }

  _is_equal(actual, expected,
            (description ? description + ': ' : '') + _brand(expected));
};