| LEFT | RIGHT | 
 |    1 /* | 
 |    2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 
 |    3  * Copyright (C) 2006-2016 Eyeo GmbH | 
 |    4  * | 
 |    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 | 
 |    7  * published by the Free Software Foundation. | 
 |    8  * | 
 |    9  * Adblock Plus is distributed in the hope that it will be useful, | 
 |   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |   12  * GNU General Public License for more details. | 
 |   13  * | 
 |   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/>. | 
 |   16  */ | 
 |   17  | 
|    1 "use strict"; |   18 "use strict"; | 
|    2  |   19  | 
|    3 let { |   20 let {createSandbox} = require("./_common"); | 
|    4   Filter, InvalidFilter, CommentFilter, RegExpFilter, WhiteListFilter, |   21  | 
|    5   ElemHideFilter, ElemHideException |   22 let Filter = null; | 
|    6 } = require("../lib/filterClassesNew"); |   23 let InvalidFilter = null; | 
 |   24 let CommentFilter = null; | 
 |   25 let ActiveFilter = null; | 
 |   26 let RegExpFilter = null; | 
 |   27 let BlockingFilter = null; | 
 |   28 let WhitelistFilter = null; | 
 |   29 let ElemHideBase = null; | 
 |   30 let ElemHideFilter = null; | 
 |   31 let ElemHideException = null; | 
 |   32 let CSSPropertyFilter = null; | 
 |   33  | 
 |   34 exports.setUp = function(callback) | 
 |   35 { | 
 |   36   let sandboxedRequire = createSandbox(); | 
 |   37   ( | 
 |   38     { | 
 |   39       Filter, InvalidFilter, CommentFilter, ActiveFilter, RegExpFilter, | 
 |   40       BlockingFilter, WhitelistFilter, ElemHideBase, ElemHideFilter, | 
 |   41       ElemHideException, CSSPropertyFilter | 
 |   42     } = sandboxedRequire("../lib/filterClassesNew") | 
 |   43   ); | 
 |   44   callback(); | 
 |   45 }; | 
|    7  |   46  | 
|    8 exports.testFromText = function(test) |   47 exports.testFromText = function(test) | 
|    9 { |   48 { | 
|   10   let tests = [ |   49   let tests = [ | 
|   11     ["!asdf", CommentFilter, "comment"], |   50     ["!asdf", CommentFilter, "comment"], | 
|   12     ["asdf", RegExpFilter, "blocking"], |   51     ["asdf", BlockingFilter, "blocking"], | 
|   13     ["asdf$image,~collapse", RegExpFilter, "blocking"], |   52     ["asdf$image,~collapse", BlockingFilter, "blocking"], | 
|   14     ["/asdf/", RegExpFilter, "blocking"], |   53     ["/asdf/", BlockingFilter, "blocking"], | 
|   15     ["/asdf??+/", InvalidFilter, "invalid"], |   54     ["/asdf??+/", InvalidFilter, "invalid"], | 
|   16     ["@@asdf", WhiteListFilter, "whitelist"], |   55     ["@@asdf", WhitelistFilter, "whitelist"], | 
|   17     ["@@asdf$image,~collapse", WhiteListFilter, "whitelist"], |   56     ["@@asdf$image,~collapse", WhitelistFilter, "whitelist"], | 
|   18     ["@@/asdf/", WhiteListFilter, "whitelist"], |   57     ["@@/asdf/", WhitelistFilter, "whitelist"], | 
|   19     ["@@/asdf??+/", InvalidFilter, "invalid"], |   58     ["@@/asdf??+/", InvalidFilter, "invalid"], | 
|   20     ["##asdf", ElemHideFilter, "elemhide"], |   59     ["##asdf", ElemHideFilter, "elemhide"], | 
|   21     ["#@#asdf", ElemHideException, "elemhideexception"], |   60     ["#@#asdf", ElemHideException, "elemhideexception"], | 
|   22     ["foobar##asdf", ElemHideFilter, "elemhide"], |   61     ["foobar##asdf", ElemHideFilter, "elemhide"], | 
|   23     ["foobar#@#asdf", ElemHideException, "elemhideexception"], |   62     ["foobar#@#asdf", ElemHideException, "elemhideexception"], | 
|   24     ["foobar##a", ElemHideFilter, "elemhide"], |   63     ["foobar##a", ElemHideFilter, "elemhide"], | 
|   25     ["foobar#@#a", ElemHideException, "elemhideexception"], |   64     ["foobar#@#a", ElemHideException, "elemhideexception"], | 
|   26  |   65  | 
|   27     ["foobar#asdf", RegExpFilter, "blocking"], |   66     ["foobar#asdf", BlockingFilter, "blocking"], | 
|   28     ["foobar|foobas##asdf", RegExpFilter, "blocking"], |   67     ["foobar|foobas##asdf", BlockingFilter, "blocking"], | 
|   29     ["foobar##asdf{asdf}", RegExpFilter, "blocking"], |   68     ["foobar##asdf{asdf}", BlockingFilter, "blocking"], | 
|   30     ["foobar##", RegExpFilter, "blocking"], |   69     ["foobar##", BlockingFilter, "blocking"], | 
|   31     ["foobar#@#", RegExpFilter, "blocking"], |   70     ["foobar#@#", BlockingFilter, "blocking"], | 
|   32     ["asdf$foobar", InvalidFilter, "invalid"], |   71     ["asdf$foobar", InvalidFilter, "invalid"], | 
|   33     ["asdf$image,foobar", InvalidFilter, "invalid"], |   72     ["asdf$image,foobar", InvalidFilter, "invalid"], | 
|   34     ["asdf$image=foobar", RegExpFilter, "blocking"], |   73     ["asdf$image=foobar", BlockingFilter, "blocking"], | 
|   35     ["asdf$image=foobar=xyz,~coLLapse", RegExpFilter, "blocking"], |   74     ["asdf$image=foobar=xyz,~collapse", BlockingFilter, "blocking"], | 
 |   75  | 
 |   76     ["##foo[-abp-properties='something']bar", InvalidFilter, "invalid"], | 
 |   77     ["#@#foo[-abp-properties='something']bar", ElemHideException, "elemhideexcep
     tion"], | 
 |   78     ["example.com##foo[-abp-properties='something']bar", CSSPropertyFilter, "css
     property"], | 
 |   79     ["example.com#@#foo[-abp-properties='something']bar", ElemHideException, "el
     emhideexception"], | 
 |   80     ["~example.com##foo[-abp-properties='something']bar", InvalidFilter, "invali
     d"], | 
 |   81     ["~example.com#@#foo[-abp-properties='something']bar", ElemHideException, "e
     lemhideexception"], | 
 |   82     ["~example.com,~example.info##foo[-abp-properties='something']bar", InvalidF
     ilter, "invalid"], | 
 |   83     ["~example.com,~example.info#@#foo[-abp-properties='something']bar", ElemHid
     eException, "elemhideexception"], | 
 |   84     ["~sub.example.com,example.com##foo[-abp-properties='something']bar", CSSPro
     pertyFilter, "cssproperty"], | 
 |   85     ["~sub.example.com,example.com#@#foo[-abp-properties='something']bar", ElemH
     ideException, "elemhideexception"], | 
 |   86     ["example.com,~sub.example.com##foo[-abp-properties='something']bar", CSSPro
     pertyFilter, "cssproperty"], | 
 |   87     ["example.com,~sub.example.com#@#foo[-abp-properties='something']bar", ElemH
     ideException, "elemhideexception"], | 
 |   88     ["example.com##[-abp-properties='something']", CSSPropertyFilter, "cssproper
     ty"], | 
 |   89     ["example.com#@#[-abp-properties='something']", ElemHideException, "elemhide
     exception"], | 
 |   90     ["example.com##[-abp-properties=\"something\"]", CSSPropertyFilter, "cssprop
     erty"], | 
 |   91     ["example.com#@#[-abp-properties=\"something\"]", ElemHideException, "elemhi
     deexception"], | 
 |   92     ["example.com##[-abp-properties=(something)]", ElemHideFilter, "elemhide"], | 
 |   93     ["example.com#@#[-abp-properties=(something)]", ElemHideException, "elemhide
     exception"], | 
|   36   ]; |   94   ]; | 
|   37   for (let [text, type, typeName, location] of tests) |   95   for (let [text, type, typeName, location] of tests) | 
|   38   { |   96   { | 
|   39     let filter = Filter.fromText(text); |   97     let filter = Filter.fromText(text); | 
|   40     try |   98     test.ok(filter instanceof Filter, "Got filter for " + text); | 
|   41     { |   99     test.equal(filter.text, text, "Correct filter text for " + text); | 
|   42       test.ok(filter instanceof Filter, "Got filter for " + text); |  100     test.ok(filter instanceof type, "Correct filter type for " + text); | 
|   43       test.equal(filter.text, text, "Correct filter text for " + text); |  101     test.equal(filter.type, typeName, "Type name for " + text + " is " + typeNam
     e); | 
|   44       test.ok(filter instanceof type, "Correct filter type for " + text); |  102     if (type == InvalidFilter) | 
|   45       test.equal(filter.type, typeName, "Type name for " + text + " is " + typeN
     ame); |  103       test.ok(filter.reason, "Invalid filter " + text + " has a reason set"); | 
|   46       if (type == InvalidFilter) |  104     filter.delete(); | 
|   47         test.ok(filter.reason, "Invalid filter " + text + " has a reason set"); |  105   } | 
 |  106   test.done(); | 
 |  107 }; | 
 |  108  | 
 |  109 exports.testClassHierarchy = function(test) | 
 |  110 { | 
 |  111   let allClasses = ["Filter", "InvalidFilter", "CommentFilter", "ActiveFilter", | 
 |  112     "RegExpFilter", "BlockingFilter", "WhitelistFilter", "ElemHideBase", | 
 |  113     "ElemHideFilter", "ElemHideException", "CSSPropertyFilter"]; | 
 |  114   let tests = [ | 
 |  115     ["/asdf??+/", "Filter", "InvalidFilter"], | 
 |  116     ["!asdf", "Filter", "CommentFilter"], | 
 |  117     ["asdf", "Filter", "ActiveFilter", "RegExpFilter", "BlockingFilter"], | 
 |  118     ["@@asdf", "Filter", "ActiveFilter", "RegExpFilter", "WhitelistFilter"], | 
 |  119     ["##asdf", "Filter", "ActiveFilter", "ElemHideBase", "ElemHideFilter"], | 
 |  120     ["#@#asdf", "Filter", "ActiveFilter", "ElemHideBase", "ElemHideException"], | 
 |  121     ["example.com##[-abp-properties='something']", "Filter", "ActiveFilter", "El
     emHideBase", "CSSPropertyFilter"], | 
 |  122   ]; | 
 |  123  | 
 |  124   for (let list of tests) | 
 |  125   { | 
 |  126     let filter = Filter.fromText(list.shift()); | 
 |  127     for (let cls of list) | 
 |  128     { | 
 |  129       test.ok(filter instanceof eval(cls), | 
 |  130           "Filter " + filter.text + " is an instance of " + cls); | 
|   48     } |  131     } | 
|   49     finally |  132  | 
|   50     { |  133     for (let cls of allClasses) | 
|   51       filter.delete(); |  134     { | 
 |  135       if (list.indexOf(cls) < 0) | 
 |  136       { | 
 |  137         test.ok(!(filter instanceof eval(cls)), | 
 |  138             "Filter " + filter.text + " isn't an instance of " + cls); | 
 |  139       } | 
|   52     } |  140     } | 
|   53   } |  141     filter.delete(); | 
 |  142   } | 
 |  143  | 
 |  144   test.done(); | 
 |  145 }; | 
 |  146  | 
 |  147 exports.testGC = function(test) | 
 |  148 { | 
 |  149   let filter1 = Filter.fromText("someknownfilter"); | 
 |  150   test.equal(filter1.hitCount, 0, "Initial hit count"); | 
 |  151  | 
 |  152   filter1.hitCount = 432; | 
 |  153  | 
 |  154   let filter2 = Filter.fromText("someknownfilter"); | 
 |  155   test.equal(filter2.hitCount, 432, "Known filter returned"); | 
 |  156  | 
 |  157   filter2.hitCount = 234; | 
 |  158   test.equal(filter1.hitCount, 234, "Changing second wrapper modifies original a
     s well"); | 
 |  159  | 
 |  160   filter1.delete(); | 
 |  161   filter2.delete(); | 
 |  162  | 
 |  163   let filter3 = Filter.fromText("someknownfilter"); | 
 |  164   test.equal(filter3.hitCount, 0, "Filter data has been reset once previous inst
     ances have been released"); | 
 |  165   filter3.delete(); | 
 |  166  | 
|   54   test.done(); |  167   test.done(); | 
|   55 }; |  168 }; | 
|   56  |  169  | 
|   57 exports.testNormalize = function(test) |  170 exports.testNormalize = function(test) | 
|   58 { |  171 { | 
|   59   let tests = [ |  172   let tests = [ | 
|   60     ["  foo bar ", "foobar"], |  | 
|   61     ["foobar", "foobar"], |  | 
|   62     [" !  comment something ", "!  comment something"], |  173     [" !  comment something ", "!  comment something"], | 
|   63     [" ! \n comment something ", "!  comment something"], |  174     [" ! \n comment something ", "!  comment something"], | 
|   64     [" foo , bar ## foo > bar ", "foo,bar##foo > bar"], |  175     ["  foo bar ", "foobar"], | 
|   65     [" foo , bar #@# foo > bar ", "foo,bar#@#foo > bar"], |  176     [" foo , bar #  # foo > bar ", "foo,bar##foo > bar", "foo,bar", "foo > bar"]
     , | 
|   66   ]; |  177     [" foo , bar # @   # foo > bar ", "foo,bar#@#foo > bar", "foo,bar", "foo > b
     ar"], | 
|   67   for (let [text, expected] of tests) |  178     ["foOBar"], | 
|   68     test.equal(Filter.normalize(text), expected); |  179     ["foOBar#xyz"], | 
 |  180     ["foOBar$iMaGe,object_subrequest,~coLLapse", "foOBar$image,object-subrequest
     ,~collapse"], | 
 |  181     ["foOBar$doMain=EXample.COM|~exAMPLE.РФ", "foOBar$domain=example.com|~exampl
     e.рф"], | 
 |  182     ["foOBar$sitekeY=SiteKey", "foOBar$sitekey=SiteKey"], | 
 |  183     ["exampLE.com##fooBAr", "example.com##fooBAr"], | 
 |  184     ["exampLE.com#@#fooBAr", "example.com#@#fooBAr"], | 
 |  185     ["exampLE.РФ#@#fooBAr", "example.рф#@#fooBAr"], | 
 |  186   ]; | 
 |  187  | 
 |  188   for (let [text, expected, selectorDomain, selector] of tests) | 
 |  189   { | 
 |  190     if (!expected) | 
 |  191       expected = text; | 
 |  192  | 
 |  193     let filter1 = Filter.fromText(text); | 
 |  194     let filter2 = Filter.fromText(expected); | 
 |  195  | 
 |  196     test.equal(filter1.text, expected, "Filter text " + text + " got normalized"
     ); | 
 |  197     test.equal(filter2.text, expected, "Already normalized text " + expected + "
      didn't change"); | 
 |  198  | 
 |  199     if (filter1 instanceof ActiveFilter) | 
 |  200     { | 
 |  201       filter1.hitCount = 567; | 
 |  202       test.equal(filter1.hitCount, filter2.hitCount, "Property changes on filter
      " + text + " get reflected on filter " + expected); | 
 |  203     } | 
 |  204  | 
 |  205     if (selectorDomain) | 
 |  206     { | 
 |  207       let expectedDomains = selectorDomain.split(",").sort().join(","); | 
 |  208       let actualDomains1 = filter1.selectorDomain.split(",").sort().join(","); | 
 |  209       let actualDomains2 = filter2.selectorDomain.split(",").sort().join(","); | 
 |  210       test.equal(actualDomains1, expectedDomains, "Correct selector domain for f
     ilter " + text); | 
 |  211       test.equal(actualDomains1, expectedDomains, "Correct selector domain for f
     ilter " + expected); | 
 |  212  | 
 |  213       test.equal(filter1.selector, selector, "Correct selector for filter " + te
     xt); | 
 |  214       test.equal(filter2.selector, selector, "Correct selector for filter " + ex
     pected); | 
 |  215     } | 
 |  216  | 
 |  217     filter1.delete(); | 
 |  218     filter2.delete(); | 
 |  219   } | 
 |  220  | 
|   69   test.done(); |  221   test.done(); | 
|   70 }; |  222 }; | 
|   71  |  223  | 
|   72 exports.testSerialize = function(test) |  224 exports.testSerialize = function(test) | 
|   73 { |  225 { | 
|   74   // Comment |  226   // Comment | 
|   75   let filter = Filter.fromText("! serialize"); |  227   let filter = Filter.fromText("! serialize"); | 
|   76   test.equal(filter.serialize(), "[Filter]\ntext=! serialize\n"); |  228   test.equal(filter.serialize(), "[Filter]\ntext=! serialize\n"); | 
|   77   filter.delete(); |  229   filter.delete(); | 
|   78  |  230  | 
| (...skipping 15 matching lines...) Expand all  Loading... | 
|   94  |  246  | 
|   95   // Element hiding filter |  247   // Element hiding filter | 
|   96   filter = Filter.fromText("example.com##serialize"); |  248   filter = Filter.fromText("example.com##serialize"); | 
|   97   test.equal(filter.serialize(), "[Filter]\ntext=example.com##serialize\n"); |  249   test.equal(filter.serialize(), "[Filter]\ntext=example.com##serialize\n"); | 
|   98   filter.disabled = true; |  250   filter.disabled = true; | 
|   99   filter.lastHit = 5; |  251   filter.lastHit = 5; | 
|  100   test.equal(filter.serialize(), "[Filter]\ntext=example.com##serialize\ndisable
     d=true\nlastHit=5\n"); |  252   test.equal(filter.serialize(), "[Filter]\ntext=example.com##serialize\ndisable
     d=true\nlastHit=5\n"); | 
|  101   filter.delete(); |  253   filter.delete(); | 
|  102  |  254  | 
|  103   test.done(); |  255   test.done(); | 
|  104 } |  256 }; | 
 |  257  | 
 |  258 exports.testInvalidReasons = function(test) | 
 |  259 { | 
 |  260   let tests = [ | 
 |  261     ["/??/", "filter_invalid_regexp"], | 
 |  262     ["asd$foobar", "filter_unknown_option"], | 
 |  263     ["~foo.com##[-abp-properties='abc']", "filter_cssproperty_nodomain"], | 
 |  264   ]; | 
 |  265  | 
 |  266   for (let [text, reason] of tests) | 
 |  267   { | 
 |  268     let filter = Filter.fromText(text); | 
 |  269     test.equals(filter.reason, reason, "Reason why filter " + text + " is invali
     d"); | 
 |  270     filter.delete(); | 
 |  271   } | 
 |  272  | 
 |  273   test.done(); | 
 |  274 }; | 
|  105  |  275  | 
|  106 exports.testActiveFilter = function(test) |  276 exports.testActiveFilter = function(test) | 
|  107 { |  277 { | 
|  108   let filter1 = Filter.fromText("asdf"); |  278   let filter1 = Filter.fromText("asdf"); | 
|  109   let filter1copy = Filter.fromText("asdf"); |  279   let filter1copy = Filter.fromText("asdf"); | 
|  110   let filter2 = Filter.fromText("##foobar"); |  280   let filter2 = Filter.fromText("##foobar"); | 
|  111  |  281  | 
|  112   try |  282   test.ok(!filter1.disabled && !filter1copy.disabled && !filter2.disabled, "Filt
     ers are initially enabled"); | 
|  113   { |  283   filter1.disabled = true; | 
|  114     test.ok(!filter1.disabled && !filter1copy.disabled && !filter2.disabled, "Fi
     lters are initially enabled"); |  284   test.ok(filter1.disabled, "Disabling filter works"); | 
|  115     filter1.disabled = true; |  285   test.ok(filter1copy.disabled, "Filter copies are also disabled"); | 
|  116     test.ok(filter1.disabled, "Disabling filter works"); |  286   test.ok(!filter2.disabled, "Disabling one filter doesn't disable others"); | 
|  117     test.ok(filter1copy.disabled, "Filter copies are also disabled"); |  287  | 
|  118     test.ok(!filter2.disabled, "Disabling one filter doesn't disable others"); |  288   test.ok(filter1.hitCount === 0 && filter1copy.hitCount === 0 && filter2.hitCou
     nt === 0, "Filters have no hit initially"); | 
|  119  |  289   filter1.hitCount = 5; | 
|  120     test.ok(filter1.hitCount === 0 && filter1copy.hitCount === 0 && filter2.hitC
     ount === 0, "Filters have no hit initially"); |  290   test.equal(filter1.hitCount, 5, "Changing hit count works"); | 
|  121     filter1.hitCount = 5; |  291   test.equal(filter1copy.hitCount, 5, "Hit count of filter copies is also change
     d"); | 
|  122     test.equal(filter1.hitCount, 5, "Changing hit count works"); |  292   test.equal(filter2.hitCount, 0, "Hit count of other filters isn't affected"); | 
|  123     test.equal(filter1copy.hitCount, 5, "Hit count of filter copies is also chan
     ged"); |  293  | 
|  124     test.equal(filter2.hitCount, 0, "Hit count of other filters isn't affected")
     ; |  294   test.ok(filter1.lastHit === 0 && filter1copy.lastHit === 0 && filter2.lastHit 
     === 0, "Filters have no last hit time initially"); | 
|  125  |  295   filter1.lastHit = 10; | 
|  126     test.ok(filter1.lastHit === 0 && filter1copy.lastHit === 0 && filter2.lastHi
     t === 0, "Filters have no last hit time initially"); |  296   test.equal(filter1.lastHit, 10, "Changing last hit time works"); | 
|  127     filter1.lastHit = 10; |  297   test.equal(filter1copy.lastHit, 10, "Last hit time of filter copies is also ch
     anged"); | 
|  128     test.equal(filter1.lastHit, 10, "Changing last hit time works"); |  298   test.equal(filter2.lastHit, 0, "Last hit time of other filters isn't affected"
     ); | 
|  129     test.equal(filter1copy.lastHit, 10, "Last hit time of filter copies is also 
     changed"); |  299  | 
|  130     test.equal(filter2.lastHit, 0, "Last hit time of other filters isn't affecte
     d"); |  300   filter1.delete(); | 
|  131   } |  301   filter1copy.delete(); | 
|  132   finally |  302   filter2.delete(); | 
|  133   { |  | 
|  134     filter1.delete(); |  | 
|  135     filter1copy.delete(); |  | 
|  136     filter2.delete(); |  | 
|  137   } |  | 
|  138  |  303  | 
|  139   test.done(); |  304   test.done(); | 
|  140 }; |  305 }; | 
|  141  |  306  | 
|  142 exports.testIsGeneric = function(test) |  307 exports.testIsGeneric = function(test) | 
|  143 { |  308 { | 
|  144   let tests = [ |  309   let tests = [ | 
|  145     ["asfd", true], |  310     ["asfd", true], | 
|  146     ["|http://example.com/asdf", true], |  311     ["|http://example.com/asdf", true], | 
|  147     ["||example.com/asdf", true], |  312     ["||example.com/asdf", true], | 
|  148     ["asfd$third-party", true], |  313     ["asfd$third-party", true], | 
|  149     ["asdf$domain=com", false], |  314     ["asdf$domain=com", false], | 
|  150     ["asdf$domain=example.com", false], |  315     ["asdf$domain=example.com", false], | 
|  151     ["asdf$image,domain=example.com", false], |  316     ["asdf$image,domain=example.com", false], | 
|  152     ["asdf$~image,domain=example.com", false], |  317     ["asdf$~image,domain=example.com", false], | 
|  153     ["asdf$third-party,domain=example.com", false], |  318     ["asdf$third-party,domain=example.com", false], | 
|  154     ["||example.com/asdf$~collapse,domain=example.com", false], |  319     ["||example.com/asdf$~coLLapse,domain=example.com", false], | 
|  155     ["||example.com/asdf$domain=~example.com", true], |  320     ["||example.com/asdf$domain=~example.com", true], | 
|  156     ["||example.com/asdf$third-party,domain=~example.com", true], |  321     ["||example.com/asdf$third-party,domain=~example.com", true], | 
|  157     ["asdf$domain=foo.example.com|~example.com", false], |  322     ["asdf$domain=foo.example.com|~example.com", false], | 
|  158     ["asdf$domain=foo.com|~example.com", false], |  323     ["asdf$domain=foo.com|~example.com", false], | 
|  159     ["asdf$domain=~foo.com|~example.com", true], |  324     ["asdf$domain=~foo.com|~example.com", true], | 
|  160   ]; |  325   ]; | 
|  161  |  326  | 
|  162   for (let [text, generic] of tests) |  327   for (let [text, generic] of tests) | 
|  163   { |  328   { | 
|  164     let filter = Filter.fromText(text); |  329     let filter = Filter.fromText(text); | 
|  165     try |  330     test.equal(filter.isGeneric(), generic, "Filter " + text + " is generic"); | 
|  166     { |  331     filter.delete(); | 
|  167       test.equal(filter.isGeneric(), generic, "Filter " + text + " is generic"); |  | 
|  168     } |  | 
|  169     finally |  | 
|  170     { |  | 
|  171       filter.delete(); |  | 
|  172     } |  | 
|  173   } |  332   } | 
|  174  |  333  | 
|  175   test.done(); |  334   test.done(); | 
|  176 } |  335 } | 
|  177  |  336  | 
|  178 exports.testElemHideSelector = function(test) |  337 exports.testElemHideSelector = function(test) | 
|  179 { |  338 { | 
|  180   function doTest(text, selector, selectorDomain) |  339   function doTest(text, selector, selectorDomain) | 
|  181   { |  340   { | 
|  182     let filter = Filter.fromText(text); |  341     let filter = Filter.fromText(text); | 
|  183     try |  342     test.equal(filter.selector, selector, "Correct selector for " + text); | 
|  184     { |  343  | 
|  185       test.equal(filter.selector, selector, "Correct selector for " + text); |  344     let actualDomains = filter.selectorDomain.split(",").sort().join(","); | 
|  186  |  345     let expectedDomains = selectorDomain.split(",").sort().join(","); | 
|  187       let actualDomains = filter.selectorDomain.split(",").sort().join(","); |  346     test.equal(actualDomains, expectedDomains, "Correct domains list for " + tex
     t); | 
|  188       let expectedDomains = selectorDomain.split(",").sort().join(","); |  347  | 
|  189       test.equal(actualDomains, expectedDomains, "Correct domains list for " + t
     ext); |  348     filter.delete(); | 
|  190     } |  | 
|  191     finally |  | 
|  192     { |  | 
|  193       filter.delete(); |  | 
|  194     } |  | 
|  195   } |  349   } | 
|  196  |  350  | 
|  197   let tests = [ |  351   let tests = [ | 
|  198     ["##foobar", "foobar", ""], |  352     ["##foobar", "foobar", ""], | 
|  199     ["~example.com##foobar", "foobar", ""], |  353     ["~example.com##foobar", "foobar", ""], | 
|  200     ["example.com##body > div:first-child", "body > div:first-child", "EXAMPLE.C
     OM"], |  354     ["example.com##body > div:first-child", "body > div:first-child", "example.c
     om"], | 
|  201     ["xYz,~example.com##foobar:not(whatever)", "foobar:not(whatever)","XYZ"], |  355     ["xYz,~example.com##foobar:not(whatever)", "foobar:not(whatever)","xyz"], | 
|  202     ["~xyz,com,~abc.com,example.info##foobar", "foobar", "COM,EXAMPLE.INFO"], |  356     ["~xyz,com,~abc.com,example.info##foobar", "foobar", "com,example.info"], | 
|  203     ["foo,bar,bas,bam##foobar", "foobar", "FOO,BAR,BAS,BAM"], |  357     ["foo,bar,bas,bam##foobar", "foobar", "foo,bar,bas,bam"], | 
|  204  |  358  | 
|  205     // Good idea to test this? Maybe consider behavior undefined in this case. |  359     // Good idea to test this? Maybe consider behavior undefined in this case. | 
|  206     ["foo,bar,bas,~bar##foobar", "foobar", "FOO,BAS"], |  360     ["foo,bar,bas,~bar##foobar", "foobar", "foo,bas"], | 
|  207   ]; |  361   ]; | 
|  208  |  362  | 
|  209   for (let [text, selector, selectorDomain] of tests) |  363   for (let [text, selector, selectorDomain] of tests) | 
|  210   { |  364   { | 
|  211     doTest(text, selector, selectorDomain); |  365     doTest(text, selector, selectorDomain); | 
|  212     doTest(text.replace("##", "#@#"), selector, selectorDomain); |  366     doTest(text.replace("##", "#@#"), selector, selectorDomain); | 
|  213   } |  367   } | 
|  214  |  368  | 
|  215   test.done(); |  369   test.done(); | 
|  216 }; |  370 }; | 
 |  371  | 
 |  372 exports.testCSSRules = function(test) | 
 |  373 { | 
 |  374   let tests = [ | 
 |  375     ["foo.com##[-abp-properties='abc']", "abc", "", ""], | 
 |  376     ["foo.com##[-abp-properties='a\"bc']", "a\\\"bc", "", ""], | 
 |  377     ["foo.com##[-abp-properties=\"abc\"]", "abc", "", ""], | 
 |  378     ["foo.com##[-abp-properties=\"a'bc\"]", "a\\'bc", "", ""], | 
 |  379     ["foo.com##aaa [-abp-properties='abc'] bbb", "abc", "aaa ", " bbb"], | 
 |  380     ["foo.com##[-abp-properties='|background-image: url(data:*)']", "^background
     \\-image\\:\\ url\\(data\\:.*\\)", "", ""], | 
 |  381   ]; | 
 |  382  | 
 |  383   for (let [text, regexp, prefix, suffix] of tests) | 
 |  384   { | 
 |  385     let filter = Filter.fromText(text); | 
 |  386     test.equal(filter.regexpString, regexp, "Regular expression of " + text); | 
 |  387     test.equal(filter.selectorPrefix, prefix, "Selector prefix of " + text); | 
 |  388     test.equal(filter.selectorSuffix, suffix, "Selector suffix of " + text); | 
 |  389     filter.delete(); | 
 |  390   } | 
 |  391  | 
 |  392   test.done(); | 
 |  393 }; | 
| LEFT | RIGHT |