js/src/jsapi-tests/testXDR.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/src/jsapi-tests/testXDR.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,268 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99:
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "jsfriendapi.h"
    1.11 +#include "jsscript.h"
    1.12 +#include "jsstr.h"
    1.13 +
    1.14 +#include "jsapi-tests/tests.h"
    1.15 +
    1.16 +#include "jsscriptinlines.h"
    1.17 +
    1.18 +static JSScript *
    1.19 +CompileScriptForPrincipalsVersionOrigin(JSContext *cx, JS::HandleObject obj,
    1.20 +                                        JSPrincipals *originPrincipals,
    1.21 +                                        const char *bytes, size_t nbytes,
    1.22 +                                        const char *filename, unsigned lineno,
    1.23 +                                        JSVersion version)
    1.24 +{
    1.25 +    size_t nchars;
    1.26 +    if (!JS_DecodeBytes(cx, bytes, nbytes, nullptr, &nchars))
    1.27 +        return nullptr;
    1.28 +    jschar *chars = static_cast<jschar *>(JS_malloc(cx, nchars * sizeof(jschar)));
    1.29 +    if (!chars)
    1.30 +        return nullptr;
    1.31 +    JS_ALWAYS_TRUE(JS_DecodeBytes(cx, bytes, nbytes, chars, &nchars));
    1.32 +    JS::CompileOptions options(cx);
    1.33 +    options.setOriginPrincipals(originPrincipals)
    1.34 +           .setFileAndLine(filename, lineno)
    1.35 +           .setVersion(version);
    1.36 +    JSScript *script = JS::Compile(cx, obj, options, chars, nchars);
    1.37 +    free(chars);
    1.38 +    return script;
    1.39 +}
    1.40 +
    1.41 +static JSScript *
    1.42 +FreezeThaw(JSContext *cx, JS::HandleScript script)
    1.43 +{
    1.44 +    // freeze
    1.45 +    uint32_t nbytes;
    1.46 +    void *memory = JS_EncodeScript(cx, script, &nbytes);
    1.47 +    if (!memory)
    1.48 +        return nullptr;
    1.49 +
    1.50 +    // thaw
    1.51 +    JSScript *script2 = JS_DecodeScript(cx, memory, nbytes,
    1.52 +                                        script->originPrincipals());
    1.53 +    js_free(memory);
    1.54 +    return script2;
    1.55 +}
    1.56 +
    1.57 +static JSScript *
    1.58 +GetScript(JSContext *cx, JS::HandleObject funobj)
    1.59 +{
    1.60 +    JS::RootedFunction fun(cx, JS_GetObjectFunction(funobj));
    1.61 +    return JS_GetFunctionScript(cx, fun);
    1.62 +}
    1.63 +
    1.64 +static JSObject *
    1.65 +FreezeThaw(JSContext *cx, JS::HandleObject funobj)
    1.66 +{
    1.67 +    // freeze
    1.68 +    uint32_t nbytes;
    1.69 +    void *memory = JS_EncodeInterpretedFunction(cx, funobj, &nbytes);
    1.70 +    if (!memory)
    1.71 +        return nullptr;
    1.72 +
    1.73 +    // thaw
    1.74 +    JSScript *script = GetScript(cx, funobj);
    1.75 +    JSObject *funobj2 = JS_DecodeInterpretedFunction(cx, memory, nbytes,
    1.76 +                                                     script->originPrincipals());
    1.77 +    js_free(memory);
    1.78 +    return funobj2;
    1.79 +}
    1.80 +
    1.81 +static TestJSPrincipals testPrincipal0(1);
    1.82 +static TestJSPrincipals testPrincipal1(1);
    1.83 +
    1.84 +BEGIN_TEST(testXDR_principals)
    1.85 +{
    1.86 +    JSScript *script;
    1.87 +    JSCompartment *compartment = js::GetContextCompartment(cx);
    1.88 +    for (int i = TEST_FIRST; i != TEST_END; ++i) {
    1.89 +        // Appease the new JSAPI assertions. The stuff being tested here is
    1.90 +        // going away anyway.
    1.91 +        JS_SetCompartmentPrincipals(compartment, &testPrincipal0);
    1.92 +        script = createScriptViaXDR(nullptr, i);
    1.93 +        CHECK(script);
    1.94 +        CHECK(JS_GetScriptPrincipals(script) == &testPrincipal0);
    1.95 +        CHECK(JS_GetScriptOriginPrincipals(script) == &testPrincipal0);
    1.96 +
    1.97 +        script = createScriptViaXDR(&testPrincipal0, i);
    1.98 +        CHECK(script);
    1.99 +        CHECK(JS_GetScriptPrincipals(script) == &testPrincipal0);
   1.100 +        CHECK(JS_GetScriptOriginPrincipals(script) == &testPrincipal0);
   1.101 +
   1.102 +        script = createScriptViaXDR(&testPrincipal1, i);
   1.103 +        CHECK(script);
   1.104 +        CHECK(JS_GetScriptPrincipals(script) == &testPrincipal0);
   1.105 +        CHECK(JS_GetScriptOriginPrincipals(script) == &testPrincipal1);
   1.106 +    }
   1.107 +
   1.108 +    return true;
   1.109 +}
   1.110 +
   1.111 +enum TestCase {
   1.112 +    TEST_FIRST,
   1.113 +    TEST_SCRIPT = TEST_FIRST,
   1.114 +    TEST_FUNCTION,
   1.115 +    TEST_SERIALIZED_FUNCTION,
   1.116 +    TEST_END
   1.117 +};
   1.118 +
   1.119 +JSScript *createScriptViaXDR(JSPrincipals *orig, int testCase)
   1.120 +{
   1.121 +    const char src[] =
   1.122 +        "function f() { return 1; }\n"
   1.123 +        "f;\n";
   1.124 +
   1.125 +    JS::RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
   1.126 +    JS::RootedScript script(cx, CompileScriptForPrincipalsVersionOrigin(cx, global, orig,
   1.127 +                                                                        src, strlen(src), "test", 1,
   1.128 +                                                                        JSVERSION_DEFAULT));
   1.129 +    if (!script)
   1.130 +        return nullptr;
   1.131 +
   1.132 +    if (testCase == TEST_SCRIPT || testCase == TEST_SERIALIZED_FUNCTION) {
   1.133 +        script = FreezeThaw(cx, script);
   1.134 +        if (!script)
   1.135 +            return nullptr;
   1.136 +        if (testCase == TEST_SCRIPT)
   1.137 +            return script;
   1.138 +    }
   1.139 +
   1.140 +    JS::RootedValue v(cx);
   1.141 +    bool ok = JS_ExecuteScript(cx, global, script, &v);
   1.142 +    if (!ok || !v.isObject())
   1.143 +        return nullptr;
   1.144 +    JS::RootedObject funobj(cx, &v.toObject());
   1.145 +    if (testCase == TEST_FUNCTION) {
   1.146 +        funobj = FreezeThaw(cx, funobj);
   1.147 +        if (!funobj)
   1.148 +            return nullptr;
   1.149 +    }
   1.150 +    return GetScript(cx, funobj);
   1.151 +}
   1.152 +
   1.153 +END_TEST(testXDR_principals)
   1.154 +
   1.155 +BEGIN_TEST(testXDR_bug506491)
   1.156 +{
   1.157 +    const char *s =
   1.158 +        "function makeClosure(s, name, value) {\n"
   1.159 +        "    eval(s);\n"
   1.160 +        "    Math.sin(value);\n"
   1.161 +        "    return let (n = name, v = value) function () { return String(v); };\n"
   1.162 +        "}\n"
   1.163 +        "var f = makeClosure('0;', 'status', 'ok');\n";
   1.164 +
   1.165 +    // compile
   1.166 +    JS::CompileOptions options(cx);
   1.167 +    options.setFileAndLine(__FILE__, __LINE__);
   1.168 +    JS::RootedScript script(cx, JS_CompileScript(cx, global, s, strlen(s),
   1.169 +                                                 options));
   1.170 +    CHECK(script);
   1.171 +
   1.172 +    script = FreezeThaw(cx, script);
   1.173 +    CHECK(script);
   1.174 +
   1.175 +    // execute
   1.176 +    JS::RootedValue v2(cx);
   1.177 +    CHECK(JS_ExecuteScript(cx, global, script, &v2));
   1.178 +
   1.179 +    // try to break the Block object that is the parent of f
   1.180 +    JS_GC(rt);
   1.181 +
   1.182 +    // confirm
   1.183 +    EVAL("f() === 'ok';\n", &v2);
   1.184 +    JS::RootedValue trueval(cx, JSVAL_TRUE);
   1.185 +    CHECK_SAME(v2, trueval);
   1.186 +    return true;
   1.187 +}
   1.188 +END_TEST(testXDR_bug506491)
   1.189 +
   1.190 +BEGIN_TEST(testXDR_bug516827)
   1.191 +{
   1.192 +    // compile an empty script
   1.193 +    JS::CompileOptions options(cx);
   1.194 +    options.setFileAndLine(__FILE__, __LINE__);
   1.195 +    JS::RootedScript script(cx, JS_CompileScript(cx, global, "", 0, options));
   1.196 +    CHECK(script);
   1.197 +
   1.198 +    script = FreezeThaw(cx, script);
   1.199 +    CHECK(script);
   1.200 +
   1.201 +    // execute with null result meaning no result wanted
   1.202 +    CHECK(JS_ExecuteScript(cx, global, script));
   1.203 +    return true;
   1.204 +}
   1.205 +END_TEST(testXDR_bug516827)
   1.206 +
   1.207 +BEGIN_TEST(testXDR_source)
   1.208 +{
   1.209 +    const char *samples[] = {
   1.210 +        // This can't possibly fail to compress well, can it?
   1.211 +        "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 }",
   1.212 +        "short",
   1.213 +        nullptr
   1.214 +    };
   1.215 +    for (const char **s = samples; *s; s++) {
   1.216 +        JS::CompileOptions options(cx);
   1.217 +        options.setFileAndLine(__FILE__, __LINE__);
   1.218 +        JS::RootedScript script(cx, JS_CompileScript(cx, global, *s, strlen(*s),
   1.219 +                                                     options));
   1.220 +        CHECK(script);
   1.221 +        script = FreezeThaw(cx, script);
   1.222 +        CHECK(script);
   1.223 +        JSString *out = JS_DecompileScript(cx, script, "testing", 0);
   1.224 +        CHECK(out);
   1.225 +        bool equal;
   1.226 +        CHECK(JS_StringEqualsAscii(cx, out, *s, &equal));
   1.227 +        CHECK(equal);
   1.228 +    }
   1.229 +    return true;
   1.230 +}
   1.231 +END_TEST(testXDR_source)
   1.232 +
   1.233 +BEGIN_TEST(testXDR_sourceMap)
   1.234 +{
   1.235 +    const char *sourceMaps[] = {
   1.236 +        "http://example.com/source-map.json",
   1.237 +        "file:///var/source-map.json",
   1.238 +        nullptr
   1.239 +    };
   1.240 +    JS::RootedScript script(cx);
   1.241 +    for (const char **sm = sourceMaps; *sm; sm++) {
   1.242 +        JS::CompileOptions options(cx);
   1.243 +        options.setFileAndLine(__FILE__, __LINE__);
   1.244 +        script = JS_CompileScript(cx, global, "", 0, options);
   1.245 +        CHECK(script);
   1.246 +
   1.247 +        size_t len = strlen(*sm);
   1.248 +        jschar *expected = js::InflateString(cx, *sm, &len);
   1.249 +        CHECK(expected);
   1.250 +
   1.251 +        // The script source takes responsibility of free'ing |expected|.
   1.252 +        CHECK(script->scriptSource()->setSourceMapURL(cx, expected));
   1.253 +        script = FreezeThaw(cx, script);
   1.254 +        CHECK(script);
   1.255 +        CHECK(script->scriptSource());
   1.256 +        CHECK(script->scriptSource()->hasSourceMapURL());
   1.257 +
   1.258 +        const jschar *actual = script->scriptSource()->sourceMapURL();
   1.259 +        CHECK(actual);
   1.260 +
   1.261 +        while (*expected) {
   1.262 +            CHECK(*actual);
   1.263 +            CHECK(*expected == *actual);
   1.264 +            expected++;
   1.265 +            actual++;
   1.266 +        }
   1.267 +        CHECK(!*actual);
   1.268 +    }
   1.269 +    return true;
   1.270 +}
   1.271 +END_TEST(testXDR_sourceMap)

mercurial