testharness-helpers.js (5507B)
1 /* 2 * testharness-helpers contains various useful extensions to testharness.js to 3 * allow them to be used across multiple tests before they have been 4 * upstreamed. This file is intended to be usable from both document and worker 5 * environments, so code should for example not rely on the DOM. 6 */ 7 8 // Asserts that two objects |actual| and |expected| are weakly equal under the 9 // following definition: 10 // 11 // |a| and |b| are weakly equal if any of the following are true: 12 // 1. If |a| is not an 'object', and |a| === |b|. 13 // 2. If |a| is an 'object', and all of the following are true: 14 // 2.1 |a.p| is weakly equal to |b.p| for all own properties |p| of |a|. 15 // 2.2 Every own property of |b| is an own property of |a|. 16 // 17 // This is a replacement for the version of assert_object_equals() in 18 // testharness.js. The latter doesn't handle own properties correctly. I.e. if 19 // |a.p| is not an own property, it still requires that |b.p| be an own 20 // property. 21 // 22 // Note that |actual| must not contain cyclic references. 23 self.assert_object_equals = function(actual, expected, description) { 24 var object_stack = []; 25 26 function _is_equal(actual, expected, prefix) { 27 if (typeof actual !== 'object') { 28 assert_equals(actual, expected, prefix); 29 return; 30 } 31 assert_equals(typeof expected, 'object', prefix); 32 assert_equals(object_stack.indexOf(actual), -1, 33 prefix + ' must not contain cyclic references.'); 34 35 object_stack.push(actual); 36 37 Object.getOwnPropertyNames(expected).forEach(function(property) { 38 assert_own_property(actual, property, prefix); 39 _is_equal(actual[property], expected[property], 40 prefix + '.' + property); 41 }); 42 Object.getOwnPropertyNames(actual).forEach(function(property) { 43 assert_own_property(expected, property, prefix); 44 }); 45 46 object_stack.pop(); 47 } 48 49 function _brand(object) { 50 return Object.prototype.toString.call(object).match(/^\[object (.*)\]$/)[1]; 51 } 52 53 _is_equal(actual, expected, 54 (description ? description + ': ' : '') + _brand(expected)); 55 }; 56 57 // Equivalent to assert_in_array, but uses a weaker equivalence relation 58 // (assert_object_equals) than '==='. 59 function assert_object_in_array(actual, expected_array, description) { 60 assert_true(expected_array.some(function(element) { 61 try { 62 assert_object_equals(actual, element); 63 return true; 64 } catch (e) { 65 return false; 66 } 67 }), description); 68 } 69 70 // Assert that the two arrays |actual| and |expected| contain the same set of 71 // elements as determined by assert_object_equals. The order is not significant. 72 // 73 // |expected| is assumed to not contain any duplicates as determined by 74 // assert_object_equals(). 75 function assert_array_equivalent(actual, expected, description) { 76 assert_true(Array.isArray(actual), description); 77 assert_equals(actual.length, expected.length, description); 78 expected.forEach(function(expected_element) { 79 // assert_in_array treats the first argument as being 'actual', and the 80 // second as being 'expected array'. We are switching them around because 81 // we want to be resilient against the |actual| array containing 82 // duplicates. 83 assert_object_in_array(expected_element, actual, description); 84 }); 85 } 86 87 // Asserts that two arrays |actual| and |expected| contain the same set of 88 // elements as determined by assert_object_equals(). The corresponding elements 89 // must occupy corresponding indices in their respective arrays. 90 function assert_array_objects_equals(actual, expected, description) { 91 assert_true(Array.isArray(actual), description); 92 assert_equals(actual.length, expected.length, description); 93 actual.forEach(function(value, index) { 94 assert_object_equals(value, expected[index], 95 description + ' : object[' + index + ']'); 96 }); 97 } 98 99 // Asserts that |object| that is an instance of some interface has the attribute 100 // |attribute_name| following the conditions specified by WebIDL, but it's 101 // acceptable that the attribute |attribute_name| is an own property of the 102 // object because we're in the middle of moving the attribute to a prototype 103 // chain. Once we complete the transition to prototype chains, 104 // assert_will_be_idl_attribute must be replaced with assert_idl_attribute 105 // defined in testharness.js. 106 // 107 // FIXME: Remove assert_will_be_idl_attribute once we complete the transition 108 // of moving the DOM attributes to prototype chains. (http://crbug.com/43394) 109 function assert_will_be_idl_attribute(object, attribute_name, description) { 110 assert_equals(typeof object, "object", description); 111 112 assert_true("hasOwnProperty" in object, description); 113 114 // Do not test if |attribute_name| is not an own property because 115 // |attribute_name| is in the middle of the transition to a prototype 116 // chain. (http://crbug.com/43394) 117 118 assert_true(attribute_name in object, description); 119 } 120 121 // Stringifies a DOM object. This function stringifies not only own properties 122 // but also DOM attributes which are on a prototype chain. Note that 123 // JSON.stringify only stringifies own properties. 124 function stringifyDOMObject(object) 125 { 126 function deepCopy(src) { 127 if (typeof src != "object") 128 return src; 129 var dst = Array.isArray(src) ? [] : {}; 130 for (var property in src) { 131 dst[property] = deepCopy(src[property]); 132 } 133 return dst; 134 } 135 return JSON.stringify(deepCopy(object)); 136 }