summaryrefslogtreecommitdiffstats
path: root/js/src/jsapi-tests/testXDR.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jsapi-tests/testXDR.cpp')
-rw-r--r--js/src/jsapi-tests/testXDR.cpp189
1 files changed, 189 insertions, 0 deletions
diff --git a/js/src/jsapi-tests/testXDR.cpp b/js/src/jsapi-tests/testXDR.cpp
new file mode 100644
index 0000000000..870094b8ff
--- /dev/null
+++ b/js/src/jsapi-tests/testXDR.cpp
@@ -0,0 +1,189 @@
+/* -*- 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/Utf8.h" // mozilla::Utf8Unit
+
+#include "jsfriendapi.h"
+
+#include "js/BuildId.h" // JS::BuildIdCharVector, JS::SetProcessBuildIdOp
+#include "js/CompilationAndEvaluation.h" // JS::Compile
+#include "js/CompileOptions.h" // JS::CompileOptions
+#include "js/SourceText.h" // JS::Source{Ownership,Text}
+#include "js/Transcoding.h"
+#include "jsapi-tests/tests.h"
+#include "util/Text.h"
+#include "vm/JSScript.h"
+
+#include "vm/JSScript-inl.h"
+
+static bool GetBuildId(JS::BuildIdCharVector* buildId) {
+ const char buildid[] = "testXDR";
+ return buildId->append(buildid, sizeof(buildid));
+}
+
+static JSScript* FreezeThaw(JSContext* cx, JS::CompileOptions& options,
+ JS::HandleScript script) {
+ JS::SetProcessBuildIdOp(::GetBuildId);
+
+ // freeze
+ JS::TranscodeBuffer buffer;
+ JS::TranscodeResult rs = JS::EncodeScript(cx, buffer, script);
+ if (rs != JS::TranscodeResult_Ok) {
+ return nullptr;
+ }
+
+ // thaw
+ JS::RootedScript script2(cx);
+ rs = JS::DecodeScript(cx, options, buffer, &script2);
+ if (rs != JS::TranscodeResult_Ok) {
+ return nullptr;
+ }
+ return script2;
+}
+
+enum TestCase {
+ TEST_FIRST,
+ TEST_SCRIPT = TEST_FIRST,
+ TEST_FUNCTION,
+ TEST_SERIALIZED_FUNCTION,
+ TEST_END
+};
+
+BEGIN_TEST(testXDR_bug506491) {
+ static const char s[] =
+ "function makeClosure(s, name, value) {\n"
+ " eval(s);\n"
+ " Math.sin(value);\n"
+ " let n = name, v = value;\n"
+ " return function () { return String(v); };\n"
+ "}\n"
+ "var f = makeClosure('0;', 'status', 'ok');\n";
+
+ // compile
+ JS::CompileOptions options(cx);
+ options.setFileAndLine(__FILE__, __LINE__);
+
+ JS::SourceText<mozilla::Utf8Unit> srcBuf;
+ CHECK(srcBuf.init(cx, s, js_strlen(s), JS::SourceOwnership::Borrowed));
+
+ JS::RootedScript script(cx, JS::Compile(cx, options, srcBuf));
+ CHECK(script);
+
+ script = FreezeThaw(cx, options, script);
+ CHECK(script);
+
+ // execute
+ JS::RootedValue v2(cx);
+ CHECK(JS_ExecuteScript(cx, script, &v2));
+
+ // try to break the Block object that is the parent of f
+ JS_GC(cx);
+
+ // confirm
+ EVAL("f() === 'ok';\n", &v2);
+ JS::RootedValue trueval(cx, JS::TrueValue());
+ CHECK_SAME(v2, trueval);
+ return true;
+}
+END_TEST(testXDR_bug506491)
+
+BEGIN_TEST(testXDR_bug516827) {
+ // compile an empty script
+ JS::CompileOptions options(cx);
+ options.setFileAndLine(__FILE__, __LINE__);
+
+ JS::SourceText<mozilla::Utf8Unit> srcBuf;
+ CHECK(srcBuf.init(cx, "", 0, JS::SourceOwnership::Borrowed));
+
+ JS::RootedScript script(cx, JS::Compile(cx, options, srcBuf));
+ CHECK(script);
+
+ script = FreezeThaw(cx, options, script);
+ CHECK(script);
+
+ // execute with null result meaning no result wanted
+ CHECK(JS_ExecuteScript(cx, script));
+ return true;
+}
+END_TEST(testXDR_bug516827)
+
+BEGIN_TEST(testXDR_source) {
+ const char* samples[] = {
+ // This can't possibly fail to compress well, can it?
+ "function f(x) { return x + x + x + x + x + x + x + x + x + x + x + x + "
+ "x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + "
+ "x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + "
+ "x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + "
+ "x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + "
+ "x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + "
+ "x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + "
+ "x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + x + "
+ "x + x + x + x + x + x + x + x + x + x + x + x }",
+ "short", nullptr};
+ for (const char** s = samples; *s; s++) {
+ JS::CompileOptions options(cx);
+ options.setFileAndLine(__FILE__, __LINE__);
+
+ JS::SourceText<mozilla::Utf8Unit> srcBuf;
+ CHECK(srcBuf.init(cx, *s, strlen(*s), JS::SourceOwnership::Borrowed));
+
+ JS::RootedScript script(cx, JS::Compile(cx, options, srcBuf));
+ CHECK(script);
+
+ script = FreezeThaw(cx, options, script);
+ CHECK(script);
+
+ JSString* out = JS_DecompileScript(cx, script);
+ CHECK(out);
+
+ bool equal;
+ CHECK(JS_StringEqualsAscii(cx, out, *s, &equal));
+ CHECK(equal);
+ }
+ return true;
+}
+END_TEST(testXDR_source)
+
+BEGIN_TEST(testXDR_sourceMap) {
+ const char* sourceMaps[] = {"http://example.com/source-map.json",
+ "file:///var/source-map.json", nullptr};
+ JS::RootedScript script(cx);
+ for (const char** sm = sourceMaps; *sm; sm++) {
+ JS::CompileOptions options(cx);
+ options.setFileAndLine(__FILE__, __LINE__);
+
+ JS::SourceText<mozilla::Utf8Unit> srcBuf;
+ CHECK(srcBuf.init(cx, "", 0, JS::SourceOwnership::Borrowed));
+
+ script = JS::Compile(cx, options, srcBuf);
+ CHECK(script);
+
+ size_t len = strlen(*sm);
+ JS::UniqueTwoByteChars expected_wrapper(js::InflateString(cx, *sm, len));
+ char16_t* expected = expected_wrapper.get();
+ CHECK(expected);
+
+ // The script source takes responsibility of free'ing |expected|.
+ CHECK(script->scriptSource()->setSourceMapURL(cx, expected));
+ script = FreezeThaw(cx, options, script);
+ CHECK(script);
+ CHECK(script->scriptSource());
+ CHECK(script->scriptSource()->hasSourceMapURL());
+
+ const char16_t* actual = script->scriptSource()->sourceMapURL();
+ CHECK(actual);
+
+ while (*expected) {
+ CHECK(*actual);
+ CHECK(*expected == *actual);
+ expected++;
+ actual++;
+ }
+ CHECK(!*actual);
+ }
+ return true;
+}
+END_TEST(testXDR_sourceMap)