From 4ae1785e0c86c137ac5c7923159d8ea5111880ed Mon Sep 17 00:00:00 2001 From: "nboyd%atg.com" Date: Wed, 15 Jul 2009 15:47:58 +0000 Subject: [PATCH] Make getOwnPropertyDescriptor and defineProperty work property for arrays. Allows getting and setting attributes on index properties when the array is in dense mode. git-svn-id: svn://10.0.0.236/trunk@257702 18797224-902f-48f8-a5cc-f745e15eee43 --- .../org/mozilla/javascript/NativeArray.java | 53 ++++++++++++++ .../js/rhino/testsrc/doctests/arrays.doctest | 48 +++++++++++++ .../doctests/object.defineproperty.doctest | 11 +++ .../object.getownpropertydescriptor.doctest | 22 ++++++ .../javascript/tests/NativeArrayTest.java | 72 +++++++++++++++++++ 5 files changed, 206 insertions(+) create mode 100644 mozilla/js/rhino/testsrc/doctests/arrays.doctest create mode 100644 mozilla/js/rhino/testsrc/org/mozilla/javascript/tests/NativeArrayTest.java diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/NativeArray.java b/mozilla/js/rhino/src/org/mozilla/javascript/NativeArray.java index a3eaa5c9c2d..7089f2bac5c 100644 --- a/mozilla/js/rhino/src/org/mozilla/javascript/NativeArray.java +++ b/mozilla/js/rhino/src/org/mozilla/javascript/NativeArray.java @@ -505,6 +505,59 @@ public class NativeArray extends IdScriptableObject return super.getDefaultValue(hint); } + private ScriptableObject defaultIndexPropertyDescriptor(Object value) { + Scriptable scope = getParentScope(); + if (scope == null) scope = this; + ScriptableObject desc = new NativeObject(); + ScriptRuntime.setObjectProtoAndParent(desc, scope); + desc.defineProperty("value", value, EMPTY); + desc.defineProperty("writable", true, EMPTY); + desc.defineProperty("enumerable", true, EMPTY); + desc.defineProperty("configurable", true, EMPTY); + return desc; + } + + @Override + protected ScriptableObject getOwnPropertyDescriptor(Context cx, Object id) { + if (dense != null) { + int index = toIndex(id); + if (0 <= index && index < length) { + Object value = dense[index]; + return defaultIndexPropertyDescriptor(value); + } + } + return super.getOwnPropertyDescriptor(cx, id); + } + + @Override + public void defineOwnProperty(Context cx, Object id, ScriptableObject desc) { + if (dense != null) { + Object[] values = dense; + dense = null; + denseOnly = false; + for (int i = 0; i < values.length; i++) { + if (values[i] != NOT_FOUND) { + put(i, this, values[i]); + } + } + } + int index = toIndex(id); + if (index >= length) { + length = index + 1; + } + super.defineOwnProperty(cx, id, desc); + } + + private int toIndex(Object id) { + if (id instanceof String) { + return (int) toArrayIndex((String) id); + } else if (id instanceof Number) { + return ((Number) id).intValue(); + } else { + return -1; + } + } + /** * See ECMA 15.4.1,2 */ diff --git a/mozilla/js/rhino/testsrc/doctests/arrays.doctest b/mozilla/js/rhino/testsrc/doctests/arrays.doctest new file mode 100644 index 00000000000..5a1233725de --- /dev/null +++ b/mozilla/js/rhino/testsrc/doctests/arrays.doctest @@ -0,0 +1,48 @@ +js> [1,2,undefined,4].join(';') +1;2;;4 +js> [1,2,null,4].join(';') +1;2;;4 +js> var arr = []; arr[0] = 1; arr[1] = 2; arr[3] = 4; arr.join(';') +1;2;;4 +js> var arr = [1,2,3,4]; delete arr[2]; arr.join(';') +1;2;;4 + +js> var arr = ["a","b","c","d"]; +js> var _ = arr.length = 2; +js> arr[2] === undefined +true +js> arr[1] === "b" +true + +js> [1,2,3].reverse().toSource() +[3, 2, 1] + +js> [2,1,3].sort().toSource() +[1, 2, 3] + +js> var arr = [1,2,3]; arr.push(4); arr.toSource() +[1, 2, 3, 4] + +js> var arr = [1,2,3]; arr.pop(); +3 +js> arr.toSource() +[1, 2] + +js> var arr = [1,2,3]; arr.shift(); +1 +js> arr.toSource() +[2, 3] + +js> var arr = [2,3]; arr.unshift(1); arr.toSource() +[1, 2, 3] + +js> var arr = [1,2,3]; arr.splice(1, 1, "a", "b").toSource() +[2] +js> arr.toSource() +[1, "a", "b", 3] + +js> [1,2,3].concat([4,5,6]).toSource() +[1, 2, 3, 4, 5, 6] + +js> [1,2,3].indexOf(2) +1 diff --git a/mozilla/js/rhino/testsrc/doctests/object.defineproperty.doctest b/mozilla/js/rhino/testsrc/doctests/object.defineproperty.doctest index 81a5fa99f97..888f55b0aa6 100644 --- a/mozilla/js/rhino/testsrc/doctests/object.defineproperty.doctest +++ b/mozilla/js/rhino/testsrc/doctests/object.defineproperty.doctest @@ -171,3 +171,14 @@ js> // make sure defineProperty works properly with numbers as ids js> Object.defineProperty({}, 0, {value:1, enumerable:true})['0'] 1 +js> // make sure defineProperty works properly with arrays +js> Object.defineProperty([], 0, {value:1, enumerable:true})[0] +1 + +js> // make sure defineProperty works properly with arrays +js> Object.defineProperty([], 'a', {value:1, enumerable:true})['a'] +1 + +js> // make sure defineProperty updates length properly for arrays +js> Object.defineProperty([], 0, {value:1}).length +1 diff --git a/mozilla/js/rhino/testsrc/doctests/object.getownpropertydescriptor.doctest b/mozilla/js/rhino/testsrc/doctests/object.getownpropertydescriptor.doctest index ecbeec6f1e6..d0538fe7194 100644 --- a/mozilla/js/rhino/testsrc/doctests/object.getownpropertydescriptor.doctest +++ b/mozilla/js/rhino/testsrc/doctests/object.getownpropertydescriptor.doctest @@ -54,3 +54,25 @@ js> Object.getOwnPropertyDescriptor({undefined: 1}, undefined).toSource() js> Object.getOwnPropertyDescriptor({0:1}, 0).toSource() ({value:1, writable:true, enumerable:true, configurable:true}) +js> Object.getOwnPropertyDescriptor([1], 0).toSource() +({value:1, writable:true, enumerable:true, configurable:true}) + +js> Object.getOwnPropertyDescriptor([1], '0').toSource() +({value:1, writable:true, enumerable:true, configurable:true}) + +js> Object.getOwnPropertyDescriptor([1], 1) === undefined +true + +js> Object.getOwnPropertyDescriptor([1], -1) === undefined +true + +js> var arr = []; +js> arr.a = 1; +1 +js> Object.getOwnPropertyDescriptor(arr, 'a').toSource() +({value:1, writable:true, enumerable:true, configurable:true}) + +js> var arr = Object.defineProperty([], 'a', {value:1, writable:false,}) +js> var desc = Object.getOwnPropertyDescriptor(arr, 'a'); ([desc.value, desc.writable]).toSource() +[1, false] + diff --git a/mozilla/js/rhino/testsrc/org/mozilla/javascript/tests/NativeArrayTest.java b/mozilla/js/rhino/testsrc/org/mozilla/javascript/tests/NativeArrayTest.java new file mode 100644 index 00000000000..86f2b3be0af --- /dev/null +++ b/mozilla/js/rhino/testsrc/org/mozilla/javascript/tests/NativeArrayTest.java @@ -0,0 +1,72 @@ +package org.mozilla.javascript.tests; + +import org.junit.Test; +import static org.junit.Assert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsNot.not; +import static org.junit.matchers.JUnitMatchers.hasItem; +import static org.junit.matchers.JUnitMatchers.both; + +import org.mozilla.javascript.NativeArray; +import java.util.Arrays; + +public class NativeArrayTest { + + @Test + public void getIdsShouldIncludeBothIndexAndNormalProperties() { + NativeArray array = new NativeArray(1); + array.put(0, array, "index"); + array.put("a", array, "normal"); + + assertThat(array.getIds(), is(new Object[]{0, "a"})); + } + + @Test + public void deleteShouldRemoveIndexProperties() { + NativeArray array = new NativeArray(new Object[]{"a"}); + array.delete(0); + assertThat(array.has(0, array), is(false)); + } + + @Test + public void deleteShouldRemoveNormalProperties() { + NativeArray array = new NativeArray(1); + array.put("p", array, "a"); + array.delete("p"); + assertThat(array.has("p", array), is(false)); + } + + @Test + public void putShouldAddIndexProperties() { + NativeArray array = new NativeArray(1); + array.put(0, array, "a"); + assertThat(array.has(0, array), is(true)); + } + + @Test + public void putShouldAddNormalProperties() { + NativeArray array = new NativeArray(1); + array.put("p", array, "a"); + assertThat(array.has("p", array), is(true)); + } + + @Test + public void getShouldReturnIndexProperties() { + NativeArray array = new NativeArray(new Object[]{"a"}); + assertThat(array.get(0, array), is((Object)"a")); + } + + @Test + public void getShouldReturnNormalProperties() { + NativeArray array = new NativeArray(1); + array.put("p", array, "a"); + assertThat(array.get("p", array), is((Object)"a")); + } + + @Test + public void hasShouldBeFalseForANewArray() { + NativeArray array = new NativeArray(0); + assertThat(array.has(0, array), is(false)); + } + +}