LEFT | RIGHT |
1 /* | 1 /* |
2 * This file is part of Adblock Plus <https://adblockplus.org/>, | 2 * This file is part of Adblock Plus <https://adblockplus.org/>, |
3 * Copyright (C) 2006-2017 eyeo GmbH | 3 * Copyright (C) 2006-2017 eyeo GmbH |
4 * | 4 * |
5 * Adblock Plus is free software: you can redistribute it and/or modify | 5 * Adblock Plus is free software: you can redistribute it and/or modify |
6 * it under the terms of the GNU General Public License version 3 as | 6 * it under the terms of the GNU General Public License version 3 as |
7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
8 * | 8 * |
9 * Adblock Plus is distributed in the hope that it will be useful, | 9 * Adblock Plus is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 * GNU General Public License for more details. | 12 * GNU General Public License for more details. |
13 * | 13 * |
14 * You should have received a copy of the GNU General Public License | 14 * You should have received a copy of the GNU General Public License |
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. | 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
16 */ | 16 */ |
17 | 17 |
18 "use strict"; | 18 "use strict"; |
19 | 19 |
20 let Filter = require("filterClasses").Filter; | 20 let Filter = require("filterClasses").Filter; |
21 let ContentBlockerList = require("../lib/abp2blocklist.js").ContentBlockerList; | 21 let ContentBlockerList = require("../lib/abp2blocklist.js").ContentBlockerList; |
22 | 22 |
23 function testRules(test, filters, expected, transformFunction) | 23 function runTest(test, assertions) |
24 { | 24 { |
25 let blockerList = new ContentBlockerList(); | 25 // All the assertions are run in parallel but we wait for all of them to |
| 26 // finish before moving on to the next test. |
| 27 test.expect(assertions.length); |
| 28 Promise.all(assertions).then(() => test.done()); |
| 29 } |
| 30 |
| 31 function testRules(test, filters, expected, transformFunction, options) |
| 32 { |
| 33 let blockerList = new ContentBlockerList(options); |
26 for (let filter of filters) | 34 for (let filter of filters) |
27 blockerList.addFilter(Filter.fromText(filter)); | 35 blockerList.addFilter(Filter.fromText(filter)); |
28 | 36 |
29 let rules = blockerList.generateRules(); | 37 return blockerList.generateRules().then(rules => |
30 if (transformFunction) | 38 { |
31 rules = transformFunction(rules); | 39 if (transformFunction) |
32 | 40 rules = transformFunction(rules); |
33 test.deepEqual(rules, expected); | 41 |
| 42 test.deepEqual(rules, expected); |
| 43 }); |
34 } | 44 } |
35 | 45 |
36 exports.generateRules = { | 46 exports.generateRules = { |
37 testElementHiding: function(test) | 47 testElementHiding: function(test) |
38 { | 48 { |
39 testRules(test, ["##.whatever"], [ | 49 runTest(test, [ |
40 {trigger: {"url-filter": "^https?://", | 50 testRules(test, ["##.whatever"], [ |
41 "url-filter-is-case-sensitive": true}, | 51 {trigger: {"url-filter": "^https?://", |
42 action: {type: "css-display-none", selector: ".whatever"}} | 52 "url-filter-is-case-sensitive": true}, |
43 ]); | 53 action: {type: "css-display-none", selector: ".whatever"}} |
44 testRules(test, ["test.com##.whatever"], [ | 54 ]), |
45 {trigger: {"url-filter": "^https?://([^/:]*\\.)?test\\.com[/:]", | 55 testRules(test, ["test.com##.whatever"], [ |
46 "url-filter-is-case-sensitive": true}, | 56 {trigger: {"url-filter": "^https?://([^/:]*\\.)?test\\.com[/:]", |
47 action: {type: "css-display-none", selector: ".whatever"}} | 57 "url-filter-is-case-sensitive": true}, |
48 ]); | 58 action: {type: "css-display-none", selector: ".whatever"}} |
49 | 59 ]) |
50 test.done(); | 60 ]); |
51 }, | 61 }, |
52 | 62 |
53 testElementHidingExceptions: function(test) | 63 testElementHidingExceptions: function(test) |
54 { | 64 { |
55 testRules(test, ["#@#whatever"], []); | 65 runTest(test, [ |
56 testRules(test, ["test.com#@#whatever"], []); | 66 testRules(test, [ |
57 testRules(test, ["~test.com#@#whatever"], []); | 67 "##.whatever", |
58 | 68 "test.com,anothertest.com###something", |
59 // We currently completely ignore any element hiding filters that have the | 69 "@@||special.test.com^$elemhide", |
60 // same selector as an element hiding exception. In these examples #whatever | 70 "@@||test.com^$generichide", |
61 // should be hidden for all domains not ending in test.com instead of | 71 "@@||anothertest.com^$elemhide", |
62 // nowhere! | 72 "@@^something^$elemhide", |
63 testRules(test, ["test.com#@#whatever", "##whatever"], []); | 73 "@@^anything^$generichide" |
64 testRules(test, ["~test.com##whatever"], []); | 74 ], [ |
65 | 75 ["^https?://", ["*test.com", "*special.test.com", "*anothertest.com"]], |
66 test.done(); | 76 ["^https?://([^/:]*\\.)?test\\.com[/:]", ["*special.test.com"]] |
| 77 ], rules => rules.map(rule => [rule.trigger["url-filter"], |
| 78 rule.trigger["unless-domain"]])), |
| 79 |
| 80 testRules(test, ["#@#whatever"], []), |
| 81 testRules(test, ["test.com#@#whatever"], []), |
| 82 testRules(test, ["~test.com#@#whatever"], []), |
| 83 |
| 84 // We currently completely ignore any element hiding filters that have the |
| 85 // same selector as an element hiding exception. In these examples |
| 86 // #whatever should be hidden for all domains not ending in test.com |
| 87 // instead of nowhere! |
| 88 testRules(test, ["test.com#@#whatever", "##whatever"], []), |
| 89 testRules(test, ["~test.com##whatever"], []) |
| 90 ]); |
67 }, | 91 }, |
68 | 92 |
69 testRequestFilters: function(test) | 93 testRequestFilters: function(test) |
70 { | 94 { |
71 testRules(test, ["/foo", "||test.com", "http://example.com/foo"], [ | 95 runTest(test, [ |
72 {trigger: {"url-filter": "^https?://.*/foo", | 96 testRules(test, [ |
73 "resource-type": ["image", "style-sheet", "script", "font", | 97 "/foo", "||test.com^", "http://example.com/foo", "^foo^" |
74 "media", "raw", "document"]}, | 98 ], [ |
75 action: {type: "block"}}, | 99 { |
76 {trigger: {"url-filter": "^https?://([^/]+\\.)?test\\.com", | 100 trigger: { |
77 "url-filter-is-case-sensitive": true, | 101 "url-filter": "^[^:]+:(//)?.*/foo", |
78 "resource-type": ["image", "style-sheet", "script", "font", | 102 "resource-type": ["image", "style-sheet", "script", "font", |
79 "media", "raw", "document"]}, | 103 "media", "raw"] |
80 action: {type: "block"}}, | 104 }, |
81 {trigger: {"url-filter": "http://example\\.com/foo", | 105 action: {type: "block"} |
82 "resource-type": ["image", "style-sheet", "script", "font", | 106 }, |
83 "media", "raw", "document"]}, | 107 { |
84 action: {type: "block"}} | 108 trigger: { |
85 ]); | 109 "url-filter": |
86 | 110 "^[^:]+:(//)?([^/]+\\.)?test\\.com([^-_.%a-z0-9].*)?$", |
87 testRules(test, ["||example.com"], [ | 111 "url-filter-is-case-sensitive": true, |
88 {trigger: {"url-filter": "^https?://([^/]+\\.)?example\\.com", | 112 "resource-type": ["image", "style-sheet", "script", "font", |
89 "url-filter-is-case-sensitive": true, | 113 "media", "raw", "document"], |
90 "resource-type": ["image", "style-sheet", "script", "font", | 114 "unless-top-url": [ |
91 "media", "raw", "document"]}, | 115 "^[^:]+:(//)?([^/]+\\.)?test\\.com([^-_.%a-z0-9].*)?$" |
92 | 116 ], |
93 action: {type: "block"}} | 117 "top-url-filter-is-case-sensitive": true |
94 ]); | 118 }, |
95 | 119 action: {type: "block"} |
96 // Rules which would match no resource-types shouldn't be generated. | 120 }, |
97 testRules(test, ["foo$document", "||foo.com$document"], []); | 121 { |
98 | 122 trigger: { |
99 test.done(); | 123 "url-filter": "^http://example\\.com/foo", |
| 124 "resource-type": ["image", "style-sheet", "script", "font", |
| 125 "media", "raw", "document"], |
| 126 "unless-top-url": ["^http://example\\.com/foo"] |
| 127 }, |
| 128 action: {type: "block"} |
| 129 }, |
| 130 { |
| 131 trigger: { |
| 132 "url-filter": "^[^:]+:(//)?.*http://example\\.com/foo", |
| 133 "resource-type": ["image", "style-sheet", "script", "font", |
| 134 "media", "raw", "document"], |
| 135 "unless-top-url": ["^[^:]+:(//)?.*http://example\\.com/foo"] |
| 136 }, |
| 137 action: {type: "block"} |
| 138 }, |
| 139 { |
| 140 trigger: { |
| 141 "url-filter": |
| 142 "^[^:]+:(//)?(.*[^-_.%A-Za-z0-9])?foo([^-_.%A-Za-z0-9].*)?$", |
| 143 "resource-type": ["image", "style-sheet", "script", "font", |
| 144 "media", "raw"] |
| 145 }, |
| 146 action: {type: "block"} |
| 147 } |
| 148 ]), |
| 149 |
| 150 testRules(test, ["||example.com"], [ |
| 151 {trigger: {"url-filter": "^[^:]+:(//)?([^/]+\\.)?example\\.com", |
| 152 "url-filter-is-case-sensitive": true, |
| 153 "resource-type": ["image", "style-sheet", "script", "font", |
| 154 "media", "raw", "document"], |
| 155 "unless-top-url": ["^[^:]+:(//)?([^/]+\\.)?example\\.com"], |
| 156 "top-url-filter-is-case-sensitive": true}, |
| 157 |
| 158 action: {type: "block"}} |
| 159 ]), |
| 160 |
| 161 // Rules which would match no resource-types shouldn't be generated. |
| 162 testRules(test, ["foo$document", "||foo.com$document"], []) |
| 163 ]); |
100 }, | 164 }, |
101 | 165 |
102 testRequestFilterExceptions: function(test) | 166 testRequestFilterExceptions: function(test) |
103 { | 167 { |
104 testRules(test, ["@@example.com"], [ | 168 runTest(test, [ |
105 {trigger: {"url-filter": "^https?://.*example\\.com", | 169 testRules(test, ["@@example.com"], [ |
106 "resource-type": ["image", "style-sheet", "script", "font", | 170 {trigger: {"url-filter": "^[^:]+:(//)?.*example\\.com", |
107 "media", "raw", "document"]}, | 171 "resource-type": ["image", "style-sheet", "script", "font", |
108 action: {type: "ignore-previous-rules"}} | 172 "media", "raw", "document"]}, |
109 ]); | 173 action: {type: "ignore-previous-rules"}} |
110 | 174 ]), |
111 testRules(test, ["@@||example.com"], [ | 175 |
112 {trigger: {"url-filter": "^https?://([^/]+\\.)?example\\.com", | 176 testRules(test, ["@@||example.com"], [ |
113 "url-filter-is-case-sensitive": true, | 177 {trigger: {"url-filter": "^[^:]+:(//)?([^/]+\\.)?example\\.com", |
114 "resource-type": ["image", "style-sheet", "script", "font", | 178 "url-filter-is-case-sensitive": true, |
115 "media", "raw", "document"]}, | 179 "resource-type": ["image", "style-sheet", "script", "font", |
116 action: {type: "ignore-previous-rules"}} | 180 "media", "raw", "document"]}, |
117 ]); | 181 action: {type: "ignore-previous-rules"}} |
118 | 182 ]) |
119 test.done(); | 183 ]); |
120 }, | 184 }, |
121 | 185 |
122 testElementIDattributeFormat: function(test) | 186 testElementIDattributeFormat: function(test) |
123 { | 187 { |
124 testRules(test, | 188 runTest(test, [ |
125 ["###example", "test.com###EXAMPLE"], | 189 testRules(test, |
126 ["[id=example]", "[id=EXAMPLE]"], | 190 ["###example", "test.com###EXAMPLE"], |
127 rules => rules.map(rule => rule.action.selector)); | 191 ["[id=example]", "[id=EXAMPLE]"], |
128 | 192 rules => rules.map(rule => rule.action.selector)) |
129 test.done(); | 193 ]); |
130 }, | 194 }, |
131 | 195 |
132 testDomainWhitelisting: function(test) | 196 testDomainWhitelisting: function(test) |
133 { | 197 { |
134 testRules(test, ["@@||example.com^$document"], [ | 198 runTest(test, [ |
135 {trigger: {"url-filter": ".*", | 199 testRules(test, ["@@||example.com^$document"], [ |
136 "if-domain": ["example.com", "www.example.com"]}, | 200 { |
137 action: {type: "ignore-previous-rules"}} | 201 trigger: { |
138 ]); | 202 "url-filter": ".*", |
139 testRules(test, ["@@||example.com^$document,image"], [ | 203 "if-domain": ["*example.com"] |
140 {trigger: {"url-filter": ".*", | 204 }, |
141 "if-domain": ["example.com", "www.example.com"]}, | 205 action: {type: "ignore-previous-rules"} |
142 action: {type: "ignore-previous-rules"}}, | 206 } |
143 {trigger: {"url-filter": "^https?://([^/]+\\.)?example\\.com", | 207 ]), |
144 "url-filter-is-case-sensitive": true, | 208 testRules(test, ["@@||example.com^$document,image"], [ |
145 "resource-type": ["image"]}, | 209 { |
146 action: {type: "ignore-previous-rules"}} | 210 trigger: { |
147 ]); | 211 "url-filter": ".*", |
148 testRules(test, ["@@||example.com/path^$font,document"], [ | 212 "if-domain": ["*example.com"] |
149 {trigger: {"url-filter": "^https?://([^/]+\\.)?example\\.com/path", | 213 }, |
150 "resource-type": ["font"]}, | 214 action: {type: "ignore-previous-rules"} |
151 action: {type: "ignore-previous-rules"}} | 215 }, |
152 ]); | 216 { |
153 | 217 trigger: { |
154 test.done(); | 218 "url-filter": |
| 219 "^https?://([^/]+\\.)?example\\.com([^-_.%a-z0-9].*)?$", |
| 220 "url-filter-is-case-sensitive": true, |
| 221 "resource-type": ["image"] |
| 222 }, |
| 223 action: {type: "ignore-previous-rules"} |
| 224 } |
| 225 ]), |
| 226 testRules(test, ["@@||example.com/path^$font,document"], [ |
| 227 { |
| 228 trigger: { |
| 229 "url-filter": |
| 230 "^https?://([^/]+\\.)?example\\.com/path([^-_.%A-Za-z0-9].*)?$", |
| 231 "resource-type": ["font"] |
| 232 }, |
| 233 action: {type: "ignore-previous-rules"} |
| 234 } |
| 235 ]) |
| 236 ]); |
| 237 }, |
| 238 |
| 239 testGenericblockExceptions: function(test) |
| 240 { |
| 241 runTest(test, [ |
| 242 testRules(test, ["^ad.jpg|", "@@||example.com^$genericblock"], |
| 243 [[undefined, ["*example.com"]]], |
| 244 rules => rules.map(rule => [rule.trigger["if-domain"], |
| 245 rule.trigger["unless-domain"]])), |
| 246 testRules(test, ["^ad.jpg|$domain=test.com", |
| 247 "@@||example.com^$genericblock"], |
| 248 [[["*test.com"], undefined]], |
| 249 rules => rules.map(rule => [rule.trigger["if-domain"], |
| 250 rule.trigger["unless-domain"]])), |
| 251 testRules(test, ["^ad.jpg|$domain=~test.com", |
| 252 "@@||example.com^$genericblock"], |
| 253 [[undefined, ["*test.com", "*example.com"]]], |
| 254 rules => rules.map(rule => [rule.trigger["if-domain"], |
| 255 rule.trigger["unless-domain"]])) |
| 256 ]); |
155 }, | 257 }, |
156 | 258 |
157 testRuleOrdering: function(test) | 259 testRuleOrdering: function(test) |
158 { | 260 { |
159 testRules( | 261 runTest(test, [ |
160 test, | 262 testRules( |
161 ["/ads.jpg", "@@example.com", "test.com#@#foo", "##bar"], | 263 test, |
162 ["css-display-none", "block", "ignore-previous-rules"], | 264 ["/ads.jpg", "@@example.com", "test.com#@#foo", "##bar"], |
163 rules => rules.map(rule => rule.action.type) | 265 ["css-display-none", "block", "ignore-previous-rules"], |
164 ); | 266 rules => rules.map(rule => rule.action.type) |
165 testRules( | 267 ), |
166 test, | 268 testRules( |
167 ["@@example.com", "##bar", "/ads.jpg", "test.com#@#foo"], | 269 test, |
168 ["css-display-none", "block", "ignore-previous-rules"], | 270 ["@@example.com", "##bar", "/ads.jpg", "test.com#@#foo"], |
169 rules => rules.map(rule => rule.action.type) | 271 ["css-display-none", "block", "ignore-previous-rules"], |
170 ); | 272 rules => rules.map(rule => rule.action.type) |
171 | 273 ) |
172 test.done(); | 274 ]); |
173 }, | 275 }, |
174 | 276 |
175 testRequestTypeMapping: function(test) | 277 testRequestTypeMapping: function(test) |
176 { | 278 { |
177 testRules( | 279 runTest(test, [ |
178 test, | 280 testRules( |
179 ["1", "2$image", "3$stylesheet", "4$script", "5$font", "6$media", | 281 test, |
180 "7$popup", "8$object", "9$object_subrequest", "10$xmlhttprequest", | 282 ["1", "2$image", "3$stylesheet", "4$script", "5$font", "6$media", |
181 "11$ping", "12$subdocument", "13$other", "14$IMAGE", | 283 "7$popup", "8$object", "9$object_subrequest", "10$xmlhttprequest", |
182 "15$script,PING,Popup", "16$~image"], | 284 "11$websocket", "12$webrtc", |
183 [["image", "style-sheet", "script", "font", "media", "raw", "document" ], | 285 "13$ping", "14$subdocument", "15$other", "16$IMAGE", |
184 ["image"], | 286 "17$script,PING,Popup", "18$~image"], |
185 ["style-sheet"], | 287 [["image", "style-sheet", "script", "font", "media", "raw"], |
186 ["script"], | 288 ["image"], |
187 ["font"], | 289 ["style-sheet"], |
188 ["media"], | 290 ["script"], |
189 ["popup"], | 291 ["font"], |
190 ["raw"], | 292 ["media"], |
191 ["raw"], | 293 ["popup"], |
192 ["document"], | 294 ["media"], |
193 ["image"], | 295 ["raw"], |
194 ["script", "popup", "raw" ], | 296 ["raw"], |
195 ["style-sheet", "script", "font", "media", "raw", "document"]], | 297 ["raw"], // WebSocket |
196 rules => rules.map(rule => rule.trigger["resource-type"]) | 298 ["raw"], // WebRTC: STUN |
197 ); | 299 ["raw"], // WebRTC: TURN |
198 | 300 ["raw"], |
199 test.done(); | 301 ["raw"], |
| 302 ["image"], |
| 303 ["script", "popup", "raw" ], |
| 304 ["style-sheet", "script", "font", "media", "raw"]], |
| 305 rules => rules.map(rule => rule.trigger["resource-type"]) |
| 306 ) |
| 307 ]); |
200 }, | 308 }, |
201 | 309 |
202 testUnsupportedfilters: function(test) | 310 testUnsupportedfilters: function(test) |
203 { | 311 { |
204 // These types of filters are currently completely unsupported. | 312 runTest(test, [ |
205 testRules(test, ["foo$sitekey=bar", "@@foo$genericblock", | 313 // These types of filters are currently completely unsupported. |
206 "@@bar$generichide"], []); | 314 testRules(test, ["foo$sitekey=bar"], []) |
207 | 315 ]); |
208 test.done(); | |
209 }, | 316 }, |
210 | 317 |
211 testFilterOptions: function(test) | 318 testFilterOptions: function(test) |
212 { | 319 { |
213 testRules(test, ["1$domain=foo.com"], ["foo.com", "www.foo.com"], | 320 runTest(test, [ |
214 rules => rules[0]["trigger"]["if-domain"]); | 321 testRules(test, ["1$domain=foo.com"], ["*foo.com"], |
215 testRules(test, ["2$domain=third-party"], ["third-party"], | 322 rules => rules[0]["trigger"]["if-domain"]), |
216 rules => rules[0]["trigger"]["if-domain"]); | 323 testRules(test, ["2$third-party"], ["third-party"], |
217 testRules(test, ["foo$match_case"], true, | 324 rules => rules[0]["trigger"]["load-type"]), |
218 rules => rules[0]["trigger"]["url-filter-is-case-sensitive"]); | 325 testRules(test, ["foo$match_case"], true, |
219 | 326 rules => rules[0]["trigger"]["url-filter-is-case-sensitive"]), |
220 test.done(); | 327 |
| 328 // Test subdomain exceptions. |
| 329 testRules(test, ["1$domain=foo.com|~bar.foo.com"], |
| 330 ["foo.com", "www.foo.com"], |
| 331 rules => rules[0]["trigger"]["if-domain"]), |
| 332 testRules(test, ["1$domain=foo.com|~www.foo.com"], |
| 333 ["foo.com"], |
| 334 rules => rules[0]["trigger"]["if-domain"]) |
| 335 ]); |
221 }, | 336 }, |
222 | 337 |
223 testUnicode: function(test) | 338 testUnicode: function(test) |
224 { | 339 { |
225 testRules(test, ["$domain=🐈.cat"], ["xn--zn8h.cat", "www.xn--zn8h.cat"], | 340 runTest(test, [ |
226 rules => rules[0]["trigger"]["if-domain"]); | 341 testRules(test, ["$domain=🐈.cat"], ["*xn--zn8h.cat"], |
227 testRules(test, ["🐈$domain=🐈.cat"], []); | 342 rules => rules[0]["trigger"]["if-domain"]), |
228 testRules(test, ["###🐈"], []); | 343 testRules(test, ["||🐈"], "^[^:]+:(//)?([^/]+\\.)?xn--zn8h", |
229 | 344 rules => rules[0]["trigger"]["url-filter"]), |
230 test.done(); | 345 testRules(test, ["🐈$domain=🐈.cat"], "^[^:]+:(//)?.*%F0%9F%90%88", |
| 346 rules => rules[0]["trigger"]["url-filter"]), |
| 347 testRules(test, ["🐈%F0%9F%90%88$domain=🐈.cat"], |
| 348 "^[^:]+:(//)?.*%F0%9F%90%88%F0%9F%90%88", |
| 349 rules => rules[0]["trigger"]["url-filter"]), |
| 350 testRules(test, ["###🐈"], "[id=🐈]", |
| 351 rules => rules[0]["action"]["selector"]) |
| 352 ]); |
| 353 }, |
| 354 |
| 355 testWebSocket: function(test) |
| 356 { |
| 357 runTest(test, [ |
| 358 testRules(test, ["foo$websocket"], [ |
| 359 {trigger: {"url-filter": "^wss?://.*foo", "resource-type": ["raw"]}, |
| 360 action: {type: "block"}} |
| 361 ]) |
| 362 ]); |
| 363 }, |
| 364 |
| 365 testWebRTC: function(test) |
| 366 { |
| 367 runTest(test, [ |
| 368 testRules(test, ["foo$webrtc"], [ |
| 369 {trigger: {"url-filter": "^stuns?:.*foo", "resource-type": ["raw"]}, |
| 370 action: {type: "block"}}, |
| 371 {trigger: {"url-filter": "^turns?:.*foo", "resource-type": ["raw"]}, |
| 372 action: {type: "block"}} |
| 373 ]) |
| 374 ]); |
| 375 }, |
| 376 |
| 377 testMerging: function(test) |
| 378 { |
| 379 runTest(test, [ |
| 380 // Single character substitutions, deletions, and insertions. |
| 381 testRules(test, ["/ads", "/adv"], ["^[^:]+:(//)?.*/ad[sv]"], |
| 382 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 383 {merge: "all"}), |
| 384 testRules(test, ["/ads", "/advs"], ["^[^:]+:(//)?.*/adv?s"], |
| 385 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 386 {merge: "all"}), |
| 387 testRules(test, ["/advs", "/ads"], ["^[^:]+:(//)?.*/adv?s"], |
| 388 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 389 {merge: "all"}), |
| 390 testRules(test, ["/adts", "/advs", "/ads"], ["^[^:]+:(//)?.*/ad[tv]?s"], |
| 391 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 392 {merge: "all"}), |
| 393 testRules(test, ["/ads", "/adts", "/advs"], ["^[^:]+:(//)?.*/ad[tv]?s"], |
| 394 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 395 {merge: "all"}), |
| 396 testRules(test, ["/adts", "/ads", "/advs"], ["^[^:]+:(//)?.*/ad[tv]?s"], |
| 397 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 398 {merge: "all"}), |
| 399 testRules(test, ["/ax", "/adx", "/adsx", "/advx"], |
| 400 ["^[^:]+:(//)?.*/ax", "^[^:]+:(//)?.*/ad[sv]?x"], |
| 401 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 402 {merge: "all"}), |
| 403 testRules(test, ["/adx", "/ax", "/adsx", "/advx"], |
| 404 ["^[^:]+:(//)?.*/ax", "^[^:]+:(//)?.*/ad[sv]?x"], |
| 405 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 406 {merge: "all"}), |
| 407 testRules(test, ["/adsx", "/advx", "/adx", "/ax"], |
| 408 ["^[^:]+:(//)?.*/ad[sv]?x", "^[^:]+:(//)?.*/ax"], |
| 409 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 410 {merge: "all"}), |
| 411 testRules(test, ["/adsx", "/advx", "/ax", "/adx"], |
| 412 ["^[^:]+:(//)?.*/ad[sv]?x", "^[^:]+:(//)?.*/ax"], |
| 413 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 414 {merge: "all"}), |
| 415 testRules(test, ["/ad-", "/a-", "/ads-", "/adv-", "/adx-"], |
| 416 ["^[^:]+:(//)?.*/a-", "^[^:]+:(//)?.*/ad[svx]?-"], |
| 417 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 418 {merge: "all"}), |
| 419 testRules(test, ["/ads-", "/a-", "/ad-", "/adv-", "/adx-"], |
| 420 ["^[^:]+:(//)?.*/ad[svx]?-", "^[^:]+:(//)?.*/a-"], |
| 421 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 422 {merge: "all"}), |
| 423 |
| 424 // Multiple character deletions and insertions. |
| 425 testRules(test, ["/ads", "/adxis"], |
| 426 ["^[^:]+:(//)?.*/ad(xi)?s"], |
| 427 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 428 {merge: "all"}), |
| 429 testRules(test, ["/adxsi", "/xsi"], |
| 430 ["^[^:]+:(//)?.*/(ad)?xsi"], |
| 431 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 432 {merge: "all"}), |
| 433 testRules(test, ["/adxsi", "/ai"], |
| 434 ["^[^:]+:(//)?.*/a(dxs)?i"], |
| 435 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 436 {merge: "all"}), |
| 437 |
| 438 // Both single and multiple character edits combined. |
| 439 testRules(test, ["/adq", "/adxsiq", "/xsiq", "/axsiq", "/bxsiq"], |
| 440 ["^[^:]+:(//)?.*/ad(xsi)?q", "^[^:]+:(//)?.*/[ab]?xsiq"], |
| 441 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 442 {merge: "all"}), |
| 443 |
| 444 testRules(test, ["/adsq", "/aq", "/adq", "/advq", "/adxq", "/adxsq"], |
| 445 ["^[^:]+:(//)?.*/ad[svx]?q", "^[^:]+:(//)?.*/a(dxs)?q"], |
| 446 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 447 {merge: "all"}), |
| 448 testRules(test, ["/adxsq", "/aq", "/adq", "/adsq", "/advq", "/adxq"], |
| 449 ["^[^:]+:(//)?.*/a(dxs)?q", "^[^:]+:(//)?.*/ad[svx]?q"], |
| 450 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 451 {merge: "all"}), |
| 452 testRules(test, ["/adxsq", "/aq", "/adsq", "/adq", "/advq", "/adxq"], |
| 453 ["^[^:]+:(//)?.*/a(dxs)?q", "^[^:]+:(//)?.*/ad[svx]?q"], |
| 454 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 455 {merge: "all"}), |
| 456 testRules(test, ["/adxsq", "/aq", "/adsq", "/advq", "/adq", "/adxq"], |
| 457 ["^[^:]+:(//)?.*/a(dxs)?q", "^[^:]+:(//)?.*/ad[svx]?q"], |
| 458 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 459 {merge: "all"}), |
| 460 testRules(test, ["/adsxiq", "/adxsq", "/aq", "/adsq", "/advq", "/adq", |
| 461 "/adxq"], |
| 462 ["^[^:]+:(//)?.*/a(dsxi)?q", "^[^:]+:(//)?.*/adxsq", |
| 463 "^[^:]+:(//)?.*/ad[svx]?q"], |
| 464 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 465 {merge: "all"}), |
| 466 testRules(test, ["/adxsiq", "/adsxiq", "/adxsq", "/aq", "/adsq", "/advq", |
| 467 "/adq", "/adxq"], |
| 468 ["^[^:]+:(//)?.*/adxsi?q", "^[^:]+:(//)?.*/a(dsxi)?q", |
| 469 "^[^:]+:(//)?.*/ad[svx]?q"], |
| 470 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 471 {merge: "all"}), |
| 472 |
| 473 // Given the 6 rules "adsi", "bdsi", "advi", "bdvi", "adxi", and "bdxi", |
| 474 // we want the 2 rules "ad[svx]i" and "bd[svx]i", not the 3 rules |
| 475 // "[ab]dsi", "[ab]dvi", and "[ab]dxi" |
| 476 testRules(test, ["/adsi", "/bdsi", "/advi", "/bdvi", "/adxi", "/bdxi"], |
| 477 ["^[^:]+:(//)?.*/ad[svx]i", "^[^:]+:(//)?.*/bd[svx]i"], |
| 478 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 479 {merge: "all"}), |
| 480 testRules(test, ["/adsi", "/bdsi", "/advi", "/bdvi", "/bdxi"], |
| 481 ["^[^:]+:(//)?.*/ad[sv]i", "^[^:]+:(//)?.*/bd[svx]i"], |
| 482 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 483 {merge: "all"}), |
| 484 |
| 485 // Make sure there's no merge where there are special characters in the |
| 486 // delta. |
| 487 testRules(test, ["/ads?q", "/adsq"], |
| 488 ["^[^:]+:(//)?.*/ads\\?q", "^[^:]+:(//)?.*/adsq"], |
| 489 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 490 {merge: "all"}), |
| 491 testRules(test, ["/ads?", "/ads-"], |
| 492 ["^[^:]+:(//)?.*/ads\\?", "^[^:]+:(//)?.*/ads-"], |
| 493 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 494 {merge: "all"}), |
| 495 testRules(test, ["/ads?-", "/ads-"], |
| 496 ["^[^:]+:(//)?.*/ads\\?-", "^[^:]+:(//)?.*/ads-"], |
| 497 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 498 {merge: "all"}), |
| 499 |
| 500 // Redundant rules should be discarded. |
| 501 testRules(test, ["/ad", "/ads", "/advertisement"], |
| 502 ["^[^:]+:(//)?.*/ad"], |
| 503 rules => rules.map(rule => rule.trigger["url-filter"]), |
| 504 {merge: "all"}) |
| 505 ]); |
231 } | 506 } |
232 }; | 507 }; |
LEFT | RIGHT |