<!-- Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ --> <!DOCTYPE HTML> <html> <head> <title>Test Maplike Interface</title> <script src="/tests/SimpleTest/SimpleTest.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> </head> <body> <script class="testbody" type="application/javascript"> /* global TestInterfaceMaplike, TestInterfaceSetlike, TestInterfaceMaplikeObject, TestInterfaceMaplikeJSObject*/ SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({set: [["dom.expose_test_interfaces", true]]}, function() { var base_properties = [["has", "function", 1], ["entries", "function", 0], ["keys", "function", 0], ["values", "function", 0], ["forEach", "function", 1], ["size", "number"]]; var maplike_properties = base_properties.concat([["set", "function", 2]]); var rw_properties = [["clear", "function", 0], ["delete", "function", 1]]; var setlike_rw_properties = base_properties.concat(rw_properties).concat([["add", "function", 1]]); var maplike_rw_properties = maplike_properties.concat(rw_properties).concat([["get", "function", 1]]); var testExistence = function testExistence(prefix, obj, properties) { for (var [name, type, args] of properties) { // Properties are somewhere up the proto chain, hasOwnProperty won't work isnot(obj[name], undefined, `${prefix} object has property ${name}`); is(typeof obj[name], type, `${prefix} object property ${name} is a ${type}`); // Check function length if (type == "function") { is(obj[name].length, args, `${prefix} object property ${name} is length ${args}`); is(obj[name].name, name, `${prefix} object method name is ${name}`); } // Find where property is on proto chain, check for enumerablility there. var owner = obj; while (owner) { var propDesc = Object.getOwnPropertyDescriptor(owner, name); if (propDesc) { ok(propDesc.enumerable, `${prefix} object property ${name} should be enumerable`); break; } owner = Object.getPrototypeOf(owner); } } }; var m; var testSet; var testIndex; // Simple map creation and functionality test info("SimpleMap: Testing simple map creation and functionality"); m = new TestInterfaceMaplike(); ok(m, "SimpleMap: got a TestInterfaceMaplike object"); testExistence("SimpleMap: ", m, maplike_rw_properties); is(m.size, 0, "SimpleMap: size should be zero"); ok(!m.has("test"), "SimpleMap: maplike has should return false"); is(m.get("test"), undefined, "SimpleMap: maplike get should return undefined on bogus lookup"); var m1 = m.set("test", 1); is(m, m1, "SimpleMap: return from set should be map object"); is(m.size, 1, "SimpleMap: size should be 1"); ok(m.has("test"), "SimpleMap: maplike has should return true"); is(m.get("test"), 1, "SimpleMap: maplike get should return value entered"); m.set("test2", 2); is(m.size, 2, "SimpleMap: size should be 2"); testSet = [["test", 1], ["test2", 2]]; testIndex = 0; m.forEach(function(v, k, o) { "use strict"; is(o, m, "SimpleMap: foreach obj is correct"); is(k, testSet[testIndex][0], "SimpleMap: foreach map key: " + k + " = " + testSet[testIndex][0]); is(v, testSet[testIndex][1], "SimpleMap: foreach map value: " + v + " = " + testSet[testIndex][1]); testIndex += 1; }); is(testIndex, 2, "SimpleMap: foreach ran correct number of times"); ok(m.has("test2"), "SimpleMap: maplike has should return true"); is(m.get("test2"), 2, "SimpleMap: maplike get should return value entered"); is(m.delete("test2"), true, "SimpleMap: maplike deletion should return boolean"); is(m.size, 1, "SimpleMap: size should be 1"); var iterable = false; for (let e of m) { iterable = true; is(e[0], "test", "SimpleMap: iterable first array element should be key"); is(e[1], 1, "SimpleMap: iterable second array element should be value"); } is(m[Symbol.iterator].length, 0, "SimpleMap: @@iterator symbol is correct length"); is(m[Symbol.iterator].name, "entries", "SimpleMap: @@iterator symbol has correct name"); is(m[Symbol.iterator], m.entries, 'SimpleMap: @@iterator is an alias for "entries"'); ok(iterable, "SimpleMap: @@iterator symbol resolved correctly"); for (let k of m.keys()) { is(k, "test", "SimpleMap: first keys element should be 'test'"); } for (let v of m.values()) { is(v, 1, "SimpleMap: first values elements should be 1"); } for (let e of m.entries()) { is(e[0], "test", "SimpleMap: entries first array element should be 'test'"); is(e[1], 1, "SimpleMap: entries second array element should be 1"); } m.clear(); is(m.size, 0, "SimpleMap: size should be 0 after clear"); // Simple set creation and functionality test info("SimpleSet: Testing simple set creation and functionality"); m = new TestInterfaceSetlike(); ok(m, "SimpleSet: got a TestInterfaceSetlike object"); testExistence("SimpleSet: ", m, setlike_rw_properties); is(m.size, 0, "SimpleSet: size should be zero"); ok(!m.has("test"), "SimpleSet: maplike has should return false"); m1 = m.add("test"); is(m, m1, "SimpleSet: return from set should be map object"); is(m.size, 1, "SimpleSet: size should be 1"); ok(m.has("test"), "SimpleSet: maplike has should return true"); m.add("test2"); is(m.size, 2, "SimpleSet: size should be 2"); testSet = ["test", "test2"]; testIndex = 0; m.forEach(function(v, k, o) { "use strict"; is(o, m, "SimpleSet: foreach obj is correct"); is(k, testSet[testIndex], "SimpleSet: foreach set key: " + k + " = " + testSet[testIndex]); testIndex += 1; }); is(testIndex, 2, "SimpleSet: foreach ran correct number of times"); ok(m.has("test2"), "SimpleSet: maplike has should return true"); is(m.delete("test2"), true, "SimpleSet: maplike deletion should return true"); is(m.size, 1, "SimpleSet: size should be 1"); iterable = false; for (let e of m) { iterable = true; is(e, "test", "SimpleSet: iterable first array element should be key"); } is(m[Symbol.iterator].length, 0, "SimpleSet: @@iterator symbol is correct length"); is(m[Symbol.iterator].name, "values", "SimpleSet: @@iterator symbol has correct name"); is(m[Symbol.iterator], m.values, 'SimpleSet: @@iterator is an alias for "values"'); ok(iterable, "SimpleSet: @@iterator symbol resolved correctly"); for (let k of m.keys()) { is(k, "test", "SimpleSet: first keys element should be 'test'"); } for (let v of m.values()) { is(v, "test", "SimpleSet: first values elements should be 'test'"); } for (let e of m.entries()) { is(e[0], "test", "SimpleSet: Entries first array element should be 'test'"); is(e[1], "test", "SimpleSet: Entries second array element should be 'test'"); } m.clear(); is(m.size, 0, "SimpleSet: size should be 0 after clear"); // Map convenience function test info("Testing map convenience functions"); m = new TestInterfaceMaplike(); ok(m, "MapConvenience: got a TestInterfaceMaplike object"); is(m.size, 0, "MapConvenience: size should be zero"); ok(!m.hasInternal("test"), "MapConvenience: maplike hasInternal should return false"); // It's fine to let getInternal to return 0 if the key doesn't exist // because this API can only be used internally in C++ and we'd throw // an error if the key doesn't exist. SimpleTest.doesThrow(() => m.getInternal("test"), 0, "MapConvenience: maplike getInternal should throw if the key doesn't exist"); m.setInternal("test", 1); is(m.size, 1, "MapConvenience: size should be 1"); ok(m.hasInternal("test"), "MapConvenience: maplike hasInternal should return true"); is(m.get("test"), 1, "MapConvenience: maplike get should return value entered"); is(m.getInternal("test"), 1, "MapConvenience: maplike getInternal should return value entered"); m.setInternal("test2", 2); is(m.size, 2, "size should be 2"); ok(m.hasInternal("test2"), "MapConvenience: maplike hasInternal should return true"); is(m.get("test2"), 2, "MapConvenience: maplike get should return value entered"); is(m.getInternal("test2"), 2, "MapConvenience: maplike getInternal should return value entered"); is(m.deleteInternal("test2"), true, "MapConvenience: maplike deleteInternal should return true"); is(m.size, 1, "MapConvenience: size should be 1"); m.clearInternal(); is(m.size, 0, "MapConvenience: size should be 0 after clearInternal"); // Map convenience function test using objects and readonly info("Testing Map convenience function test using objects and readonly"); m = new TestInterfaceMaplikeObject(); ok(m, "ReadOnlyMapConvenience: got a TestInterfaceMaplikeObject object"); is(m.size, 0, "ReadOnlyMapConvenience: size should be zero"); is(m.set, undefined, "ReadOnlyMapConvenience: readonly map, should be no set function"); is(m.clear, undefined, "ReadOnlyMapConvenience: readonly map, should be no clear function"); is(m.delete, undefined, "ReadOnlyMapConvenience: readonly map, should be no delete function"); ok(!m.hasInternal("test"), "ReadOnlyMapConvenience: maplike hasInternal should return false"); SimpleTest.doesThrow(() => m.getInternal("test"), "ReadOnlyMapConvenience: maplike getInternal should throw when the key doesn't exist"); m.setInternal("test"); is(m.size, 1, "size should be 1"); ok(m.hasInternal("test"), "ReadOnlyMapConvenience: maplike hasInternal should return true"); ok(m.getInternal("test") instanceof TestInterfaceMaplike, "ReadOnlyMapConvenience: maplike getInternal should return the object"); m.setInternal("test2"); is(m.size, 2, "size should be 2"); ok(m.hasInternal("test2"), "ReadOnlyMapConvenience: maplike hasInternal should return true"); ok(m.getInternal("test2") instanceof TestInterfaceMaplike, "ReadOnlyMapConvenience: maplike getInternal should return the object"); is(m.deleteInternal("test2"), true, "ReadOnlyMapConvenience: maplike deleteInternal should return true"); is(m.size, 1, "ReadOnlyMapConvenience: size should be 1"); m.clearInternal(); is(m.size, 0, "ReadOnlyMapConvenience: size should be 0 after clearInternal"); // Map convenience function test using JavaScript objects info("Testing Map convenience function test using javascript objects"); m = new TestInterfaceMaplikeJSObject(); ok(m, "JSObjectMapConvenience: got a TestInterfaceMaplikeJSObject object"); is(m.size, 0, "JSObjectMapConvenience: size should be zero"); is(m.set, undefined, "JSObjectMapConvenience: readonly map, should be no set function"); is(m.clear, undefined, "JSObjectMapConvenience: readonly map, should be no clear function"); is(m.delete, undefined, "JSObjectMapConvenience: readonly map, should be no delete function"); ok(!m.hasInternal("test"), "JSObjectMapConvenience: maplike hasInternal should return false"); SimpleTest.doesThrow(() => m.getInternal("test"), "JSObjectMapConvenience: maplike getInternal should throw when the key doesn't exist"); let testObject = {"Hey1": 1}; m.setInternal("test", testObject); is(m.size, 1, "size should be 1"); ok(m.hasInternal("test"), "JSObjectMapConvenience: maplike hasInternal should return true"); let addedObject = m.getInternal("test"); is(addedObject, testObject, "JSObjectMapConvenience: maplike getInternal should return the object"); testObject = {"Hey2": 2}; m.setInternal("test2", testObject); is(m.size, 2, "size should be 2"); ok(m.hasInternal("test2"), "JSObjectMapConvenience: maplike hasInternal should return true"); addedObject = m.getInternal("test2"); is(addedObject, testObject, "JSObjectMapConvenience: maplike getInternal should return the object"); is(m.deleteInternal("test2"), true, "JSObjectMapConvenience: maplike deleteInternal should return true"); is(m.size, 1, "JSObjectMapConvenience: size should be 1"); m.clearInternal(); is(m.size, 0, "JSObjectMapConvenience: size should be 0 after clearInternal"); // JS implemented map creation convenience function test // Test this override for forEach info("ForEachThisOverride: Testing this override for forEach"); m = new TestInterfaceMaplike(); m.set("test", 1); m.forEach(function(v, k, o) { "use strict"; is(o, m, "ForEachThisOverride: foreach obj is correct"); is(this, 5, "ForEachThisOverride: 'this' value should be correct"); }, 5); // Test defaulting arguments on maplike to undefined info("MapArgsDefault: Testing maplike defaulting arguments to undefined"); m = new TestInterfaceMaplike(); m.set(); is(m.size, 1, "MapArgsDefault: should have 1 entry"); m.forEach(function(v, k) { "use strict"; is(typeof k, "string", "MapArgsDefault: key is a string"); is(k, "undefined", "MapArgsDefault: key is the string undefined"); is(v, 0, "MapArgsDefault: value is 0"); }); is(m.get(), 0, "MapArgsDefault: no argument to get() returns correct value"); m.delete(); is(m.size, 0, "MapArgsDefault: should have 0 entries"); // Test defaulting arguments on setlike to undefined info("SetArgsDefault: Testing setlike defaulting arguments to undefined"); m = new TestInterfaceSetlike(); m.add(); is(m.size, 1, "SetArgsDefault: should have 1 entry"); m.forEach(function(v, k) { "use strict"; is(typeof k, "string", "SetArgsDefault: key is a string"); is(k, "undefined", "SetArgsDefault: key is the string undefined"); }); m.delete(); is(m.size, 0, "SetArgsDefault: should have 0 entries"); SimpleTest.finish(); }); </script> </body> </html>