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