value_and_accessor: "Invalid property. A property cannot both have accessors and be writable or have a value: %0",
proto_object_or_null: "Object prototype may only be an Object or null",
property_desc_object: "Property description must be an object: %0",
+ redefine_disallowed: "Cannot redefine property: %0",
+ define_disallowed: "Cannot define property, object is not extensible: %0",
// RangeError
invalid_array_length: "Invalid array length",
stack_overflow: "Maximum call stack size exceeded",
if (result.type() == CALLBACKS) {
Object* structure = result.GetCallbackObject();
- if (structure->IsProxy()) {
- // Property that is internally implemented as a callback.
+ if (structure->IsProxy() || structure->IsAccessorInfo()) {
+ // Property that is internally implemented as a callback or
+ // an API defined callback.
Object* value = obj->GetPropertyWithCallback(
obj, structure, name, result.holder());
elms->set(0, Heap::false_value());
elms->set(1, FixedArray::cast(structure)->get(0));
elms->set(2, FixedArray::cast(structure)->get(1));
} else {
- // TODO(ricow): Handle API callbacks.
return Heap::undefined_value();
}
} else {
}
elms->set(3, Heap::ToBoolean(!result.IsDontEnum()));
- elms->set(4, Heap::ToBoolean(!result.IsReadOnly()));
+ elms->set(4, Heap::ToBoolean(!result.IsDontDelete()));
return *desc;
}
}
+static Object* Runtime_DefineOrRedefineAccessorProperty(Arguments args) {
+ ASSERT(args.length() == 5);
+ HandleScope scope;
+ Handle<JSObject> obj = args.at<JSObject>(0);
+ CONVERT_CHECKED(String, name, args[1]);
+ CONVERT_CHECKED(Smi, flag_setter, args[2]);
+ CONVERT_CHECKED(JSFunction, fun, args[3]);
+ CONVERT_CHECKED(Smi, flag_attr, args[4]);
+ int unchecked = flag_attr->value();
+ RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
+
+ LookupResult result;
+ obj->LocalLookupRealNamedProperty(name, &result);
+
+ PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
+ // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
+ // delete it to avoid running into trouble in DefineAccessor, which
+ // handles this incorrectly if the property is readonly (does nothing)
+ if (result.type() == FIELD || result.type() == NORMAL
+ || result.type() == CONSTANT_FUNCTION)
+ obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
+
+ return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
+}
+
+static Object* Runtime_DefineOrRedefineDataProperty(Arguments args) {
+ ASSERT(args.length() == 4);
+ HandleScope scope;
+ Handle<Object> obj = args.at<Object>(0);
+ Handle<Object> name = args.at<Object>(1);
+ Handle<Object> obj_value = args.at<Object>(2);
+ Handle<JSObject> js_object = Handle<JSObject>::cast(obj);
+ Handle<String> key_string = Handle<String>::cast(name);
+
+ CONVERT_CHECKED(Smi, flag, args[3]);
+ int unchecked = flag->value();
+ RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
+
+ LookupResult result;
+ js_object->LocalLookupRealNamedProperty(*key_string, &result);
+
+ PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
+
+ // Take special care when attributes are different and there is already
+ // a property. For simplicity we normalize the property which enables us
+ // to not worry about changing the instance_descriptor and creating a new
+ // map. The current version of SetObjectProperty does not handle attributes
+ // correctly in the case where a property is a field and is reset with
+ // new attributes.
+ if (result.IsProperty() && attr != result.GetAttributes()) {
+ PropertyDetails details = PropertyDetails(attr, NORMAL);
+ // New attributes - normalize to avoid writing to instance descriptor
+ js_object->NormalizeProperties(KEEP_INOBJECT_PROPERTIES, 0);
+ return js_object->SetNormalizedProperty(*key_string, *obj_value, details);
+ }
+
+ return Runtime::SetObjectProperty(js_object, name, obj_value, attr);
+}
+
+
Object* Runtime::SetObjectProperty(Handle<Object> object,
Handle<Object> key,
Handle<Object> value,
F(ResolvePossiblyDirectEval, 3, 2) \
\
F(SetProperty, -1 /* 3 or 4 */, 1) \
+ F(DefineOrRedefineDataProperty, 4, 1) \
+ F(DefineOrRedefineAccessorProperty, 5, 1) \
F(IgnoreAttributesAndSetProperty, -1 /* 3 or 4 */, 1) \
\
/* Arrays */ \
}
+// ECMA-262, section 9.2, page 30
+function ToBoolean(x) {
+ if (IS_BOOLEAN(x)) return x;
+ if (IS_STRING(x)) return x.length != 0;
+ if (x == null) return false;
+ if (IS_NUMBER(x)) return !((x == 0) || NUMBER_IS_NAN(x));
+ return true;
+}
+
+
// ECMA-262, section 9.3, page 31.
function ToNumber(x) {
if (IS_NUMBER(x)) return x;
}
-// ... where did this come from?
-function ToBoolean(x) {
- if (IS_BOOLEAN(x)) return x;
- if (IS_STRING(x)) return x.length != 0;
- if (x == null) return false;
- if (IS_NUMBER(x)) return !((x == 0) || NUMBER_IS_NAN(x));
- return true;
-}
-
-
// ECMA-262, section 9.9, page 36.
function ToObject(x) {
if (IS_STRING(x)) return new $String(x);
}
+// ES5, section 9.12
+function SameValue(x, y) {
+ if (typeof x != typeof y) return false;
+ if (IS_NULL_OR_UNDEFINED(x)) return true;
+ if (IS_NUMBER(x)) {
+ if (NUMBER_IS_NAN(x) && NUMBER_IS_NAN(y)) return true;
+ // x is +0 and y is -0 or vice versa
+ if (x === 0 && y === 0 && !%_IsSmi(x) && !%_IsSmi(y) &&
+ ((1 / x < 0 && 1 / y > 0) || (1 / x > 0 && 1 / y < 0))) {
+ return false;
+ }
+ return x == y;
+ }
+ if (IS_STRING(x)) return %StringEquals(x, y);
+ if (IS_BOOLEAN(x))return %NumberEquals(%ToNumber(x),%ToNumber(y));
+
+ return %_ObjectEquals(x, y);
+}
+
/* ---------------------------------
- - - U t i l i t i e s - - -
// ES5 8.10.4
function FromPropertyDescriptor(desc) {
- if(IS_UNDEFINED(desc)) return desc;
+ if (IS_UNDEFINED(desc)) return desc;
var obj = new $Object();
if (IsDataDescriptor(desc)) {
obj.value = desc.getValue();
desc.setEnumerable(ToBoolean(obj.enumerable));
}
-
if ("configurable" in obj) {
desc.setConfigurable(ToBoolean(obj.configurable));
}
this.writable_ = false;
this.hasWritable_ = false;
this.enumerable_ = false;
+ this.hasEnumerable_ = false;
this.configurable_ = false;
+ this.hasConfigurable_ = false;
this.get_ = void 0;
this.hasGetter_ = false;
this.set_ = void 0;
}
+PropertyDescriptor.prototype.hasValue = function() {
+ return this.hasValue_;
+}
+
+
PropertyDescriptor.prototype.setEnumerable = function(enumerable) {
this.enumerable_ = enumerable;
+ this.hasEnumerable_ = true;
}
}
+PropertyDescriptor.prototype.hasEnumerable = function() {
+ return this.hasEnumerable_;
+}
+
+
PropertyDescriptor.prototype.setWritable = function(writable) {
this.writable_ = writable;
this.hasWritable_ = true;
PropertyDescriptor.prototype.setConfigurable = function(configurable) {
this.configurable_ = configurable;
+ this.hasConfigurable_ = true;
+}
+
+
+PropertyDescriptor.prototype.hasConfigurable = function() {
+ return this.hasConfigurable_;
}
}
+PropertyDescriptor.prototype.hasGetter = function() {
+ return this.hasGetter_;
+}
+
+
PropertyDescriptor.prototype.setSet = function(set) {
this.set_ = set;
this.hasSetter_ = true;
}
+PropertyDescriptor.prototype.hasSetter = function() {
+ return this.hasSetter_;
+}
+
+
+
// ES5 section 8.12.1.
function GetOwnProperty(obj, p) {
var desc = new PropertyDescriptor();
// obj is an accessor [true, Get, Set, Enumerable, Configurable]
var props = %GetOwnProperty(ToObject(obj), ToString(p));
- if (IS_UNDEFINED(props))
- return void 0;
+ if (IS_UNDEFINED(props)) return void 0;
// This is an accessor
if (props[0]) {
}
-// ES5 8.12.9. This version cannot cope with the property p already
-// being present on obj.
+// ES5 section 8.12.2.
+function GetProperty(obj, p) {
+ var prop = GetOwnProperty(obj);
+ if (!IS_UNDEFINED(prop)) return prop;
+ var proto = obj.__proto__;
+ if (IS_NULL(proto)) return void 0;
+ return GetProperty(proto, p);
+}
+
+
+// ES5 section 8.12.6
+function HasProperty(obj, p) {
+ var desc = GetProperty(obj, p);
+ return IS_UNDEFINED(desc) ? false : true;
+}
+
+
+// ES5 8.12.9.
function DefineOwnProperty(obj, p, desc, should_throw) {
- var flag = desc.isEnumerable() ? 0 : DONT_ENUM;
- if (IsDataDescriptor(desc)) {
- flag |= desc.isWritable() ? 0 : (DONT_DELETE | READ_ONLY);
- %SetProperty(obj, p, desc.getValue(), flag);
+ var current = GetOwnProperty(obj, p);
+ var extensible = %IsExtensible(ToObject(obj));
+
+ // Error handling according to spec.
+ // Step 3
+ if (IS_UNDEFINED(current) && !extensible)
+ throw MakeTypeError("define_disallowed", ["defineProperty"]);
+
+ if (!IS_UNDEFINED(current) && !current.isConfigurable()) {
+ // Step 7
+ if (desc.isConfigurable() || desc.isEnumerable() != current.isEnumerable())
+ throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
+ // Step 9
+ if (IsDataDescriptor(current) != IsDataDescriptor(desc))
+ throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
+ // Step 10
+ if (IsDataDescriptor(current) && IsDataDescriptor(desc)) {
+ if (!current.isWritable() && desc.isWritable())
+ throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
+ if (!current.isWritable() && desc.hasValue() &&
+ !SameValue(desc.getValue(), current.getValue())) {
+ throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
+ }
+ }
+ // Step 11
+ if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) {
+ if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())){
+ throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
+ }
+ if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet()))
+ throw MakeTypeError("redefine_disallowed", ["defineProperty"]);
+ }
+ }
+
+ // Send flags - enumerable and configurable are common - writable is
+ // only send to the data descriptor.
+ // Take special care if enumerable and configurable is not defined on
+ // desc (we need to preserve the existing values from current).
+ var flag = NONE;
+ if (desc.hasEnumerable()) {
+ flag |= desc.isEnumerable() ? 0 : DONT_ENUM;
+ } else if (!IS_UNDEFINED(current)) {
+ flag |= current.isEnumerable() ? 0 : DONT_ENUM;
} else {
- if (IS_FUNCTION(desc.getGet())) %DefineAccessor(obj, p, GETTER, desc.getGet(), flag);
- if (IS_FUNCTION(desc.getSet())) %DefineAccessor(obj, p, SETTER, desc.getSet(), flag);
+ flag |= DONT_ENUM;
+ }
+
+ if (desc.hasConfigurable()) {
+ flag |= desc.isConfigurable() ? 0 : DONT_DELETE;
+ } else if (!IS_UNDEFINED(current)) {
+ flag |= current.isConfigurable() ? 0 : DONT_DELETE;
+ } else
+ flag |= DONT_DELETE;
+
+ if (IsDataDescriptor(desc) || IsGenericDescriptor(desc)) {
+ flag |= desc.isWritable() ? 0 : READ_ONLY;
+ %DefineOrRedefineDataProperty(obj, p, desc.getValue(), flag);
+ } else {
+ if (desc.hasGetter() && IS_FUNCTION(desc.getGet())) {
+ %DefineOrRedefineAccessorProperty(obj, p, GETTER, desc.getGet(), flag);
+ }
+ if (desc.hasSetter() && IS_FUNCTION(desc.getSet())) {
+ %DefineOrRedefineAccessorProperty(obj, p, SETTER, desc.getSet(), flag);
+ }
}
return true;
}
}
-// ES5 section 15.2.3.7. This version cannot cope with the properies already
-// being present on obj. Therefore it is not exposed as
-// Object.defineProperties yet.
+// ES5 section 15.2.3.6.
+function ObjectDefineProperty(obj, p, attributes) {
+ if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
+ throw MakeTypeError("obj_ctor_property_non_object", ["defineProperty"]);
+ var name = ToString(p);
+ var desc = ToPropertyDescriptor(attributes);
+ DefineOwnProperty(obj, name, desc, true);
+ return obj;
+}
+
+
+// ES5 section 15.2.3.7.
function ObjectDefineProperties(obj, properties) {
+ if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj))
+ throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]);
var props = ToObject(properties);
var key_values = [];
for (var key in props) {
InstallFunctions($Object, DONT_ENUM, $Array(
"keys", ObjectKeys,
"create", ObjectCreate,
+ "defineProperty", ObjectDefineProperty,
+ "defineProperties", ObjectDefineProperties,
"getPrototypeOf", ObjectGetPrototypeOf,
"getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
"getOwnPropertyNames", ObjectGetOwnPropertyNames
}
}
+THREADED_TEST(DefinePropertyOnAPIAccessor) {
+ v8::HandleScope scope;
+ Local<ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
+ LocalContext context;
+ context->Global()->Set(v8_str("obj"), templ->NewInstance());
+
+ // Uses getOwnPropertyDescriptor to check the configurable status
+ Local<Script> script_desc
+ = Script::Compile(v8_str("var prop =Object.getOwnPropertyDescriptor( "
+ "obj, 'x');"
+ "prop.configurable;"));
+ Local<Value> result = script_desc->Run();
+ CHECK_EQ(result->BooleanValue(), true);
+
+ // Redefine get - but still configurable
+ Local<Script> script_define
+ = Script::Compile(v8_str("var desc = { get: function(){return 42; },"
+ " configurable: true };"
+ "Object.defineProperty(obj, 'x', desc);"
+ "obj.x"));
+ result = script_define->Run();
+ CHECK_EQ(result, v8_num(42));
+
+ // Check that the accessor is still configurable
+ result = script_desc->Run();
+ CHECK_EQ(result->BooleanValue(), true);
+
+ // Redefine to a non-configurable
+ script_define
+ = Script::Compile(v8_str("var desc = { get: function(){return 43; },"
+ " configurable: false };"
+ "Object.defineProperty(obj, 'x', desc);"
+ "obj.x"));
+ result = script_define->Run();
+ CHECK_EQ(result, v8_num(43));
+ result = script_desc->Run();
+ CHECK_EQ(result->BooleanValue(), false);
+
+ // Make sure that it is not possible to redefine again
+ v8::TryCatch try_catch;
+ result = script_define->Run();
+ CHECK(try_catch.HasCaught());
+ String::AsciiValue exception_value(try_catch.Exception());
+ CHECK_EQ(*exception_value,
+ "TypeError: Cannot redefine property: defineProperty");
+}
+
+THREADED_TEST(DefinePropertyOnDefineGetterSetter) {
+ v8::HandleScope scope;
+ Local<ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"));
+ LocalContext context;
+ context->Global()->Set(v8_str("obj"), templ->NewInstance());
+
+ Local<Script> script_desc = Script::Compile(v8_str("var prop ="
+ "Object.getOwnPropertyDescriptor( "
+ "obj, 'x');"
+ "prop.configurable;"));
+ Local<Value> result = script_desc->Run();
+ CHECK_EQ(result->BooleanValue(), true);
+
+ Local<Script> script_define =
+ Script::Compile(v8_str("var desc = {get: function(){return 42; },"
+ " configurable: true };"
+ "Object.defineProperty(obj, 'x', desc);"
+ "obj.x"));
+ result = script_define->Run();
+ CHECK_EQ(result, v8_num(42));
+
+
+ result = script_desc->Run();
+ CHECK_EQ(result->BooleanValue(), true);
+
+
+ script_define =
+ Script::Compile(v8_str("var desc = {get: function(){return 43; },"
+ " configurable: false };"
+ "Object.defineProperty(obj, 'x', desc);"
+ "obj.x"));
+ result = script_define->Run();
+ CHECK_EQ(result, v8_num(43));
+ result = script_desc->Run();
+
+ CHECK_EQ(result->BooleanValue(), false);
+
+ v8::TryCatch try_catch;
+ result = script_define->Run();
+ CHECK(try_catch.HasCaught());
+ String::AsciiValue exception_value(try_catch.Exception());
+ CHECK_EQ(*exception_value,
+ "TypeError: Cannot redefine property: defineProperty");
+}
+
+
+
+
v8::Persistent<Value> xValue;
chapter15/15.1: UNIMPLEMENTED
chapter15/15.2/15.2.3/15.2.3.1: UNIMPLEMENTED
chapter15/15.2/15.2.3/15.2.3.5: UNIMPLEMENTED
-chapter15/15.2/15.2.3/15.2.3.6: UNIMPLEMENTED
-chapter15/15.2/15.2.3/15.2.3.7: UNIMPLEMENTED
chapter15/15.2/15.2.3/15.2.3.8: UNIMPLEMENTED
chapter15/15.2/15.2.3/15.2.3.9: UNIMPLEMENTED
chapter15/15.2/15.2.3/15.2.3.10: UNIMPLEMENTED
chapter15/15.2/15.2.3/15.2.3.12: UNIMPLEMENTED
chapter15/15.2/15.2.3/15.2.3.13: UNIMPLEMENTED
-# Object.getPrototypeOf
-chapter15/15.2/15.2.3/15.2.3.2: PASS
-
-# Object.getOwnPropertyDescriptor
-chapter15/15.2/15.2.3/15.2.3.3: PASS
-
-# NOT IMPLEMENTED: defineProperty
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-3: FAIL_OK
-
-# NOT IMPLEMENTED: getOwnPropertyNames
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-16: FAIL_OK
-
-# NOT IMPLEMENTED: defineProperty
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-18: FAIL_OK
-
-# NOT IMPLEMENTED: defineProperties
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-19: FAIL_OK
-
# NOT IMPLEMENTED: seal
chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-20: FAIL_OK
# NOT IMPLEMENTED: bind
chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-38: FAIL_OK
-# Built-ins have wrong descriptor (should all be false)
+# NaN is writable
chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-178: FAIL_OK
+# Infinity is writable
chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-179: FAIL_OK
+# undefined is writable
chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-180: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-182: FAIL_OK
# Our Function object has a "arguments" property which is used as a non
# property in in the test
chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-183: FAIL_OK
-
# Our Function object has a "caller" property which is used as a non
# property in in the test
chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-184: FAIL_OK
-# Built-ins have wrong descriptor (should all be false)
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-185: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-186: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-187: FAIL_OK
+# Our function object has a name property which is used as a non
+# property in the test
chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-188: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-189: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-190: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-191: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-192: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-193: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-194: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-195: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-201: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-210: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-211: FAIL_OK
-
# NOT IMPLEMENTED: RegExp.prototype.source
chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-212: FAIL_OK
# NOT IMPLEMENTED: RegExp.prototype.multiline
chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-215: FAIL_OK
-# Errors have wrong descriptor (should all be false)
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-216: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-217: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-218: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-219: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-220: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-221: FAIL_OK
-chapter15/15.2/15.2.3/15.2.3.3/15.2.3.3-4-222: FAIL_OK
-
-# Object.getOwnPropertyNames
-chapter15/15.2/15.2.3/15.2.3.4: PASS
-
# All of the tests below marked SUBSETFAIL (in 15.2.3.4) fail because
# the tests assumes that objects can not have more properties
# than those described in the spec - but according to spec they can
-# Object.keys
-chapter15/15.2/15.2.3/15.2.3.14: PASS
-
# We fail this because Object.keys returns numbers for element indices
# rather than strings.
-chapter15/15.2/15.2.3/15.2.3.14/15.2.3.14-3-3: FAIL_OK
+#chapter15/15.2/15.2.3/15.2.3.14/15.2.3.14-3-3: FAIL_OK
chapter15/15.3: UNIMPLEMENTED
chapter15/15.4/15.4.4/15.4.4.21: UNIMPLEMENTED
chapter15/15.4/15.4.4/15.4.4.22: UNIMPLEMENTED
-# Array.prototype.every
-chapter15/15.4/15.4.4/15.4.4.16: PASS
-
# Wrong test - because this is not given as argument to arr.every
# this._15_4_4_16_5_1 evaluates to undefined
chapter15/15.4/15.4.4/15.4.4.16/15.4.4.16-5-1: FAIL_OK
# if (val>1) in test should be if (val>2)
chapter15/15.4/15.4.4/15.4.4.16/15.4.4.16-8-10: FAIL_OK
-
-# Array.prototype.some
-chapter15/15.4/15.4.4/15.4.4.17: PASS
-
# Wrong assumption - according to spec some returns a Boolean, not a number
chapter15/15.4/15.4.4/15.4.4.17/15.4.4.17-4-9: FAIL_OK
# Same as 15.4.4.16-10-8
chapter15/15.4/15.4.4/15.4.4.17/15.4.4.17-8-10: FAIL_OK
-
-# Array.prototype.forEach
-chapter15/15.4/15.4.4/15.4.4.18: PASS
-
# Same as 15.4.4.16-5-1
chapter15/15.4/15.4.4/15.4.4.18/15.4.4.18-5-1: FAIL_OK
# Same as 15.4.4.16-7-7
chapter15/15.4/15.4.4/15.4.4.18/15.4.4.18-7-6: FAIL_OK
-
-# Array.prototype.map
-chapter15/15.4/15.4.4/15.4.4.19: PASS
-
# Same as 15.4.4.16-5-1
chapter15/15.4/15.4.4/15.4.4.19/15.4.4.19-5-1: FAIL_OK
--- /dev/null
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Tests the object.defineProperty method - ES 15.2.3.6
+
+
+
+// Check that an exception is thrown when null is passed as object.
+try {
+ Object.defineProperty(null, null, null);
+ assertTrue(false);
+} catch (e) {
+ assertTrue(/called on non-object/.test(e));
+}
+
+// Check that an exception is thrown when undefined is passed as object.
+try {
+ Object.defineProperty(undefined, undefined, undefined);
+ assertTrue(false);
+} catch (e) {
+ assertTrue(/called on non-object/.test(e));
+}
+
+// Check that an exception is thrown when non-object is passed as object.
+try {
+ Object.defineProperty(0, "foo", undefined);
+ assertTrue(false);
+} catch (e) {
+ assertTrue(/called on non-object/.test(e));
+}
+
+// Object
+var obj1 = {};
+
+// Values
+var val1 = 0;
+var val2 = 0;
+var val3 = 0;
+
+// Descriptors
+var emptyDesc = {};
+
+var accessorConfigurable = {
+ set: function() { val1++; },
+ get: function() { return val1; },
+ configurable: true
+};
+
+var accessorNoConfigurable = {
+ set: function() { val2++; },
+ get: function() { return val2; },
+ configurable: false
+};
+
+var accessorOnlySet = {
+ set: function() { val3++; },
+ configurable: true
+};
+
+var accessorOnlyGet = {
+ get: function() { return val3; },
+ configurable: true
+};
+
+var accessorDefault = {set: function(){} };
+
+var dataConfigurable = { value: 1000, configurable: true };
+
+var dataNoConfigurable = { value: 2000, configurable: false };
+
+var dataWritable = { value: 3000, writable: true};
+
+
+// Check that we can't add property with undefined attributes.
+try {
+ Object.defineProperty(obj1, "foo", undefined);
+ assertTrue(false);
+} catch (e) {
+ assertTrue(/must be an object/.test(e));
+}
+
+// Make sure that we can add a property with an empty descriptor and
+// that it has the default descriptor values.
+Object.defineProperty(obj1, "foo", emptyDesc);
+
+// foo should be undefined as it has no get, set or value
+assertEquals(undefined, obj1.foo);
+
+// We should, however, be able to retrieve the propertydescriptor which should
+// have all default values (according to 8.6.1).
+var desc = Object.getOwnPropertyDescriptor(obj1, "foo");
+assertFalse(desc.configurable);
+assertFalse(desc.enumerable);
+assertFalse(desc.writable);
+assertEquals(desc.get, undefined);
+assertEquals(desc.set, undefined);
+assertEquals(desc.value, undefined);
+
+// Make sure that getOwnPropertyDescriptor does not return a descriptor
+// with default values if called with non existing property (otherwise
+// the test above is invalid).
+desc = Object.getOwnPropertyDescriptor(obj1, "bar");
+assertEquals(desc, undefined);
+
+// Make sure that foo can't be reset (as configurable is false).
+try {
+ Object.defineProperty(obj1, "foo", accessorConfigurable);
+} catch (e) {
+ assertTrue(/Cannot redefine property/.test(e));
+}
+
+
+// Accessor properties
+
+Object.defineProperty(obj1, "bar", accessorConfigurable);
+desc = Object.getOwnPropertyDescriptor(obj1, "bar");
+assertTrue(desc.configurable);
+assertFalse(desc.enumerable);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.get, accessorConfigurable.get);
+assertEquals(desc.set, accessorConfigurable.set);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj1.bar = 1);
+assertEquals(1, val1);
+assertEquals(1, obj1.bar = 1);
+assertEquals(2, val1);
+assertEquals(2, obj1.bar);
+
+// Redefine bar with non configurable test
+Object.defineProperty(obj1, "bar", accessorNoConfigurable);
+desc = Object.getOwnPropertyDescriptor(obj1, "bar");
+assertFalse(desc.configurable);
+assertFalse(desc.enumerable);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.get, accessorNoConfigurable.get);
+assertEquals(desc.set, accessorNoConfigurable.set);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj1.bar = 1);
+assertEquals(2, val1);
+assertEquals(1, val2);
+assertEquals(1, obj1.bar = 1)
+assertEquals(2, val1);
+assertEquals(2, val2);
+assertEquals(2, obj1.bar);
+
+// Try to redefine bar again - should fail as configurable is false.
+try {
+ Object.defineProperty(obj1, "bar", accessorConfigurable);
+ assertTrue(false);
+} catch(e) {
+ assertTrue(/Cannot redefine property/.test(e));
+}
+
+// Try to redefine bar again using the data descriptor - should fail.
+try {
+ Object.defineProperty(obj1, "bar", dataConfigurable);
+ assertTrue(false);
+} catch(e) {
+ assertTrue(/Cannot redefine property/.test(e));
+}
+
+// Redefine using same descriptor - should succeed.
+Object.defineProperty(obj1, "bar", accessorNoConfigurable);
+desc = Object.getOwnPropertyDescriptor(obj1, "bar");
+assertFalse(desc.configurable);
+assertFalse(desc.enumerable);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.get, accessorNoConfigurable.get);
+assertEquals(desc.set, accessorNoConfigurable.set);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj1.bar = 1);
+assertEquals(2, val1);
+assertEquals(3, val2);
+assertEquals(1, obj1.bar = 1)
+assertEquals(2, val1);
+assertEquals(4, val2);
+assertEquals(4, obj1.bar);
+
+// Define an accessor that has only a setter
+Object.defineProperty(obj1, "setOnly", accessorOnlySet);
+desc = Object.getOwnPropertyDescriptor(obj1, "setOnly");
+assertTrue(desc.configurable);
+assertFalse(desc.enumerable);
+assertEquals(desc.set, accessorOnlySet.set);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.value, undefined);
+assertEquals(desc.get, undefined);
+assertEquals(1, obj1.setOnly = 1);
+assertEquals(1, val3);
+
+// Add a getter - should not touch the setter
+Object.defineProperty(obj1, "setOnly", accessorOnlyGet);
+desc = Object.getOwnPropertyDescriptor(obj1, "setOnly");
+assertTrue(desc.configurable);
+assertFalse(desc.enumerable);
+assertEquals(desc.get, accessorOnlyGet.get);
+assertEquals(desc.set, accessorOnlySet.set);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj1.setOnly = 1);
+assertEquals(2, val3);
+
+// The above should also work if redefining just a getter or setter on
+// an existing property with both a getter and a setter.
+Object.defineProperty(obj1, "both", accessorConfigurable);
+
+Object.defineProperty(obj1, "both", accessorOnlySet);
+desc = Object.getOwnPropertyDescriptor(obj1, "both");
+assertTrue(desc.configurable);
+assertFalse(desc.enumerable);
+assertEquals(desc.set, accessorOnlySet.set);
+assertEquals(desc.get, accessorConfigurable.get);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj1.both = 1);
+assertEquals(3, val3);
+
+
+// Data properties
+
+Object.defineProperty(obj1, "foobar", dataConfigurable);
+desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
+assertEquals(obj1.foobar, 1000);
+assertEquals(desc.value, 1000);
+assertTrue(desc.configurable);
+assertFalse(desc.writable);
+assertFalse(desc.enumerable);
+assertEquals(desc.get, undefined);
+assertEquals(desc.set, undefined);
+//Try writing to non writable attribute - should remain 1000
+obj1.foobar = 1001;
+assertEquals(obj1.foobar, 1000);
+
+
+// Redefine to writable descriptor - now writing to foobar should be allowed
+Object.defineProperty(obj1, "foobar", dataWritable);
+desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
+assertEquals(obj1.foobar, 3000);
+assertEquals(desc.value, 3000);
+// Note that since dataWritable does not define configurable the configurable
+// setting from the redefined property (in this case true) is used.
+assertTrue(desc.configurable);
+assertTrue(desc.writable);
+assertFalse(desc.enumerable);
+assertEquals(desc.get, undefined);
+assertEquals(desc.set, undefined);
+// Writing to the property should now be allowed
+obj1.foobar = 1001;
+assertEquals(obj1.foobar, 1001);
+
+
+// Redefine with non configurable data property.
+Object.defineProperty(obj1, "foobar", dataNoConfigurable);
+desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
+assertEquals(obj1.foobar, 2000);
+assertEquals(desc.value, 2000);
+assertFalse(desc.configurable);
+assertFalse(desc.writable);
+assertFalse(desc.enumerable);
+assertEquals(desc.get, undefined);
+assertEquals(desc.set, undefined);
+
+// Try redefine again - shold fail because configurable is now false.
+try {
+ Object.defineProperty(obj1, "foobar", dataConfigurable);
+ assertTrue(false);
+} catch (e) {
+ assertTrue(/Cannot redefine property/.test(e));
+}
+
+// Try redefine again with accessor property - shold also fail.
+try {
+ Object.defineProperty(obj1, "foobar", dataConfigurable);
+ assertTrue(false);
+} catch (e) {
+ assertTrue(/Cannot redefine property/.test(e));
+}
+
+
+// Redifine with the same descriptor - should succeed (step 6).
+Object.defineProperty(obj1, "foobar", dataNoConfigurable);
+desc = Object.getOwnPropertyDescriptor(obj1, "foobar");
+assertEquals(obj1.foobar, 2000);
+assertEquals(desc.value, 2000);
+assertFalse(desc.configurable);
+assertFalse(desc.writable);
+assertFalse(desc.enumerable);
+assertEquals(desc.get, undefined);
+assertEquals(desc.set, undefined);
+
+
+// New object
+var obj2 = {};
+
+// Make accessor - redefine to data
+Object.defineProperty(obj2, "foo", accessorConfigurable);
+
+// Redefine to data property
+Object.defineProperty(obj2, "foo", dataConfigurable);
+desc = Object.getOwnPropertyDescriptor(obj2, "foo");
+assertEquals(obj2.foo, 1000);
+assertEquals(desc.value, 1000);
+assertTrue(desc.configurable);
+assertFalse(desc.writable);
+assertFalse(desc.enumerable);
+assertEquals(desc.get, undefined);
+assertEquals(desc.set, undefined);
+
+
+// Redefine back to accessor
+Object.defineProperty(obj2, "foo", accessorConfigurable);
+desc = Object.getOwnPropertyDescriptor(obj2, "foo");
+assertTrue(desc.configurable);
+assertFalse(desc.enumerable);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.get, accessorConfigurable.get);
+assertEquals(desc.set, accessorConfigurable.set);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj2.foo = 1);
+assertEquals(3, val1);
+assertEquals(4, val2);
+assertEquals(3, obj2.foo);
+
+// Make data - redefine to accessor
+Object.defineProperty(obj2, "bar", dataConfigurable)
+
+// Redefine to accessor property
+Object.defineProperty(obj2, "bar", accessorConfigurable);
+desc = Object.getOwnPropertyDescriptor(obj2, "bar");
+assertTrue(desc.configurable);
+assertFalse(desc.enumerable);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.get, accessorConfigurable.get);
+assertEquals(desc.set, accessorConfigurable.set);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj2.bar = 1);
+assertEquals(4, val1);
+assertEquals(4, val2);
+assertEquals(4, obj2.foo);
+
+// Redefine back to data property
+Object.defineProperty(obj2, "bar", dataConfigurable);
+desc = Object.getOwnPropertyDescriptor(obj2, "bar");
+assertEquals(obj2.bar, 1000);
+assertEquals(desc.value, 1000);
+assertTrue(desc.configurable);
+assertFalse(desc.writable);
+assertFalse(desc.enumerable);
+assertEquals(desc.get, undefined);
+assertEquals(desc.set, undefined);
+
+
+// Redefinition of an accessor defined using __defineGetter__ and
+// __defineSetter__
+function get(){return this.x}
+function set(x){this.x=x};
+
+var obj3 = {x:1000};
+obj3.__defineGetter__("foo", get);
+obj3.__defineSetter__("foo", set);
+
+desc = Object.getOwnPropertyDescriptor(obj3, "foo");
+assertTrue(desc.configurable);
+assertTrue(desc.enumerable);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.get, get);
+assertEquals(desc.set, set);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj3.foo = 1);
+assertEquals(1, obj3.x);
+assertEquals(1, obj3.foo);
+
+// Redefine to accessor property (non configurable) - note that enumerable
+// which we do not redefine should remain the same (true).
+Object.defineProperty(obj3, "foo", accessorNoConfigurable);
+desc = Object.getOwnPropertyDescriptor(obj3, "foo");
+assertFalse(desc.configurable);
+assertTrue(desc.enumerable);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.get, accessorNoConfigurable.get);
+assertEquals(desc.set, accessorNoConfigurable.set);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj3.foo = 1);
+assertEquals(5, val2);
+assertEquals(5, obj3.foo);
+
+
+obj3.__defineGetter__("bar", get);
+obj3.__defineSetter__("bar", set);
+
+
+// Redefine back to data property
+Object.defineProperty(obj3, "bar", dataConfigurable);
+desc = Object.getOwnPropertyDescriptor(obj3, "bar");
+assertEquals(obj3.bar, 1000);
+assertEquals(desc.value, 1000);
+assertTrue(desc.configurable);
+assertFalse(desc.writable);
+assertTrue(desc.enumerable);
+assertEquals(desc.get, undefined);
+assertEquals(desc.set, undefined);
+
+
+var obj4 = {};
+var func = function (){return 42;};
+obj4.bar = func;
+assertEquals(42, obj4.bar());
+
+Object.defineProperty(obj4, "bar", accessorConfigurable);
+desc = Object.getOwnPropertyDescriptor(obj4, "bar");
+assertTrue(desc.configurable);
+assertTrue(desc.enumerable);
+assertEquals(desc.writable, undefined);
+assertEquals(desc.get, accessorConfigurable.get);
+assertEquals(desc.set, accessorConfigurable.set);
+assertEquals(desc.value, undefined);
+assertEquals(1, obj4.bar = 1);
+assertEquals(5, val1);
+assertEquals(5, obj4.bar);
+
+// Make sure an error is thrown when trying to access to redefined function
+try {
+ obj4.bar();
+ assertTrue(false);
+} catch (e) {
+ assertTrue(/is not a function/.test(e));
+}
+
+
+