1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
|
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=500931
-->
<window title="Mozilla Bug 522764"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=522764 "
target="_blank">Mozilla Bug 522764 </a>
</body>
<!-- test code goes here -->
<script type="application/javascript"><![CDATA[
var Ci = Components.interfaces;
var Cu = Components.utils;
var sandbox = new Cu.Sandbox("about:blank");
var test_utils = window.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils);
function getCOW(x) {
if (typeof x != 'object' && typeof x != 'function')
return x;
x = Cu.waiveXrays(x);
var rval = {};
if (typeof x == "function")
rval = eval(uneval(x));
for (var i in x) {
if (x.__lookupGetter__(i))
rval.__defineGetter__(i, eval(uneval(x.__lookupGetter__(i))))
else
rval[i] = getCOW(x[i]);
}
return rval;
}
// Give the sandbox a way to create ChromeObjectWrapped objects.
sandbox.getCOW = getCOW;
// Define test API functions in the sandbox.
const TEST_API = ['is', 'isnot', 'ok', 'todo_is', 'todo_isnot', 'todo'];
TEST_API.forEach(function(name) { sandbox[name] = window[name]; });
sandbox.alienObject = {
__exposedProps__: {funProp: 'r'},
funProp: function foo(x) {
return x + 1;
}
};
sandbox.chromeGet = function (obj, prop) { return obj[prop]; };
function COWTests() {
function getNames(cow) {
let names = [];
for (let name in cow) {
names.push(name);
}
return names;
}
// This function is actually decompiled and run inside a
// sandbox with content privileges.
// TODO: This could use some refactoring; creating helper
// functions like assertIsWritable(myObj, 'someproperty') might
// be useful.
function isProp(obj, propName, value, desc) {
try {
is(obj[propName], value, "getting " + propName + " on " + desc);
ok(propName in obj,
propName + " on " + desc + " should exist");
ok(Object.hasOwnProperty.call(obj, propName),
propName + " on " + desc + " should exist");
} catch (e) {
ok(false, "getting " + propName + " on " + desc + " threw " + e);
}
}
function isPropHidden(obj, propName, desc) {
try {
is(obj[propName], undefined,
"getting " + propName + " on " + desc + " should return undefined");
ok(!(propName in obj),
propName + " on " + desc + " should act as if it doesn't exist");
ok(!Object.hasOwnProperty.call(obj, propName),
propName + " on " + desc + " should act as if it doesn't exist");
} catch (e) {
ok(false, "getting " + propName + " on " + desc + " threw " + e);
}
}
const PROPS_TO_TEST = ['foo', 'bar', 'prototype'];
var empty = {};
var nonempty = {foo: 42, bar: 33};
is(getCOW(empty).foo, undefined,
"shouldn't throw when accessing exposed properties that doesn't exist");
PROPS_TO_TEST.forEach(function(name) {
isPropHidden(getCOW(nonempty), name, "object without exposedProps");
});
// Test function objects.
var func = function(x) { return 42; };
func.__exposedProps__ = { foo: "r" };
func.foo = "foo property";
var funcCOW = getCOW(func);
try {
funcCOW.foo;
ok(false, 'Functions are no longer COWable');
} catch (e) {
ok(/denied|insecure/.test(e), 'Functions are no longer COWable');
}
is(funcCOW(), 42, "Chrome functions should be callable");
// Test object with empty exposedProps
var strict = { __exposedProps__: {}, foo: "foo property" };
var strictCOW = getCOW(strict);
PROPS_TO_TEST.forEach(function(name) {
isPropHidden(strictCOW, name, "object with empty exposedProps");
});
is(getNames(strictCOW).length, 0,
"object with empty exposedProps shouldn't have any properties");
// Test object with one exposed property
var strict = { __exposedProps__: { foo: "r" }, foo: "foo property" };
var strictCOWr = getCOW(strict);
PROPS_TO_TEST.forEach(function(name) {
if (name == "foo") {
isProp(strictCOWr, name, "foo property",
"object with exposed 'foo'");
}
else {
isPropHidden(strictCOW, name, "object with exposed 'foo'");
}
});
is(getNames(strictCOWr).length, 1,
"object with exposedProps only enumerate exposed props");
is(getNames(strictCOWr)[0], "foo",
"object with exposedProps only enumerate exposed props");
// Test writable property
var writable = getCOW({ __exposedProps__: {foo: 'w'}});
try {
ok(!("foo" in writable),
"non-existing write-only property shouldn't exist");
writable.foo = 5;
is(chromeGet(writable, "foo"), 5, "writing to a write-only exposed prop works");
todo("foo" in writable,
"existing write-only property should exist");
} catch (e) {
ok(false, "writing to a write-only exposed prop shouldn't throw " + e);
}
try {
writable.foo;
todo(false, "reading from a write-only exposed prop should throw");
} catch (e) {
todo(/Permission denied/.test(e),
"reading from a write-only exposed prop should throw");
}
try {
delete writable.foo;
is(chromeGet(writable, "foo"), undefined,
"deleting a write-only exposed prop works");
} catch (e) {
ok(false, "deleting a write-only exposed prop shouldn't throw " + e);
}
// Test readable property
var readable = { __exposedProps__: {foo: 'r'},
foo: 5,
bar: 6 };
try {
isProp(getCOW(readable), "foo", 5,
"reading from a readable exposed prop works");
} catch (e) {
ok(false, "reading from a readable exposed prop shouldn't throw " + e);
}
try {
getCOW(readable).foo = 1;
ok(false, "writing to a read-only exposed prop should fail");
} catch (e) {
ok(/Permission denied/.test(e),
"writing to a read-only exposed prop should fail");
}
try {
delete getCOW(readable).foo;
ok(false, "deleting a read-only exposed prop shouldn't work");
} catch (e) {
ok(/Permission denied/.test(e),
"deleting a read-only exposed prop should throw error");
}
try {
var props = getNames(getCOW(readable));
is(props.length, 1, "COW w/ one exposed prop should enumerate once");
is(props[0], 'foo', "COW w/ one exposed prop should enumerate it");
} catch (e) {
ok(false, "COW w/ a readable prop should not raise exc " +
"on enumeration: " + e);
}
// Test read/write property
var readwrite = getCOW({ __exposedProps__: {foo: 'rw'}});
try {
ok(!("foo" in readwrite),
"non-existing readwrite property shouldn't exist");
readwrite.foo = 5;
is(readwrite.foo, 5, "writing to a readwrite exposed prop looks like it worked");
is(chromeGet(readwrite, "foo"), 5, "writing to a readwrite exposed prop works");
ok("foo" in readwrite,
"existing readwrite property should exist");
} catch (e) {
ok(false, "writing to a readwrite exposed prop shouldn't throw " + e);
}
try {
delete readwrite.foo;
is(readwrite.foo, undefined, "deleting readwrite prop looks like it worked");
ok(!("foo" in readwrite), "deleting readwrite prop looks like it really worked");
is(chromeGet(readwrite, "foo"), undefined,
"deleting a readwrite exposed prop works");
} catch (e) {
ok(false, "deleting a readwrite exposed prop shouldn't throw " + e);
}
// Readables and functions
try {
var COWFunc = getCOW((function() { return 5; }));
is(COWFunc(), 5, "COWed functions should be callable");
} catch (e) {
todo(false, "COWed functions should not raise " + e);
}
}
// Decompile the COW test suite, re-evaluate it in the sandbox and execute it.
Cu.evalInSandbox('(' + uneval(COWTests) + ')()', sandbox);
// Test that COWed objects passing from content to chrome get unwrapped.
function returnCOW() {
return getCOW({__exposedProps__: {},
bar: 6});
}
var unwrapped = Cu.evalInSandbox(
'(' + uneval(returnCOW) + ')()',
sandbox
);
try {
is(unwrapped.bar, 6,
"COWs should be unwrapped when entering chrome space");
} catch (e) {
todo(false, "COWs should be unwrapped when entering chrome space, " +
"not raise " + e);
}
]]></script>
</window>
|