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: Improved matching algorithm Created May 4, 2017, 2:36 a.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 {merge = false, advancedMerge = false} = {})
25 { 24 {
26 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);
27 for (let filter of filters) 34 for (let filter of filters)
28 blockerList.addFilter(Filter.fromText(filter)); 35 blockerList.addFilter(Filter.fromText(filter));
29 36
30 let rules = blockerList.generateRules({merge, advancedMerge}); 37 return blockerList.generateRules().then(rules =>
31 if (transformFunction) 38 {
32 rules = transformFunction(rules); 39 if (transformFunction)
33 40 rules = transformFunction(rules);
34 test.deepEqual(rules, expected); 41
42 test.deepEqual(rules, expected);
43 });
35 } 44 }
36 45
37 exports.generateRules = { 46 exports.generateRules = {
38 testElementHiding: function(test) 47 testElementHiding: function(test)
39 { 48 {
40 testRules(test, ["##.whatever"], [ 49 runTest(test, [
41 {trigger: {"url-filter": "^https?://", 50 testRules(test, ["##.whatever"], [
42 "url-filter-is-case-sensitive": true}, 51 {trigger: {"url-filter": "^https?://",
43 action: {type: "css-display-none", selector: ".whatever"}} 52 "url-filter-is-case-sensitive": true},
44 ]); 53 action: {type: "css-display-none", selector: ".whatever"}}
45 testRules(test, ["test.com##.whatever"], [ 54 ]),
46 {trigger: {"url-filter": "^https?://([^/:]*\\.)?test\\.com[/:]", 55 testRules(test, ["test.com##.whatever"], [
47 "url-filter-is-case-sensitive": true}, 56 {trigger: {"url-filter": "^https?://([^/:]*\\.)?test\\.com[/:]",
48 action: {type: "css-display-none", selector: ".whatever"}} 57 "url-filter-is-case-sensitive": true},
49 ]); 58 action: {type: "css-display-none", selector: ".whatever"}}
50 59 ])
51 test.done(); 60 ]);
52 }, 61 },
53 62
54 testElementHidingExceptions: function(test) 63 testElementHidingExceptions: function(test)
55 { 64 {
56 testRules(test, ["#@#whatever"], []); 65 runTest(test, [
57 testRules(test, ["test.com#@#whatever"], []); 66 testRules(test, [
58 testRules(test, ["~test.com#@#whatever"], []); 67 "##.whatever",
59 68 "test.com,anothertest.com###something",
60 // We currently completely ignore any element hiding filters that have the 69 "@@||special.test.com^$elemhide",
61 // same selector as an element hiding exception. In these examples #whatever 70 "@@||test.com^$generichide",
62 // should be hidden for all domains not ending in test.com instead of 71 "@@||anothertest.com^$elemhide",
63 // nowhere! 72 "@@^something^$elemhide",
64 testRules(test, ["test.com#@#whatever", "##whatever"], []); 73 "@@^anything^$generichide"
65 testRules(test, ["~test.com##whatever"], []); 74 ], [
66 75 ["^https?://", ["*test.com", "*special.test.com", "*anothertest.com"]],
67 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 ]);
68 }, 91 },
69 92
70 testRequestFilters: function(test) 93 testRequestFilters: function(test)
71 { 94 {
72 testRules(test, ["/foo", "||test.com", "http://example.com/foo"], [ 95 runTest(test, [
73 {trigger: {"url-filter": "^https?://.*/foo", 96 testRules(test, [
74 "resource-type": ["image", "style-sheet", "script", "font", 97 "/foo", "||test.com^", "http://example.com/foo", "^foo^"
75 "media", "raw", "document"]}, 98 ], [
76 action: {type: "block"}}, 99 {
77 {trigger: {"url-filter": "^https?://([^/]+\\.)?test\\.com", 100 trigger: {
78 "url-filter-is-case-sensitive": true, 101 "url-filter": "^[^:]+:(//)?.*/foo",
79 "resource-type": ["image", "style-sheet", "script", "font", 102 "resource-type": ["image", "style-sheet", "script", "font",
80 "media", "raw", "document"]}, 103 "media", "raw"]
81 action: {type: "block"}}, 104 },
82 {trigger: {"url-filter": "http://example\\.com/foo", 105 action: {type: "block"}
83 "resource-type": ["image", "style-sheet", "script", "font", 106 },
84 "media", "raw", "document"]}, 107 {
85 action: {type: "block"}} 108 trigger: {
86 ]); 109 "url-filter":
87 110 "^[^:]+:(//)?([^/]+\\.)?test\\.com([^-_.%a-z0-9].*)?$",
88 testRules(test, ["||example.com"], [ 111 "url-filter-is-case-sensitive": true,
89 {trigger: {"url-filter": "^https?://([^/]+\\.)?example\\.com", 112 "resource-type": ["image", "style-sheet", "script", "font",
90 "url-filter-is-case-sensitive": true, 113 "media", "raw", "document"],
91 "resource-type": ["image", "style-sheet", "script", "font", 114 "unless-top-url": [
92 "media", "raw", "document"]}, 115 "^[^:]+:(//)?([^/]+\\.)?test\\.com([^-_.%a-z0-9].*)?$"
93 116 ],
94 action: {type: "block"}} 117 "top-url-filter-is-case-sensitive": true
95 ]); 118 },
96 119 action: {type: "block"}
97 // Rules which would match no resource-types shouldn't be generated. 120 },
98 testRules(test, ["foo$document", "||foo.com$document"], []); 121 {
99 122 trigger: {
100 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 ]);
101 }, 164 },
102 165
103 testRequestFilterExceptions: function(test) 166 testRequestFilterExceptions: function(test)
104 { 167 {
105 testRules(test, ["@@example.com"], [ 168 runTest(test, [
106 {trigger: {"url-filter": "^https?://.*example\\.com", 169 testRules(test, ["@@example.com"], [
107 "resource-type": ["image", "style-sheet", "script", "font", 170 {trigger: {"url-filter": "^[^:]+:(//)?.*example\\.com",
108 "media", "raw", "document"]}, 171 "resource-type": ["image", "style-sheet", "script", "font",
109 action: {type: "ignore-previous-rules"}} 172 "media", "raw", "document"]},
110 ]); 173 action: {type: "ignore-previous-rules"}}
111 174 ]),
112 testRules(test, ["@@||example.com"], [ 175
113 {trigger: {"url-filter": "^https?://([^/]+\\.)?example\\.com", 176 testRules(test, ["@@||example.com"], [
114 "url-filter-is-case-sensitive": true, 177 {trigger: {"url-filter": "^[^:]+:(//)?([^/]+\\.)?example\\.com",
115 "resource-type": ["image", "style-sheet", "script", "font", 178 "url-filter-is-case-sensitive": true,
116 "media", "raw", "document"]}, 179 "resource-type": ["image", "style-sheet", "script", "font",
117 action: {type: "ignore-previous-rules"}} 180 "media", "raw", "document"]},
118 ]); 181 action: {type: "ignore-previous-rules"}}
119 182 ])
120 test.done(); 183 ]);
121 }, 184 },
122 185
123 testElementIDattributeFormat: function(test) 186 testElementIDattributeFormat: function(test)
124 { 187 {
125 testRules(test, 188 runTest(test, [
126 ["###example", "test.com###EXAMPLE"], 189 testRules(test,
127 ["[id=example]", "[id=EXAMPLE]"], 190 ["###example", "test.com###EXAMPLE"],
128 rules => rules.map(rule => rule.action.selector)); 191 ["[id=example]", "[id=EXAMPLE]"],
129 192 rules => rules.map(rule => rule.action.selector))
130 test.done(); 193 ]);
131 }, 194 },
132 195
133 testDomainWhitelisting: function(test) 196 testDomainWhitelisting: function(test)
134 { 197 {
135 testRules(test, ["@@||example.com^$document"], [ 198 runTest(test, [
136 {trigger: {"url-filter": ".*", 199 testRules(test, ["@@||example.com^$document"], [
137 "if-domain": ["example.com", "www.example.com"]}, 200 {
138 action: {type: "ignore-previous-rules"}} 201 trigger: {
139 ]); 202 "url-filter": ".*",
140 testRules(test, ["@@||example.com^$document,image"], [ 203 "if-domain": ["*example.com"]
141 {trigger: {"url-filter": ".*", 204 },
142 "if-domain": ["example.com", "www.example.com"]}, 205 action: {type: "ignore-previous-rules"}
143 action: {type: "ignore-previous-rules"}}, 206 }
144 {trigger: {"url-filter": "^https?://([^/]+\\.)?example\\.com", 207 ]),
145 "url-filter-is-case-sensitive": true, 208 testRules(test, ["@@||example.com^$document,image"], [
146 "resource-type": ["image"]}, 209 {
147 action: {type: "ignore-previous-rules"}} 210 trigger: {
148 ]); 211 "url-filter": ".*",
149 testRules(test, ["@@||example.com/path^$font,document"], [ 212 "if-domain": ["*example.com"]
150 {trigger: {"url-filter": "^https?://([^/]+\\.)?example\\.com/path", 213 },
151 "resource-type": ["font"]}, 214 action: {type: "ignore-previous-rules"}
152 action: {type: "ignore-previous-rules"}} 215 },
153 ]); 216 {
154 217 trigger: {
155 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 ]);
156 }, 257 },
157 258
158 testRuleOrdering: function(test) 259 testRuleOrdering: function(test)
159 { 260 {
160 testRules( 261 runTest(test, [
161 test, 262 testRules(
162 ["/ads.jpg", "@@example.com", "test.com#@#foo", "##bar"], 263 test,
163 ["css-display-none", "block", "ignore-previous-rules"], 264 ["/ads.jpg", "@@example.com", "test.com#@#foo", "##bar"],
164 rules => rules.map(rule => rule.action.type) 265 ["css-display-none", "block", "ignore-previous-rules"],
165 ); 266 rules => rules.map(rule => rule.action.type)
166 testRules( 267 ),
167 test, 268 testRules(
168 ["@@example.com", "##bar", "/ads.jpg", "test.com#@#foo"], 269 test,
169 ["css-display-none", "block", "ignore-previous-rules"], 270 ["@@example.com", "##bar", "/ads.jpg", "test.com#@#foo"],
170 rules => rules.map(rule => rule.action.type) 271 ["css-display-none", "block", "ignore-previous-rules"],
171 ); 272 rules => rules.map(rule => rule.action.type)
172 273 )
173 test.done(); 274 ]);
174 }, 275 },
175 276
176 testRequestTypeMapping: function(test) 277 testRequestTypeMapping: function(test)
177 { 278 {
178 testRules( 279 runTest(test, [
179 test, 280 testRules(
180 ["1", "2$image", "3$stylesheet", "4$script", "5$font", "6$media", 281 test,
181 "7$popup", "8$object", "9$object_subrequest", "10$xmlhttprequest", 282 ["1", "2$image", "3$stylesheet", "4$script", "5$font", "6$media",
182 "11$ping", "12$subdocument", "13$other", "14$IMAGE", 283 "7$popup", "8$object", "9$object_subrequest", "10$xmlhttprequest",
183 "15$script,PING,Popup", "16$~image"], 284 "11$websocket", "12$webrtc",
184 [["image", "style-sheet", "script", "font", "media", "raw", "document" ], 285 "13$ping", "14$subdocument", "15$other", "16$IMAGE",
185 ["image"], 286 "17$script,PING,Popup", "18$~image"],
186 ["style-sheet"], 287 [["image", "style-sheet", "script", "font", "media", "raw"],
187 ["script"], 288 ["image"],
188 ["font"], 289 ["style-sheet"],
189 ["media"], 290 ["script"],
190 ["popup"], 291 ["font"],
191 ["media"], 292 ["media"],
192 ["raw"], 293 ["popup"],
193 ["raw"], 294 ["media"],
194 ["raw"], 295 ["raw"],
195 ["document"], 296 ["raw"],
196 ["raw"], 297 ["raw"], // WebSocket
197 ["image"], 298 ["raw"], // WebRTC: STUN
198 ["script", "popup", "raw" ], 299 ["raw"], // WebRTC: TURN
199 ["style-sheet", "script", "font", "media", "raw", "document"]], 300 ["raw"],
200 rules => rules.map(rule => rule.trigger["resource-type"]) 301 ["raw"],
201 ); 302 ["image"],
202 303 ["script", "popup", "raw" ],
203 test.done(); 304 ["style-sheet", "script", "font", "media", "raw"]],
305 rules => rules.map(rule => rule.trigger["resource-type"])
306 )
307 ]);
204 }, 308 },
205 309
206 testUnsupportedfilters: function(test) 310 testUnsupportedfilters: function(test)
207 { 311 {
208 // These types of filters are currently completely unsupported. 312 runTest(test, [
209 testRules(test, ["foo$sitekey=bar", "@@foo$genericblock", 313 // These types of filters are currently completely unsupported.
210 "@@bar$generichide"], []); 314 testRules(test, ["foo$sitekey=bar"], [])
211 315 ]);
212 test.done();
213 }, 316 },
214 317
215 testFilterOptions: function(test) 318 testFilterOptions: function(test)
216 { 319 {
217 testRules(test, ["1$domain=foo.com"], ["foo.com", "www.foo.com"], 320 runTest(test, [
218 rules => rules[0]["trigger"]["if-domain"]); 321 testRules(test, ["1$domain=foo.com"], ["*foo.com"],
219 testRules(test, ["2$domain=third-party"], ["third-party"], 322 rules => rules[0]["trigger"]["if-domain"]),
220 rules => rules[0]["trigger"]["if-domain"]); 323 testRules(test, ["2$third-party"], ["third-party"],
221 testRules(test, ["foo$match_case"], true, 324 rules => rules[0]["trigger"]["load-type"]),
222 rules => rules[0]["trigger"]["url-filter-is-case-sensitive"]); 325 testRules(test, ["foo$match_case"], true,
223 326 rules => rules[0]["trigger"]["url-filter-is-case-sensitive"]),
224 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 ]);
225 }, 336 },
226 337
227 testUnicode: function(test) 338 testUnicode: function(test)
228 { 339 {
229 testRules(test, ["$domain=🐈.cat"], ["xn--zn8h.cat", "www.xn--zn8h.cat"], 340 runTest(test, [
230 rules => rules[0]["trigger"]["if-domain"]); 341 testRules(test, ["$domain=🐈.cat"], ["*xn--zn8h.cat"],
231 testRules(test, ["🐈$domain=🐈.cat"], []); 342 rules => rules[0]["trigger"]["if-domain"]),
232 testRules(test, ["###🐈"], []); 343 testRules(test, ["||🐈"], "^[^:]+:(//)?([^/]+\\.)?xn--zn8h",
233 344 rules => rules[0]["trigger"]["url-filter"]),
234 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 ]);
235 }, 375 },
236 376
237 testMerging: function(test) 377 testMerging: function(test)
238 { 378 {
239 testRules(test, ["/ads", "/adv"], ["^https?://.*/ad[sv]"], 379 runTest(test, [
240 rules => rules.map(rule => rule.trigger["url-filter"]), 380 // Single character substitutions, deletions, and insertions.
241 {merge: true}); 381 testRules(test, ["/ads", "/adv"], ["^[^:]+:(//)?.*/ad[sv]"],
242 testRules(test, ["/ads", "/adv", "/ad"], ["^https?://.*/ad[sv]?"], 382 rules => rules.map(rule => rule.trigger["url-filter"]),
243 rules => rules.map(rule => rule.trigger["url-filter"]), 383 {merge: "all"}),
244 {merge: true}); 384 testRules(test, ["/ads", "/advs"], ["^[^:]+:(//)?.*/adv?s"],
245 testRules(test, ["/ad", "/ads", "/adv"], ["^https?://.*/ad[sv]?"], 385 rules => rules.map(rule => rule.trigger["url-filter"]),
246 rules => rules.map(rule => rule.trigger["url-filter"]), 386 {merge: "all"}),
247 {merge: true}); 387 testRules(test, ["/advs", "/ads"], ["^[^:]+:(//)?.*/adv?s"],
248 testRules(test, ["/a", "/ad", "/ads", "/adv"], 388 rules => rules.map(rule => rule.trigger["url-filter"]),
249 ["^https?://.*/a", "^https?://.*/ad[sv]?"], 389 {merge: "all"}),
250 rules => rules.map(rule => rule.trigger["url-filter"]), 390 testRules(test, ["/adts", "/advs", "/ads"], ["^[^:]+:(//)?.*/ad[tv]?s"],
251 {merge: true}); 391 rules => rules.map(rule => rule.trigger["url-filter"]),
252 testRules(test, ["/ad", "/a", "/ads", "/adv"], 392 {merge: "all"}),
253 ["^https?://.*/a", "^https?://.*/ad[sv]?"], 393 testRules(test, ["/ads", "/adts", "/advs"], ["^[^:]+:(//)?.*/ad[tv]?s"],
254 rules => rules.map(rule => rule.trigger["url-filter"]), 394 rules => rules.map(rule => rule.trigger["url-filter"]),
255 {merge: true}); 395 {merge: "all"}),
256 testRules(test, ["/ads", "/adv", "/ad", "/a"], 396 testRules(test, ["/adts", "/ads", "/advs"], ["^[^:]+:(//)?.*/ad[tv]?s"],
257 ["^https?://.*/ad[sv]?", "^https?://.*/a"], 397 rules => rules.map(rule => rule.trigger["url-filter"]),
258 rules => rules.map(rule => rule.trigger["url-filter"]), 398 {merge: "all"}),
259 {merge: true}); 399 testRules(test, ["/ax", "/adx", "/adsx", "/advx"],
260 testRules(test, ["/ads", "/adv", "/a", "/ad"], 400 ["^[^:]+:(//)?.*/ax", "^[^:]+:(//)?.*/ad[sv]?x"],
261 ["^https?://.*/ad[sv]?", "^https?://.*/a"], 401 rules => rules.map(rule => rule.trigger["url-filter"]),
262 rules => rules.map(rule => rule.trigger["url-filter"]), 402 {merge: "all"}),
263 {merge: true}); 403 testRules(test, ["/adx", "/ax", "/adsx", "/advx"],
264 testRules(test, ["/ad", "/a", "/ads", "/adv", "/adx"], 404 ["^[^:]+:(//)?.*/ax", "^[^:]+:(//)?.*/ad[sv]?x"],
265 ["^https?://.*/a", "^https?://.*/ad[svx]?"], 405 rules => rules.map(rule => rule.trigger["url-filter"]),
266 rules => rules.map(rule => rule.trigger["url-filter"]), 406 {merge: "all"}),
267 {merge: true}); 407 testRules(test, ["/adsx", "/advx", "/adx", "/ax"],
268 testRules(test, ["/ads", "/a", "/ad", "/adv", "/adx"], 408 ["^[^:]+:(//)?.*/ad[sv]?x", "^[^:]+:(//)?.*/ax"],
269 ["^https?://.*/ad[svx]?", "^https?://.*/a"], 409 rules => rules.map(rule => rule.trigger["url-filter"]),
270 rules => rules.map(rule => rule.trigger["url-filter"]), 410 {merge: "all"}),
271 {merge: true}); 411 testRules(test, ["/adsx", "/advx", "/ax", "/adx"],
272 testRules(test, ["/ads", "/a", "/ad", "/adv", "/adx", "/adxs"], 412 ["^[^:]+:(//)?.*/ad[sv]?x", "^[^:]+:(//)?.*/ax"],
273 ["^https?://.*/ad[svx]?", "^https?://.*/a", "^https?://.*/adxs"], 413 rules => rules.map(rule => rule.trigger["url-filter"]),
274 rules => rules.map(rule => rule.trigger["url-filter"]), 414 {merge: "all"}),
275 {merge: true}); 415 testRules(test, ["/ad-", "/a-", "/ads-", "/adv-", "/adx-"],
276 testRules(test, ["/adxs", "/a", "/ad", "/ads", "/adv", "/adx"], 416 ["^[^:]+:(//)?.*/a-", "^[^:]+:(//)?.*/ad[svx]?-"],
277 ["^https?://.*/adxs", "^https?://.*/a", "^https?://.*/ad[svx]?"], 417 rules => rules.map(rule => rule.trigger["url-filter"]),
278 rules => rules.map(rule => rule.trigger["url-filter"]), 418 {merge: "all"}),
279 {merge: true}); 419 testRules(test, ["/ads-", "/a-", "/ad-", "/adv-", "/adx-"],
280 testRules(test, ["/adxs", "/a", "/ads", "/ad", "/adv", "/adx"], 420 ["^[^:]+:(//)?.*/ad[svx]?-", "^[^:]+:(//)?.*/a-"],
281 ["^https?://.*/adxs", "^https?://.*/a", "^https?://.*/ad[svx]?"], 421 rules => rules.map(rule => rule.trigger["url-filter"]),
282 rules => rules.map(rule => rule.trigger["url-filter"]), 422 {merge: "all"}),
283 {merge: true}); 423
284 testRules(test, ["/adxs", "/a", "/ads", "/adv", "/ad", "/adx"], 424 // Multiple character deletions and insertions.
285 ["^https?://.*/adxs", "^https?://.*/a", "^https?://.*/ad[svx]?"], 425 testRules(test, ["/ads", "/adxis"],
286 rules => rules.map(rule => rule.trigger["url-filter"]), 426 ["^[^:]+:(//)?.*/ad(xi)?s"],
287 {merge: true}); 427 rules => rules.map(rule => rule.trigger["url-filter"]),
288 testRules(test, ["/adsxi", "/adxs", "/a", "/ads", "/adv", "/ad", "/adx"], 428 {merge: "all"}),
289 ["^https?://.*/adsxi", "^https?://.*/adxs", "^https?://.*/a", 429 testRules(test, ["/adxsi", "/xsi"],
290 "^https?://.*/ad[svx]?"], 430 ["^[^:]+:(//)?.*/(ad)?xsi"],
291 rules => rules.map(rule => rule.trigger["url-filter"]), 431 rules => rules.map(rule => rule.trigger["url-filter"]),
292 {merge: true}); 432 {merge: "all"}),
293 testRules(test, ["/adxsi", "/adsxi", "/adxs", "/a", "/ads", "/adv", "/ad", 433 testRules(test, ["/adxsi", "/ai"],
294 "/adx"], 434 ["^[^:]+:(//)?.*/a(dxs)?i"],
295 ["^https?://.*/adxsi?", "^https?://.*/adsxi", "^https?://.*/a", 435 rules => rules.map(rule => rule.trigger["url-filter"]),
296 "^https?://.*/ad[svx]?"], 436 {merge: "all"}),
297 rules => rules.map(rule => rule.trigger["url-filter"]), 437
298 {merge: true}); 438 // Both single and multiple character edits combined.
299 439 testRules(test, ["/adq", "/adxsiq", "/xsiq", "/axsiq", "/bxsiq"],
300 // Given "ads", "bds", "adv", "bdv", "adx", and "bdx", we want "ad[svx]" 440 ["^[^:]+:(//)?.*/ad(xsi)?q", "^[^:]+:(//)?.*/[ab]?xsiq"],
301 // and "bd[svx]" (2 rules), not "[ab]ds", "[ab]dv", and "[ab]dx" (3 rules). 441 rules => rules.map(rule => rule.trigger["url-filter"]),
302 testRules(test, ["/ads", "/bds", "/adv", "/bdv", "/adx", "/bdx"], 442 {merge: "all"}),
303 ["^https?://.*/ad[svx]", "^https?://.*/bd[svx]"], 443
304 rules => rules.map(rule => rule.trigger["url-filter"]), 444 testRules(test, ["/adsq", "/aq", "/adq", "/advq", "/adxq", "/adxsq"],
305 {merge: true}); 445 ["^[^:]+:(//)?.*/ad[svx]?q", "^[^:]+:(//)?.*/a(dxs)?q"],
306 testRules(test, ["/ads", "/bds", "/adv", "/bdv", "/bdx"], 446 rules => rules.map(rule => rule.trigger["url-filter"]),
307 ["^https?://.*/ad[sv]", "^https?://.*/bd[svx]"], 447 {merge: "all"}),
308 rules => rules.map(rule => rule.trigger["url-filter"]), 448 testRules(test, ["/adxsq", "/aq", "/adq", "/adsq", "/advq", "/adxq"],
309 {merge: true}); 449 ["^[^:]+:(//)?.*/a(dxs)?q", "^[^:]+:(//)?.*/ad[svx]?q"],
310 450 rules => rules.map(rule => rule.trigger["url-filter"]),
311 // Make sure it ignores special characters. 451 {merge: "all"}),
312 testRules(test, ["/ads?", "/ads"], 452 testRules(test, ["/adxsq", "/aq", "/adsq", "/adq", "/advq", "/adxq"],
313 ["^https?://.*/ads\\?", "^https?://.*/ads"], 453 ["^[^:]+:(//)?.*/a(dxs)?q", "^[^:]+:(//)?.*/ad[svx]?q"],
314 rules => rules.map(rule => rule.trigger["url-filter"]), 454 rules => rules.map(rule => rule.trigger["url-filter"]),
315 {merge: true}); 455 {merge: "all"}),
316 testRules(test, ["/ads?", "/ads-"], 456 testRules(test, ["/adxsq", "/aq", "/adsq", "/advq", "/adq", "/adxq"],
317 ["^https?://.*/ads\\?", "^https?://.*/ads-"], 457 ["^[^:]+:(//)?.*/a(dxs)?q", "^[^:]+:(//)?.*/ad[svx]?q"],
318 rules => rules.map(rule => rule.trigger["url-filter"]), 458 rules => rules.map(rule => rule.trigger["url-filter"]),
319 {merge: true}); 459 {merge: "all"}),
320 testRules(test, ["/ads?-", "/ads-"], 460 testRules(test, ["/adsxiq", "/adxsq", "/aq", "/adsq", "/advq", "/adq",
321 ["^https?://.*/ads\\?-", "^https?://.*/ads-"], 461 "/adxq"],
322 rules => rules.map(rule => rule.trigger["url-filter"]), 462 ["^[^:]+:(//)?.*/a(dsxi)?q", "^[^:]+:(//)?.*/adxsq",
323 {merge: true}); 463 "^[^:]+:(//)?.*/ad[svx]?q"],
324 464 rules => rules.map(rule => rule.trigger["url-filter"]),
325 // Test advanced merge. 465 {merge: "all"}),
326 testRules(test, ["/ad", "/adxsi"], 466 testRules(test, ["/adxsiq", "/adsxiq", "/adxsq", "/aq", "/adsq", "/advq",
327 ["^https?://.*/ad(xsi)?"], 467 "/adq", "/adxq"],
328 rules => rules.map(rule => rule.trigger["url-filter"]), 468 ["^[^:]+:(//)?.*/adxsi?q", "^[^:]+:(//)?.*/a(dsxi)?q",
329 {merge: true, advancedMerge: true}); 469 "^[^:]+:(//)?.*/ad[svx]?q"],
330 testRules(test, ["/adxsi", "/xsi"], 470 rules => rules.map(rule => rule.trigger["url-filter"]),
331 ["^https?://.*/(ad)?xsi"], 471 {merge: "all"}),
332 rules => rules.map(rule => rule.trigger["url-filter"]), 472
333 {merge: true, advancedMerge: true}); 473 // Given the 6 rules "adsi", "bdsi", "advi", "bdvi", "adxi", and "bdxi",
334 testRules(test, ["/ad", "/adxsi", "/xsi", "/axsi", "/bxsi"], 474 // we want the 2 rules "ad[svx]i" and "bd[svx]i", not the 3 rules
335 ["^https?://.*/ad(xsi)?", "^https?://.*/[ab]?xsi"], 475 // "[ab]dsi", "[ab]dvi", and "[ab]dxi"
336 rules => rules.map(rule => rule.trigger["url-filter"]), 476 testRules(test, ["/adsi", "/bdsi", "/advi", "/bdvi", "/adxi", "/bdxi"],
337 {merge: true, advancedMerge: true}); 477 ["^[^:]+:(//)?.*/ad[svx]i", "^[^:]+:(//)?.*/bd[svx]i"],
338 478 rules => rules.map(rule => rule.trigger["url-filter"]),
339 test.done(); 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 ]);
340 } 506 }
341 }; 507 };
LEFTRIGHT

Powered by Google App Engine
This is Rietveld