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>