|
1 # This Source Code Form is subject to the terms of the Mozilla Public |
|
2 # License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
4 |
|
5 |
|
6 import unittest |
|
7 from StringIO import StringIO |
|
8 from cuddlefish.manifest import scan_module |
|
9 |
|
10 class Extra: |
|
11 def failUnlessKeysAre(self, d, keys): |
|
12 self.failUnlessEqual(sorted(d.keys()), sorted(keys)) |
|
13 |
|
14 class Require(unittest.TestCase, Extra): |
|
15 def scan(self, text): |
|
16 lines = StringIO(text).readlines() |
|
17 requires, problems, locations = scan_module("fake.js", lines) |
|
18 self.failUnlessEqual(problems, False) |
|
19 return requires |
|
20 |
|
21 def scan_locations(self, text): |
|
22 lines = StringIO(text).readlines() |
|
23 requires, problems, locations = scan_module("fake.js", lines) |
|
24 self.failUnlessEqual(problems, False) |
|
25 return requires, locations |
|
26 |
|
27 def test_modules(self): |
|
28 mod = """var foo = require('one');""" |
|
29 requires = self.scan(mod) |
|
30 self.failUnlessKeysAre(requires, ["one"]) |
|
31 |
|
32 mod = """var foo = require(\"one\");""" |
|
33 requires = self.scan(mod) |
|
34 self.failUnlessKeysAre(requires, ["one"]) |
|
35 |
|
36 mod = """var foo=require( 'one' ) ; """ |
|
37 requires = self.scan(mod) |
|
38 self.failUnlessKeysAre(requires, ["one"]) |
|
39 |
|
40 mod = """var foo = require('o'+'ne'); // tricky, denied""" |
|
41 requires = self.scan(mod) |
|
42 self.failUnlessKeysAre(requires, []) |
|
43 |
|
44 mod = """require('one').immediately.do().stuff();""" |
|
45 requires, locations = self.scan_locations(mod) |
|
46 self.failUnlessKeysAre(requires, ["one"]) |
|
47 self.failUnlessEqual(locations, {"one": 1}) |
|
48 |
|
49 # these forms are commented out, and thus ignored |
|
50 |
|
51 mod = """// var foo = require('one');""" |
|
52 requires = self.scan(mod) |
|
53 self.failUnlessKeysAre(requires, []) |
|
54 |
|
55 mod = """/* var foo = require('one');""" |
|
56 requires = self.scan(mod) |
|
57 self.failUnlessKeysAre(requires, []) |
|
58 |
|
59 mod = """ * var foo = require('one');""" |
|
60 requires = self.scan(mod) |
|
61 self.failUnlessKeysAre(requires, []) |
|
62 |
|
63 mod = """ ' var foo = require('one');""" |
|
64 requires = self.scan(mod) |
|
65 self.failUnlessKeysAre(requires, ["one"]) |
|
66 |
|
67 mod = """ \" var foo = require('one');""" |
|
68 requires = self.scan(mod) |
|
69 self.failUnlessKeysAre(requires, ["one"]) |
|
70 |
|
71 # multiple requires |
|
72 |
|
73 mod = """const foo = require('one'); |
|
74 const foo = require('two');""" |
|
75 requires, locations = self.scan_locations(mod) |
|
76 self.failUnlessKeysAre(requires, ["one", "two"]) |
|
77 self.failUnlessEqual(locations["one"], 1) |
|
78 self.failUnlessEqual(locations["two"], 2) |
|
79 |
|
80 mod = """const foo = require('repeated'); |
|
81 const bar = require('repeated'); |
|
82 const baz = require('repeated');""" |
|
83 requires, locations = self.scan_locations(mod) |
|
84 self.failUnlessKeysAre(requires, ["repeated"]) |
|
85 self.failUnlessEqual(locations["repeated"], 1) # first occurrence |
|
86 |
|
87 mod = """const foo = require('one'); const foo = require('two');""" |
|
88 requires = self.scan(mod) |
|
89 self.failUnlessKeysAre(requires, ["one", "two"]) |
|
90 |
|
91 # define calls |
|
92 |
|
93 mod = """define('one', ['two', 'numbers/three'], function(t, th) {});""" |
|
94 requires = self.scan(mod) |
|
95 self.failUnlessKeysAre(requires, ["two", "numbers/three"]) |
|
96 |
|
97 mod = """define( |
|
98 ['odd', |
|
99 "numbers/four"], function() {});""" |
|
100 requires = self.scan(mod) |
|
101 self.failUnlessKeysAre(requires, ["odd", "numbers/four"]) |
|
102 |
|
103 mod = """define(function(require, exports, module) { |
|
104 var a = require("some/module/a"), |
|
105 b = require('b/v1'); |
|
106 exports.a = a; |
|
107 //This is a fakeout: require('bad'); |
|
108 /* And another var bad = require('bad2'); */ |
|
109 require('foo').goFoo(); |
|
110 });""" |
|
111 requires = self.scan(mod) |
|
112 self.failUnlessKeysAre(requires, ["some/module/a", "b/v1", "foo"]) |
|
113 |
|
114 mod = """define ( |
|
115 "foo", |
|
116 ["bar"], function (bar) { |
|
117 var me = require("me"); |
|
118 } |
|
119 )""" |
|
120 requires = self.scan(mod) |
|
121 self.failUnlessKeysAre(requires, ["bar", "me"]) |
|
122 |
|
123 mod = """define(['se' + 'ven', 'eight', nine], function () {});""" |
|
124 requires = self.scan(mod) |
|
125 self.failUnlessKeysAre(requires, ["eight"]) |
|
126 |
|
127 # async require calls |
|
128 |
|
129 mod = """require(['one'], function(one) {var o = require("one");});""" |
|
130 requires = self.scan(mod) |
|
131 self.failUnlessKeysAre(requires, ["one"]) |
|
132 |
|
133 mod = """require([ 'one' ], function(one) {var t = require("two");});""" |
|
134 requires = self.scan(mod) |
|
135 self.failUnlessKeysAre(requires, ["one", "two"]) |
|
136 |
|
137 mod = """require ( ['two', 'numbers/three'], function(t, th) {});""" |
|
138 requires = self.scan(mod) |
|
139 self.failUnlessKeysAre(requires, ["two", "numbers/three"]) |
|
140 |
|
141 mod = """require ( |
|
142 ["bar", "fa" + 'ke' ], function (bar) { |
|
143 var me = require("me"); |
|
144 // require("bad").doBad(); |
|
145 } |
|
146 )""" |
|
147 requires = self.scan(mod) |
|
148 self.failUnlessKeysAre(requires, ["bar", "me"]) |
|
149 |
|
150 def scan2(text, fn="fake.js"): |
|
151 stderr = StringIO() |
|
152 lines = StringIO(text).readlines() |
|
153 requires, problems, locations = scan_module(fn, lines, stderr) |
|
154 stderr.seek(0) |
|
155 return requires, problems, stderr.readlines() |
|
156 |
|
157 class Chrome(unittest.TestCase, Extra): |
|
158 |
|
159 def test_ignore_loader(self): |
|
160 # we specifically ignore the loader itself |
|
161 mod = """let {Cc,Ci} = require('chrome');""" |
|
162 requires, problems, err = scan2(mod, "blah/cuddlefish.js") |
|
163 self.failUnlessKeysAre(requires, ["chrome"]) |
|
164 self.failUnlessEqual(problems, False) |
|
165 self.failUnlessEqual(err, []) |
|
166 |
|
167 def test_chrome(self): |
|
168 mod = """let {Cc,Ci} = require('chrome');""" |
|
169 requires, problems, err = scan2(mod) |
|
170 self.failUnlessKeysAre(requires, ["chrome"]) |
|
171 self.failUnlessEqual(problems, False) |
|
172 self.failUnlessEqual(err, []) |
|
173 |
|
174 mod = """var foo = require('foo'); |
|
175 let {Cc,Ci} = require('chrome');""" |
|
176 requires, problems, err = scan2(mod) |
|
177 self.failUnlessKeysAre(requires, ["foo", "chrome"]) |
|
178 self.failUnlessEqual(problems, False) |
|
179 self.failUnlessEqual(err, []) |
|
180 |
|
181 mod = """let c = require('chrome');""" |
|
182 requires, problems, err = scan2(mod) |
|
183 self.failUnlessKeysAre(requires, ["chrome"]) |
|
184 self.failUnlessEqual(problems, False) |
|
185 self.failUnlessEqual(err, []) |
|
186 |
|
187 mod = """var foo = require('foo'); |
|
188 let c = require('chrome');""" |
|
189 requires, problems, err = scan2(mod) |
|
190 self.failUnlessKeysAre(requires, ["foo", "chrome"]) |
|
191 self.failUnlessEqual(problems, False) |
|
192 self.failUnlessEqual(err, []) |
|
193 |
|
194 def test_not_chrome(self): |
|
195 # from bug 596595 |
|
196 mod = r'soughtLines: new RegExp("^\\s*(\\[[0-9 .]*\\])?\\s*\\(\\((EE|WW)\\)|.* [Cc]hipsets?: \\)|\\s*Backtrace")' |
|
197 requires, problems, err = scan2(mod) |
|
198 self.failUnlessKeysAre(requires, []) |
|
199 self.failUnlessEqual((problems,err), (False, [])) |
|
200 |
|
201 def test_not_chrome2(self): |
|
202 # from bug 655788 |
|
203 mod = r"var foo = 'some stuff Cr';" |
|
204 requires, problems, err = scan2(mod) |
|
205 self.failUnlessKeysAre(requires, []) |
|
206 self.failUnlessEqual((problems,err), (False, [])) |
|
207 |
|
208 class BadChrome(unittest.TestCase, Extra): |
|
209 def test_bad_alias(self): |
|
210 # using Components.* gets you an error, with a message that teaches |
|
211 # you the correct approach. |
|
212 mod = """let Cc = Components.classes; |
|
213 let Cu = Components.utils; |
|
214 """ |
|
215 requires, problems, err = scan2(mod) |
|
216 self.failUnlessKeysAre(requires, []) |
|
217 self.failUnlessEqual(problems, True) |
|
218 self.failUnlessEqual(err[1], "The following lines from file fake.js:\n") |
|
219 self.failUnlessEqual(err[2], " 1: let Cc = Components.classes;\n") |
|
220 self.failUnlessEqual(err[3], " 2: let Cu = Components.utils;\n") |
|
221 self.failUnlessEqual(err[4], "use 'Components' to access chrome authority. To do so, you need to add a\n") |
|
222 self.failUnlessEqual(err[5], "line somewhat like the following:\n") |
|
223 self.failUnlessEqual(err[7], ' const {Cc,Cu} = require("chrome");\n') |
|
224 self.failUnlessEqual(err[9], "Then you can use any shortcuts to its properties that you import from the\n") |
|
225 |
|
226 def test_bad_misc(self): |
|
227 # If it looks like you're using something that doesn't have an alias, |
|
228 # the warning also suggests a better way. |
|
229 mod = """if (Components.isSuccessCode(foo)) |
|
230 """ |
|
231 requires, problems, err = scan2(mod) |
|
232 self.failUnlessKeysAre(requires, []) |
|
233 self.failUnlessEqual(problems, True) |
|
234 self.failUnlessEqual(err[1], "The following lines from file fake.js:\n") |
|
235 self.failUnlessEqual(err[2], " 1: if (Components.isSuccessCode(foo))\n") |
|
236 self.failUnlessEqual(err[3], "use 'Components' to access chrome authority. To do so, you need to add a\n") |
|
237 self.failUnlessEqual(err[4], "line somewhat like the following:\n") |
|
238 self.failUnlessEqual(err[6], ' const {components} = require("chrome");\n') |
|
239 self.failUnlessEqual(err[8], "Then you can use any shortcuts to its properties that you import from the\n") |
|
240 |
|
241 def test_chrome_components(self): |
|
242 # Bug 636145/774636: We no longer tolerate usages of "Components", |
|
243 # even when adding `require("chrome")` to your module. |
|
244 mod = """require("chrome"); |
|
245 var ios = Components.classes['@mozilla.org/network/io-service;1'];""" |
|
246 requires, problems, err = scan2(mod) |
|
247 self.failUnlessKeysAre(requires, ["chrome"]) |
|
248 self.failUnlessEqual(problems, True) |
|
249 self.failUnlessEqual(err[1], "The following lines from file fake.js:\n") |
|
250 self.failUnlessEqual(err[2], " 2: var ios = Components.classes['@mozilla.org/network/io-service;1'];\n") |
|
251 self.failUnlessEqual(err[3], "use 'Components' to access chrome authority. To do so, you need to add a\n") |
|
252 self.failUnlessEqual(err[4], "line somewhat like the following:\n") |
|
253 self.failUnlessEqual(err[6], ' const {Cc} = require("chrome");\n') |
|
254 self.failUnlessEqual(err[8], "Then you can use any shortcuts to its properties that you import from the\n") |
|
255 |
|
256 if __name__ == '__main__': |
|
257 unittest.main() |