| Index: test/filterClasses.js | 
| =================================================================== | 
| --- a/test/filterClasses.js | 
| +++ b/test/filterClasses.js | 
| @@ -20,33 +20,35 @@ | 
| const {createSandbox} = require("./_common"); | 
|  | 
| let Filter = null; | 
| let InvalidFilter = null; | 
| let CommentFilter = null; | 
| let ActiveFilter = null; | 
| let RegExpFilter = null; | 
| let BlockingFilter = null; | 
| +let ScriptFilter = null; | 
| let WhitelistFilter = null; | 
| let ElemHideBase = null; | 
| let ElemHideFilter = null; | 
| let ElemHideException = null; | 
| let ElemHideEmulationFilter = null; | 
| +let SnippetFilter = null; | 
|  | 
| let t = null; | 
| let defaultTypes = null; | 
|  | 
| exports.setUp = function(callback) | 
| { | 
| let sandboxedRequire = createSandbox(); | 
| ( | 
| {Filter, InvalidFilter, CommentFilter, ActiveFilter, RegExpFilter, | 
| -     BlockingFilter, WhitelistFilter, ElemHideBase, ElemHideFilter, | 
| -     ElemHideException, | 
| -     ElemHideEmulationFilter} = sandboxedRequire("../lib/filterClasses") | 
| +     BlockingFilter, WhitelistFilter, ScriptFilter, ElemHideBase, | 
| +     ElemHideFilter, ElemHideException, ElemHideEmulationFilter, | 
| +     SnippetFilter} = sandboxedRequire("../lib/filterClasses") | 
| ); | 
| t = RegExpFilter.typeMap; | 
| defaultTypes = 0x7FFFFFFF & ~(t.CSP | t.ELEMHIDE | t.DOCUMENT | t.POPUP | | 
| t.GENERICHIDE | t.GENERICBLOCK); | 
|  | 
| callback(); | 
| }; | 
|  | 
| @@ -109,16 +111,25 @@ | 
| result.push("type=elemhideemulation"); | 
|  | 
| result.push("selectorDomains=" + | 
| [...filter.domains || []] | 
| .filter(([domain, isIncluded]) => isIncluded) | 
| .map(([domain]) => domain.toLowerCase())); | 
| result.push("selector=" + filter.selector); | 
| } | 
| +    else if (filter instanceof SnippetFilter) | 
| +    { | 
| +      result.push("type=snippet"); | 
| +      result.push("scriptDomains=" + | 
| +                  [...filter.domains || []] | 
| +                  .filter(([domain, isIncluded]) => isIncluded) | 
| +                  .map(([domain]) => domain.toLowerCase())); | 
| +      result.push("script=" + filter.script); | 
| +    } | 
| } | 
| return result; | 
| } | 
|  | 
| function addDefaults(expected) | 
| { | 
| let type = null; | 
| let hasProperty = {}; | 
| @@ -132,17 +143,18 @@ | 
|  | 
| function addProperty(prop, value) | 
| { | 
| if (!(prop in hasProperty)) | 
| expected.push(prop + "=" + value); | 
| } | 
|  | 
| if (type == "whitelist" || type == "filterlist" || type == "elemhide" || | 
| -      type == "elemhideexception" || type == "elemhideemulation") | 
| +      type == "elemhideexception" || type == "elemhideemulation" || | 
| +      type == "snippet") | 
| { | 
| addProperty("disabled", "false"); | 
| addProperty("lastHit", "0"); | 
| addProperty("hitCount", "0"); | 
| } | 
| if (type == "whitelist" || type == "filterlist") | 
| { | 
| addProperty("contentType", 0x7FFFFFFF & ~( | 
| @@ -160,16 +172,21 @@ | 
| addProperty("rewrite", "null"); | 
| } | 
| if (type == "elemhide" || type == "elemhideexception" || | 
| type == "elemhideemulation") | 
| { | 
| addProperty("selectorDomains", ""); | 
| addProperty("domains", ""); | 
| } | 
| +  if (type == "snippet") | 
| +  { | 
| +    addProperty("scriptDomains", ""); | 
| +    addProperty("domains", ""); | 
| +  } | 
| } | 
|  | 
| function compareFilter(test, text, expected, postInit) | 
| { | 
| addDefaults(expected); | 
|  | 
| let filter = Filter.fromText(text); | 
| if (postInit) | 
| @@ -200,22 +217,24 @@ | 
| exports.testFilterClassDefinitions = function(test) | 
| { | 
| test.equal(typeof Filter, "function", "typeof Filter"); | 
| test.equal(typeof InvalidFilter, "function", "typeof InvalidFilter"); | 
| test.equal(typeof CommentFilter, "function", "typeof CommentFilter"); | 
| test.equal(typeof ActiveFilter, "function", "typeof ActiveFilter"); | 
| test.equal(typeof RegExpFilter, "function", "typeof RegExpFilter"); | 
| test.equal(typeof BlockingFilter, "function", "typeof BlockingFilter"); | 
| +  test.equal(typeof ScriptFilter, "function", "typeof ScriptFilter"); | 
| test.equal(typeof WhitelistFilter, "function", "typeof WhitelistFilter"); | 
| test.equal(typeof ElemHideBase, "function", "typeof ElemHideBase"); | 
| test.equal(typeof ElemHideFilter, "function", "typeof ElemHideFilter"); | 
| test.equal(typeof ElemHideException, "function", "typeof ElemHideException"); | 
| test.equal(typeof ElemHideEmulationFilter, "function", | 
| "typeof ElemHideEmulationFilter"); | 
| +  test.equal(typeof SnippetFilter, "function", "typeof SnippetFilter"); | 
|  | 
| test.done(); | 
| }; | 
|  | 
| exports.testComments = function(test) | 
| { | 
| compareFilter(test, "!asdf", ["type=comment", "text=!asdf"]); | 
| compareFilter(test, "!foo#bar", ["type=comment", "text=!foo#bar"]); | 
| @@ -418,16 +437,26 @@ | 
| "selectorDomains=foo.com", | 
| "selector=:-abp-properties(/margin: [3-4]\\7B 2\\7D /)", | 
| "domains=foo.com" | 
| ] | 
| ); | 
| test.done(); | 
| }; | 
|  | 
| +exports.testSnippetFilters = function(test) | 
| +{ | 
| +  compareFilter(test, "foo.com#$#abc", ["type=snippet", "text=foo.com#$#abc", "scriptDomains=foo.com", "script=abc", "domains=foo.com"]); | 
| +  compareFilter(test, "foo.com,~bar.com#$#abc", ["type=snippet", "text=foo.com,~bar.com#$#abc", "scriptDomains=foo.com", "script=abc", "domains=foo.com|~bar.com"]); | 
| +  compareFilter(test, "foo.com,~bar#$#abc", ["type=snippet", "text=foo.com,~bar#$#abc", "scriptDomains=foo.com", "script=abc", "domains=foo.com|~bar"]); | 
| +  compareFilter(test, "~foo.com,bar.com#$#abc", ["type=snippet", "text=~foo.com,bar.com#$#abc", "scriptDomains=bar.com", "script=abc", "domains=bar.com|~foo.com"]); | 
| + | 
| +  test.done(); | 
| +}; | 
| + | 
| exports.testFilterNormalization = function(test) | 
| { | 
| // Line breaks etc | 
| test.equal(Filter.normalize("\n\t\nad\ns"), | 
| "ads"); | 
|  | 
| // Comment filters | 
| test.equal(Filter.normalize("   !  fo  o##  bar   "), | 
| @@ -457,16 +486,20 @@ | 
|  | 
| // Incorrect syntax: the separator "#@#" cannot contain spaces; treated as a | 
| // regular filter instead (not an element hiding filter either!), because | 
| // unlike the case with "# ?##" the "##" following the "@" is not considered | 
| // to be a separator | 
| test.equal(Filter.normalize("   domain.c  om# @## sele ctor   "), | 
| "domain.com#@##selector"); | 
|  | 
| +  // Snippet filters | 
| +  test.equal(Filter.normalize("   domain.c  om#$#  sni pp  et   "), | 
| +             "domain.com#$#sni pp  et"); | 
| + | 
| // Regular filters | 
| let normalized = Filter.normalize( | 
| "    b$l 	 a$sitekey=  foo  ,domain= do main.com |foo   .com,c sp= c   s p  " | 
| ); | 
| test.equal( | 
| normalized, | 
| "b$la$sitekey=foo,domain=domain.com|foo.com,csp=c s p" | 
| ); | 
|  |