Bug 1832850 - Part 5: Move the allocateObject definition into gc/Nursery.h r=jandem
[gecko.git] / js / src / jsapi-tests / tests.cpp
blobd2babb1c8e9147d75f2475dd831b3ce1f14459aa
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 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "jsapi-tests/tests.h"
9 #include "mozilla/Utf8.h" // mozilla::Utf8Unit
11 #include <stdio.h>
13 #include "js/ArrayBuffer.h"
14 #include "js/CompilationAndEvaluation.h" // JS::Evaluate
15 #include "js/GlobalObject.h" // JS_NewGlobalObject
16 #include "js/Initialization.h"
17 #include "js/PropertyAndElement.h" // JS_DefineFunction
18 #include "js/RootingAPI.h"
19 #include "js/SourceText.h" // JS::Source{Ownership,Text}
21 JSAPIRuntimeTest* JSAPIRuntimeTest::list;
22 JSAPIFrontendTest* JSAPIFrontendTest::list;
24 bool JSAPIRuntimeTest::init(JSContext* maybeReusableContext) {
25 if (maybeReusableContext && reuseGlobal) {
26 cx = maybeReusableContext;
27 global.init(cx, JS::CurrentGlobalOrNull(cx));
28 return init();
31 MaybeFreeContext(maybeReusableContext);
33 cx = createContext();
34 if (!cx) {
35 return false;
38 js::UseInternalJobQueues(cx);
40 if (!JS::InitSelfHostedCode(cx)) {
41 return false;
43 global.init(cx);
44 createGlobal();
45 if (!global) {
46 return false;
48 JS::EnterRealm(cx, global);
49 return init();
52 JSContext* JSAPIRuntimeTest::maybeForgetContext() {
53 if (!reuseGlobal) {
54 return nullptr;
57 JSContext* reusableCx = cx;
58 global.reset();
59 cx = nullptr;
60 return reusableCx;
63 /* static */
64 void JSAPIRuntimeTest::MaybeFreeContext(JSContext* maybeCx) {
65 if (maybeCx) {
66 JS::LeaveRealm(maybeCx, nullptr);
67 JS_DestroyContext(maybeCx);
71 void JSAPIRuntimeTest::uninit() {
72 global.reset();
73 MaybeFreeContext(cx);
74 cx = nullptr;
75 msgs.clear();
78 bool JSAPIRuntimeTest::exec(const char* utf8, const char* filename,
79 int lineno) {
80 JS::CompileOptions opts(cx);
81 opts.setFileAndLine(filename, lineno);
83 JS::SourceText<mozilla::Utf8Unit> srcBuf;
84 JS::RootedValue v(cx);
85 return (srcBuf.init(cx, utf8, strlen(utf8), JS::SourceOwnership::Borrowed) &&
86 JS::Evaluate(cx, opts, srcBuf, &v)) ||
87 fail(JSAPITestString(utf8), filename, lineno);
90 bool JSAPIRuntimeTest::execDontReport(const char* utf8, const char* filename,
91 int lineno) {
92 JS::CompileOptions opts(cx);
93 opts.setFileAndLine(filename, lineno);
95 JS::SourceText<mozilla::Utf8Unit> srcBuf;
96 JS::RootedValue v(cx);
97 return srcBuf.init(cx, utf8, strlen(utf8), JS::SourceOwnership::Borrowed) &&
98 JS::Evaluate(cx, opts, srcBuf, &v);
101 bool JSAPIRuntimeTest::evaluate(const char* utf8, const char* filename,
102 int lineno, JS::MutableHandleValue vp) {
103 JS::CompileOptions opts(cx);
104 opts.setFileAndLine(filename, lineno);
106 JS::SourceText<mozilla::Utf8Unit> srcBuf;
107 return (srcBuf.init(cx, utf8, strlen(utf8), JS::SourceOwnership::Borrowed) &&
108 JS::Evaluate(cx, opts, srcBuf, vp)) ||
109 fail(JSAPITestString(utf8), filename, lineno);
112 bool JSAPIRuntimeTest::definePrint() {
113 return JS_DefineFunction(cx, global, "print", (JSNative)print, 0, 0);
116 JSObject* JSAPIRuntimeTest::createGlobal(JSPrincipals* principals) {
117 /* Create the global object. */
118 JS::RootedObject newGlobal(cx);
119 JS::RealmOptions options;
120 options.creationOptions()
121 .setWeakRefsEnabled(JS::WeakRefSpecifier::EnabledWithCleanupSome)
122 .setSharedMemoryAndAtomicsEnabled(true);
123 newGlobal = JS_NewGlobalObject(cx, getGlobalClass(), principals,
124 JS::FireOnNewGlobalHook, options);
125 if (!newGlobal) {
126 return nullptr;
129 global = newGlobal;
130 return newGlobal;
133 struct CommandOptions {
134 bool list = false;
135 bool frontendOnly = false;
136 bool help = false;
137 const char* filter = nullptr;
140 void parseArgs(int argc, char* argv[], CommandOptions& options) {
141 for (int i = 1; i < argc; i++) {
142 if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
143 options.help = true;
144 continue;
147 if (strcmp(argv[i], "--list") == 0) {
148 options.list = true;
149 continue;
152 if (strcmp(argv[i], "--frontend-only") == 0) {
153 options.frontendOnly = true;
154 continue;
157 if (!options.filter) {
158 options.filter = argv[i];
159 continue;
162 printf("error: Unrecognized option: %s\n", argv[i]);
163 options.help = true;
167 template <typename TestT>
168 void PrintTests(TestT* list) {
169 for (TestT* test = list; test; test = test->next) {
170 printf("%s\n", test->name());
174 template <typename TestT, typename InitF, typename RunF, typename BeforeUninitF>
175 void RunTests(int& total, int& failures, CommandOptions& options, TestT* list,
176 InitF init, RunF run, BeforeUninitF beforeUninit) {
177 for (TestT* test = list; test; test = test->next) {
178 const char* name = test->name();
179 if (options.filter && strstr(name, options.filter) == nullptr) {
180 continue;
183 total += 1;
185 printf("%s\n", name);
187 // Make sure the test name is printed before we enter the test that can
188 // crash on failure.
189 fflush(stdout);
191 if (!init(test)) {
192 printf("TEST-UNEXPECTED-FAIL | %s | Failed to initialize.\n", name);
193 failures++;
194 test->uninit();
195 continue;
198 if (run(test)) {
199 printf("TEST-PASS | %s | ok\n", name);
200 } else {
201 JSAPITestString messages = test->messages();
202 printf("%s | %s | %.*s\n",
203 (test->knownFail ? "TEST-KNOWN-FAIL" : "TEST-UNEXPECTED-FAIL"),
204 name, (int)messages.length(), messages.begin());
205 if (!test->knownFail) {
206 failures++;
210 beforeUninit(test);
212 test->uninit();
216 int main(int argc, char* argv[]) {
217 int total = 0;
218 int failures = 0;
219 CommandOptions options;
220 parseArgs(argc, argv, options);
222 if (options.help) {
223 printf("Usage: jsapi-tests [OPTIONS] [FILTER]\n");
224 printf("\n");
225 printf("Options:\n");
226 printf(" -h, --help Display this message\n");
227 printf(" --list List all tests\n");
228 printf(
229 " --frontend-only Run tests for frontend-only APIs, with "
230 "light-weight entry point\n");
231 return 0;
234 if (!options.frontendOnly) {
235 if (!JS_Init()) {
236 printf("TEST-UNEXPECTED-FAIL | jsapi-tests | JS_Init() failed.\n");
237 return 1;
239 } else {
240 if (!JS_FrontendOnlyInit()) {
241 printf("TEST-UNEXPECTED-FAIL | jsapi-tests | JS_Init() failed.\n");
242 return 1;
246 if (options.list) {
247 PrintTests(JSAPIRuntimeTest::list);
248 PrintTests(JSAPIFrontendTest::list);
249 return 0;
252 // Reinitializing the global for every test is quite slow, due to having to
253 // recompile all self-hosted builtins. Allow tests to opt-in to reusing the
254 // global.
255 JSContext* maybeReusedContext = nullptr;
257 if (!options.frontendOnly) {
258 RunTests(
259 total, failures, options, JSAPIRuntimeTest::list,
260 [&maybeReusedContext](JSAPIRuntimeTest* test) {
261 return test->init(maybeReusedContext);
263 [](JSAPIRuntimeTest* test) { return test->run(test->global); },
264 [&maybeReusedContext](JSAPIRuntimeTest* test) {
265 // Return a non-nullptr pointer if the context & global can safely be
266 // reused for the next test.
267 maybeReusedContext = test->maybeForgetContext();
270 RunTests(
271 total, failures, options, JSAPIFrontendTest::list,
272 [](JSAPIFrontendTest* test) { return test->init(); },
273 [](JSAPIFrontendTest* test) { return test->run(); },
274 [](JSAPIFrontendTest* test) {});
276 if (!options.frontendOnly) {
277 JSAPIRuntimeTest::MaybeFreeContext(maybeReusedContext);
279 MOZ_RELEASE_ASSERT(!JSRuntime::hasLiveRuntimes());
280 JS_ShutDown();
281 } else {
282 JS_FrontendOnlyShutDown();
285 if (failures) {
286 printf("\n%d unexpected failure%s.\n", failures,
287 (failures == 1 ? "" : "s"));
288 return 1;
290 printf("\nPassed: ran %d tests.\n", total);
291 return 0;