diff options
Diffstat (limited to '')
28 files changed, 1737 insertions, 0 deletions
diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-Date-timing.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-Date-timing.js new file mode 100644 index 0000000000..597961e8cc --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-Date-timing.js @@ -0,0 +1,42 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/avoid-Date-timing"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, type, message) { + return { code, errors: [{ message, type }] }; +} + +ruleTester.run("avoid-Date-timing", rule, { + valid: [ + "new Date('2017-07-11');", + "new Date(1499790192440);", + "new Date(2017, 7, 11);", + "Date.UTC(2017, 7);", + ], + invalid: [ + invalidCode( + "Date.now();", + "CallExpression", + "use performance.now() instead of Date.now() for timing measurements" + ), + invalidCode( + "new Date();", + "NewExpression", + "use performance.now() instead of new Date() for timing measurements" + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-removeChild.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-removeChild.js new file mode 100644 index 0000000000..e6a146898d --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/avoid-removeChild.js @@ -0,0 +1,46 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/avoid-removeChild"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, message) { + if (!message) { + message = + "use element.remove() instead of " + + "element.parentNode.removeChild(element)"; + } + return { code, errors: [{ message, type: "CallExpression" }] }; +} + +ruleTester.run("avoid-removeChild", rule, { + valid: [ + "elt.remove();", + "elt.parentNode.parentNode.removeChild(elt2.parentNode);", + "elt.parentNode.removeChild(elt2);", + "elt.removeChild(elt2);", + ], + invalid: [ + invalidCode("elt.parentNode.removeChild(elt);"), + invalidCode("elt.parentNode.parentNode.removeChild(elt.parentNode);"), + invalidCode("$(e).parentNode.removeChild($(e));"), + invalidCode("$('e').parentNode.removeChild($('e'));"), + invalidCode( + "elt.removeChild(elt.firstChild);", + "use element.firstChild.remove() instead of " + + "element.removeChild(element.firstChild)" + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/balanced-listeners.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/balanced-listeners.js new file mode 100644 index 0000000000..ca84e3474f --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/balanced-listeners.js @@ -0,0 +1,89 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/balanced-listeners"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function error(code, message) { + return { + code, + errors: [{ message, type: "Identifier" }], + }; +} + +ruleTester.run("balanced-listeners", rule, { + valid: [ + "elt.addEventListener('event', handler);" + + "elt.removeEventListener('event', handler);", + + "elt.addEventListener('event', handler, true);" + + "elt.removeEventListener('event', handler, true);", + + "elt.addEventListener('event', handler, false);" + + "elt.removeEventListener('event', handler, false);", + + "elt.addEventListener('event', handler);" + + "elt.removeEventListener('event', handler, false);", + + "elt.addEventListener('event', handler, false);" + + "elt.removeEventListener('event', handler);", + + "elt.addEventListener('event', handler, {capture: false});" + + "elt.removeEventListener('event', handler);", + + "elt.addEventListener('event', handler);" + + "elt.removeEventListener('event', handler, {capture: false});", + + "elt.addEventListener('event', handler, {capture: true});" + + "elt.removeEventListener('event', handler, true);", + + "elt.addEventListener('event', handler, true);" + + "elt.removeEventListener('event', handler, {capture: true});", + + "elt.addEventListener('event', handler, {once: true});", + + "elt.addEventListener('event', handler, {once: true, capture: true});", + ], + invalid: [ + error( + "elt.addEventListener('click', handler, false);", + "No corresponding 'removeEventListener(click)' was found." + ), + + error( + "elt.addEventListener('click', handler, false);" + + "elt.removeEventListener('click', handler, true);", + "No corresponding 'removeEventListener(click)' was found." + ), + + error( + "elt.addEventListener('click', handler, {capture: false});" + + "elt.removeEventListener('click', handler, true);", + "No corresponding 'removeEventListener(click)' was found." + ), + + error( + "elt.addEventListener('click', handler, {capture: true});" + + "elt.removeEventListener('click', handler);", + "No corresponding 'removeEventListener(click)' was found." + ), + + error( + "elt.addEventListener('click', handler, true);" + + "elt.removeEventListener('click', handler);", + "No corresponding 'removeEventListener(click)' was found." + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/balanced-observers.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/balanced-observers.js new file mode 100644 index 0000000000..e5f31fa969 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/balanced-observers.js @@ -0,0 +1,74 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/balanced-observers"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function error(code, message) { + return { + code, + errors: [{ message, type: "Identifier" }], + }; +} + +ruleTester.run("balanced-observers", rule, { + valid: [ + "Services.obs.addObserver(observer, 'observable');" + + "Services.obs.removeObserver(observer, 'observable');", + "Services.prefs.addObserver('preference.name', otherObserver);" + + "Services.prefs.removeObserver('preference.name', otherObserver);", + ], + invalid: [ + error( + // missing Services.obs.removeObserver + "Services.obs.addObserver(observer, 'observable');", + "No corresponding 'removeObserver(\"observable\")' was found." + ), + + error( + // wrong observable name for Services.obs.removeObserver + "Services.obs.addObserver(observer, 'observable');" + + "Services.obs.removeObserver(observer, 'different-observable');", + "No corresponding 'removeObserver(\"observable\")' was found." + ), + + error( + // missing Services.prefs.removeObserver + "Services.prefs.addObserver('preference.name', otherObserver);", + "No corresponding 'removeObserver(\"preference.name\")' was found." + ), + + error( + // wrong observable name for Services.prefs.removeObserver + "Services.prefs.addObserver('preference.name', otherObserver);" + + "Services.prefs.removeObserver('other.preference', otherObserver);", + "No corresponding 'removeObserver(\"preference.name\")' was found." + ), + + error( + // mismatch Services.prefs vs Services.obs + "Services.obs.addObserver(observer, 'observable');" + + "Services.prefs.removeObserver(observer, 'observable');", + "No corresponding 'removeObserver(\"observable\")' was found." + ), + + error( + "Services.prefs.addObserver('preference.name', otherObserver);" + + // mismatch Services.prefs vs Services.obs + "Services.obs.removeObserver('preference.name', otherObserver);", + "No corresponding 'removeObserver(\"preference.name\")' was found." + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/consistent-if-bracing.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/consistent-if-bracing.js new file mode 100644 index 0000000000..b6b5b849b9 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/consistent-if-bracing.js @@ -0,0 +1,40 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/consistent-if-bracing"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 8 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code) { + return { code, errors: [{ messageId: "consistentIfBracing" }] }; +} + +ruleTester.run("consistent-if-bracing", rule, { + valid: [ + "if (true) {1} else {0}", + "if (false) 1; else 0", + "if (true) {1} else if (true) {2} else {0}", + "if (true) {1} else if (true) {2} else if (true) {3} else {0}", + ], + invalid: [ + invalidCode(`if (true) {1} else 0`), + invalidCode("if (true) 1; else {0}"), + invalidCode("if (true) {1} else if (true) 2; else {0}"), + invalidCode("if (true) 1; else if (true) {2} else {0}"), + invalidCode("if (true) {1} else if (true) 2; else {0}"), + invalidCode("if (true) {1} else if (true) {2} else 0"), + invalidCode("if (true) {1} else if (true) {2} else if (true) 3; else {0}"), + invalidCode("if (true) {if (true) 1; else {0}} else {0}"), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/mark-exported-symbols-as-used.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/mark-exported-symbols-as-used.js new file mode 100644 index 0000000000..d004650997 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/mark-exported-symbols-as-used.js @@ -0,0 +1,45 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/mark-exported-symbols-as-used"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, type, message) { + return { code, errors: [{ message, type }] }; +} + +ruleTester.run("mark-exported-symbols-as-used", rule, { + valid: [ + "var EXPORTED_SYMBOLS = ['foo'];", + "this.EXPORTED_SYMBOLS = ['foo'];", + ], + invalid: [ + invalidCode( + "let EXPORTED_SYMBOLS = ['foo'];", + "VariableDeclaration", + "EXPORTED_SYMBOLS cannot be declared via `let`. Use `var` or `this.EXPORTED_SYMBOLS =`" + ), + invalidCode( + "var EXPORTED_SYMBOLS = 'foo';", + "VariableDeclaration", + "Unexpected assignment of non-Array to EXPORTED_SYMBOLS" + ), + invalidCode( + "this.EXPORTED_SYMBOLS = 'foo';", + "AssignmentExpression", + "Unexpected assignment of non-Array to EXPORTED_SYMBOLS" + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-arbitrary-setTimeout.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-arbitrary-setTimeout.js new file mode 100644 index 0000000000..907b439b3c --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-arbitrary-setTimeout.js @@ -0,0 +1,41 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/no-arbitrary-setTimeout"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function wrapCode(code, filename = "xpcshell/test_foo.js") { + return { code, filename }; +} + +function invalidCode(code) { + let message = + "listen for events instead of setTimeout() with arbitrary delay"; + let obj = wrapCode(code); + obj.errors = [{ message, type: "CallExpression" }]; + return obj; +} + +ruleTester.run("no-arbitrary-setTimeout", rule, { + valid: [ + wrapCode("setTimeout(function() {}, 0);"), + wrapCode("setTimeout(function() {});"), + wrapCode("setTimeout(function() {}, 10);", "test_foo.js"), + ], + invalid: [ + invalidCode("setTimeout(function() {}, 10);"), + invalidCode("setTimeout(function() {}, timeout);"), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-compare-against-boolean-literals.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-compare-against-boolean-literals.js new file mode 100644 index 0000000000..722e6b5dda --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-compare-against-boolean-literals.js @@ -0,0 +1,61 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/no-compare-against-boolean-literals"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function callError(message) { + return [{ message, type: "BinaryExpression" }]; +} + +const MESSAGE = "Don't compare for inexact equality against boolean literals"; + +ruleTester.run("no-compare-against-boolean-literals", rule, { + valid: [`if (!foo) {}`, `if (!!foo) {}`], + invalid: [ + { + code: `if (foo == true) {}`, + errors: callError(MESSAGE), + }, + { + code: `if (foo != true) {}`, + errors: callError(MESSAGE), + }, + { + code: `if (foo == false) {}`, + errors: callError(MESSAGE), + }, + { + code: `if (foo != false) {}`, + errors: callError(MESSAGE), + }, + { + code: `if (true == foo) {}`, + errors: callError(MESSAGE), + }, + { + code: `if (true != foo) {}`, + errors: callError(MESSAGE), + }, + { + code: `if (false == foo) {}`, + errors: callError(MESSAGE), + }, + { + code: `if (false != foo) {}`, + errors: callError(MESSAGE), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-define-cc-etc.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-define-cc-etc.js new file mode 100644 index 0000000000..735c7f4654 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-define-cc-etc.js @@ -0,0 +1,62 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/no-define-cc-etc"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 9 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, varNames) { + if (!Array.isArray(varNames)) { + varNames = [varNames]; + } + return { + code, + errors: varNames.map(name => { + return { + message: `${name} is now defined in global scope, a separate definition is no longer necessary.`, + type: "VariableDeclarator", + }; + }), + }; +} + +ruleTester.run("no-define-cc-etc", rule, { + valid: [ + "var Cm = Components.manager;", + "const CC = Components.Constructor;", + "var {Constructor: CC, manager: Cm} = Components;", + "const {Constructor: CC, manager: Cm} = Components;", + "foo.Cc.test();", + "const {bar, ...foo} = obj;", + ], + invalid: [ + invalidCode("var Cc;", "Cc"), + invalidCode("let Cc;", "Cc"), + invalidCode("let Ci;", "Ci"), + invalidCode("let Cr;", "Cr"), + invalidCode("let Cu;", "Cu"), + invalidCode("var Cc = Components.classes;", "Cc"), + invalidCode("const {classes: Cc} = Components;", "Cc"), + invalidCode("let {classes: Cc, manager: Cm} = Components", "Cc"), + invalidCode("const Cu = Components.utils;", "Cu"), + invalidCode("var Ci = Components.interfaces, Cc = Components.classes;", [ + "Ci", + "Cc", + ]), + invalidCode("var {'interfaces': Ci, 'classes': Cc} = Components;", [ + "Ci", + "Cc", + ]), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-throw-cr-literal.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-throw-cr-literal.js new file mode 100644 index 0000000000..6750213e72 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-throw-cr-literal.js @@ -0,0 +1,62 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/no-throw-cr-literal"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, output, messageId) { + return { + code, + output, + errors: [{ messageId, type: "ThrowStatement" }], + }; +} + +ruleTester.run("no-throw-cr-literal", rule, { + valid: [ + 'throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);', + 'throw Components.Exception("", Components.results.NS_ERROR_UNEXPECTED);', + 'function t() { throw Components.Exception("", Cr.NS_ERROR_NO_CONTENT); }', + // We don't handle combined values, regular no-throw-literal catches them + 'throw Components.results.NS_ERROR_UNEXPECTED + "whoops";', + ], + invalid: [ + invalidCode( + "throw Cr.NS_ERROR_NO_INTERFACE;", + 'throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE);', + "bareCR" + ), + invalidCode( + "throw Components.results.NS_ERROR_ABORT;", + 'throw Components.Exception("", Components.results.NS_ERROR_ABORT);', + "bareComponentsResults" + ), + invalidCode( + "function t() { throw Cr.NS_ERROR_NULL_POINTER; }", + 'function t() { throw Components.Exception("", Cr.NS_ERROR_NULL_POINTER); }', + "bareCR" + ), + invalidCode( + "throw new Error(Cr.NS_ERROR_ABORT);", + 'throw Components.Exception("", Cr.NS_ERROR_ABORT);', + "newErrorCR" + ), + invalidCode( + "throw new Error(Components.results.NS_ERROR_ABORT);", + 'throw Components.Exception("", Components.results.NS_ERROR_ABORT);', + "newErrorComponentsResults" + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-parameters.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-parameters.js new file mode 100644 index 0000000000..0c9b12f6eb --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-parameters.js @@ -0,0 +1,147 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/no-useless-parameters"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function callError(message) { + return [{ message, type: "CallExpression" }]; +} + +ruleTester.run("no-useless-parameters", rule, { + valid: [ + "Services.prefs.clearUserPref('browser.search.custom');", + "Services.removeObserver('notification name', {});", + "Services.io.newURI('http://example.com');", + "Services.io.newURI('http://example.com', 'utf8');", + "elt.addEventListener('click', handler);", + "elt.addEventListener('click', handler, true);", + "elt.addEventListener('click', handler, {once: true});", + "elt.removeEventListener('click', handler);", + "elt.removeEventListener('click', handler, true);", + "Services.obs.addObserver(this, 'topic', true);", + "Services.obs.addObserver(this, 'topic');", + "Services.prefs.addObserver('branch', this, true);", + "Services.prefs.addObserver('branch', this);", + "array.appendElement(elt);", + "Services.obs.notifyObservers(obj, 'topic', 'data');", + "Services.obs.notifyObservers(obj, 'topic');", + "window.getComputedStyle(elt);", + "window.getComputedStyle(elt, ':before');", + ], + invalid: [ + { + code: "Services.prefs.clearUserPref('browser.search.custom', false);", + output: "Services.prefs.clearUserPref('browser.search.custom');", + errors: callError("clearUserPref takes only 1 parameter."), + }, + { + code: "Services.prefs.clearUserPref('browser.search.custom',\n false);", + output: "Services.prefs.clearUserPref('browser.search.custom');", + errors: callError("clearUserPref takes only 1 parameter."), + }, + { + code: "Services.removeObserver('notification name', {}, false);", + output: "Services.removeObserver('notification name', {});", + errors: callError("removeObserver only takes 2 parameters."), + }, + { + code: "Services.removeObserver('notification name', {}, true);", + output: "Services.removeObserver('notification name', {});", + errors: callError("removeObserver only takes 2 parameters."), + }, + { + code: "Services.io.newURI('http://example.com', null, null);", + output: "Services.io.newURI('http://example.com');", + errors: callError("newURI's last parameters are optional."), + }, + { + code: "Services.io.newURI('http://example.com', 'utf8', null);", + output: "Services.io.newURI('http://example.com', 'utf8');", + errors: callError("newURI's last parameters are optional."), + }, + { + code: "Services.io.newURI('http://example.com', null);", + output: "Services.io.newURI('http://example.com');", + errors: callError("newURI's last parameters are optional."), + }, + { + code: "Services.io.newURI('http://example.com', '', '');", + output: "Services.io.newURI('http://example.com');", + errors: callError("newURI's last parameters are optional."), + }, + { + code: "Services.io.newURI('http://example.com', '');", + output: "Services.io.newURI('http://example.com');", + errors: callError("newURI's last parameters are optional."), + }, + { + code: "elt.addEventListener('click', handler, false);", + output: "elt.addEventListener('click', handler);", + errors: callError( + "addEventListener's third parameter can be omitted when it's false." + ), + }, + { + code: "elt.removeEventListener('click', handler, false);", + output: "elt.removeEventListener('click', handler);", + errors: callError( + "removeEventListener's third parameter can be omitted when it's" + + " false." + ), + }, + { + code: "Services.obs.addObserver(this, 'topic', false);", + output: "Services.obs.addObserver(this, 'topic');", + errors: callError( + "addObserver's third parameter can be omitted when it's false." + ), + }, + { + code: "Services.prefs.addObserver('branch', this, false);", + output: "Services.prefs.addObserver('branch', this);", + errors: callError( + "addObserver's third parameter can be omitted when it's false." + ), + }, + { + code: "array.appendElement(elt, false);", + output: "array.appendElement(elt);", + errors: callError( + "appendElement's second parameter can be omitted when it's false." + ), + }, + { + code: "Services.obs.notifyObservers(obj, 'topic', null);", + output: "Services.obs.notifyObservers(obj, 'topic');", + errors: callError("notifyObservers's third parameter can be omitted."), + }, + { + code: "Services.obs.notifyObservers(obj, 'topic', '');", + output: "Services.obs.notifyObservers(obj, 'topic');", + errors: callError("notifyObservers's third parameter can be omitted."), + }, + { + code: "window.getComputedStyle(elt, null);", + output: "window.getComputedStyle(elt);", + errors: callError("getComputedStyle's second parameter can be omitted."), + }, + { + code: "window.getComputedStyle(elt, '');", + output: "window.getComputedStyle(elt);", + errors: callError("getComputedStyle's second parameter can be omitted."), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-removeEventListener.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-removeEventListener.js new file mode 100644 index 0000000000..9f59c78d05 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-removeEventListener.js @@ -0,0 +1,99 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/no-useless-removeEventListener"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code) { + let message = + "use {once: true} instead of removeEventListener " + + "as the first instruction of the listener"; + return { code, errors: [{ message, type: "CallExpression" }] }; +} + +ruleTester.run("no-useless-removeEventListener", rule, { + valid: [ + // Listeners that aren't a function are always valid. + "elt.addEventListener('click', handler);", + "elt.addEventListener('click', handler, true);", + "elt.addEventListener('click', handler, {once: true});", + + // Should not fail on empty functions. + "elt.addEventListener('click', function() {});", + + // Should not reject when removing a listener for another event. + "elt.addEventListener('click', function listener() {" + + " elt.removeEventListener('keypress', listener);" + + "});", + + // Should not reject when there's another instruction before + // removeEventListener. + "elt.addEventListener('click', function listener() {" + + " elt.focus();" + + " elt.removeEventListener('click', listener);" + + "});", + + // Should not reject when wantsUntrusted is true. + "elt.addEventListener('click', function listener() {" + + " elt.removeEventListener('click', listener);" + + "}, false, true);", + + // Should not reject when there's a literal and a variable + "elt.addEventListener('click', function listener() {" + + " elt.removeEventListener(eventName, listener);" + + "});", + + // Should not reject when there's 2 different variables + "elt.addEventListener(event1, function listener() {" + + " elt.removeEventListener(event2, listener);" + + "});", + + // Should not fail if this is a different type of event listener function. + "myfunc.addEventListener(listener);", + ], + invalid: [ + invalidCode( + "elt.addEventListener('click', function listener() {" + + " elt.removeEventListener('click', listener);" + + "});" + ), + invalidCode( + "elt.addEventListener('click', function listener() {" + + " elt.removeEventListener('click', listener, true);" + + "}, true);" + ), + invalidCode( + "elt.addEventListener('click', function listener() {" + + " elt.removeEventListener('click', listener);" + + "}, {once: true});" + ), + invalidCode( + "elt.addEventListener('click', function listener() {" + + " /* Comment */" + + " elt.removeEventListener('click', listener);" + + "});" + ), + invalidCode( + "elt.addEventListener('click', function() {" + + " elt.removeEventListener('click', arguments.callee);" + + "});" + ), + invalidCode( + "elt.addEventListener(eventName, function listener() {" + + " elt.removeEventListener(eventName, listener);" + + "});" + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-run-test.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-run-test.js new file mode 100644 index 0000000000..3541467143 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/no-useless-run-test.js @@ -0,0 +1,124 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/no-useless-run-test"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, output) { + let message = + "Useless run_test function - only contains run_next_test; whole function can be removed"; + return { code, output, errors: [{ message, type: "FunctionDeclaration" }] }; +} + +ruleTester.run("no-useless-run-test", rule, { + valid: [ + "function run_test() {}", + "function run_test() {let args = 1; run_next_test();}", + "function run_test() {fakeCall(); run_next_test();}", + ], + invalid: [ + // Single-line case. + invalidCode("function run_test() { run_next_test(); }", ""), + // Multiple-line cases + invalidCode( + ` +function run_test() { + run_next_test(); +}`, + `` + ), + invalidCode( + ` +foo(); +function run_test() { + run_next_test(); +} +`, + ` +foo(); +` + ), + invalidCode( + ` +foo(); +function run_test() { + run_next_test(); +} +bar(); +`, + ` +foo(); +bar(); +` + ), + invalidCode( + ` +foo(); + +function run_test() { + run_next_test(); +} + +bar();`, + ` +foo(); + +bar();` + ), + invalidCode( + ` +foo(); + +function run_test() { + run_next_test(); +} + +// A comment +bar(); +`, + ` +foo(); + +// A comment +bar(); +` + ), + invalidCode( + ` +foo(); + +/** + * A useful comment. + */ +function run_test() { + run_next_test(); +} + +// A comment +bar(); +`, + ` +foo(); + +/** + * A useful comment. + */ + +// A comment +bar(); +` + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/prefer-boolean-length-check.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/prefer-boolean-length-check.js new file mode 100644 index 0000000000..daf3c6f3d9 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/prefer-boolean-length-check.js @@ -0,0 +1,97 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/prefer-boolean-length-check"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidError() { + let message = "Prefer boolean length check"; + return [{ message, type: "BinaryExpression" }]; +} + +ruleTester.run("check-length", rule, { + valid: [ + "if (foo.length && foo.length) {}", + "if (!foo.length) {}", + "if (foo.value == 0) {}", + "if (foo.value > 0) {}", + "if (0 == foo.value) {}", + "if (0 < foo.value) {}", + "var a = !!foo.length", + "function bar() { return !!foo.length }", + ], + invalid: [ + { + code: "if (foo.length == 0) {}", + output: "if (!foo.length) {}", + errors: invalidError(), + }, + { + code: "if (foo.length > 0) {}", + output: "if (foo.length) {}", + errors: invalidError(), + }, + { + code: "if (0 < foo.length) {}", + output: "if (foo.length) {}", + errors: invalidError(), + }, + { + code: "if (0 == foo.length) {}", + output: "if (!foo.length) {}", + errors: invalidError(), + }, + { + code: "if (foo && foo.length == 0) {}", + output: "if (foo && !foo.length) {}", + errors: invalidError(), + }, + { + code: "if (foo.bar.length == 0) {}", + output: "if (!foo.bar.length) {}", + errors: invalidError(), + }, + { + code: "var a = foo.length>0", + output: "var a = !!foo.length", + errors: invalidError(), + }, + { + code: "function bar() { return foo.length>0 }", + output: "function bar() { return !!foo.length }", + errors: invalidError(), + }, + { + code: "if (foo && bar.length>0) {}", + output: "if (foo && bar.length) {}", + errors: invalidError(), + }, + { + code: "while (foo && bar.length>0) {}", + output: "while (foo && bar.length) {}", + errors: invalidError(), + }, + { + code: "x = y && bar.length > 0", + output: "x = y && !!bar.length", + errors: invalidError(), + }, + { + code: "function bar() { return x && foo.length > 0}", + output: "function bar() { return x && !!foo.length}", + errors: invalidError(), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/prefer-formatValues.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/prefer-formatValues.js new file mode 100644 index 0000000000..0883130f17 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/prefer-formatValues.js @@ -0,0 +1,72 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/prefer-formatValues"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function error(line, column = undefined) { + return { + message: + "prefer to use a single document.l10n.formatValues call instead " + + "of multiple calls to document.l10n.formatValue or document.l10n.formatValues", + type: "CallExpression", + line, + column, + }; +} + +ruleTester.run("check-length", rule, { + valid: [ + "document.l10n.formatValue('foobar');", + "document.l10n.formatValues(['foobar', 'foobaz']);", + `if (foo) { + document.l10n.formatValue('foobar'); + } else { + document.l10n.formatValue('foobaz'); + }`, + `document.l10n.formatValue('foobaz'); + if (foo) { + document.l10n.formatValue('foobar'); + }`, + `if (foo) { + document.l10n.formatValue('foobar'); + } + document.l10n.formatValue('foobaz');`, + `if (foo) { + document.l10n.formatValue('foobar'); + } + document.l10n.formatValues(['foobaz']);`, + ], + invalid: [ + { + code: `document.l10n.formatValue('foobar'); + document.l10n.formatValue('foobaz');`, + errors: [error(1, 1), error(2, 14)], + }, + { + code: `document.l10n.formatValue('foobar'); + if (foo) { + document.l10n.formatValue('foobiz'); + } + document.l10n.formatValue('foobaz');`, + errors: [error(1, 1), error(5, 14)], + }, + { + code: `document.l10n.formatValues('foobar'); + document.l10n.formatValue('foobaz');`, + errors: [error(1, 1), error(2, 14)], + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-chromeutils-import-null.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-chromeutils-import-null.js new file mode 100644 index 0000000000..6584f728ac --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-chromeutils-import-null.js @@ -0,0 +1,42 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-chromeutils-import-null"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 8 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidError() { + let message = + "ChromeUtils.import should not be called with (..., null) to " + + "retrieve the JSM global object. Rely on explicit exports instead."; + return [{ message, type: "CallExpression" }]; +} + +ruleTester.run("reject-chromeutils-import-null", rule, { + valid: ['ChromeUtils.import("resource://some/path/to/My.jsm")'], + invalid: [ + { + code: 'ChromeUtils.import("resource://some/path/to/My.jsm", null)', + errors: invalidError(), + }, + { + code: ` +ChromeUtils.import( + "resource://some/path/to/My.jsm", + null +);`, + errors: invalidError(), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-importGlobalProperties.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-importGlobalProperties.js new file mode 100644 index 0000000000..04c0e0408b --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-importGlobalProperties.js @@ -0,0 +1,46 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-importGlobalProperties"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 8 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +ruleTester.run("reject-importGlobalProperties", rule, { + valid: [ + { + code: "Cu.something();", + }, + { + options: ["allownonwebidl"], + code: "Cu.importGlobalProperties(['fetch'])", + }, + ], + invalid: [ + { + code: "Cu.importGlobalProperties(['fetch'])", + options: ["everything"], + errors: [{ messageId: "unexpectedCall" }], + }, + { + code: "Cu.importGlobalProperties(['TextEncoder'])", + options: ["everything"], + errors: [{ messageId: "unexpectedCall" }], + }, + { + code: "Cu.importGlobalProperties(['TextEncoder'])", + options: ["allownonwebidl"], + errors: [{ messageId: "unexpectedCallWebIdl" }], + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-relative-requires.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-relative-requires.js new file mode 100644 index 0000000000..19f30559ec --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-relative-requires.js @@ -0,0 +1,58 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-relative-requires"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 8 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidError() { + let message = "relative paths are not allowed with require()"; + return [{ message, type: "CallExpression" }]; +} + +ruleTester.run("reject-relative-requires", rule, { + valid: [ + 'require("devtools/absolute/path")', + 'require("resource://gre/modules/SomeModule.jsm")', + 'loader.lazyRequireGetter(this, "path", "devtools/absolute/path", true)', + 'loader.lazyRequireGetter(this, "Path", "devtools/absolute/path")', + ], + invalid: [ + { + code: 'require("./relative/path")', + errors: invalidError(), + }, + { + code: 'require("../parent/folder/path")', + errors: invalidError(), + }, + { + code: 'loader.lazyRequireGetter(this, "path", "./relative/path", true)', + errors: invalidError(), + }, + { + code: + 'loader.lazyRequireGetter(this, "path", "../parent/folder/path", true)', + errors: invalidError(), + }, + { + code: 'loader.lazyRequireGetter(this, "path", "./relative/path")', + errors: invalidError(), + }, + { + code: 'loader.lazyRequireGetter(this, "path", "../parent/folder/path")', + errors: invalidError(), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-some-requires.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-some-requires.js new file mode 100644 index 0000000000..b56dd2cf96 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/reject-some-requires.js @@ -0,0 +1,49 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/reject-some-requires"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 8 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function requirePathError(path) { + const message = `require(${path}) is not allowed`; + return [{ message, type: "CallExpression" }]; +} + +const DEVTOOLS_FORBIDDEN_PATH = "^(resource://)?devtools/forbidden"; + +ruleTester.run("reject-some-requires", rule, { + valid: [ + { + code: 'require("devtools/not-forbidden/path")', + options: [DEVTOOLS_FORBIDDEN_PATH], + }, + { + code: 'require("resource://devtools/not-forbidden/path")', + options: [DEVTOOLS_FORBIDDEN_PATH], + }, + ], + invalid: [ + { + code: 'require("devtools/forbidden/path")', + errors: requirePathError("devtools/forbidden/path"), + options: [DEVTOOLS_FORBIDDEN_PATH], + }, + { + code: 'require("resource://devtools/forbidden/path")', + errors: requirePathError("resource://devtools/forbidden/path"), + options: [DEVTOOLS_FORBIDDEN_PATH], + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/rejects-requires-await.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/rejects-requires-await.js new file mode 100644 index 0000000000..ea6273a8ee --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/rejects-requires-await.js @@ -0,0 +1,32 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/rejects-requires-await"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 8 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, messageId) { + return { code, errors: [{ messageId: "rejectRequiresAwait" }] }; +} + +ruleTester.run("reject-requires-await", rule, { + valid: [ + "async() => { await Assert.rejects(foo, /assertion/) }", + "async() => { await Assert.rejects(foo, /assertion/, 'msg') }", + ], + invalid: [ + invalidCode("Assert.rejects(foo)"), + invalidCode("Assert.rejects(foo, 'msg')"), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-cc-etc.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-cc-etc.js new file mode 100644 index 0000000000..7ad729d22b --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-cc-etc.js @@ -0,0 +1,55 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-cc-etc"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, originalName, newName) { + return { + code, + errors: [ + { + message: `Use ${newName} rather than ${originalName}`, + type: "MemberExpression", + }, + ], + }; +} + +ruleTester.run("use-cc-etc", rule, { + valid: ["Components.Constructor();", "let x = Components.foo;"], + invalid: [ + invalidCode( + "let foo = Components.classes['bar'];", + "Components.classes", + "Cc" + ), + invalidCode( + "let bar = Components.interfaces.bar;", + "Components.interfaces", + "Ci" + ), + invalidCode( + "Components.results.NS_ERROR_ILLEGAL_INPUT;", + "Components.results", + "Cr" + ), + invalidCode( + "Components.utils.reportError('fake');", + "Components.utils", + "Cu" + ), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-chromeutils-generateqi.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-chromeutils-generateqi.js new file mode 100644 index 0000000000..26c6b350bc --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-chromeutils-generateqi.js @@ -0,0 +1,81 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-chromeutils-generateqi"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function callError(message) { + return [{ message, type: "CallExpression" }]; +} +function error(message, type) { + return [{ message, type }]; +} + +const MSG_NO_JS_QUERY_INTERFACE = + "Please use ChromeUtils.generateQI rather than manually creating " + + "JavaScript QueryInterface functions"; + +const MSG_NO_XPCOMUTILS_GENERATEQI = + "Please use ChromeUtils.generateQI instead of XPCOMUtils.generateQI"; + +/* globals nsIFlug */ +function QueryInterface(iid) { + if ( + iid.equals(Ci.nsISupports) || + iid.equals(Ci.nsIMeh) || + iid.equals(nsIFlug) || + iid.equals(Ci.amIFoo) + ) { + return this; + } + throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE); +} + +ruleTester.run("use-chromeutils-generateqi", rule, { + valid: [ + `X.prototype.QueryInterface = ChromeUtils.generateQI(["nsIMeh"]);`, + `X.prototype = { QueryInterface: ChromeUtils.generateQI(["nsIMeh"]) }`, + ], + invalid: [ + { + code: `X.prototype.QueryInterface = XPCOMUtils.generateQI(["nsIMeh"]);`, + output: `X.prototype.QueryInterface = ChromeUtils.generateQI(["nsIMeh"]);`, + errors: callError(MSG_NO_XPCOMUTILS_GENERATEQI), + }, + { + code: `X.prototype = { QueryInterface: XPCOMUtils.generateQI(["nsIMeh"]) };`, + output: `X.prototype = { QueryInterface: ChromeUtils.generateQI(["nsIMeh"]) };`, + errors: callError(MSG_NO_XPCOMUTILS_GENERATEQI), + }, + { + code: `X.prototype = { QueryInterface: ${QueryInterface} };`, + output: `X.prototype = { QueryInterface: ChromeUtils.generateQI(["nsIMeh", "nsIFlug", "amIFoo"]) };`, + errors: error(MSG_NO_JS_QUERY_INTERFACE, "Property"), + }, + { + code: `X.prototype = { ${String(QueryInterface).replace( + /^function /, + "" + )} };`, + output: `X.prototype = { QueryInterface: ChromeUtils.generateQI(["nsIMeh", "nsIFlug", "amIFoo"]) };`, + errors: error(MSG_NO_JS_QUERY_INTERFACE, "Property"), + }, + { + code: `X.prototype.QueryInterface = ${QueryInterface};`, + output: `X.prototype.QueryInterface = ChromeUtils.generateQI(["nsIMeh", "nsIFlug", "amIFoo"]);`, + errors: error(MSG_NO_JS_QUERY_INTERFACE, "AssignmentExpression"), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-chromeutils-import.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-chromeutils-import.js new file mode 100644 index 0000000000..635c436233 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-chromeutils-import.js @@ -0,0 +1,80 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-chromeutils-import"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function callError(message) { + return [{ message, type: "CallExpression" }]; +} + +const MESSAGE_IMPORT = "Please use ChromeUtils.import instead of Cu.import"; +const MESSAGE_DEFINE = + "Please use ChromeUtils.defineModuleGetter instead of " + + "XPCOMUtils.defineLazyModuleGetter"; + +ruleTester.run("use-chromeutils-import", rule, { + valid: [ + `ChromeUtils.import("resource://gre/modules/Service.jsm");`, + `ChromeUtils.import("resource://gre/modules/Service.jsm", this);`, + `ChromeUtils.defineModuleGetter(this, "Services", + "resource://gre/modules/Service.jsm");`, + `XPCOMUtils.defineLazyModuleGetter(this, "Services", + "resource://gre/modules/Service.jsm", + "Foo");`, + `XPCOMUtils.defineLazyModuleGetter(this, "Services", + "resource://gre/modules/Service.jsm", + undefined, preServicesLambda);`, + { + options: [{ allowCu: true }], + code: `Cu.import("resource://gre/modules/Service.jsm");`, + }, + ], + invalid: [ + { + code: `Cu.import("resource://gre/modules/Services.jsm");`, + output: `ChromeUtils.import("resource://gre/modules/Services.jsm");`, + errors: callError(MESSAGE_IMPORT), + }, + { + code: `Cu.import("resource://gre/modules/Services.jsm", this);`, + output: `ChromeUtils.import("resource://gre/modules/Services.jsm", this);`, + errors: callError(MESSAGE_IMPORT), + }, + { + code: `Components.utils.import("resource://gre/modules/Services.jsm");`, + output: `ChromeUtils.import("resource://gre/modules/Services.jsm");`, + errors: callError(MESSAGE_IMPORT), + }, + { + code: `Components.utils.import("resource://gre/modules/Services.jsm");`, + output: `ChromeUtils.import("resource://gre/modules/Services.jsm");`, + errors: callError(MESSAGE_IMPORT), + }, + { + options: [{ allowCu: true }], + code: `Components.utils.import("resource://gre/modules/Services.jsm", this);`, + output: `ChromeUtils.import("resource://gre/modules/Services.jsm", this);`, + errors: callError(MESSAGE_IMPORT), + }, + { + code: `XPCOMUtils.defineLazyModuleGetter(this, "Services", + "resource://gre/modules/Services.jsm");`, + output: `ChromeUtils.defineModuleGetter(this, "Services", + "resource://gre/modules/Services.jsm");`, + errors: callError(MESSAGE_DEFINE), + }, + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-default-preference-values.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-default-preference-values.js new file mode 100644 index 0000000000..f4ad001a08 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-default-preference-values.js @@ -0,0 +1,41 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-default-preference-values"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code) { + let message = "provide a default value instead of using a try/catch block"; + return { code, errors: [{ message, type: "TryStatement" }] }; +} + +let types = ["Bool", "Char", "Float", "Int"]; +let methods = types.map(type => "get" + type + "Pref"); + +ruleTester.run("use-default-preference-values", rule, { + valid: [].concat( + methods.map(m => "blah = branch." + m + "('blah', true);"), + methods.map(m => "blah = branch." + m + "('blah');"), + methods.map( + m => "try { canThrow(); blah = branch." + m + "('blah'); } catch(e) {}" + ) + ), + + invalid: [].concat( + methods.map(m => + invalidCode("try { blah = branch." + m + "('blah'); } catch(e) {}") + ) + ), +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-includes-instead-of-indexOf.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-includes-instead-of-indexOf.js new file mode 100644 index 0000000000..cb1810b305 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-includes-instead-of-indexOf.js @@ -0,0 +1,38 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-includes-instead-of-indexOf"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code) { + let message = "use .includes instead of .indexOf"; + return { code, errors: [{ message, type: "BinaryExpression" }] }; +} + +ruleTester.run("use-includes-instead-of-indexOf", rule, { + valid: [ + "let a = foo.includes(bar);", + "let a = foo.indexOf(bar) > 0;", + "let a = foo.indexOf(bar) != 0;", + ], + invalid: [ + invalidCode("let a = foo.indexOf(bar) >= 0;"), + invalidCode("let a = foo.indexOf(bar) != -1;"), + invalidCode("let a = foo.indexOf(bar) !== -1;"), + invalidCode("let a = foo.indexOf(bar) == -1;"), + invalidCode("let a = foo.indexOf(bar) === -1;"), + invalidCode("let a = foo.indexOf(bar) < 0;"), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-ownerGlobal.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-ownerGlobal.js new file mode 100644 index 0000000000..b08bdf1632 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-ownerGlobal.js @@ -0,0 +1,35 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-ownerGlobal"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code) { + let message = "use .ownerGlobal instead of .ownerDocument.defaultView"; + return { code, errors: [{ message, type: "MemberExpression" }] }; +} + +ruleTester.run("use-ownerGlobal", rule, { + valid: [ + "aEvent.target.ownerGlobal;", + "this.DOMPointNode.ownerGlobal.getSelection();", + "windowToMessageManager(node.ownerGlobal);", + ], + invalid: [ + invalidCode("aEvent.target.ownerDocument.defaultView;"), + invalidCode("this.DOMPointNode.ownerDocument.defaultView.getSelection();"), + invalidCode("windowToMessageManager(node.ownerDocument.defaultView);"), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-returnValue.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-returnValue.js new file mode 100644 index 0000000000..81952452e4 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-returnValue.js @@ -0,0 +1,39 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-returnValue"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, methodName) { + let message = `{Array/String}.${methodName} doesn't modify the instance in-place`; + return { code, errors: [{ message, type: "ExpressionStatement" }] }; +} + +ruleTester.run("use-returnValue", rule, { + valid: [ + "a = foo.concat(bar)", + "b = bar.concat([1,3,4])", + "c = baz.concat()", + "d = qux.join(' ')", + "e = quux.slice(1)", + ], + invalid: [ + invalidCode("foo.concat(bar)", "concat"), + invalidCode("bar.concat([1,3,4])", "concat"), + invalidCode("baz.concat()", "concat"), + invalidCode("qux.join(' ')", "join"), + invalidCode("quux.slice(1)", "slice"), + ], +}); diff --git a/tools/lint/eslint/eslint-plugin-mozilla/tests/use-services.js b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-services.js new file mode 100644 index 0000000000..b8d5338fc4 --- /dev/null +++ b/tools/lint/eslint/eslint-plugin-mozilla/tests/use-services.js @@ -0,0 +1,40 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require("../lib/rules/use-services"); +var RuleTester = require("eslint").RuleTester; + +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +function invalidCode(code, name) { + let message = `Use Services.${name} rather than getService().`; + return { code, errors: [{ message, type: "CallExpression" }] }; +} + +ruleTester.run("use-services", rule, { + valid: [ + 'Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator)', + 'Components.classes["@mozilla.org/uuid-generator;1"].getService(Components.interfaces.nsIUUIDGenerator)', + "Services.wm.addListener()", + ], + invalid: [ + invalidCode( + 'Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);', + "wm" + ), + invalidCode( + 'Components.classes["@mozilla.org/toolkit/app-startup;1"].getService(Components.interfaces.nsIAppStartup);', + "startup" + ), + ], +}); |