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 |