summaryrefslogtreecommitdiffstats
path: root/js/xpconnect/tests/unit/test_defineModuleGetter.js
blob: 34acceb853187e01880bf210c98fcbc0c5cbeb75 (plain)
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/AppConstants.jsm", temp);

  let obj = {};
  let child = Object.create(obj);
  let sealed = Object.seal(Object.create(obj));


  // Test valid import

  ChromeUtils.defineModuleGetter(obj, "AppConstants",
                                 "resource://gre/modules/AppConstants.jsm");

  assertIsGetter(obj, "AppConstants");
  equal(child.AppConstants, temp.AppConstants, "Getter works on descendent object");
  assertIsValue(child, "AppConstants", temp.AppConstants);
  assertIsGetter(obj, "AppConstants");

  Assert.throws(() => sealed.AppConstants, /Object is not extensible/,
                "Cannot access lazy getter from sealed object");
  Assert.throws(() => sealed.AppConstants = null, /Object is not extensible/,
                "Cannot access lazy setter from sealed object");
  assertIsGetter(obj, "AppConstants");

  equal(obj.AppConstants, temp.AppConstants, "Getter works on object");
  assertIsValue(obj, "AppConstants", temp.AppConstants);


  // Test overwriting via setter

  child = Object.create(obj);

  ChromeUtils.defineModuleGetter(obj, "AppConstants",
                                 "resource://gre/modules/AppConstants.jsm");

  assertIsGetter(obj, "AppConstants");

  child.AppConstants = "foo";
  assertIsValue(child, "AppConstants", "foo");
  assertIsGetter(obj, "AppConstants");

  obj.AppConstants = "foo";
  assertIsValue(obj, "AppConstants", "foo");


  // Test import missing property

  ChromeUtils.defineModuleGetter(obj, "meh",
                                 "resource://gre/modules/AppConstants.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");
});