| OLD | NEW |
| (Empty) |
| 1 (function() | |
| 2 { | |
| 3 module("Filter classes", {setup: prepareFilterComponents, teardown: restoreFil
terComponents}); | |
| 4 | |
| 5 function serializeFilter(filter) | |
| 6 { | |
| 7 // Filter serialization only writes out essential properties, need to do a f
ull serialization here | |
| 8 let result = []; | |
| 9 result.push("text=" + filter.text); | |
| 10 if (filter instanceof InvalidFilter) | |
| 11 { | |
| 12 result.push("type=invalid"); | |
| 13 if (filter.reason) | |
| 14 result.push("reason=" + filter.reason); | |
| 15 } | |
| 16 else if (filter instanceof CommentFilter) | |
| 17 { | |
| 18 result.push("type=comment"); | |
| 19 } | |
| 20 else if (filter instanceof ActiveFilter) | |
| 21 { | |
| 22 result.push("disabled=" + filter.disabled); | |
| 23 result.push("lastHit=" + filter.lastHit); | |
| 24 result.push("hitCount=" + filter.hitCount); | |
| 25 | |
| 26 let domains = []; | |
| 27 if (filter.domains) | |
| 28 { | |
| 29 for (let domain in filter.domains) | |
| 30 if (domain != "") | |
| 31 domains.push(filter.domains[domain] ? domain : "~" + domain); | |
| 32 } | |
| 33 result.push("domains=" + domains.sort().join("|")); | |
| 34 | |
| 35 if (filter instanceof RegExpFilter) | |
| 36 { | |
| 37 result.push("regexp=" + filter.regexp.source); | |
| 38 result.push("contentType=" + filter.contentType); | |
| 39 result.push("matchCase=" + filter.matchCase); | |
| 40 | |
| 41 let sitekeys = filter.sitekeys || []; | |
| 42 result.push("sitekeys=" + sitekeys.slice().sort().join("|")); | |
| 43 | |
| 44 result.push("thirdParty=" + filter.thirdParty); | |
| 45 if (filter instanceof BlockingFilter) | |
| 46 { | |
| 47 result.push("type=filterlist"); | |
| 48 result.push("collapse=" + filter.collapse); | |
| 49 } | |
| 50 else if (filter instanceof WhitelistFilter) | |
| 51 { | |
| 52 result.push("type=whitelist"); | |
| 53 } | |
| 54 } | |
| 55 else if (filter instanceof ElemHideBase) | |
| 56 { | |
| 57 if (filter instanceof ElemHideFilter) | |
| 58 result.push("type=elemhide"); | |
| 59 else if (filter instanceof ElemHideException) | |
| 60 result.push("type=elemhideexception"); | |
| 61 else if (filter instanceof CSSPropertyFilter) | |
| 62 { | |
| 63 result.push("type=cssrule"); | |
| 64 result.push("prefix=" + (filter.selectorPrefix || "")); | |
| 65 result.push("regexp=" + filter.regexpString); | |
| 66 result.push("suffix=" + (filter.selectorSuffix || "")); | |
| 67 } | |
| 68 | |
| 69 result.push("selectorDomain=" + (filter.selectorDomain || "")); | |
| 70 result.push("selector=" + filter.selector); | |
| 71 } | |
| 72 } | |
| 73 return result; | |
| 74 } | |
| 75 | |
| 76 function addDefaults(expected) | |
| 77 { | |
| 78 let type = null; | |
| 79 let hasProperty = {}; | |
| 80 for (let entry of expected) | |
| 81 { | |
| 82 if (/^type=(.*)/.test(entry)) | |
| 83 type = RegExp.$1; | |
| 84 else if (/^(\w+)/.test(entry)) | |
| 85 hasProperty[RegExp.$1] = true; | |
| 86 } | |
| 87 | |
| 88 function addProperty(prop, value) | |
| 89 { | |
| 90 if (!(prop in hasProperty)) | |
| 91 expected.push(prop + "=" + value); | |
| 92 } | |
| 93 | |
| 94 if (type == "whitelist" || type == "filterlist" || type == "elemhide" || typ
e == "elemhideexception" || type == "cssrule") | |
| 95 { | |
| 96 addProperty("disabled", "false"); | |
| 97 addProperty("lastHit", "0"); | |
| 98 addProperty("hitCount", "0"); | |
| 99 } | |
| 100 if (type == "whitelist" || type == "filterlist") | |
| 101 { | |
| 102 addProperty("contentType", 0x7FFFFFFF & ~( | |
| 103 RegExpFilter.typeMap.DOCUMENT | RegExpFilter.typeMap.ELEMHIDE | | |
| 104 RegExpFilter.typeMap.POPUP | RegExpFilter.typeMap.GENERICHIDE | | |
| 105 RegExpFilter.typeMap.GENERICBLOCK | |
| 106 )); | |
| 107 addProperty("matchCase", "false"); | |
| 108 addProperty("thirdParty", "null"); | |
| 109 addProperty("domains", ""); | |
| 110 addProperty("sitekeys", ""); | |
| 111 } | |
| 112 if (type == "filterlist") | |
| 113 { | |
| 114 addProperty("collapse", "null"); | |
| 115 } | |
| 116 if (type == "elemhide" || type == "elemhideexception" || type == "cssrule") | |
| 117 { | |
| 118 addProperty("selectorDomain", ""); | |
| 119 addProperty("domains", ""); | |
| 120 } | |
| 121 if (type == "cssrule") | |
| 122 { | |
| 123 addProperty("regexp", ""); | |
| 124 addProperty("prefix", ""); | |
| 125 addProperty("suffix", ""); | |
| 126 } | |
| 127 } | |
| 128 | |
| 129 function compareFilter(text, expected, postInit) | |
| 130 { | |
| 131 addDefaults(expected); | |
| 132 | |
| 133 let filter = Filter.fromText(text); | |
| 134 if (postInit) | |
| 135 postInit(filter) | |
| 136 let result = serializeFilter(filter); | |
| 137 equal(result.sort().join("\n"), expected.sort().join("\n"), text); | |
| 138 | |
| 139 // Test round-trip | |
| 140 let filter2; | |
| 141 let buffer = []; | |
| 142 filter.serialize(buffer); | |
| 143 if (buffer.length) | |
| 144 { | |
| 145 let map = Object.create(null); | |
| 146 for (let line of buffer.slice(1)) | |
| 147 { | |
| 148 if (/(.*?)=(.*)/.test(line)) | |
| 149 map[RegExp.$1] = RegExp.$2; | |
| 150 } | |
| 151 filter2 = Filter.fromObject(map); | |
| 152 } | |
| 153 else | |
| 154 { | |
| 155 filter2 = Filter.fromText(filter.text); | |
| 156 } | |
| 157 | |
| 158 equal(serializeFilter(filter).join("\n"), serializeFilter(filter2).join("\n"
), text + " deserialization"); | |
| 159 } | |
| 160 | |
| 161 test("Filter class definitions", function() | |
| 162 { | |
| 163 equal(typeof Filter, "function", "typeof Filter"); | |
| 164 equal(typeof InvalidFilter, "function", "typeof InvalidFilter"); | |
| 165 equal(typeof CommentFilter, "function", "typeof CommentFilter"); | |
| 166 equal(typeof ActiveFilter, "function", "typeof ActiveFilter"); | |
| 167 equal(typeof RegExpFilter, "function", "typeof RegExpFilter"); | |
| 168 equal(typeof BlockingFilter, "function", "typeof BlockingFilter"); | |
| 169 equal(typeof WhitelistFilter, "function", "typeof WhitelistFilter"); | |
| 170 equal(typeof ElemHideBase, "function", "typeof ElemHideBase"); | |
| 171 equal(typeof ElemHideFilter, "function", "typeof ElemHideFilter"); | |
| 172 equal(typeof ElemHideException, "function", "typeof ElemHideException"); | |
| 173 equal(typeof CSSPropertyFilter, "function", "typeof CSSPropertyFilter"); | |
| 174 }); | |
| 175 | |
| 176 test("Comments", function() | |
| 177 { | |
| 178 compareFilter("!asdf", ["type=comment", "text=!asdf"]); | |
| 179 compareFilter("!foo#bar", ["type=comment", "text=!foo#bar"]); | |
| 180 compareFilter("!foo##bar", ["type=comment", "text=!foo##bar"]); | |
| 181 }); | |
| 182 | |
| 183 test("Invalid filters", function() | |
| 184 { | |
| 185 compareFilter("/??/", ["type=invalid", "text=/??/", "reason=filter_invalid_r
egexp"]); | |
| 186 compareFilter("#dd(asd)(ddd)", ["type=invalid", "text=#dd(asd)(ddd)", "reaso
n=filter_elemhide_duplicate_id"]); | |
| 187 compareFilter("#*", ["type=invalid", "text=#*", "reason=filter_elemhide_nocr
iteria"]); | |
| 188 | |
| 189 function compareCSSRule(domains) | |
| 190 { | |
| 191 let filterText = domains + "##[-abp-properties='abc']"; | |
| 192 compareFilter(filterText, ["type=invalid", "text=" + filterText, "reason=f
ilter_cssproperty_nodomain"]); | |
| 193 } | |
| 194 compareCSSRule(""); | |
| 195 compareCSSRule("~foo.com"); | |
| 196 compareCSSRule("~foo.com,~bar.com"); | |
| 197 compareCSSRule("foo"); | |
| 198 compareCSSRule("~foo.com,bar"); | |
| 199 }); | |
| 200 | |
| 201 test("Filters with state", function() | |
| 202 { | |
| 203 compareFilter("blabla", ["type=filterlist", "text=blabla", "regexp=blabla"])
; | |
| 204 compareFilter("blabla_default", ["type=filterlist", "text=blabla_default", "
regexp=blabla_default"], function(filter) | |
| 205 { | |
| 206 filter.disabled = false; | |
| 207 filter.hitCount = 0; | |
| 208 filter.lastHit = 0; | |
| 209 }); | |
| 210 compareFilter("blabla_non_default", ["type=filterlist", "text=blabla_non_def
ault", "regexp=blabla_non_default", "disabled=true", "hitCount=12", "lastHit=20"
], function(filter) | |
| 211 { | |
| 212 filter.disabled = true; | |
| 213 filter.hitCount = 12; | |
| 214 filter.lastHit = 20; | |
| 215 }); | |
| 216 }); | |
| 217 | |
| 218 let t = RegExpFilter.typeMap; | |
| 219 let defaultTypes = 0x7FFFFFFF & ~(t.ELEMHIDE | t.DOCUMENT | t.POPUP | t.GENERI
CHIDE | t.GENERICBLOCK); | |
| 220 | |
| 221 test("Special characters", function() | |
| 222 { | |
| 223 compareFilter("/ddd|f?a[s]d/", ["type=filterlist", "text=/ddd|f?a[s]d/", "re
gexp=ddd|f?a[s]d"]); | |
| 224 compareFilter("*asdf*d**dd*", ["type=filterlist", "text=*asdf*d**dd*", "rege
xp=asdf.*d.*dd"]); | |
| 225 compareFilter("|*asd|f*d**dd*|", ["type=filterlist", "text=|*asd|f*d**dd*|",
"regexp=^.*asd\\|f.*d.*dd.*$"]); | |
| 226 compareFilter("dd[]{}$%<>&()d", ["type=filterlist", "text=dd[]{}$%<>&()d", "
regexp=dd\\[\\]\\{\\}\\$\\%\\<\\>\\&\\(\\)d"]); | |
| 227 | |
| 228 compareFilter("@@/ddd|f?a[s]d/", ["type=whitelist", "text=@@/ddd|f?a[s]d/",
"regexp=ddd|f?a[s]d", "contentType=" + defaultTypes]); | |
| 229 compareFilter("@@*asdf*d**dd*", ["type=whitelist", "text=@@*asdf*d**dd*", "r
egexp=asdf.*d.*dd", "contentType=" + defaultTypes]); | |
| 230 compareFilter("@@|*asd|f*d**dd*|", ["type=whitelist", "text=@@|*asd|f*d**dd*
|", "regexp=^.*asd\\|f.*d.*dd.*$", "contentType=" + defaultTypes]); | |
| 231 compareFilter("@@dd[]{}$%<>&()d", ["type=whitelist", "text=@@dd[]{}$%<>&()d"
, "regexp=dd\\[\\]\\{\\}\\$\\%\\<\\>\\&\\(\\)d", "contentType=" + defaultTypes])
; | |
| 232 }); | |
| 233 | |
| 234 test("Filter options", function() | |
| 235 { | |
| 236 compareFilter("bla$match-case,script,other,third-party,domain=foo.com,siteke
y=foo", ["type=filterlist", "text=bla$match-case,script,other,third-party,domain
=foo.com,sitekey=foo", "regexp=bla", "matchCase=true", "contentType=" + (t.SCRIP
T | t.OTHER), "thirdParty=true", "domains=FOO.COM", "sitekeys=FOO"]); | |
| 237 compareFilter("bla$~match-case,~script,~other,~third-party,domain=~bar.com",
["type=filterlist", "text=bla$~match-case,~script,~other,~third-party,domain=~b
ar.com", "regexp=bla", "contentType=" + (defaultTypes & ~(t.SCRIPT | t.OTHER)),
"thirdParty=false", "domains=~BAR.COM"]); | |
| 238 compareFilter("@@bla$match-case,script,other,third-party,domain=foo.com|bar.
com|~bar.foo.com|~foo.bar.com,sitekey=foo|bar", ["type=whitelist", "text=@@bla$m
atch-case,script,other,third-party,domain=foo.com|bar.com|~bar.foo.com|~foo.bar.
com,sitekey=foo|bar", "regexp=bla", "matchCase=true", "contentType=" + (t.SCRIPT
| t.OTHER), "thirdParty=true", "domains=BAR.COM|FOO.COM|~BAR.FOO.COM|~FOO.BAR.C
OM", "sitekeys=BAR|FOO"]); | |
| 239 | |
| 240 // background and image should be the same for backwards compatibility | |
| 241 compareFilter("bla$image", ["type=filterlist", "text=bla$image", "regexp=bla
", "contentType=" + (t.IMAGE)]); | |
| 242 compareFilter("bla$background", ["type=filterlist", "text=bla$background", "
regexp=bla", "contentType=" + (t.IMAGE)]); | |
| 243 compareFilter("bla$~image", ["type=filterlist", "text=bla$~image", "regexp=b
la", "contentType=" + (defaultTypes & ~t.IMAGE)]); | |
| 244 compareFilter("bla$~background", ["type=filterlist", "text=bla$~background",
"regexp=bla", "contentType=" + (defaultTypes & ~t.IMAGE)]); | |
| 245 | |
| 246 compareFilter("@@bla$~script,~other", ["type=whitelist", "text=@@bla$~script
,~other", "regexp=bla", "contentType=" + (defaultTypes & ~(t.SCRIPT | t.OTHER))]
); | |
| 247 compareFilter("@@http://bla$~script,~other", ["type=whitelist", "text=@@http
://bla$~script,~other", "regexp=http\\:\\/\\/bla", "contentType=" + (defaultType
s & ~(t.SCRIPT | t.OTHER))]); | |
| 248 compareFilter("@@|ftp://bla$~script,~other", ["type=whitelist", "text=@@|ftp
://bla$~script,~other", "regexp=^ftp\\:\\/\\/bla", "contentType=" + (defaultType
s & ~(t.SCRIPT | t.OTHER))]); | |
| 249 compareFilter("@@bla$~script,~other,document", ["type=whitelist", "text=@@bl
a$~script,~other,document", "regexp=bla", "contentType=" + (defaultTypes & ~(t.
SCRIPT | t.OTHER) | t.DOCUMENT)]); | |
| 250 compareFilter("@@bla$~script,~other,~document", ["type=whitelist", "text=@@b
la$~script,~other,~document", "regexp=bla", "contentType=" + (defaultTypes & ~(t
.SCRIPT | t.OTHER))]); | |
| 251 compareFilter("@@bla$document", ["type=whitelist", "text=@@bla$document", "r
egexp=bla", "contentType=" + t.DOCUMENT]); | |
| 252 compareFilter("@@bla$~script,~other,elemhide", ["type=whitelist", "text=@@bl
a$~script,~other,elemhide", "regexp=bla", "contentType=" + (defaultTypes & ~(t.
SCRIPT | t.OTHER) | t.ELEMHIDE)]); | |
| 253 compareFilter("@@bla$~script,~other,~elemhide", ["type=whitelist", "text=@@b
la$~script,~other,~elemhide", "regexp=bla", "contentType=" + (defaultTypes & ~(t
.SCRIPT | t.OTHER))]); | |
| 254 compareFilter("@@bla$elemhide", ["type=whitelist", "text=@@bla$elemhide", "r
egexp=bla", "contentType=" + t.ELEMHIDE]); | |
| 255 | |
| 256 compareFilter("@@bla$~script,~other,donottrack", ["type=invalid", "text=@@bl
a$~script,~other,donottrack", "reason=filter_unknown_option"]); | |
| 257 compareFilter("@@bla$~script,~other,~donottrack", ["type=invalid", "text=@@b
la$~script,~other,~donottrack", "reason=filter_unknown_option"]); | |
| 258 compareFilter("@@bla$donottrack", ["type=invalid", "text=@@bla$donottrack",
"reason=filter_unknown_option"]); | |
| 259 compareFilter("@@bla$foobar", ["type=invalid", "text=@@bla$foobar", "reason=
filter_unknown_option"]); | |
| 260 compareFilter("@@bla$image,foobar", ["type=invalid", "text=@@bla$image,fooba
r", "reason=filter_unknown_option"]); | |
| 261 compareFilter("@@bla$foobar,image", ["type=invalid", "text=@@bla$foobar,imag
e", "reason=filter_unknown_option"]); | |
| 262 }); | |
| 263 | |
| 264 test("Element hiding rules", function() | |
| 265 { | |
| 266 compareFilter("#ddd", ["type=elemhide", "text=#ddd", "selector=ddd"]); | |
| 267 compareFilter("#ddd(fff)", ["type=elemhide", "text=#ddd(fff)", "selector=ddd
.fff,ddd#fff"]); | |
| 268 compareFilter("#ddd(foo=bar)(foo2^=bar2)(foo3*=bar3)(foo4$=bar4)", ["type=el
emhide", "text=#ddd(foo=bar)(foo2^=bar2)(foo3*=bar3)(foo4$=bar4)", 'selector=ddd
[foo="bar"][foo2^="bar2"][foo3*="bar3"][foo4$="bar4"]']); | |
| 269 compareFilter("#ddd(fff)(foo=bar)", ["type=elemhide", "text=#ddd(fff)(foo=ba
r)", 'selector=ddd.fff[foo="bar"],ddd#fff[foo="bar"]']); | |
| 270 compareFilter("#*(fff)", ["type=elemhide", "text=#*(fff)", "selector=.fff,#f
ff"]); | |
| 271 compareFilter("#*(foo=bar)", ["type=elemhide", "text=#*(foo=bar)", 'selector
=[foo="bar"]']); | |
| 272 compareFilter("##body > div:first-child", ["type=elemhide", "text=##body > d
iv:first-child", "selector=body > div:first-child"]); | |
| 273 compareFilter("foo#ddd", ["type=elemhide", "text=foo#ddd", "selectorDomain=f
oo", "selector=ddd", "domains=FOO"]); | |
| 274 compareFilter("foo,bar#ddd", ["type=elemhide", "text=foo,bar#ddd", "selector
Domain=foo,bar", "selector=ddd", "domains=BAR|FOO"]); | |
| 275 compareFilter("foo,~bar#ddd", ["type=elemhide", "text=foo,~bar#ddd", "select
orDomain=foo", "selector=ddd", "domains=FOO|~BAR"]); | |
| 276 compareFilter("foo,~baz,bar#ddd", ["type=elemhide", "text=foo,~baz,bar#ddd",
"selectorDomain=foo,bar", "selector=ddd", "domains=BAR|FOO|~BAZ"]); | |
| 277 }); | |
| 278 | |
| 279 test("Element hiding exceptions", function() | |
| 280 { | |
| 281 compareFilter("#@ddd", ["type=elemhideexception", "text=#@ddd", "selector=dd
d"]); | |
| 282 compareFilter("#@ddd(fff)", ["type=elemhideexception", "text=#@ddd(fff)", "s
elector=ddd.fff,ddd#fff"]); | |
| 283 compareFilter("#@ddd(foo=bar)(foo2^=bar2)(foo3*=bar3)(foo4$=bar4)", ["type=e
lemhideexception", "text=#@ddd(foo=bar)(foo2^=bar2)(foo3*=bar3)(foo4$=bar4)", 's
elector=ddd[foo="bar"][foo2^="bar2"][foo3*="bar3"][foo4$="bar4"]']); | |
| 284 compareFilter("#@ddd(fff)(foo=bar)", ["type=elemhideexception", "text=#@ddd(
fff)(foo=bar)", 'selector=ddd.fff[foo="bar"],ddd#fff[foo="bar"]']); | |
| 285 compareFilter("#@*(fff)", ["type=elemhideexception", "text=#@*(fff)", "selec
tor=.fff,#fff"]); | |
| 286 compareFilter("#@*(foo=bar)", ["type=elemhideexception", "text=#@*(foo=bar)"
, 'selector=[foo="bar"]']); | |
| 287 compareFilter("#@#body > div:first-child", ["type=elemhideexception", "text=
#@#body > div:first-child", "selector=body > div:first-child"]); | |
| 288 compareFilter("foo#@ddd", ["type=elemhideexception", "text=foo#@ddd", "selec
torDomain=foo", "selector=ddd", "domains=FOO"]); | |
| 289 compareFilter("foo,bar#@ddd", ["type=elemhideexception", "text=foo,bar#@ddd"
, "selectorDomain=foo,bar", "selector=ddd", "domains=BAR|FOO"]); | |
| 290 compareFilter("foo,~bar#@ddd", ["type=elemhideexception", "text=foo,~bar#@dd
d", "selectorDomain=foo", "selector=ddd", "domains=FOO|~BAR"]); | |
| 291 compareFilter("foo,~baz,bar#@ddd", ["type=elemhideexception", "text=foo,~baz
,bar#@ddd", "selectorDomain=foo,bar", "selector=ddd", "domains=BAR|FOO|~BAZ"]); | |
| 292 }); | |
| 293 | |
| 294 test("CSS property filters", function() | |
| 295 { | |
| 296 // Check valid domain combinations | |
| 297 compareFilter("foo.com##[-abp-properties='abc']", ["type=cssrule", "text=foo
.com##[-abp-properties='abc']", "selectorDomain=foo.com", "selector=[-abp-proper
ties='abc']", "domains=FOO.COM", "regexp=abc"]); | |
| 298 compareFilter("foo.com,~bar.com##[-abp-properties='abc']", ["type=cssrule",
"text=foo.com,~bar.com##[-abp-properties='abc']", "selectorDomain=foo.com", "sel
ector=[-abp-properties='abc']", "domains=FOO.COM|~BAR.COM", "regexp=abc"]); | |
| 299 compareFilter("foo.com,~bar##[-abp-properties='abc']", ["type=cssrule", "tex
t=foo.com,~bar##[-abp-properties='abc']", "selectorDomain=foo.com", "selector=[-
abp-properties='abc']", "domains=FOO.COM|~BAR", "regexp=abc"]); | |
| 300 compareFilter("~foo.com,bar.com##[-abp-properties='abc']", ["type=cssrule",
"text=~foo.com,bar.com##[-abp-properties='abc']", "selectorDomain=bar.com", "sel
ector=[-abp-properties='abc']", "domains=BAR.COM|~FOO.COM", "regexp=abc"]); | |
| 301 | |
| 302 compareFilter("##[-abp-properties='']", ["type=elemhide", "text=##[-abp-prop
erties='']", "selector=[-abp-properties='']"]); | |
| 303 compareFilter("foo.com#@#[-abp-properties='abc']", ["type=elemhideexception"
, "text=foo.com#@#[-abp-properties='abc']", "selectorDomain=foo.com", "selector=
[-abp-properties='abc']", "domains=FOO.COM"]); | |
| 304 compareFilter("foo.com##aaa [-abp-properties='abc'] bbb", ["type=cssrule", "
text=foo.com##aaa [-abp-properties='abc'] bbb", "selectorDomain=foo.com", "selec
tor=aaa [-abp-properties='abc'] bbb", "domains=FOO.COM", "prefix=aaa ", "regexp=
abc", "suffix= bbb"]); | |
| 305 compareFilter("foo.com##[-abp-properties='|background-image: url(data:*)']",
["type=cssrule", "text=foo.com##[-abp-properties='|background-image: url(data:*
)']", "selectorDomain=foo.com", "selector=[-abp-properties='|background-image: u
rl(data:*)']", "domains=FOO.COM", "regexp=^background\\-image\\:\\ url\\(data\\:
.*\\)"]); | |
| 306 }); | |
| 307 })(); | |
| OLD | NEW |