Răsfoiți Sursa

'length' property of arrays should have same delete semantics as own non-indexed non-configurable props
Added more tests for delete on standard Arrays and Typed Arrays

Irina Yatsenko 7 ani în urmă
părinte
comite
b255e18bd2

+ 6 - 0
lib/Runtime/Library/JavascriptArray.cpp

@@ -12237,6 +12237,9 @@ Case0:
     {
         if (propertyId == PropertyIds::length)
         {
+            JavascriptError::ThrowCantDeleteIfStrictModeOrNonconfigurable(
+                flags, GetScriptContext(), BuiltInPropertyRecords::length.buffer);
+
             return false;
         }
         return DynamicObject::DeleteProperty(propertyId, flags);
@@ -12246,6 +12249,9 @@ Case0:
     {
         if (BuiltInPropertyRecords::length.Equals(propertyNameString))
         {
+            JavascriptError::ThrowCantDeleteIfStrictModeOrNonconfigurable(
+                flags, GetScriptContext(), BuiltInPropertyRecords::length.buffer);
+
             return false;
         }
         return DynamicObject::DeleteProperty(propertyNameString, flags);

+ 0 - 8
test/Array/delete.baseline

@@ -1,8 +0,0 @@
-true
-T1:8 : ,arr.proto.1,arr.proto.2,10,17,26,37,50
-true
-T2:8 : ,arr.proto.1,arr.proto.2,arr.proto.3,17,26,37,50
-true
-T3:8 : ,arr.proto.1,arr.proto.2,arr.proto.3,17,26,37,obj.proto7
-true
-T4:8 : ,arr.proto.1,arr.proto.2,arr.proto.3,17,26,37,obj.proto7

+ 91 - 15
test/Array/delete.js

@@ -3,24 +3,100 @@
 // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
 //-------------------------------------------------------------------------------------------------------
 
-function write(v) { WScript.Echo(v + ""); }
+if (this.WScript && this.WScript.LoadScriptFile) { // Check for running in ch
+    this.WScript.LoadScriptFile("..\\UnitTestFramework\\UnitTestFramework.js");
+}
 
-Object.prototype[5]  = "obj.proto5";
-Object.prototype[7]  = "obj.proto7";
+var tests = [
+    {
+        name: "Deleting of configurable non-indexed properties on Arrays",
+        body: function () {
+            var arr = [1,4,9,16];
 
-Array.prototype[1]   = "arr.proto.1";
-Array.prototype[2]   = "arr.proto.2";
-Array.prototype[3]   = "arr.proto.3";
-Array.prototype[6]   = "arr.proto.6";
+            arr.non_indexed = 'whatever';
+            Object.defineProperty(arr, 'with_getter', { get: function() { return 'with getter'; }, configurable: true });
 
-var n=8;
-var i=0;
+            assert.areEqual('whatever', arr.non_indexed, "arr.non_indexed is set to 'whatever'");
+            assert.areEqual('with getter', arr.with_getter, "arr.with_getter is set to 'with getter'");
 
-var arr = new Array(n);
+            var res = delete arr.non_indexed;
+            assert.areEqual(true, res, "Deleting own property should succeed");
+            assert.areEqual(undefined, arr.non_indexed, "arr.non_indexed has been deleted");
 
-for (i=3;i<n;i++) { arr[i] = i * i + 1; }
+            var res = delete arr.with_getter;
+            assert.areEqual(true, res, "Deleting own property with a getter should succeed");
+            assert.areEqual(undefined, arr.with_getter, "arr.with_getter has been deleted");
+        }
+    },
+    {
+        name: "Deleting of non-configurable non-indexed properties on Arrays",
+        body: function () {
+            var arr = [1,4,9,16];
+            var id = 'id';
+            Object.defineProperty(arr, id, { value: 17, configurable: false });
 
-write(delete arr[1]);   write("T1:" + arr.length + " : " + arr);
-write(delete arr[3]);   write("T2:" + arr.length + " : " + arr);
-write(delete arr[n-1]); write("T3:" + arr.length + " : " + arr);
-write(delete arr[n+1]); write("T4:" + arr.length + " : " + arr);
+            var res = delete arr[id];
+            assert.areEqual(false, res);
+            assert.areEqual(17, arr[id], "arr['id'] value after failed delete");
+
+            assert.throws(function () { 'use strict'; delete arr[id]; }, TypeError, 
+                "Should throw on delete of non-indexed property in array", 
+                "Calling delete on 'id' is not allowed in strict mode");
+        }
+    },
+    {
+        name: "Deleting of the 'length' property on Arrays",
+        body: function () {
+            var arr = [1,4,9,16];
+
+            var res = delete arr.length;
+            assert.areEqual(false, res, "delete of arr.length should fail (as noop)");
+            assert.areEqual(4, arr.length, "arr.length after attempting to delete it");
+
+            assert.throws(function () { 'use strict'; delete arr.length; }, TypeError, 
+                "Should throw on delete of 'length' property in array", 
+                "Calling delete on 'length' is not allowed in strict mode");
+            assert.areEqual(4, arr.length, "arr.length after attempting to delete it in strict mode");
+        }
+    },
+    {
+        name: "Deleting of indexed properties on Arrays",
+        body: function () {
+            var arr = [1,4,9,16];
+
+            var res = delete arr[1];
+            assert.areEqual(true, res, "delete of arr[1] should succeed");
+            assert.areEqual(undefined, arr[1], "arr[1] value after delete should be undefined");
+            assert.areEqual(4, arr.length, "the array's lenght should not change");
+
+            res = delete arr[42];
+            assert.areEqual(true, res, "delete of arr[42] (beyond the array bounds) should succeed");
+            assert.areEqual(4, arr.length, "the array's length is unchanged");
+
+            const last = arr.length - 1;
+            res = delete arr[last];
+            assert.areEqual(true, res, "delete of last element should succeed");
+            assert.areEqual(undefined, arr[last], "arr[last] value after delete should be undefined");
+            assert.areEqual(4, arr.length, "the array's lenght should not change");
+        }
+    },
+    {
+        name: "Deleting of indexed properties on Arrays that are also set on prototypes",
+        body: function () {
+            Object.prototype[4]  = "obj.proto";
+            Array.prototype[1]   = "arr.proto";
+            var arr = [1,4,9,16,25];
+
+            var res = delete arr[1];
+            assert.areEqual(true, res, "delete of arr[1] should succeed");
+            assert.areEqual("arr.proto", arr[1], "arr[1] after deleting should be picked up from the Array prototype");
+
+            var res = delete arr[4];
+            assert.areEqual(true, res, "delete of arr[4] should succeed");
+            assert.areEqual("obj.proto", arr[4], "arr[4] after deleting should be picked up from the Object prototype");
+            assert.areEqual(5, arr.length, "arr.length after deleting of the last element");
+        }
+    },
+];
+
+testRunner.runTests(tests, { verbose: false /*so no need to provide baseline*/ });

+ 0 - 1
test/Array/rlexe.xml

@@ -146,7 +146,6 @@
   <test>
     <default>
       <files>delete.js</files>
-      <baseline>delete.baseline</baseline>
     </default>
   </test>
   <test>

+ 23 - 6
test/typedarray/delete.js

@@ -17,21 +17,23 @@ var tests = [
             ta.non_indexed = 'whatever';
             assert.areEqual('whatever', ta.non_indexed, "ta.non_indexed is set to 'whatever'");
 
-            delete ta.non_indexed;
+            var res = delete ta.non_indexed;
+            assert.areEqual(true, res, "delete of configurable non-indexed property should succeed");
             assert.areEqual(undefined, ta.non_indexed, "ta.non_indexed has been deleted");
         }
     },
     {
-        name: "delete of nonconfigurable non-indexed properties on Typed arrays",
+        name: "Deleting of non-configurable non-indexed properties on Typed arrays",
         body: function () {
             const ta = Int8Array.of(42);
             var id = 'id';
             Object.defineProperty(ta, id, { value: 17, configurable: false });
 
-            delete ta[id];
+            var res = delete ta[id];
+            assert.areEqual(false, res, "delete of non-configurable property should fail");
             assert.areEqual(17, ta[id], "ta['id'] value after failed delete");
 
-            assert.throws(function () { 'use strict'; delete ta[id]; }, TypeError, "Should throw on delete of indexed property in typed array", "Calling delete on 'id' is not allowed in strict mode");
+            assert.throws(function () { 'use strict'; delete ta[id]; }, TypeError, "Should throw on delete of non-indexed property in typed array", "Calling delete on 'id' is not allowed in strict mode");
         }
     },
     {
@@ -39,12 +41,27 @@ var tests = [
         body: function () {
             const ta = Int8Array.of(42);
 
-            delete ta[0];
+            var res = delete ta[0];
+            assert.areEqual(false, res, "delete of ta[0] should fail");
             assert.areEqual(42, ta[0], "ta[0] value after failed delete");
 
             assert.throws(function () { 'use strict'; delete ta[0]; }, TypeError, "Should throw on delete of indexed property in typed array", "Calling delete on '0' is not allowed in strict mode");
         }
-    }
+    },
+    {
+        name: "Typed arrays ignore delete of the inherited 'length' property",
+        body: function () {
+            const ta = Int8Array.of(42);
+
+            var res = delete ta.length;
+            assert.areEqual(true, res, "delete of ta.length should succeed (as noop)");
+            assert.areEqual(1, ta.length, "ta.length after attempting to delete it");
+
+            res = (function () { 'use strict'; return delete ta.length; })();
+            assert.areEqual(true, res, "delete of ta.length should succeed (as noop) in strict mode");
+            assert.areEqual(1, ta.length, "ta.length after attempting to delete it in strict mode");
+        }
+    },
 ];
 
 testRunner.runTests(tests, { verbose: false /*so no need to provide baseline*/ });