js/xpconnect/tests/chrome/test_cows.xul

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/js/xpconnect/tests/chrome/test_cows.xul	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,327 @@
     1.4 +<?xml version="1.0"?>
     1.5 +<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
     1.6 +<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
     1.7 +                 type="text/css"?>
     1.8 +<!--
     1.9 +https://bugzilla.mozilla.org/show_bug.cgi?id=500931
    1.10 +-->
    1.11 +<window title="Mozilla Bug 522764"
    1.12 +  xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
    1.13 +  <script type="application/javascript"
    1.14 +          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
    1.15 +
    1.16 +  <!-- test results are displayed in the html:body -->
    1.17 +  <body xmlns="http://www.w3.org/1999/xhtml">
    1.18 +  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=522764 "
    1.19 +     target="_blank">Mozilla Bug 522764 </a>
    1.20 +  </body>
    1.21 +
    1.22 +  <!-- test code goes here -->
    1.23 +  <script type="application/javascript"><![CDATA[
    1.24 +const Ci = Components.interfaces;
    1.25 +const Cu = Components.utils;
    1.26 +
    1.27 +var sandbox = new Cu.Sandbox("about:blank");
    1.28 +
    1.29 +var test_utils = window.QueryInterface(Ci.nsIInterfaceRequestor).
    1.30 +                 getInterface(Ci.nsIDOMWindowUtils);
    1.31 +
    1.32 +function getCOW(x) {
    1.33 +  if (typeof x != 'object' && typeof x != 'function')
    1.34 +    return x;
    1.35 +  var rval = {};
    1.36 +  if (typeof x == "function")
    1.37 +    rval = eval(uneval(x));
    1.38 +  for (var i in x) {
    1.39 +    if (x.__lookupGetter__(i))
    1.40 +      rval.__defineGetter__(i, eval(uneval(x.__lookupGetter__(i))))
    1.41 +    else
    1.42 +      rval[i] = getCOW(x[i]);
    1.43 +  }
    1.44 +  return rval;
    1.45 +}
    1.46 +
    1.47 +// Give the sandbox a way to create ChromeObjectWrapped objects.
    1.48 +sandbox.getCOW = getCOW;
    1.49 +
    1.50 +// Define test API functions in the sandbox.
    1.51 +const TEST_API = ['is', 'isnot', 'ok', 'todo_is', 'todo_isnot', 'todo'];
    1.52 +TEST_API.forEach(function(name) { sandbox[name] = window[name]; });
    1.53 +
    1.54 +sandbox.alienObject = {
    1.55 +  __exposedProps__: {funProp: 'r'},
    1.56 +  funProp: function foo(x) {
    1.57 +    return x + 1;
    1.58 +  }
    1.59 +};
    1.60 +
    1.61 +sandbox.chromeGet = function (obj, prop) { return obj[prop]; };
    1.62 +
    1.63 +function COWTests() {
    1.64 +    // This function is actually decompiled and run inside a
    1.65 +    // sandbox with content privileges.
    1.66 +
    1.67 +    // TODO: This could use some refactoring; creating helper
    1.68 +    // functions like assertIsWritable(myObj, 'someproperty') might
    1.69 +    // be useful.
    1.70 +
    1.71 +    function isProp(obj, propName, value, desc) {
    1.72 +      try {
    1.73 +          is(obj[propName], value, "getting " + propName + " on " + desc);
    1.74 +          ok(propName in obj,
    1.75 +             propName + " on " + desc + " should exist");
    1.76 +          ok(Object.hasOwnProperty.call(obj, propName),
    1.77 +             propName + " on " + desc + " should exist");
    1.78 +      } catch (e) {
    1.79 +          ok(false, "getting " + propName + " on " + desc + " threw " + e);
    1.80 +      }
    1.81 +    }
    1.82 +    function isPropHidden(obj, propName, desc) {
    1.83 +      try {
    1.84 +          is(obj[propName], undefined,
    1.85 +             "getting " + propName + " on " + desc + " should return undefined");
    1.86 +          ok(!(propName in obj),
    1.87 +             propName + " on " + desc + " should act as if it doesn't exist");
    1.88 +          ok(!Object.hasOwnProperty.call(obj, propName),
    1.89 +             propName + " on " + desc + " should act as if it doesn't exist");
    1.90 +      } catch (e) {
    1.91 +          ok(false, "getting " + propName + " on " + desc + " threw " + e);
    1.92 +      }
    1.93 +    }
    1.94 +
    1.95 +    const PROPS_TO_TEST = ['foo', 'bar', 'prototype'];
    1.96 +
    1.97 +    var empty = {};
    1.98 +    var nonempty = {foo: 42, bar: 33};
    1.99 +    is(getCOW(empty).foo, undefined,
   1.100 +       "shouldn't throw when accessing exposed properties that doesn't exist");
   1.101 +
   1.102 +    PROPS_TO_TEST.forEach(function(name) {
   1.103 +        isPropHidden(getCOW(nonempty), name, "object without exposedProps");
   1.104 +    });
   1.105 +
   1.106 +    // Test function objects without __exposedProps__
   1.107 +    var func = function(x) { return 42; };
   1.108 +    func.foo = "foo property";
   1.109 +    var funcCOW = getCOW(func);
   1.110 +    PROPS_TO_TEST.forEach(function(name) {
   1.111 +        isPropHidden(funcCOW, name, "function without exposedProps");
   1.112 +    });
   1.113 +    is([name for (name in funcCOW)].length, 0,
   1.114 +       "function without exposedProps shouldn't have any properties");
   1.115 +    is(funcCOW(), 42, "COW without exposedProps should still be callable");
   1.116 +
   1.117 +    // Test function objects with __exposedProps__
   1.118 +    var func = function(x) { return 42; };
   1.119 +    func.foo = "foo property";
   1.120 +    func.__exposedProps__ = { foo: "r" };
   1.121 +    var funcCOWr = getCOW(func);
   1.122 +    PROPS_TO_TEST.forEach(function(name) {
   1.123 +        if (name == "foo") {
   1.124 +            isProp(funcCOWr, name, "foo property",
   1.125 +                   "function with exposedProps");
   1.126 +        }
   1.127 +        else {
   1.128 +            isPropHidden(funcCOWr, name, "function with exposedProps");
   1.129 +        }
   1.130 +    });
   1.131 +    is([name for (name in funcCOWr)].length, 1,
   1.132 +       "function with exposedProps should only enumerate exposed props");
   1.133 +    is([name for (name in funcCOWr)][0], "foo",
   1.134 +       "function with exposedProps should only enumerate exposed props");
   1.135 +    is(funcCOWr(), 42, "COW with exposedProps should be callable");
   1.136 +
   1.137 +    // Test function objects with __exposedProps__
   1.138 +    var func = function(x) { return 42; };
   1.139 +    func.foo = "foo property";
   1.140 +    func.__exposedProps__ = { foo: "r", bar: "r" };
   1.141 +    var funcCOWr2 = getCOW(func);
   1.142 +    PROPS_TO_TEST.forEach(function(name) {
   1.143 +        if (name == "foo") {
   1.144 +            isProp(funcCOWr2, name, "foo property",
   1.145 +                   "function with more exposedProps");
   1.146 +        }
   1.147 +        else {
   1.148 +            isPropHidden(funcCOWr2, name, "function with more exposedProps");
   1.149 +        }
   1.150 +    });
   1.151 +    is([name for (name in funcCOWr2)].length, 1,
   1.152 +       "function with exposedProps should only enumerate exposed props");
   1.153 +    is([name for (name in funcCOWr2)][0], "foo",
   1.154 +       "function with exposedProps should only enumerate exposed props");
   1.155 +
   1.156 +    // Test object with empty exposedProps
   1.157 +    var strict = { __exposedProps__: {}, foo: "foo property" };
   1.158 +    var strictCOW = getCOW(strict);
   1.159 +    PROPS_TO_TEST.forEach(function(name) {
   1.160 +        isPropHidden(strictCOW, name, "object with empty exposedProps");
   1.161 +    });
   1.162 +    is([name for (name in strictCOW)].length, 0,
   1.163 +       "object with empty exposedProps shouldn't have any properties");
   1.164 +
   1.165 +    // Test object with one exposed property
   1.166 +    var strict = { __exposedProps__: { foo: "r" }, foo: "foo property" };
   1.167 +    var strictCOWr = getCOW(strict);
   1.168 +    PROPS_TO_TEST.forEach(function(name) {
   1.169 +        if (name == "foo") {
   1.170 +            isProp(strictCOWr, name, "foo property",
   1.171 +                   "object with exposed 'foo'");
   1.172 +        }
   1.173 +        else {
   1.174 +            isPropHidden(strictCOW, name, "object with exposed 'foo'");
   1.175 +        }
   1.176 +    });
   1.177 +    is([name for (name in strictCOWr)].length, 1,
   1.178 +       "object with exposedProps only enumerate exposed props");
   1.179 +    is([name for (name in strictCOWr)][0], "foo",
   1.180 +       "object with exposedProps only enumerate exposed props");
   1.181 +
   1.182 +    // Test writable property
   1.183 +    var writable = getCOW({ __exposedProps__: {foo: 'w'}});
   1.184 +    try {
   1.185 +        ok(!("foo" in writable),
   1.186 +           "non-existing write-only property shouldn't exist");
   1.187 +        writable.foo = 5;
   1.188 +        is(chromeGet(writable, "foo"), 5, "writing to a write-only exposed prop works");
   1.189 +        todo("foo" in writable,
   1.190 +             "existing write-only property should exist");
   1.191 +    } catch (e) {
   1.192 +        ok(false, "writing to a write-only exposed prop shouldn't throw " + e);
   1.193 +    }
   1.194 +    try {
   1.195 +        writable.foo;
   1.196 +        todo(false, "reading from a write-only exposed prop should throw");
   1.197 +    } catch (e) {
   1.198 +        todo(/Permission denied/.test(e),
   1.199 +             "reading from a write-only exposed prop should throw");
   1.200 +    }
   1.201 +    try {
   1.202 +        delete writable.foo;
   1.203 +        is(chromeGet(writable, "foo"), undefined,
   1.204 +           "deleting a write-only exposed prop works");
   1.205 +    } catch (e) {
   1.206 +        ok(false, "deleting a write-only exposed prop shouldn't throw " + e);
   1.207 +    }
   1.208 +
   1.209 +    // Test readable property
   1.210 +    var readable = { __exposedProps__: {foo: 'r'},
   1.211 +                     foo: 5,
   1.212 +                     bar: 6 };
   1.213 +    try {
   1.214 +        isProp(getCOW(readable), "foo", 5,
   1.215 +               "reading from a readable exposed prop works");
   1.216 +    } catch (e) {
   1.217 +        ok(false, "reading from a readable exposed prop shouldn't throw " + e);
   1.218 +    }
   1.219 +    try {
   1.220 +        getCOW(readable).foo = 1;
   1.221 +        ok(false, "writing to a read-only exposed prop should fail");
   1.222 +    } catch (e) {
   1.223 +        ok(/Permission denied/.test(e),
   1.224 +           "writing to a read-only exposed prop should fail");
   1.225 +    }
   1.226 +    try {
   1.227 +        delete getCOW(readable).foo;
   1.228 +        ok(false, "deleting a read-only exposed prop shouldn't work");
   1.229 +    } catch (e) {
   1.230 +        ok(/Permission denied/.test(e),
   1.231 +           "deleting a read-only exposed prop should throw error");
   1.232 +    }
   1.233 +
   1.234 +    try {
   1.235 +        var props = [name for (name in getCOW(readable))];
   1.236 +        is(props.length, 1, "COW w/ one exposed prop should enumerate once");
   1.237 +        is(props[0], 'foo', "COW w/ one exposed prop should enumerate it");
   1.238 +    } catch (e) {
   1.239 +        ok(false, "COW w/ a readable prop should not raise exc " +
   1.240 +                  "on enumeration: " + e);
   1.241 +    }
   1.242 +
   1.243 +    // Test read/write property
   1.244 +    var readwrite = getCOW({ __exposedProps__: {foo: 'rw'}});
   1.245 +    try {
   1.246 +        ok(!("foo" in readwrite),
   1.247 +           "non-existing readwrite property shouldn't exist");
   1.248 +        readwrite.foo = 5;
   1.249 +        is(readwrite.foo, 5, "writing to a readwrite exposed prop looks like it worked");
   1.250 +        is(chromeGet(readwrite, "foo"), 5, "writing to a readwrite exposed prop works");
   1.251 +        ok("foo" in readwrite,
   1.252 +           "existing readwrite property should exist");
   1.253 +    } catch (e) {
   1.254 +        ok(false, "writing to a readwrite exposed prop shouldn't throw " + e);
   1.255 +    }
   1.256 +    try {
   1.257 +        delete readwrite.foo;
   1.258 +        is(readwrite.foo, undefined, "deleting readwrite prop looks like it worked");
   1.259 +        ok(!("foo" in readwrite), "deleting readwrite prop looks like it really worked");
   1.260 +        is(chromeGet(readwrite, "foo"), undefined,
   1.261 +           "deleting a readwrite exposed prop works");
   1.262 +    } catch (e) {
   1.263 +        ok(false, "deleting a readwrite exposed prop shouldn't throw " + e);
   1.264 +    }
   1.265 +
   1.266 +    // Readables and functions
   1.267 +    try {
   1.268 +        var COWFunc = getCOW((function() { return 5; }));
   1.269 +        is(COWFunc(), 5, "COWed functions should be callable");
   1.270 +    } catch (e) {
   1.271 +        todo(false, "COWed functions should not raise " + e);
   1.272 +    }
   1.273 +    try {
   1.274 +        var objWithFunc = {__exposedProps__: {foo: 'r'},
   1.275 +                           foo: function foo() { return 5; }};
   1.276 +        is(getCOW((objWithFunc)).foo(), 5,
   1.277 +           "Readable function exposed props should be callable");
   1.278 +    } catch (e) {
   1.279 +        ok(false, "Readable function exposed props should be callable" + e);
   1.280 +    }
   1.281 +
   1.282 +    // Readables with getters
   1.283 +    var obj = {
   1.284 +        get prop() { return { __exposedProps__: {}, test: "FAIL" } },
   1.285 +        __exposedProps__: {prop: 'r'}
   1.286 +    };
   1.287 +    is(getCOW(obj).prop.test, undefined, "getting prop.test shouldn't return anything");
   1.288 +    ok(!("test" in getCOW(obj).prop), "getting prop.test shouldn't return anything");
   1.289 +
   1.290 +    // Alien objects
   1.291 +    try {
   1.292 +        is(alienObject.funProp(1), 2,
   1.293 +           "COWs wrapping objects from different principals should work");
   1.294 +    } catch (e) {
   1.295 +        ok(false, "COWs wrapping objs from different principals " +
   1.296 +                  "shouldn't throw " + e);
   1.297 +    }
   1.298 +
   1.299 +    try {
   1.300 +        is(alienObject.funProp(1), 2,
   1.301 +           "COWs wrapping objs from different principals should work twice");
   1.302 +    } catch (e) {
   1.303 +        ok(false, "COWs wrapping objs from different principals " +
   1.304 +                  "shouldn't throw on second access but not first: " + e);
   1.305 +    }
   1.306 +}
   1.307 +
   1.308 +// Decompile the COW test suite, re-evaluate it in the sandbox and execute it.
   1.309 +Cu.evalInSandbox('(' + uneval(COWTests) + ')()', sandbox);
   1.310 +
   1.311 +// Test that COWed objects passing from content to chrome get unwrapped.
   1.312 +function returnCOW() {
   1.313 +    return getCOW({__exposedProps__: {},
   1.314 +                  bar: 6});
   1.315 +}
   1.316 +
   1.317 +var unwrapped = Cu.evalInSandbox(
   1.318 +    '(' + uneval(returnCOW) + ')()',
   1.319 +    sandbox
   1.320 +);
   1.321 +
   1.322 +try {
   1.323 +    is(unwrapped.bar, 6,
   1.324 +       "COWs should be unwrapped when entering chrome space");
   1.325 +} catch (e) {
   1.326 +    todo(false, "COWs should be unwrapped when entering chrome space, " +
   1.327 +                "not raise " + e);
   1.328 +}
   1.329 +  ]]></script>
   1.330 +</window>

mercurial