diff options
Diffstat (limited to 'js/src/jsapi-tests/testXDR.cpp')
-rw-r--r-- | js/src/jsapi-tests/testXDR.cpp | 189 |
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) |