| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
- function verifyProperties(obj, property, value)
- {
- const descriptor = Object.getOwnPropertyDescriptor(obj, property);
- assert.areEqual(value, obj[property], "Object.fromEntries should set correct valued");
- assert.isTrue(descriptor.enumerable, "Object.fromEntries should create enumerable properties");
- assert.isTrue(descriptor.configurable, "Object.fromEntries should create configurable properties");
- assert.isTrue(descriptor.writable, "Object.fromEntries should create writable properties");
- obj[property] = "other value";
- assert.areEqual("other value", obj[property], "should actually be able to write to properties created by Object.fromEntries");
- assert.doesNotThrow(()=>{"use strict"; delete obj[property];}, "deleting properties created by Object.fromEntries should not throw");
- assert.isUndefined(obj[property], "deleting properties created by Object.fromEntries should succeed");
- }
- function verifyObject(expected, actual)
- {
- for (let i in actual)
- {
- assert.isTrue(expected.hasOwnProperty(i), "Object.fromEntries shouldn't create unexpected properties");
- }
- for (let i in expected)
- {
- verifyProperties(actual, i, expected[i]);
- }
- }
- const tests = [
- {
- name : "Object.fromEntries invalid parameters",
- body : function () {
- assert.throws(()=>{Object.fromEntries(null);}, TypeError, "Object.fromEntries throws when called with null parameter");
- assert.throws(()=>{Object.fromEntries(undefined);}, TypeError, "Object.fromEntries throws when called with undefined parameter");
- assert.throws(()=>{Object.fromEntries("something");}, TypeError, "Object.fromEntries throws when called with string literal parameter");
- assert.throws(()=>{Object.fromEntries(456);}, TypeError, "Object.fromEntries throws when called with number literal parameter");
- assert.throws(()=>{Object.fromEntries(Number());}, TypeError, "Object.fromEntries throws when called with Number Object parameter");
- assert.doesNotThrow(()=>{Object.fromEntries(String());}, "Object.fromEntries does not throw when called with String Object parameter with length 0");
- assert.throws(()=>{Object.fromEntries(String("anything"));}, TypeError, "Object.fromEntries throws when called with String Object parameter with length > 0");
- assert.throws(()=>{Object.fromEntries({});}, TypeError, "Object.fromEntries throws when called with Object literal");
- assert.throws(()=>{Object.fromEntries({a : "5", b : "10"});}, TypeError, "Object.fromEntries throws when called with Object literal");
- }
- },
- {
- name : "Object.fromEntries basic cases",
- body : function () {
- const obj1 = Object.fromEntries([["first", 50], ["second", 30], ["third", 60], ["fourth", 70]]);
- verifyObject({first : 50, second : 30, third : 60, fourth : 70}, obj1);
- const obj2 = Object.fromEntries([Object("a12234"),Object("b2kls"),Object("c3deg")]);
- verifyObject({a : "1", b : "2", c : "3"}, obj2);
- function testArguments()
- {
- verifyObject(expected, Object.fromEntries(arguments));
- }
- const expected = { abc : "one", bcd : "two", hsa : "three"};
- testArguments(["abc", "one"], ["bcd", "two"], ["hsa", "three"]);
- }
- },
- {
- name : "Object.fromEntries with array-like object",
- body : function ()
- {
- const arrayLike = {0 : ["abc", "one"], 1 : ["bcd", "two"], 2 : ["hsa", "three"], length : 3, current : 0}
- assert.throws(()=>{ Object.fromEntries(arrayLike); }, TypeError, "Object.fromEntries throws when parameter has no iterator");
- arrayLike[Symbol.iterator] = function () {
- const array = this;
- return {
- next : function () {
- const value = array[String(array.current)];
- ++array.current;
- return {
- value : value,
- done : array.length < array.current
- };
- }
- };
- };
- verifyObject({ abc : "one", bcd : "two", hsa : "three"}, Object.fromEntries(arrayLike));
- }
- },
- {
- name : "Object.fromEntries does not call setters",
- body : function () {
- let calledSet = false;
- Object.defineProperty(Object.prototype, "prop", {
- set : function () { calledSet = true; }
- });
- const obj = Object.fromEntries([["prop", 10]]);
- verifyProperties(obj, "prop", 10);
- assert.isFalse(calledSet, "Object.fromEntries should not call setters");
- }
- },
- {
- name : "Object.fromEntries iterates over generators",
- body : function () {
- function* gen1 ()
- {
- yield ["val1", 10];
- yield ["val2", 50];
- yield ["val3", 60, "other stuff"];
- }
- const obj = Object.fromEntries(gen1());
- verifyObject({val1 : 10, val2 : 50, val3: 60}, obj);
- let unreachable = false;
- function* gen2 ()
- {
- yield ["val1", 10];
- yield "val2";
- unreachable = true;
- yield ["val3", 60, "other stuff"];
- }
- assert.throws(()=>{Object.fromEntries(gen2())}, TypeError, "When generator provides invalid case Object.fromEntries should throw");
- assert.isFalse(unreachable, "Object.fromEntries does not continue after invalid case provided");
- }
- },
- {
- name : "Object.fromEntries accesses properties in correct order from generator",
- body : function () {
- const accessedProps = [];
- const handler = {
- get : function (target, prop, receiver) {
- accessedProps.push(prop + Reflect.get(target, prop));
- return Reflect.get(target, prop);
- }
- }
- function* gen () {
- yield new Proxy(["a", "b", "c"], handler);
- yield new Proxy(["e", "g", "h", "j"], handler);
- }
- const obj = Object.fromEntries(gen());
- verifyObject({a : "b", e : "g"}, obj);
- const expected = ["0a", "1b", "0e", "1g"];
- const len = accessedProps.length;
- assert.areEqual(4, len, "Object.fromEntries accesses correct number of properties");
- for (let i = 0; i < len; ++i)
- {
- assert.areEqual(expected[i], accessedProps[i], "Object.fromEntries accesses the correct properties");
- }
- }
- },
- {
- name : "Object.fromEntries accesses Proxy properties correctly",
- body : function () {
- const accessedProps = [];
- const handler = {
- get : function (target, prop, receiver) {
- accessedProps.push(String(prop));
- return Reflect.get(target, prop);
- },
- set : function () {
- throw new Error ("Should not be called");
- }
- }
- let result;
- assert.doesNotThrow(()=>{result = Object.fromEntries(new Proxy([["a", 5], ["b", 2], ["c", 4]], handler)); });
- verifyObject({a : 5, b : 2, c : 4}, result);
- expected = ["Symbol(Symbol.iterator)", "length", "0", "length", "1", "length", "2", "length"];
- for (let i = 0; i < 3; ++i)
- {
- assert.areEqual(expected[i], accessedProps[i], "Object.fromEntries accesses the correct properties");
- }
- }
- },
- {
- name : "Object.fromEntries uses overridden array iterator",
- body : function () {
- let calls = 0;
- Array.prototype[Symbol.iterator] = function () {
- return {
- next : function () {
- switch (calls)
- {
- case 0:
- calls = 1;
- return { done : false, value : ["key", "value"]}
- case 1:
- calls = 2;
- return { done : true, value : null }
- case 2:
- throw new Error ("Should not be reached");
- }
- }
- }
- }
- let result;
- assert.doesNotThrow(()=>{ result = Object.fromEntries([1, 2, 3, 4]);}, "Once iterator is done should not be called again");
- verifyObject({key : "value"}, result);
- }
- },
- {
- name : "Object.fromEntries properties",
- body : function () {
- assert.areEqual("fromEntries", Object.fromEntries.name, "Object.fromEntries.name should be 'fromEntries'");
- assert.areEqual(1, Object.fromEntries.length, "Object.fromEntries.length should be 1");
- const descriptor = Object.getOwnPropertyDescriptor(Object, "fromEntries");
- assert.isFalse(descriptor.enumerable, "Object.fromEntries should be enumerable");
- assert.isTrue(descriptor.writable, "Object.fromEntries should be writable");
- assert.isTrue(descriptor.configurable, "Object.fromEntries should be configurable");
- assert.doesNotThrow(()=>{"use strict"; delete Object.fromEntries.length;}, "Deleting Object.fromEntries.length should succeed");
- assert.areEqual(0, Object.fromEntries.length, "After deletion Object.fromEntries.length should be 0");
- assert.doesNotThrow(()=>{"use strict"; delete Object.fromEntries;}, "Deleting Object.fromEntries should succeed");
- assert.isUndefined(Object.fromEntries, "After deletion Object.fromEntries should be undefined");
- }
- }
- ];
- testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });
|