test_cows.xhtml (6763B)
1 <?xml version="1.0"?> 2 <?xml-stylesheet href="chrome://global/skin" type="text/css"?> 3 <?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" 4 type="text/css"?> 5 <!-- 6 https://bugzilla.mozilla.org/show_bug.cgi?id=500931 7 --> 8 <window title="Mozilla Bug 522764" 9 xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"> 10 <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> 11 12 <!-- test results are displayed in the html:body --> 13 <body xmlns="http://www.w3.org/1999/xhtml"> 14 <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=522764 " 15 target="_blank">Mozilla Bug 522764 </a> 16 </body> 17 18 <!-- test code goes here --> 19 <script type="application/javascript"><![CDATA[ 20 add_task(async () => { 21 var sandbox = new Cu.Sandbox("about:blank"); 22 23 await SpecialPowers.pushPrefEnv({"set": [["security.allow_eval_with_system_principal", 24 true]]}); 25 26 /* eslint-disable no-eval */ 27 28 function getCOW(x) { 29 if (typeof x != 'object' && typeof x != 'function') 30 return x; 31 x = Cu.waiveXrays(x); 32 var rval = {}; 33 if (typeof x == "function") 34 rval = eval(`(${x.toString()})`); 35 for (var i in x) { 36 if (x.__lookupGetter__(i)) 37 rval.__defineGetter__(i, eval(`(${x.__lookupGetter__(i).toString()})`)) 38 else 39 rval[i] = getCOW(x[i]); 40 } 41 return rval; 42 } 43 44 // Give the sandbox a way to create ChromeObjectWrapped objects. 45 sandbox.getCOW = getCOW; 46 47 // Define test API functions in the sandbox. 48 const TEST_API = ['is', 'isnot', 'ok', 'todo_is', 'todo_isnot', 'todo']; 49 TEST_API.forEach(function(name) { sandbox[name] = window[name]; }); 50 51 sandbox.chromeGet = function (obj, prop) { return obj[prop]; }; 52 53 function COWTests() { 54 function getNames(cow) { 55 let names = []; 56 for (let name in cow) { 57 names.push(name); 58 } 59 return names; 60 } 61 62 // This function is actually stringified and run inside a 63 // sandbox with content privileges. 64 65 // TODO: This could use some refactoring; creating helper 66 // functions like assertIsWritable(myObj, 'someproperty') might 67 // be useful. 68 69 function isPropHidden(obj, propName, desc) { 70 try { 71 is(obj[propName], undefined, 72 "getting " + propName + " on " + desc + " should return undefined"); 73 ok(!(propName in obj), 74 propName + " on " + desc + " should act as if it doesn't exist"); 75 ok(!Object.hasOwnProperty.call(obj, propName), 76 propName + " on " + desc + " should act as if it doesn't exist"); 77 } catch (e) { 78 ok(false, "getting " + propName + " on " + desc + " threw " + e); 79 } 80 } 81 82 const PROPS_TO_TEST = ['foo', 'bar', 'prototype']; 83 84 var empty = {}; 85 var nonempty = {foo: 42, bar: 33}; 86 is(getCOW(empty).foo, undefined, 87 "shouldn't throw when accessing exposed properties that don't exist"); 88 89 PROPS_TO_TEST.forEach(function(name) { 90 isPropHidden(getCOW(nonempty), name, "object without exposedProps"); 91 }); 92 93 // Test function objects. 94 var func = function() { return 42; }; 95 func.foo = "foo property"; 96 var funcCOW = getCOW(func); 97 try { 98 funcCOW.foo; 99 ok(false, 'Functions are no longer COWable'); 100 } catch (e) { 101 ok(/denied|insecure/.test(e), 'Functions are no longer COWable'); 102 } 103 is(funcCOW(), 42, "Chrome functions should be callable"); 104 105 // Test writable property 106 var writable = getCOW({}); 107 try { 108 ok(!("foo" in writable), 109 "non-existing write-only property shouldn't exist"); 110 writable.foo = 5; 111 ok(false, "writing to a write-only exposed prop should throw"); 112 } catch (e) { 113 ok(/Permission denied/.test(e), 114 "writing to a write-only exposed prop should throw the right error"); 115 } 116 is(writable.foo, undefined, 117 "reading from a write-only exposed prop should return undefined"); 118 try { 119 delete writable.foo; 120 ok(false, "deleting a write-only exposed prop should throw"); 121 } catch (e) { 122 ok(true, "deleting a write-only exposed prop should throw " + e); 123 } 124 125 // Test readable property 126 var readable = { foo: 5, 127 bar: 6 }; 128 try { 129 isPropHidden(getCOW(readable), "foo", undefined, 130 "reading from a readable exposed prop shouldn't work"); 131 } catch (e) { 132 ok(false, "reading from a readable exposed prop shouldn't throw " + e); 133 } 134 try { 135 getCOW(readable).foo = 1; 136 ok(false, "writing to a read-only exposed prop should fail"); 137 } catch (e) { 138 ok(/Permission denied/.test(e), 139 "writing to a read-only exposed prop should fail"); 140 } 141 try { 142 delete getCOW(readable).foo; 143 ok(false, "deleting a read-only exposed prop shouldn't work"); 144 } catch (e) { 145 ok(/Permission denied/.test(e), 146 "deleting a read-only exposed prop should throw error"); 147 } 148 149 try { 150 var props = getNames(getCOW(readable)); 151 is(props.length, 0, "COW w/ one exposed prop should not enumerate"); 152 } catch (e) { 153 ok(false, "COW w/ a readable prop should not raise exc " + 154 "on enumeration: " + e); 155 } 156 157 // Test read/write property 158 var readwrite = getCOW({}); 159 try { 160 ok(!("foo" in readwrite), 161 "non-existing readwrite property shouldn't exist"); 162 readwrite.foo = 5; 163 ok(false, "writing to a readwrite exposed prop should throw"); 164 } catch (e) { 165 ok(/Permission denied/.test(e), 166 "writing to a readwrite exposed prop should throw the right error"); 167 } 168 try { 169 delete readwrite.foo; 170 ok(false, "deleting a readwrite prop should throw"); 171 } catch (e) { 172 ok(/Permission denied/.test(e), 173 "deleting a readwrite exposed prop should throw the right error"); 174 } 175 176 // Readables and functions 177 try { 178 var COWFunc = getCOW((function() { return 5; })); 179 is(COWFunc(), 5, "COWed functions should be callable"); 180 } catch (e) { 181 todo(false, "COWed functions should not raise " + e); 182 } 183 } 184 185 // Stringify the COW test suite and directly evaluate it in the sandbox. 186 Cu.evalInSandbox('(' + COWTests.toString() + ')()', sandbox); 187 188 // Test that COWed objects passing from content to chrome get unwrapped. 189 function returnCOW() { 190 return getCOW({bar: 6}); 191 } 192 193 var unwrapped = Cu.evalInSandbox( 194 '(' + returnCOW.toString() + ')()', 195 sandbox 196 ); 197 198 try { 199 is(unwrapped.bar, 6, 200 "COWs should be unwrapped when entering chrome space"); 201 } catch (e) { 202 todo(false, "COWs should be unwrapped when entering chrome space, " + 203 "not raise " + e); 204 } 205 }); 206 ]]></script> 207 </window>