| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
| * vim: set ts=8 sts=4 et sw=4 tw=99: |
| */ |
| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| #include "jsapi-tests/tests.h" |
| |
| static bool |
| Getter(JSContext* cx, unsigned argc, JS::Value* vp) |
| { |
| JS::CallArgs args = CallArgsFromVp(argc, vp); |
| args.rval().setBoolean(true); |
| return true; |
| } |
| |
| enum PropertyDescriptorKind { |
| DataDescriptor, AccessorDescriptor |
| }; |
| |
| static bool |
| CheckDescriptor(JS::Handle<JSPropertyDescriptor> desc, PropertyDescriptorKind kind, |
| bool enumerable, bool writable, bool configurable) |
| { |
| if (!desc.object()) |
| return false; |
| if (!(kind == DataDescriptor ? desc.isDataDescriptor() : desc.isAccessorDescriptor())) |
| return false; |
| if (desc.enumerable() != enumerable) |
| return false; |
| if (kind == DataDescriptor && desc.writable() != writable) |
| return false; |
| if (desc.configurable() != configurable) |
| return false; |
| return true; |
| } |
| |
| BEGIN_TEST(testDefinePropertyIgnoredAttributes) |
| { |
| JS::RootedObject obj(cx, JS_NewPlainObject(cx)); |
| JS::Rooted<JSPropertyDescriptor> desc(cx); |
| JS::RootedValue defineValue(cx); |
| |
| // Try a getter. Allow it to fill in the defaults. Because we're passing a |
| // JSNative, JS_DefineProperty will infer JSPROP_GETTER even though we |
| // aren't passing it. |
| CHECK(JS_DefineProperty(cx, obj, "foo", defineValue, |
| JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_PERMANENT | JSPROP_SHARED, |
| Getter)); |
| |
| CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "foo", &desc)); |
| |
| // Note that JSPROP_READONLY is meaningless for accessor properties. |
| CHECK(CheckDescriptor(desc, AccessorDescriptor, false, true, false)); |
| |
| // Install another configurable property, so we can futz with it. |
| CHECK(JS_DefineProperty(cx, obj, "bar", defineValue, |
| JSPROP_IGNORE_ENUMERATE | JSPROP_SHARED, |
| Getter)); |
| CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "bar", &desc)); |
| CHECK(CheckDescriptor(desc, AccessorDescriptor, false, true, true)); |
| |
| // Rewrite the descriptor to now be enumerable, leaving the configurability |
| // unchanged. |
| CHECK(JS_DefineProperty(cx, obj, "bar", defineValue, |
| JSPROP_IGNORE_PERMANENT | JSPROP_ENUMERATE | JSPROP_SHARED, |
| Getter)); |
| CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "bar", &desc)); |
| CHECK(CheckDescriptor(desc, AccessorDescriptor, true, true, true)); |
| |
| // Now try the same game with a value property |
| defineValue.setObject(*obj); |
| CHECK(JS_DefineProperty(cx, obj, "baz", defineValue, |
| JSPROP_IGNORE_ENUMERATE | |
| JSPROP_IGNORE_READONLY | |
| JSPROP_IGNORE_PERMANENT)); |
| CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "baz", &desc)); |
| CHECK(CheckDescriptor(desc, DataDescriptor, false, false, false)); |
| |
| // Now again with a configurable property |
| CHECK(JS_DefineProperty(cx, obj, "quux", defineValue, |
| JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_READONLY)); |
| CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "quux", &desc)); |
| CHECK(CheckDescriptor(desc, DataDescriptor, false, false, true)); |
| |
| // Just make it writable. Leave the old value and everything else alone. |
| defineValue.setUndefined(); |
| CHECK(JS_DefineProperty(cx, obj, "quux", defineValue, |
| JSPROP_IGNORE_ENUMERATE | |
| JSPROP_IGNORE_PERMANENT | |
| JSPROP_IGNORE_VALUE)); |
| |
| CHECK(JS_GetOwnPropertyDescriptor(cx, obj, "quux", &desc)); |
| CHECK(CheckDescriptor(desc, DataDescriptor, false, true, true)); |
| CHECK_SAME(JS::ObjectValue(*obj), desc.value()); |
| |
| return true; |
| } |
| END_TEST(testDefinePropertyIgnoredAttributes) |