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
|
"use strict";
function assertIsGetter(obj, prop) {
let desc = Object.getOwnPropertyDescriptor(obj, prop);
ok(desc, `Property ${prop} exists on object`);
equal(typeof desc.get, "function", `Getter function exists for property ${prop}`);
equal(typeof desc.set, "function", `Setter function exists for property ${prop}`);
equal(desc.enumerable, true, `Property ${prop} is enumerable`);
equal(desc.configurable, true, `Property ${prop} is configurable`);
}
function assertIsValue(obj, prop, value) {
let desc = Object.getOwnPropertyDescriptor(obj, prop);
ok(desc, `Property ${prop} exists on object`);
ok("value" in desc, `${prop} is a data property`);
equal(desc.value, value, `${prop} has the expected value`);
equal(desc.enumerable, true, `Property ${prop} is enumerable`);
equal(desc.configurable, true, `Property ${prop} is configurable`);
equal(desc.writable, true, `Property ${prop} is writable`);
}
add_task(async function() {
let temp = {};
ChromeUtils.import("resource://gre/modules/Services.jsm", temp);
let obj = {};
let child = Object.create(obj);
let sealed = Object.seal(Object.create(obj));
// Test valid import
ChromeUtils.defineModuleGetter(obj, "Services",
"resource://gre/modules/Services.jsm");
assertIsGetter(obj, "Services");
equal(child.Services, temp.Services, "Getter works on descendent object");
assertIsValue(child, "Services", temp.Services);
assertIsGetter(obj, "Services");
Assert.throws(() => sealed.Services, /Object is not extensible/,
"Cannot access lazy getter from sealed object");
Assert.throws(() => sealed.Services = null, /Object is not extensible/,
"Cannot access lazy setter from sealed object");
assertIsGetter(obj, "Services");
equal(obj.Services, temp.Services, "Getter works on object");
assertIsValue(obj, "Services", temp.Services);
// Test overwriting via setter
child = Object.create(obj);
ChromeUtils.defineModuleGetter(obj, "Services",
"resource://gre/modules/Services.jsm");
assertIsGetter(obj, "Services");
child.Services = "foo";
assertIsValue(child, "Services", "foo");
assertIsGetter(obj, "Services");
obj.Services = "foo";
assertIsValue(obj, "Services", "foo");
// Test import missing property
ChromeUtils.defineModuleGetter(obj, "meh",
"resource://gre/modules/Services.jsm");
assertIsGetter(obj, "meh");
equal(obj.meh, undefined, "Missing property returns undefined");
assertIsValue(obj, "meh", undefined);
// Test import broken module
ChromeUtils.defineModuleGetter(obj, "broken",
"resource://test/bogus_exports_type.jsm");
assertIsGetter(obj, "broken");
let errorPattern = /EXPORTED_SYMBOLS is not an array/;
Assert.throws(() => child.broken, errorPattern,
"Broken import throws on child");
Assert.throws(() => child.broken, errorPattern,
"Broken import throws on child again");
Assert.throws(() => sealed.broken, errorPattern,
"Broken import throws on sealed child");
Assert.throws(() => obj.broken, errorPattern,
"Broken import throws on object");
assertIsGetter(obj, "broken");
// Test import missing module
ChromeUtils.defineModuleGetter(obj, "missing",
"resource://test/does_not_exist.jsm");
assertIsGetter(obj, "missing");
Assert.throws(() => obj.missing, /NS_ERROR_FILE_NOT_FOUND/,
"missing import throws on object");
assertIsGetter(obj, "missing");
// Test overwriting broken import via setter
assertIsGetter(obj, "broken");
obj.broken = "foo";
assertIsValue(obj, "broken", "foo");
});
|