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
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
));
31 MaybeFreeContext(maybeReusableContext
);
38 js::UseInternalJobQueues(cx
);
40 if (!JS::InitSelfHostedCode(cx
)) {
48 JS::EnterRealm(cx
, global
);
52 JSContext
* JSAPIRuntimeTest::maybeForgetContext() {
57 JSContext
* reusableCx
= cx
;
64 void JSAPIRuntimeTest::MaybeFreeContext(JSContext
* maybeCx
) {
66 JS::LeaveRealm(maybeCx
, nullptr);
67 JS_DestroyContext(maybeCx
);
71 void JSAPIRuntimeTest::uninit() {
78 bool JSAPIRuntimeTest::exec(const char* utf8
, const char* filename
,
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
,
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
);
133 struct CommandOptions
{
135 bool frontendOnly
= 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) {
147 if (strcmp(argv
[i
], "--list") == 0) {
152 if (strcmp(argv
[i
], "--frontend-only") == 0) {
153 options
.frontendOnly
= true;
157 if (!options
.filter
) {
158 options
.filter
= argv
[i
];
162 printf("error: Unrecognized option: %s\n", argv
[i
]);
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) {
185 printf("%s\n", name
);
187 // Make sure the test name is printed before we enter the test that can
192 printf("TEST-UNEXPECTED-FAIL | %s | Failed to initialize.\n", name
);
199 printf("TEST-PASS | %s | ok\n", name
);
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
) {
216 int main(int argc
, char* argv
[]) {
219 CommandOptions options
;
220 parseArgs(argc
, argv
, options
);
223 printf("Usage: jsapi-tests [OPTIONS] [FILTER]\n");
225 printf("Options:\n");
226 printf(" -h, --help Display this message\n");
227 printf(" --list List all tests\n");
229 " --frontend-only Run tests for frontend-only APIs, with "
230 "light-weight entry point\n");
234 if (!options
.frontendOnly
) {
236 printf("TEST-UNEXPECTED-FAIL | jsapi-tests | JS_Init() failed.\n");
240 if (!JS_FrontendOnlyInit()) {
241 printf("TEST-UNEXPECTED-FAIL | jsapi-tests | JS_Init() failed.\n");
247 PrintTests(JSAPIRuntimeTest::list
);
248 PrintTests(JSAPIFrontendTest::list
);
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
255 JSContext
* maybeReusedContext
= nullptr;
257 if (!options
.frontendOnly
) {
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();
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());
282 JS_FrontendOnlyShutDown();
286 printf("\n%d unexpected failure%s.\n", failures
,
287 (failures
== 1 ? "" : "s"));
290 printf("\nPassed: ran %d tests.\n", total
);