summaryrefslogtreecommitdiffstats
path: root/js/src/jsapi-tests/tests.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jsapi-tests/tests.cpp')
-rw-r--r--js/src/jsapi-tests/tests.cpp193
1 files changed, 193 insertions, 0 deletions
diff --git a/js/src/jsapi-tests/tests.cpp b/js/src/jsapi-tests/tests.cpp
new file mode 100644
index 0000000000..aee00ba1b3
--- /dev/null
+++ b/js/src/jsapi-tests/tests.cpp
@@ -0,0 +1,193 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * 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"
+
+#include "mozilla/Utf8.h" // mozilla::Utf8Unit
+
+#include <stdio.h>
+
+#include "js/CompilationAndEvaluation.h" // JS::Evaluate
+#include "js/Initialization.h"
+#include "js/RootingAPI.h"
+#include "js/SourceText.h" // JS::Source{Ownership,Text}
+
+JSAPITest* JSAPITest::list;
+
+bool JSAPITest::init(JSContext* maybeReusableContext) {
+ if (maybeReusableContext && reuseGlobal) {
+ cx = maybeReusableContext;
+ global.init(cx, JS::CurrentGlobalOrNull(cx));
+ return init();
+ }
+
+ MaybeFreeContext(maybeReusableContext);
+
+ cx = createContext();
+ if (!cx) {
+ return false;
+ }
+ js::UseInternalJobQueues(cx);
+ if (!JS::InitSelfHostedCode(cx)) {
+ return false;
+ }
+ global.init(cx);
+ createGlobal();
+ if (!global) {
+ return false;
+ }
+ JS::EnterRealm(cx, global);
+ return init();
+}
+
+JSContext* JSAPITest::maybeForgetContext() {
+ if (!reuseGlobal) {
+ return nullptr;
+ }
+
+ JSContext* reusableCx = cx;
+ global.reset();
+ cx = nullptr;
+ return reusableCx;
+}
+
+/* static */
+void JSAPITest::MaybeFreeContext(JSContext* maybeCx) {
+ if (maybeCx) {
+ JS::LeaveRealm(maybeCx, nullptr);
+ JS_DestroyContext(maybeCx);
+ }
+}
+
+void JSAPITest::uninit() {
+ global.reset();
+ MaybeFreeContext(cx);
+ cx = nullptr;
+ msgs.clear();
+}
+
+bool JSAPITest::exec(const char* utf8, const char* filename, int lineno) {
+ JS::CompileOptions opts(cx);
+ opts.setFileAndLine(filename, lineno);
+
+ JS::SourceText<mozilla::Utf8Unit> srcBuf;
+ JS::RootedValue v(cx);
+ return (srcBuf.init(cx, utf8, strlen(utf8), JS::SourceOwnership::Borrowed) &&
+ JS::Evaluate(cx, opts, srcBuf, &v)) ||
+ fail(JSAPITestString(utf8), filename, lineno);
+}
+
+bool JSAPITest::execDontReport(const char* utf8, const char* filename,
+ int lineno) {
+ JS::CompileOptions opts(cx);
+ opts.setFileAndLine(filename, lineno);
+
+ JS::SourceText<mozilla::Utf8Unit> srcBuf;
+ JS::RootedValue v(cx);
+ return srcBuf.init(cx, utf8, strlen(utf8), JS::SourceOwnership::Borrowed) &&
+ JS::Evaluate(cx, opts, srcBuf, &v);
+}
+
+bool JSAPITest::evaluate(const char* utf8, const char* filename, int lineno,
+ JS::MutableHandleValue vp) {
+ JS::CompileOptions opts(cx);
+ opts.setFileAndLine(filename, lineno);
+
+ JS::SourceText<mozilla::Utf8Unit> srcBuf;
+ return (srcBuf.init(cx, utf8, strlen(utf8), JS::SourceOwnership::Borrowed) &&
+ JS::Evaluate(cx, opts, srcBuf, vp)) ||
+ fail(JSAPITestString(utf8), filename, lineno);
+}
+
+bool JSAPITest::definePrint() {
+ return JS_DefineFunction(cx, global, "print", (JSNative)print, 0, 0);
+}
+
+JSObject* JSAPITest::createGlobal(JSPrincipals* principals) {
+ /* Create the global object. */
+ JS::RootedObject newGlobal(cx);
+ JS::RealmOptions options;
+ options.creationOptions()
+ .setStreamsEnabled(true)
+ .setWeakRefsEnabled(JS::WeakRefSpecifier::EnabledWithCleanupSome)
+ .setSharedMemoryAndAtomicsEnabled(true);
+ newGlobal = JS_NewGlobalObject(cx, getGlobalClass(), principals,
+ JS::FireOnNewGlobalHook, options);
+ if (!newGlobal) {
+ return nullptr;
+ }
+
+ global = newGlobal;
+ return newGlobal;
+}
+
+int main(int argc, char* argv[]) {
+ int total = 0;
+ int failures = 0;
+ const char* filter = (argc == 2) ? argv[1] : nullptr;
+
+ if (!JS_Init()) {
+ printf("TEST-UNEXPECTED-FAIL | jsapi-tests | JS_Init() failed.\n");
+ return 1;
+ }
+
+ if (filter && strcmp(filter, "--list") == 0) {
+ for (JSAPITest* test = JSAPITest::list; test; test = test->next) {
+ printf("%s\n", test->name());
+ }
+ return 0;
+ }
+
+ // Reinitializing the global for every test is quite slow, due to having to
+ // recompile all self-hosted builtins. Allow tests to opt-in to reusing the
+ // global.
+ JSContext* maybeReusedContext = nullptr;
+ for (JSAPITest* test = JSAPITest::list; test; test = test->next) {
+ const char* name = test->name();
+ if (filter && strstr(name, filter) == nullptr) {
+ continue;
+ }
+
+ total += 1;
+
+ printf("%s\n", name);
+ if (!test->init(maybeReusedContext)) {
+ printf("TEST-UNEXPECTED-FAIL | %s | Failed to initialize.\n", name);
+ failures++;
+ test->uninit();
+ continue;
+ }
+
+ if (test->run(test->global)) {
+ printf("TEST-PASS | %s | ok\n", name);
+ } else {
+ JSAPITestString messages = test->messages();
+ printf("%s | %s | %.*s\n",
+ (test->knownFail ? "TEST-KNOWN-FAIL" : "TEST-UNEXPECTED-FAIL"),
+ name, (int)messages.length(), messages.begin());
+ if (!test->knownFail) {
+ failures++;
+ }
+ }
+
+ // Return a non-nullptr pointer if the context & global can safely be
+ // reused for the next test.
+ maybeReusedContext = test->maybeForgetContext();
+ test->uninit();
+ }
+ JSAPITest::MaybeFreeContext(maybeReusedContext);
+
+ MOZ_RELEASE_ASSERT(!JSRuntime::hasLiveRuntimes());
+ JS_ShutDown();
+
+ if (failures) {
+ printf("\n%d unexpected failure%s.\n", failures,
+ (failures == 1 ? "" : "s"));
+ return 1;
+ }
+ printf("\nPassed: ran %d tests.\n", total);
+ return 0;
+}