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
This commit is contained in:
nboyd%atg.com
2009-07-15 15:47:58 +00:00
parent 6d54681c8c
commit 4ae1785e0c
5 changed files with 206 additions and 0 deletions

View File

@@ -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
*/

View File

@@ -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

View File

@@ -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

View File

@@ -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]

View File

@@ -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));
}
}