Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: test/abp2blocklist.js

Issue 29426594: Issue 3673 - Merge closely matching rules (Closed) Base URL: https://hg.adblockplus.org/abp2blocklist
Left Patch Set: Ignore special characters Created May 2, 2017, 3:29 p.m.
Right Patch Set: Rebase Created July 28, 2017, 1:31 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « lib/abp2blocklist.js ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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 };
LEFTRIGHT

Powered by Google App Engine
This is Rietveld