Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / js / src / jsapi-tests / testNewObject.cpp
blobbdddede03b78dc3ca929a2160ed2153e98ac2352
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "js/Array.h" // JS::GetArrayLength, JS::IsArrayObject
9 #include "js/CallAndConstruct.h" // JS::Construct
10 #include "js/Object.h" // JS::GetClass
11 #include "js/PropertyAndElement.h" // JS_GetElement, JS_SetElement
12 #include "jsapi-tests/tests.h"
13 #include "vm/PlainObject.h" // js::PlainObject::class_
15 #include "vm/NativeObject-inl.h"
17 using namespace js;
19 static bool constructHook(JSContext* cx, unsigned argc, JS::Value* vp) {
20 JS::CallArgs args = CallArgsFromVp(argc, vp);
22 // Check that arguments were passed properly from JS_New.
24 JS::RootedObject obj(cx, JS_NewPlainObject(cx));
25 if (!obj) {
26 JS_ReportErrorASCII(cx, "test failed, could not construct object");
27 return false;
29 if (strcmp(JS::GetClass(obj)->name, "Object") != 0) {
30 JS_ReportErrorASCII(cx, "test failed, wrong class for 'this'");
31 return false;
33 if (args.length() != 3) {
34 JS_ReportErrorASCII(cx, "test failed, argc == %d", args.length());
35 return false;
37 if (!args[0].isInt32() || args[2].toInt32() != 2) {
38 JS_ReportErrorASCII(cx, "test failed, wrong value in args[2]");
39 return false;
41 if (!args.isConstructing()) {
42 JS_ReportErrorASCII(cx, "test failed, not constructing");
43 return false;
46 // Perform a side-effect to indicate that this hook was actually called.
47 JS::RootedValue value(cx, args[0]);
48 JS::RootedObject callee(cx, &args.callee());
49 if (!JS_SetElement(cx, callee, 0, value)) {
50 return false;
53 args.rval().setObject(*obj);
55 // trash the argv, perversely
56 args[0].setUndefined();
57 args[1].setUndefined();
58 args[2].setUndefined();
60 return true;
63 BEGIN_TEST(testNewObject_1) {
64 static const size_t N = 1000;
65 JS::RootedValueVector argv(cx);
66 CHECK(argv.resize(N));
68 JS::RootedValue Array(cx);
69 EVAL("Array", &Array);
71 bool isArray;
73 // With no arguments.
74 JS::RootedObject obj(cx);
75 CHECK(JS::Construct(cx, Array, JS::HandleValueArray::empty(), &obj));
76 CHECK(JS::IsArrayObject(cx, obj, &isArray));
77 CHECK(isArray);
78 uint32_t len;
79 CHECK(JS::GetArrayLength(cx, obj, &len));
80 CHECK_EQUAL(len, 0u);
82 // With one argument.
83 argv[0].setInt32(4);
84 CHECK(JS::Construct(cx, Array, JS::HandleValueArray::subarray(argv, 0, 1),
85 &obj));
86 CHECK(JS::IsArrayObject(cx, obj, &isArray));
87 CHECK(isArray);
88 CHECK(JS::GetArrayLength(cx, obj, &len));
89 CHECK_EQUAL(len, 4u);
91 // With N arguments.
92 for (size_t i = 0; i < N; i++) {
93 argv[i].setInt32(i);
95 CHECK(JS::Construct(cx, Array, JS::HandleValueArray::subarray(argv, 0, N),
96 &obj));
97 CHECK(JS::IsArrayObject(cx, obj, &isArray));
98 CHECK(isArray);
99 CHECK(JS::GetArrayLength(cx, obj, &len));
100 CHECK_EQUAL(len, N);
101 JS::RootedValue v(cx);
102 CHECK(JS_GetElement(cx, obj, N - 1, &v));
103 CHECK(v.isInt32(N - 1));
105 // With JSClass.construct.
106 static const JSClassOps clsOps = {
107 nullptr, // addProperty
108 nullptr, // delProperty
109 nullptr, // enumerate
110 nullptr, // newEnumerate
111 nullptr, // resolve
112 nullptr, // mayResolve
113 nullptr, // finalize
114 nullptr, // call
115 constructHook, // construct
116 nullptr, // trace
118 static const JSClass cls = {"testNewObject_1", 0, &clsOps};
119 JS::RootedObject ctor(cx, JS_NewObject(cx, &cls));
120 CHECK(ctor);
121 JS::RootedValue ctorVal(cx, JS::ObjectValue(*ctor));
122 CHECK(JS::Construct(cx, ctorVal, JS::HandleValueArray::subarray(argv, 0, 3),
123 &obj));
124 CHECK(JS_GetElement(cx, ctor, 0, &v));
125 CHECK(v.isInt32(0));
127 return true;
129 END_TEST(testNewObject_1)
131 BEGIN_TEST(testNewObject_IsMapObject) {
132 // Test IsMapObject and IsSetObject
134 JS::RootedValue vMap(cx);
135 EVAL("Map", &vMap);
137 bool isMap = false;
138 bool isSet = false;
139 JS::RootedObject mapObj(cx);
140 CHECK(JS::Construct(cx, vMap, JS::HandleValueArray::empty(), &mapObj));
141 CHECK(JS::IsMapObject(cx, mapObj, &isMap));
142 CHECK(isMap);
143 CHECK(JS::IsSetObject(cx, mapObj, &isSet));
144 CHECK(!isSet);
146 JS::RootedValue vSet(cx);
147 EVAL("Set", &vSet);
149 JS::RootedObject setObj(cx);
150 CHECK(JS::Construct(cx, vSet, JS::HandleValueArray::empty(), &setObj));
151 CHECK(JS::IsMapObject(cx, setObj, &isMap));
152 CHECK(!isMap);
153 CHECK(JS::IsSetObject(cx, setObj, &isSet));
154 CHECK(isSet);
156 return true;
158 END_TEST(testNewObject_IsMapObject)
160 static const JSClass Base_class = {
161 "Base",
162 JSCLASS_HAS_RESERVED_SLOTS(8), // flags
165 BEGIN_TEST(testNewObject_Subclassing) {
166 JSObject* proto =
167 JS_InitClass(cx, global, nullptr, nullptr, "Base", Base_constructor, 0,
168 nullptr, nullptr, nullptr, nullptr);
169 if (!proto) {
170 return false;
173 CHECK_EQUAL(JS::GetClass(proto), &PlainObject::class_);
175 // Calling Base without `new` should fail with a TypeError.
176 JS::RootedValue expectedError(cx);
177 EVAL("TypeError", &expectedError);
178 JS::RootedValue actualError(cx);
179 EVAL(
180 "try {\n"
181 " Base();\n"
182 "} catch (e) {\n"
183 " e.constructor;\n"
184 "}\n",
185 &actualError);
186 CHECK_SAME(actualError, expectedError);
188 // Check prototype chains when a JS class extends a base class that's
189 // implemented in C++ using JS_NewObjectForConstructor.
190 EXEC(
191 "class MyClass extends Base {\n"
192 " ok() { return true; }\n"
193 "}\n"
194 "let myObj = new MyClass();\n");
196 JS::RootedValue result(cx);
197 EVAL("myObj.ok()", &result);
198 CHECK_SAME(result, JS::TrueValue());
200 EVAL("myObj.__proto__ === MyClass.prototype", &result);
201 CHECK_SAME(result, JS::TrueValue());
202 EVAL("myObj.__proto__.__proto__ === Base.prototype", &result);
203 CHECK_SAME(result, JS::TrueValue());
205 EVAL("myObj", &result);
206 CHECK_EQUAL(JS::GetClass(&result.toObject()), &Base_class);
208 // All reserved slots are initialized to undefined.
209 for (uint32_t i = 0; i < JSCLASS_RESERVED_SLOTS(&Base_class); i++) {
210 CHECK_SAME(JS::GetReservedSlot(&result.toObject(), i),
211 JS::UndefinedValue());
214 return true;
217 static bool Base_constructor(JSContext* cx, unsigned argc, JS::Value* vp) {
218 JS::CallArgs args = CallArgsFromVp(argc, vp);
219 JS::RootedObject obj(cx, JS_NewObjectForConstructor(cx, &Base_class, args));
220 if (!obj) {
221 return false;
223 args.rval().setObject(*obj);
224 return true;
227 END_TEST(testNewObject_Subclassing)
229 static const JSClass TestClass = {"TestObject", JSCLASS_HAS_RESERVED_SLOTS(0)};
231 BEGIN_TEST(testNewObject_elements) {
232 Rooted<NativeObject*> obj(
233 cx, NewBuiltinClassInstance(cx, &TestClass, GenericObject));
234 CHECK(obj);
235 CHECK(!obj->isTenured());
236 CHECK(obj->hasEmptyElements());
237 CHECK(!obj->hasFixedElements());
238 CHECK(!obj->hasDynamicElements());
240 CHECK(obj->ensureElements(cx, 1));
241 CHECK(!obj->hasEmptyElements());
242 CHECK(!obj->hasFixedElements());
243 CHECK(obj->hasDynamicElements());
245 RootedObject array(cx, NewArrayObject(cx, 1));
246 CHECK(array);
247 obj = &array->as<NativeObject>();
248 CHECK(!obj->isTenured());
249 CHECK(!obj->hasEmptyElements());
250 CHECK(obj->hasFixedElements());
251 CHECK(!obj->hasDynamicElements());
253 return true;
255 END_TEST(testNewObject_elements)