summaryrefslogtreecommitdiffstats
path: root/js/src/jsapi-tests/testFrontendErrors.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jsapi-tests/testFrontendErrors.cpp')
-rw-r--r--js/src/jsapi-tests/testFrontendErrors.cpp353
1 files changed, 353 insertions, 0 deletions
diff --git a/js/src/jsapi-tests/testFrontendErrors.cpp b/js/src/jsapi-tests/testFrontendErrors.cpp
new file mode 100644
index 0000000000..c9d3ee1eb5
--- /dev/null
+++ b/js/src/jsapi-tests/testFrontendErrors.cpp
@@ -0,0 +1,353 @@
+/* -*- 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 "mozilla/RefPtr.h" // RefPtr
+#include "mozilla/Utf8.h" // mozilla::Utf8Unit
+
+#include <string.h> // strcmp
+
+#include "frontend/FrontendContext.h" // js::FrontendContext
+#include "js/AllocPolicy.h" // js::ReportOutOfMemory
+#include "js/CompileOptions.h" // JS::PrefableCompileOptions, JS::CompileOptions
+#include "js/Exception.h" // JS_IsExceptionPending, JS_IsThrowingOutOfMemory, JS_GetPendingException, JS_ClearPendingException, JS_ErrorFromException
+#include "js/experimental/CompileScript.h" // JS::NewFrontendContext, JS::DestroyFrontendContext, JS::SetNativeStackQuota, JS::CompileGlobalScriptToStencil, JS::ConvertFrontendErrorsToRuntimeErrors, JS::HadFrontendErrors, JS::HadFrontendOverRecursed, JS::HadFrontendOutOfMemory, JS::HadFrontendAllocationOverflow, JS::GetFrontendWarningCount, JS::GetFrontendWarningAt
+#include "js/friend/ErrorMessages.h" // JSMSG_*
+#include "js/friend/StackLimits.h" // js::ReportOverRecursed
+#include "js/RootingAPI.h" // JS::Rooted
+#include "js/SourceText.h" // JS::SourceText
+#include "js/Stack.h" // JS::NativeStackSize
+#include "js/Warnings.h" // JS::SetWarningReporter
+#include "jsapi-tests/tests.h"
+#include "util/NativeStack.h" // js::GetNativeStackBase
+#include "vm/ErrorObject.h" // js::ErrorObject
+#include "vm/JSContext.h" // JSContext
+#include "vm/JSObject.h" // JSObject
+#include "vm/NativeObject.h" // js::NativeObject
+#include "vm/Runtime.h" // js::ReportAllocationOverflow
+
+using namespace JS;
+
+BEGIN_TEST(testFrontendErrors_error) {
+ JS::FrontendContext* fc = JS::NewFrontendContext();
+ CHECK(fc);
+
+ static constexpr JS::NativeStackSize stackSize = 128 * sizeof(size_t) * 1024;
+
+ JS::SetNativeStackQuota(fc, stackSize);
+
+ JS::PrefableCompileOptions prefableOptions;
+ JS::CompileOptions options(prefableOptions);
+ const char* filename = "testFrontendErrors_error.js";
+ options.setFile(filename);
+
+ CHECK(!JS::HadFrontendErrors(fc));
+
+ {
+ const char source[] = "syntax error";
+
+ JS::SourceText<mozilla::Utf8Unit> srcBuf;
+ CHECK(
+ srcBuf.init(fc, source, strlen(source), JS::SourceOwnership::Borrowed));
+ JS::CompilationStorage compileStorage;
+ RefPtr<JS::Stencil> stencil =
+ JS::CompileGlobalScriptToStencil(fc, options, srcBuf, compileStorage);
+ CHECK(!stencil);
+ }
+
+ CHECK(JS::HadFrontendErrors(fc));
+ CHECK(!JS::HadFrontendOverRecursed(fc));
+ CHECK(!JS::HadFrontendOutOfMemory(fc));
+ CHECK(!JS::HadFrontendAllocationOverflow(fc));
+ CHECK(JS::GetFrontendWarningCount(fc) == 0);
+
+ {
+ const JSErrorReport* report = JS::GetFrontendErrorReport(fc, options);
+ CHECK(report);
+
+ CHECK(report->errorNumber == JSMSG_UNEXPECTED_TOKEN_NO_EXPECT);
+ // FrontendContext's error report borrows the filename.
+ CHECK(report->filename.c_str() == filename);
+ }
+
+ CHECK(!JS_IsExceptionPending(cx));
+
+ JS::SetWarningReporter(cx, warningReporter);
+
+ bool result = JS::ConvertFrontendErrorsToRuntimeErrors(cx, fc, options);
+ CHECK(result);
+
+ CHECK(JS_IsExceptionPending(cx));
+ CHECK(!warningReporterCalled);
+ CHECK(!JS_IsThrowingOutOfMemory(cx));
+
+ {
+ JS::Rooted<JS::Value> exception(cx);
+ CHECK(JS_GetPendingException(cx, &exception));
+
+ CHECK(exception.isObject());
+ JS::Rooted<JSObject*> exceptionObj(cx, &exception.toObject());
+
+ const JSErrorReport* report = JS_ErrorFromException(cx, exceptionObj);
+ CHECK(report);
+
+ CHECK(report->errorNumber == JSMSG_UNEXPECTED_TOKEN_NO_EXPECT);
+ // Runtime's error report doesn't borrow the filename.
+ CHECK(report->filename.c_str() != filename);
+ CHECK(strcmp(report->filename.c_str(), filename) == 0);
+ }
+
+ JS_ClearPendingException(cx);
+
+ JS::DestroyFrontendContext(fc);
+
+ return true;
+}
+
+static bool warningReporterCalled;
+
+static void warningReporter(JSContext* cx, JSErrorReport* report) {
+ warningReporterCalled = true;
+}
+END_TEST(testFrontendErrors_error)
+
+/* static */ bool cls_testFrontendErrors_error::warningReporterCalled = false;
+
+BEGIN_TEST(testFrontendErrors_warning) {
+ JS::FrontendContext* fc = JS::NewFrontendContext();
+ CHECK(fc);
+
+ static constexpr JS::NativeStackSize stackSize = 128 * sizeof(size_t) * 1024;
+
+ JS::SetNativeStackQuota(fc, stackSize);
+
+ JS::PrefableCompileOptions prefableOptions;
+ JS::CompileOptions options(prefableOptions);
+ options.setFile(filename);
+
+ {
+ const char source[] = "function f() { return; f(); }";
+
+ JS::SourceText<mozilla::Utf8Unit> srcBuf;
+ CHECK(
+ srcBuf.init(fc, source, strlen(source), JS::SourceOwnership::Borrowed));
+ JS::CompilationStorage compileStorage;
+ RefPtr<JS::Stencil> stencil =
+ JS::CompileGlobalScriptToStencil(fc, options, srcBuf, compileStorage);
+ CHECK(stencil);
+ }
+
+ CHECK(!JS::HadFrontendErrors(fc));
+ CHECK(!JS::HadFrontendOverRecursed(fc));
+ CHECK(!JS::HadFrontendOutOfMemory(fc));
+ CHECK(!JS::HadFrontendAllocationOverflow(fc));
+ CHECK(JS::GetFrontendWarningCount(fc) == 1);
+
+ {
+ const JSErrorReport* report = JS::GetFrontendWarningAt(fc, 0, options);
+ CHECK(report);
+
+ CHECK(report->errorNumber == JSMSG_STMT_AFTER_RETURN);
+ // FrontendContext's error report borrows the filename.
+ CHECK(report->filename.c_str() == filename);
+ }
+
+ CHECK(!JS_IsExceptionPending(cx));
+
+ JS::SetWarningReporter(cx, warningReporter);
+
+ bool result = JS::ConvertFrontendErrorsToRuntimeErrors(cx, fc, options);
+ CHECK(result);
+
+ CHECK(!JS_IsExceptionPending(cx));
+ CHECK(warningReporterCalled);
+ CHECK(!JS_IsThrowingOutOfMemory(cx));
+
+ CHECK(errorNumberMatches);
+ CHECK(filenameMatches);
+
+ JS::DestroyFrontendContext(fc);
+
+ return true;
+}
+
+static const char* filename;
+static bool warningReporterCalled;
+static bool errorNumberMatches;
+static bool filenameMatches;
+
+static void warningReporter(JSContext* cx, JSErrorReport* report) {
+ warningReporterCalled = true;
+
+ errorNumberMatches = report->errorNumber == JSMSG_STMT_AFTER_RETURN;
+ filenameMatches = report->filename.c_str() == filename;
+}
+END_TEST(testFrontendErrors_warning)
+
+/* static */ const char* cls_testFrontendErrors_warning::filename =
+ "testFrontendErrors_warning.js";
+/* static */ bool cls_testFrontendErrors_warning::warningReporterCalled = false;
+/* static */ bool cls_testFrontendErrors_warning::errorNumberMatches = false;
+/* static */ bool cls_testFrontendErrors_warning::filenameMatches = false;
+
+BEGIN_TEST(testFrontendErrors_oom) {
+ JS::FrontendContext* fc = JS::NewFrontendContext();
+ CHECK(fc);
+
+ JS::PrefableCompileOptions prefableOptions;
+ JS::CompileOptions options(prefableOptions);
+
+ CHECK(!JS::HadFrontendErrors(fc));
+
+ js::ReportOutOfMemory(fc);
+
+ CHECK(JS::HadFrontendErrors(fc));
+ CHECK(!JS::HadFrontendOverRecursed(fc));
+ CHECK(JS::HadFrontendOutOfMemory(fc));
+ CHECK(!JS::HadFrontendAllocationOverflow(fc));
+ CHECK(JS::GetFrontendWarningCount(fc) == 0);
+
+ CHECK(!JS_IsExceptionPending(cx));
+
+ JS::SetWarningReporter(cx, warningReporter);
+
+ bool result = JS::ConvertFrontendErrorsToRuntimeErrors(cx, fc, options);
+ CHECK(!result);
+
+ CHECK(JS_IsExceptionPending(cx));
+ CHECK(!warningReporterCalled);
+ CHECK(JS_IsThrowingOutOfMemory(cx));
+
+ JS_ClearPendingException(cx);
+
+ JS::DestroyFrontendContext(fc);
+
+ return true;
+}
+
+static bool warningReporterCalled;
+
+static void warningReporter(JSContext* cx, JSErrorReport* report) {
+ warningReporterCalled = true;
+}
+END_TEST(testFrontendErrors_oom)
+
+/* static */ bool cls_testFrontendErrors_oom::warningReporterCalled = false;
+
+BEGIN_TEST(testFrontendErrors_overRecursed) {
+ JS::FrontendContext* fc = JS::NewFrontendContext();
+ CHECK(fc);
+
+ JS::PrefableCompileOptions prefableOptions;
+ JS::CompileOptions options(prefableOptions);
+
+ CHECK(!JS::HadFrontendErrors(fc));
+
+ js::ReportOverRecursed(fc);
+
+ CHECK(JS::HadFrontendErrors(fc));
+ CHECK(JS::HadFrontendOverRecursed(fc));
+ CHECK(!JS::HadFrontendOutOfMemory(fc));
+ CHECK(!JS::HadFrontendAllocationOverflow(fc));
+ CHECK(JS::GetFrontendWarningCount(fc) == 0);
+
+ CHECK(!JS_IsExceptionPending(cx));
+
+ JS::SetWarningReporter(cx, warningReporter);
+
+ bool result = JS::ConvertFrontendErrorsToRuntimeErrors(cx, fc, options);
+ CHECK(result);
+
+ CHECK(JS_IsExceptionPending(cx));
+ CHECK(!warningReporterCalled);
+ CHECK(!JS_IsThrowingOutOfMemory(cx));
+
+ {
+ JS::Rooted<JS::Value> exception(cx);
+ CHECK(JS_GetPendingException(cx, &exception));
+
+ CHECK(exception.isObject());
+ JS::Rooted<JSObject*> exceptionObj(cx, &exception.toObject());
+
+ const JSErrorReport* report = JS_ErrorFromException(cx, exceptionObj);
+ CHECK(report);
+
+ CHECK(report->errorNumber == JSMSG_OVER_RECURSED);
+ }
+
+ JS_ClearPendingException(cx);
+
+ JS::DestroyFrontendContext(fc);
+
+ return true;
+}
+
+static bool warningReporterCalled;
+
+static void warningReporter(JSContext* cx, JSErrorReport* report) {
+ warningReporterCalled = true;
+}
+END_TEST(testFrontendErrors_overRecursed)
+
+/* static */ bool cls_testFrontendErrors_overRecursed::warningReporterCalled =
+ false;
+
+BEGIN_TEST(testFrontendErrors_allocationOverflow) {
+ JS::FrontendContext* fc = JS::NewFrontendContext();
+ CHECK(fc);
+
+ JS::PrefableCompileOptions prefableOptions;
+ JS::CompileOptions options(prefableOptions);
+
+ CHECK(!JS::HadFrontendErrors(fc));
+
+ js::ReportAllocationOverflow(fc);
+
+ CHECK(JS::HadFrontendErrors(fc));
+ CHECK(!JS::HadFrontendOverRecursed(fc));
+ CHECK(!JS::HadFrontendOutOfMemory(fc));
+ CHECK(JS::HadFrontendAllocationOverflow(fc));
+ CHECK(JS::GetFrontendWarningCount(fc) == 0);
+
+ CHECK(!JS_IsExceptionPending(cx));
+
+ JS::SetWarningReporter(cx, warningReporter);
+
+ bool result = JS::ConvertFrontendErrorsToRuntimeErrors(cx, fc, options);
+ CHECK(result);
+
+ CHECK(JS_IsExceptionPending(cx));
+ CHECK(!warningReporterCalled);
+ CHECK(!JS_IsThrowingOutOfMemory(cx));
+
+ {
+ JS::Rooted<JS::Value> exception(cx);
+ CHECK(JS_GetPendingException(cx, &exception));
+
+ CHECK(exception.isObject());
+ JS::Rooted<JSObject*> exceptionObj(cx, &exception.toObject());
+
+ const JSErrorReport* report = JS_ErrorFromException(cx, exceptionObj);
+ CHECK(report);
+
+ CHECK(report->errorNumber == JSMSG_ALLOC_OVERFLOW);
+ }
+
+ JS_ClearPendingException(cx);
+
+ JS::DestroyFrontendContext(fc);
+
+ return true;
+}
+
+static bool warningReporterCalled;
+
+static void warningReporter(JSContext* cx, JSErrorReport* report) {
+ warningReporterCalled = true;
+}
+END_TEST(testFrontendErrors_allocationOverflow)
+
+/* static */ bool
+ cls_testFrontendErrors_allocationOverflow::warningReporterCalled = false;