| Index: test/snippets.js | 
| =================================================================== | 
| --- a/test/snippets.js | 
| +++ b/test/snippets.js | 
| @@ -14,260 +14,255 @@ | 
| * You should have received a copy of the GNU General Public License | 
| * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | 
| */ | 
| /* eslint no-new-func: "off" */ | 
| "use strict"; | 
| +const assert = require("assert"); | 
| const {createSandbox} = require("./_common"); | 
| let snippets = null; | 
| let parseScript = null; | 
| let compileScript = null; | 
| let Filter = null; | 
| let SnippetFilter = null; | 
| -exports.setUp = function(callback) | 
| +describe("Snippets", () => | 
| { | 
| - let sandboxedRequire = createSandbox(); | 
| - ( | 
| - {Filter, SnippetFilter} = sandboxedRequire("../lib/filterClasses"), | 
| - {snippets, parseScript, compileScript} = sandboxedRequire("../lib/snippets") | 
| - ); | 
| + beforeEach(() => | 
| + { | 
| + let sandboxedRequire = createSandbox(); | 
| + ( | 
| + {Filter, SnippetFilter} = sandboxedRequire("../lib/filterClasses"), | 
| + {snippets, parseScript, compileScript} = sandboxedRequire("../lib/snippets") | 
| + ); | 
| + }); | 
| - callback(); | 
| -}; | 
| + it("Domain Restrictions", () => | 
| + { | 
| + function testScriptMatches(description, filters, domain, expectedMatches) | 
| + { | 
| + for (let filter of filters.map(Filter.fromText)) | 
| + { | 
| + if (filter instanceof SnippetFilter) | 
| + snippets.add(filter); | 
| + } | 
| -exports.testDomainRestrictions = function(test) | 
| -{ | 
| - function testScriptMatches(description, filters, domain, expectedMatches) | 
| - { | 
| - for (let filter of filters.map(Filter.fromText)) | 
| - { | 
| - if (filter instanceof SnippetFilter) | 
| - snippets.add(filter); | 
| + let matches = snippets.getFiltersForDomain(domain).map( | 
| + filter => filter.script | 
| + ); | 
| + assert.deepEqual(matches.sort(), expectedMatches.sort(), description); | 
| + | 
| + snippets.clear(); | 
| } | 
| - let matches = snippets.getFiltersForDomain(domain).map( | 
| - filter => filter.script | 
| + testScriptMatches( | 
| + "Ignore generic filters", | 
| + [ | 
| + "#$#foo-1", "example.com#$#foo-2", | 
| + "~example.com#$#foo-3" | 
| + ], | 
| + "example.com", | 
| + ["foo-2"] | 
| + ); | 
| + testScriptMatches( | 
| + "Ignore filters that include parent domain but exclude subdomain", | 
| + [ | 
| + "~www.example.com,example.com#$#foo" | 
| + ], | 
| + "www.example.com", | 
| + [] | 
| + ); | 
| + testScriptMatches( | 
| + "Ignore filters for other subdomain", | 
| + [ | 
| + "www.example.com#$#foo-1", | 
| + "other.example.com#$#foo-2" | 
| + ], | 
| + "other.example.com", | 
| + ["foo-2"] | 
| ); | 
| - test.deepEqual(matches.sort(), expectedMatches.sort(), description); | 
| + }); | 
| + | 
| + it("Filters container", () => | 
| + { | 
| + let events = []; | 
| + | 
| + function eventHandler(...args) | 
| + { | 
| + events.push([...args]); | 
| + } | 
| + | 
| + function compareRules(description, domain, expectedMatches) | 
| + { | 
| + let result = snippets.getFiltersForDomain(domain); | 
| + assert.deepEqual(result.sort(), expectedMatches.sort(), description); | 
| + } | 
| + | 
| + snippets.on("snippets.filterAdded", | 
| + eventHandler.bind(null, "snippets.filterAdded")); | 
| + snippets.on("snippets.filterRemoved", | 
| + eventHandler.bind(null, "snippets.filterRemoved")); | 
| + snippets.on("snippets.filtersCleared", | 
| + eventHandler.bind(null, "snippets.filtersCleared")); | 
| + | 
| + let domainFilter = Filter.fromText("example.com#$#filter1"); | 
| + let subdomainFilter = Filter.fromText("www.example.com#$#filter2"); | 
| + let otherDomainFilter = Filter.fromText("other.example.com#$#filter3"); | 
| + | 
| + snippets.add(domainFilter); | 
| + snippets.add(subdomainFilter); | 
| + snippets.add(otherDomainFilter); | 
| + compareRules( | 
| + "Return all matching filters", | 
| + "www.example.com", | 
| + [domainFilter, subdomainFilter] | 
| + ); | 
| + | 
| + snippets.remove(domainFilter); | 
| + compareRules( | 
| + "Return all matching filters after removing one", | 
| + "www.example.com", | 
| + [subdomainFilter] | 
| + ); | 
| snippets.clear(); | 
| - } | 
| - | 
| - testScriptMatches( | 
| - "Ignore generic filters", | 
| - [ | 
| - "#$#foo-1", "example.com#$#foo-2", | 
| - "~example.com#$#foo-3" | 
| - ], | 
| - "example.com", | 
| - ["foo-2"] | 
| - ); | 
| - testScriptMatches( | 
| - "Ignore filters that include parent domain but exclude subdomain", | 
| - [ | 
| - "~www.example.com,example.com#$#foo" | 
| - ], | 
| - "www.example.com", | 
| - [] | 
| - ); | 
| - testScriptMatches( | 
| - "Ignore filters for other subdomain", | 
| - [ | 
| - "www.example.com#$#foo-1", | 
| - "other.example.com#$#foo-2" | 
| - ], | 
| - "other.example.com", | 
| - ["foo-2"] | 
| - ); | 
| - | 
| - test.done(); | 
| -}; | 
| - | 
| -exports.testSnippetFiltersContainer = function(test) | 
| -{ | 
| - let events = []; | 
| - | 
| - function eventHandler(...args) | 
| - { | 
| - events.push([...args]); | 
| - } | 
| - | 
| - function compareRules(description, domain, expectedMatches) | 
| - { | 
| - let result = snippets.getFiltersForDomain(domain); | 
| - test.deepEqual(result.sort(), expectedMatches.sort(), description); | 
| - } | 
| + compareRules( | 
| + "Return no filters after clearing", | 
| + "www.example.com", | 
| + [] | 
| + ); | 
| - snippets.on("snippets.filterAdded", | 
| - eventHandler.bind(null, "snippets.filterAdded")); | 
| - snippets.on("snippets.filterRemoved", | 
| - eventHandler.bind(null, "snippets.filterRemoved")); | 
| - snippets.on("snippets.filtersCleared", | 
| - eventHandler.bind(null, "snippets.filtersCleared")); | 
| - | 
| - let domainFilter = Filter.fromText("example.com#$#filter1"); | 
| - let subdomainFilter = Filter.fromText("www.example.com#$#filter2"); | 
| - let otherDomainFilter = Filter.fromText("other.example.com#$#filter3"); | 
| - | 
| - snippets.add(domainFilter); | 
| - snippets.add(subdomainFilter); | 
| - snippets.add(otherDomainFilter); | 
| - compareRules( | 
| - "Return all matching filters", | 
| - "www.example.com", | 
| - [domainFilter, subdomainFilter] | 
| - ); | 
| + assert.deepEqual(events, [ | 
| + ["snippets.filterAdded", domainFilter], | 
| + ["snippets.filterAdded", subdomainFilter], | 
| + ["snippets.filterAdded", otherDomainFilter], | 
| + ["snippets.filterRemoved", domainFilter], | 
| + ["snippets.filtersCleared"] | 
| + ], | 
| + "Event log"); | 
| + }); | 
| - snippets.remove(domainFilter); | 
| - compareRules( | 
| - "Return all matching filters after removing one", | 
| - "www.example.com", | 
| - [subdomainFilter] | 
| - ); | 
| - | 
| - snippets.clear(); | 
| - compareRules( | 
| - "Return no filters after clearing", | 
| - "www.example.com", | 
| - [] | 
| - ); | 
| - | 
| - test.deepEqual(events, [ | 
| - ["snippets.filterAdded", domainFilter], | 
| - ["snippets.filterAdded", subdomainFilter], | 
| - ["snippets.filterAdded", otherDomainFilter], | 
| - ["snippets.filterRemoved", domainFilter], | 
| - ["snippets.filtersCleared"] | 
| - ], | 
| - "Event log"); | 
| - | 
| - test.done(); | 
| -}; | 
| - | 
| -exports.testScriptParsing = function(test) | 
| -{ | 
| - function checkParsedScript(description, script, expectedTree) | 
| + it("Script Parsing", () => | 
| { | 
| - let tree = parseScript(script); | 
| - test.deepEqual(tree, expectedTree, description); | 
| - } | 
| + function checkParsedScript(description, script, expectedTree) | 
| + { | 
| + let tree = parseScript(script); | 
| + assert.deepEqual(tree, expectedTree, description); | 
| + } | 
| - checkParsedScript("Script with no arguments", "foo", [["foo"]]); | 
| - checkParsedScript("Script with one argument", "foo 1", [["foo", "1"]]); | 
| - checkParsedScript("Script with two arguments", "foo 1 Hello", | 
| - [["foo", "1", "Hello"]]); | 
| - checkParsedScript("Script with argument containing an escaped space", | 
| - "foo Hello\\ world", | 
| - [["foo", "Hello world"]]); | 
| - checkParsedScript("Script with argument containing a quoted space", | 
| - "foo 'Hello world'", | 
| - [["foo", "Hello world"]]); | 
| - checkParsedScript("Script with argument containing a quoted escaped quote", | 
| - "foo 'Hello \\'world\\''", | 
| - [["foo", "Hello 'world'"]]); | 
| - checkParsedScript("Script with argument containing an escaped semicolon", | 
| - "foo TL\\;DR", | 
| - [["foo", "TL;DR"]]); | 
| - checkParsedScript("Script with argument containing a quoted semicolon", | 
| - "foo 'TL;DR'", | 
| - [["foo", "TL;DR"]]); | 
| - checkParsedScript("Script with argument containing single character " + | 
| - "escape sequences", | 
| - "foo yin\\tyang\\n", | 
| - [["foo", "yin\tyang\n"]]); | 
| - checkParsedScript("Script with argument containing Unicode escape sequences", | 
| - "foo \\u0062\\ud83d\\ude42r " + | 
| - "'l\\ud83d\\ude02mbd\\ud83d\\ude02'", [ | 
| - ["foo", "b\ud83d\ude42r", "l\ud83d\ude02mbd\ud83d\ude02"] | 
| - ]); | 
| - checkParsedScript("Script with multiple commands", "foo; bar", | 
| - [["foo"], ["bar"]]); | 
| - checkParsedScript("Script with multiple commands and multiple arguments each", | 
| - "foo 1 Hello; bar world! #", | 
| - [["foo", "1", "Hello"], ["bar", "world!", "#"]]); | 
| - checkParsedScript("Script with multiple commands and multiple " + | 
| - "escaped and quoted arguments each", | 
| - "foo 1 'Hello, \\'Tommy\\'!' ;" + | 
| - "bar Hi!\\ How\\ are\\ you? http://example.com", [ | 
| - ["foo", "1", "Hello, 'Tommy'!"], | 
| - ["bar", "Hi! How are you?", "http://example.com"] | 
| - ]); | 
| - checkParsedScript("Script with command names containing " + | 
| - "whitespace (spaces, tabs, newlines, etc.), " + | 
| - "quotes, and semicolons", | 
| - "fo\\'\\ \\ \\\t\\\n\\;o 1 2 3; 'b a r' 1 2", | 
| - [["fo' \t\n;o", "1", "2", "3"], ["b a r", "1", "2"]]); | 
| - checkParsedScript("Script containing Unicode composite characters", | 
| - "f\ud83d\ude42\ud83d\ude42 b\ud83d\ude02r", | 
| - [["f\ud83d\ude42\ud83d\ude42", "b\ud83d\ude02r"]]); | 
| - checkParsedScript("Script with no-op commands", "foo; ;;; ; ; bar 1", | 
| - [["foo"], ["bar", "1"]]); | 
| - checkParsedScript("Script with blank argument in the middle", "foo '' Hello", | 
| - [["foo", "", "Hello"]]); | 
| - checkParsedScript("Script with blank argument at the end", "foo Hello ''", | 
| - [["foo", "Hello", ""]]); | 
| - checkParsedScript("Script with consecutive blank arguments", "foo '' ''", | 
| - [["foo", "", ""]]); | 
| + checkParsedScript("Script with no arguments", "foo", [["foo"]]); | 
| + checkParsedScript("Script with one argument", "foo 1", [["foo", "1"]]); | 
| + checkParsedScript("Script with two arguments", "foo 1 Hello", | 
| + [["foo", "1", "Hello"]]); | 
| + checkParsedScript("Script with argument containing an escaped space", | 
| + "foo Hello\\ world", | 
| + [["foo", "Hello world"]]); | 
| + checkParsedScript("Script with argument containing a quoted space", | 
| + "foo 'Hello world'", | 
| + [["foo", "Hello world"]]); | 
| + checkParsedScript("Script with argument containing a quoted escaped quote", | 
| + "foo 'Hello \\'world\\''", | 
| + [["foo", "Hello 'world'"]]); | 
| + checkParsedScript("Script with argument containing an escaped semicolon", | 
| + "foo TL\\;DR", | 
| + [["foo", "TL;DR"]]); | 
| + checkParsedScript("Script with argument containing a quoted semicolon", | 
| + "foo 'TL;DR'", | 
| + [["foo", "TL;DR"]]); | 
| + checkParsedScript("Script with argument containing single character " + | 
| + "escape sequences", | 
| + "foo yin\\tyang\\n", | 
| + [["foo", "yin\tyang\n"]]); | 
| + checkParsedScript("Script with argument containing Unicode escape sequences", | 
| + "foo \\u0062\\ud83d\\ude42r " + | 
| + "'l\\ud83d\\ude02mbd\\ud83d\\ude02'", [ | 
| + ["foo", "b\ud83d\ude42r", "l\ud83d\ude02mbd\ud83d\ude02"] | 
| + ]); | 
| + checkParsedScript("Script with multiple commands", "foo; bar", | 
| + [["foo"], ["bar"]]); | 
| + checkParsedScript("Script with multiple commands and multiple arguments each", | 
| + "foo 1 Hello; bar world! #", | 
| + [["foo", "1", "Hello"], ["bar", "world!", "#"]]); | 
| + checkParsedScript("Script with multiple commands and multiple " + | 
| + "escaped and quoted arguments each", | 
| + "foo 1 'Hello, \\'Tommy\\'!' ;" + | 
| + "bar Hi!\\ How\\ are\\ you? http://example.com", [ | 
| + ["foo", "1", "Hello, 'Tommy'!"], | 
| + ["bar", "Hi! How are you?", "http://example.com"] | 
| + ]); | 
| + checkParsedScript("Script with command names containing " + | 
| + "whitespace (spaces, tabs, newlines, etc.), " + | 
| + "quotes, and semicolons", | 
| + "fo\\'\\ \\ \\\t\\\n\\;o 1 2 3; 'b a r' 1 2", | 
| + [["fo' \t\n;o", "1", "2", "3"], ["b a r", "1", "2"]]); | 
| + checkParsedScript("Script containing Unicode composite characters", | 
| + "f\ud83d\ude42\ud83d\ude42 b\ud83d\ude02r", | 
| + [["f\ud83d\ude42\ud83d\ude42", "b\ud83d\ude02r"]]); | 
| + checkParsedScript("Script with no-op commands", "foo; ;;; ; ; bar 1", | 
| + [["foo"], ["bar", "1"]]); | 
| + checkParsedScript("Script with blank argument in the middle", "foo '' Hello", | 
| + [["foo", "", "Hello"]]); | 
| + checkParsedScript("Script with blank argument at the end", "foo Hello ''", | 
| + [["foo", "Hello", ""]]); | 
| + checkParsedScript("Script with consecutive blank arguments", "foo '' ''", | 
| + [["foo", "", ""]]); | 
| - // Undocumented quirks (#6853). | 
| - checkParsedScript("Script with quotes within an argument", "foo Hello''world", | 
| - [["foo", "Helloworld"]]); | 
| - checkParsedScript("Script with quotes within an argument containing whitespace", | 
| - "foo Hello' 'world", | 
| - [["foo", "Hello world"]]); | 
| - checkParsedScript("Script with quotes within an argument containing non-whitespace", | 
| - "foo Hello','world", | 
| - [["foo", "Hello,world"]]); | 
| - checkParsedScript("Script with quotes within an argument containing whitespace and non-whitespace", | 
| - "foo Hello', 'world", | 
| - [["foo", "Hello, world"]]); | 
| - checkParsedScript("Script with opening quote at the beginning of an argument", | 
| - "foo 'Hello, 'world", | 
| - [["foo", "Hello, world"]]); | 
| - checkParsedScript("Script with closing quote at the end of an argument", | 
| - "foo Hello,' world'", | 
| - [["foo", "Hello, world"]]); | 
| + // Undocumented quirks (#6853). | 
| + checkParsedScript("Script with quotes within an argument", "foo Hello''world", | 
| + [["foo", "Helloworld"]]); | 
| + checkParsedScript("Script with quotes within an argument containing whitespace", | 
| + "foo Hello' 'world", | 
| + [["foo", "Hello world"]]); | 
| + checkParsedScript("Script with quotes within an argument containing non-whitespace", | 
| + "foo Hello','world", | 
| + [["foo", "Hello,world"]]); | 
| + checkParsedScript("Script with quotes within an argument containing whitespace and non-whitespace", | 
| + "foo Hello', 'world", | 
| + [["foo", "Hello, world"]]); | 
| + checkParsedScript("Script with opening quote at the beginning of an argument", | 
| + "foo 'Hello, 'world", | 
| + [["foo", "Hello, world"]]); | 
| + checkParsedScript("Script with closing quote at the end of an argument", | 
| + "foo Hello,' world'", | 
| + [["foo", "Hello, world"]]); | 
| - checkParsedScript("Script with closing quote missing", "foo 'Hello, world", | 
| - []); | 
| - checkParsedScript("Script with closing quote missing in last command", | 
| - "foo Hello; bar 'How are you?", | 
| - [["foo", "Hello"]]); | 
| - checkParsedScript("Script ending with a backslash", | 
| - "foo Hello; bar 'How are you?' \\", | 
| - [["foo", "Hello"]]); | 
| + checkParsedScript("Script with closing quote missing", "foo 'Hello, world", | 
| + []); | 
| + checkParsedScript("Script with closing quote missing in last command", | 
| + "foo Hello; bar 'How are you?", | 
| + [["foo", "Hello"]]); | 
| + checkParsedScript("Script ending with a backslash", | 
| + "foo Hello; bar 'How are you?' \\", | 
| + [["foo", "Hello"]]); | 
| + }); | 
| - test.done(); | 
| -}; | 
| - | 
| -exports.testScriptCompilation = function(test) | 
| -{ | 
| - let libraries = [ | 
| - ` | 
| + it("Script Compilation", () => | 
| + { | 
| + let libraries = [ | 
| + ` | 
| let foo = 0; | 
| exports.setFoo = function(value) | 
| { | 
| foo = value; | 
| }; | 
| exports.assertFoo = function(expected) | 
| { | 
| if (foo != expected) | 
| throw new Error("Value mismatch"); | 
| }; | 
| ` | 
| - ]; | 
| + ]; | 
| - let template = ` | 
| + let template = ` | 
| "use strict"; | 
| { | 
| const libraries = ${JSON.stringify(libraries)}; | 
| const script = {{{script}}}; | 
| let imports = Object.create(null); | 
| for (let library of libraries) | 
| @@ -280,35 +275,34 @@ | 
| let value = imports[name]; | 
| if (typeof value == "function") | 
| value(...args); | 
| } | 
| } | 
| } | 
| `; | 
| - function verifyExecutable(script) | 
| - { | 
| - let actual = compileScript(script, libraries); | 
| - let expected = template.replace("{{{script}}}", | 
| - JSON.stringify(parseScript(script))); | 
| + function verifyExecutable(script) | 
| + { | 
| + let actual = compileScript(script, libraries); | 
| + let expected = template.replace("{{{script}}}", | 
| + JSON.stringify(parseScript(script))); | 
| - test.equal(expected, actual); | 
| - } | 
| + assert.equal(expected, actual); | 
| + } | 
| - verifyExecutable("hello 'How are you?'"); | 
| - | 
| - // Test script execution. | 
| - new Function(compileScript("setFoo 123; assertFoo 123", libraries))(); | 
| + verifyExecutable("hello 'How are you?'"); | 
| - // Override setFoo in a second library, without overriding assertFoo. A | 
| - // couple of things to note here: (1) each library has its own variables; | 
| - // (2) script execution is stateless, i.e. the values are not retained | 
| - // between executions. In the example below, assertFoo does not find 456 but | 
| - // it doesn't find 123 either. It's the initial value 0. | 
| - new Function( | 
| - compileScript("setFoo 456; assertFoo 0", [ | 
| - ...libraries, "let foo = 1; exports.setFoo = value => { foo = value; };" | 
| - ]) | 
| - )(); | 
| + // Test script execution. | 
| + new Function(compileScript("setFoo 123; assertFoo 123", libraries))(); | 
| - test.done(); | 
| -}; | 
| + // Override setFoo in a second library, without overriding assertFoo. A | 
| + // couple of things to note here: (1) each library has its own variables; | 
| + // (2) script execution is stateless, i.e. the values are not retained | 
| + // between executions. In the example below, assertFoo does not find 456 but | 
| + // it doesn't find 123 either. It's the initial value 0. | 
| + new Function( | 
| + compileScript("setFoo 456; assertFoo 0", [ | 
| + ...libraries, "let foo = 1; exports.setFoo = value => { foo = value; };" | 
| + ]) | 
| + )(); | 
| + }); | 
| +}); |