michael@0: # This Source Code Form is subject to the terms of the Mozilla Public michael@0: # License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: # file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: michael@0: michael@0: import unittest michael@0: from StringIO import StringIO michael@0: from cuddlefish.manifest import scan_module michael@0: michael@0: class Extra: michael@0: def failUnlessKeysAre(self, d, keys): michael@0: self.failUnlessEqual(sorted(d.keys()), sorted(keys)) michael@0: michael@0: class Require(unittest.TestCase, Extra): michael@0: def scan(self, text): michael@0: lines = StringIO(text).readlines() michael@0: requires, problems, locations = scan_module("fake.js", lines) michael@0: self.failUnlessEqual(problems, False) michael@0: return requires michael@0: michael@0: def scan_locations(self, text): michael@0: lines = StringIO(text).readlines() michael@0: requires, problems, locations = scan_module("fake.js", lines) michael@0: self.failUnlessEqual(problems, False) michael@0: return requires, locations michael@0: michael@0: def test_modules(self): michael@0: mod = """var foo = require('one');""" michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, ["one"]) michael@0: michael@0: mod = """var foo = require(\"one\");""" michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, ["one"]) michael@0: michael@0: mod = """var foo=require( 'one' ) ; """ michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, ["one"]) michael@0: michael@0: mod = """var foo = require('o'+'ne'); // tricky, denied""" michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, []) michael@0: michael@0: mod = """require('one').immediately.do().stuff();""" michael@0: requires, locations = self.scan_locations(mod) michael@0: self.failUnlessKeysAre(requires, ["one"]) michael@0: self.failUnlessEqual(locations, {"one": 1}) michael@0: michael@0: # these forms are commented out, and thus ignored michael@0: michael@0: mod = """// var foo = require('one');""" michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, []) michael@0: michael@0: mod = """/* var foo = require('one');""" michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, []) michael@0: michael@0: mod = """ * var foo = require('one');""" michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, []) michael@0: michael@0: mod = """ ' var foo = require('one');""" michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, ["one"]) michael@0: michael@0: mod = """ \" var foo = require('one');""" michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, ["one"]) michael@0: michael@0: # multiple requires michael@0: michael@0: mod = """const foo = require('one'); michael@0: const foo = require('two');""" michael@0: requires, locations = self.scan_locations(mod) michael@0: self.failUnlessKeysAre(requires, ["one", "two"]) michael@0: self.failUnlessEqual(locations["one"], 1) michael@0: self.failUnlessEqual(locations["two"], 2) michael@0: michael@0: mod = """const foo = require('repeated'); michael@0: const bar = require('repeated'); michael@0: const baz = require('repeated');""" michael@0: requires, locations = self.scan_locations(mod) michael@0: self.failUnlessKeysAre(requires, ["repeated"]) michael@0: self.failUnlessEqual(locations["repeated"], 1) # first occurrence michael@0: michael@0: mod = """const foo = require('one'); const foo = require('two');""" michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, ["one", "two"]) michael@0: michael@0: # define calls michael@0: michael@0: mod = """define('one', ['two', 'numbers/three'], function(t, th) {});""" michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, ["two", "numbers/three"]) michael@0: michael@0: mod = """define( michael@0: ['odd', michael@0: "numbers/four"], function() {});""" michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, ["odd", "numbers/four"]) michael@0: michael@0: mod = """define(function(require, exports, module) { michael@0: var a = require("some/module/a"), michael@0: b = require('b/v1'); michael@0: exports.a = a; michael@0: //This is a fakeout: require('bad'); michael@0: /* And another var bad = require('bad2'); */ michael@0: require('foo').goFoo(); michael@0: });""" michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, ["some/module/a", "b/v1", "foo"]) michael@0: michael@0: mod = """define ( michael@0: "foo", michael@0: ["bar"], function (bar) { michael@0: var me = require("me"); michael@0: } michael@0: )""" michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, ["bar", "me"]) michael@0: michael@0: mod = """define(['se' + 'ven', 'eight', nine], function () {});""" michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, ["eight"]) michael@0: michael@0: # async require calls michael@0: michael@0: mod = """require(['one'], function(one) {var o = require("one");});""" michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, ["one"]) michael@0: michael@0: mod = """require([ 'one' ], function(one) {var t = require("two");});""" michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, ["one", "two"]) michael@0: michael@0: mod = """require ( ['two', 'numbers/three'], function(t, th) {});""" michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, ["two", "numbers/three"]) michael@0: michael@0: mod = """require ( michael@0: ["bar", "fa" + 'ke' ], function (bar) { michael@0: var me = require("me"); michael@0: // require("bad").doBad(); michael@0: } michael@0: )""" michael@0: requires = self.scan(mod) michael@0: self.failUnlessKeysAre(requires, ["bar", "me"]) michael@0: michael@0: def scan2(text, fn="fake.js"): michael@0: stderr = StringIO() michael@0: lines = StringIO(text).readlines() michael@0: requires, problems, locations = scan_module(fn, lines, stderr) michael@0: stderr.seek(0) michael@0: return requires, problems, stderr.readlines() michael@0: michael@0: class Chrome(unittest.TestCase, Extra): michael@0: michael@0: def test_ignore_loader(self): michael@0: # we specifically ignore the loader itself michael@0: mod = """let {Cc,Ci} = require('chrome');""" michael@0: requires, problems, err = scan2(mod, "blah/cuddlefish.js") michael@0: self.failUnlessKeysAre(requires, ["chrome"]) michael@0: self.failUnlessEqual(problems, False) michael@0: self.failUnlessEqual(err, []) michael@0: michael@0: def test_chrome(self): michael@0: mod = """let {Cc,Ci} = require('chrome');""" michael@0: requires, problems, err = scan2(mod) michael@0: self.failUnlessKeysAre(requires, ["chrome"]) michael@0: self.failUnlessEqual(problems, False) michael@0: self.failUnlessEqual(err, []) michael@0: michael@0: mod = """var foo = require('foo'); michael@0: let {Cc,Ci} = require('chrome');""" michael@0: requires, problems, err = scan2(mod) michael@0: self.failUnlessKeysAre(requires, ["foo", "chrome"]) michael@0: self.failUnlessEqual(problems, False) michael@0: self.failUnlessEqual(err, []) michael@0: michael@0: mod = """let c = require('chrome');""" michael@0: requires, problems, err = scan2(mod) michael@0: self.failUnlessKeysAre(requires, ["chrome"]) michael@0: self.failUnlessEqual(problems, False) michael@0: self.failUnlessEqual(err, []) michael@0: michael@0: mod = """var foo = require('foo'); michael@0: let c = require('chrome');""" michael@0: requires, problems, err = scan2(mod) michael@0: self.failUnlessKeysAre(requires, ["foo", "chrome"]) michael@0: self.failUnlessEqual(problems, False) michael@0: self.failUnlessEqual(err, []) michael@0: michael@0: def test_not_chrome(self): michael@0: # from bug 596595 michael@0: mod = r'soughtLines: new RegExp("^\\s*(\\[[0-9 .]*\\])?\\s*\\(\\((EE|WW)\\)|.* [Cc]hipsets?: \\)|\\s*Backtrace")' michael@0: requires, problems, err = scan2(mod) michael@0: self.failUnlessKeysAre(requires, []) michael@0: self.failUnlessEqual((problems,err), (False, [])) michael@0: michael@0: def test_not_chrome2(self): michael@0: # from bug 655788 michael@0: mod = r"var foo = 'some stuff Cr';" michael@0: requires, problems, err = scan2(mod) michael@0: self.failUnlessKeysAre(requires, []) michael@0: self.failUnlessEqual((problems,err), (False, [])) michael@0: michael@0: class BadChrome(unittest.TestCase, Extra): michael@0: def test_bad_alias(self): michael@0: # using Components.* gets you an error, with a message that teaches michael@0: # you the correct approach. michael@0: mod = """let Cc = Components.classes; michael@0: let Cu = Components.utils; michael@0: """ michael@0: requires, problems, err = scan2(mod) michael@0: self.failUnlessKeysAre(requires, []) michael@0: self.failUnlessEqual(problems, True) michael@0: self.failUnlessEqual(err[1], "The following lines from file fake.js:\n") michael@0: self.failUnlessEqual(err[2], " 1: let Cc = Components.classes;\n") michael@0: self.failUnlessEqual(err[3], " 2: let Cu = Components.utils;\n") michael@0: self.failUnlessEqual(err[4], "use 'Components' to access chrome authority. To do so, you need to add a\n") michael@0: self.failUnlessEqual(err[5], "line somewhat like the following:\n") michael@0: self.failUnlessEqual(err[7], ' const {Cc,Cu} = require("chrome");\n') michael@0: self.failUnlessEqual(err[9], "Then you can use any shortcuts to its properties that you import from the\n") michael@0: michael@0: def test_bad_misc(self): michael@0: # If it looks like you're using something that doesn't have an alias, michael@0: # the warning also suggests a better way. michael@0: mod = """if (Components.isSuccessCode(foo)) michael@0: """ michael@0: requires, problems, err = scan2(mod) michael@0: self.failUnlessKeysAre(requires, []) michael@0: self.failUnlessEqual(problems, True) michael@0: self.failUnlessEqual(err[1], "The following lines from file fake.js:\n") michael@0: self.failUnlessEqual(err[2], " 1: if (Components.isSuccessCode(foo))\n") michael@0: self.failUnlessEqual(err[3], "use 'Components' to access chrome authority. To do so, you need to add a\n") michael@0: self.failUnlessEqual(err[4], "line somewhat like the following:\n") michael@0: self.failUnlessEqual(err[6], ' const {components} = require("chrome");\n') michael@0: self.failUnlessEqual(err[8], "Then you can use any shortcuts to its properties that you import from the\n") michael@0: michael@0: def test_chrome_components(self): michael@0: # Bug 636145/774636: We no longer tolerate usages of "Components", michael@0: # even when adding `require("chrome")` to your module. michael@0: mod = """require("chrome"); michael@0: var ios = Components.classes['@mozilla.org/network/io-service;1'];""" michael@0: requires, problems, err = scan2(mod) michael@0: self.failUnlessKeysAre(requires, ["chrome"]) michael@0: self.failUnlessEqual(problems, True) michael@0: self.failUnlessEqual(err[1], "The following lines from file fake.js:\n") michael@0: self.failUnlessEqual(err[2], " 2: var ios = Components.classes['@mozilla.org/network/io-service;1'];\n") michael@0: self.failUnlessEqual(err[3], "use 'Components' to access chrome authority. To do so, you need to add a\n") michael@0: self.failUnlessEqual(err[4], "line somewhat like the following:\n") michael@0: self.failUnlessEqual(err[6], ' const {Cc} = require("chrome");\n') michael@0: self.failUnlessEqual(err[8], "Then you can use any shortcuts to its properties that you import from the\n") michael@0: michael@0: if __name__ == '__main__': michael@0: unittest.main()