| Index: test/filterClasses.js | 
| =================================================================== | 
| new file mode 100644 | 
| --- /dev/null | 
| +++ b/test/filterClasses.js | 
| @@ -0,0 +1,264 @@ | 
| +"use strict"; | 
| + | 
| +let { | 
| +  Filter, InvalidFilter, CommentFilter, RegExpFilter, WhitelistFilter, | 
| +  ElemHideFilter, ElemHideException, CSSPropertyFilter | 
| +} = require("../lib/filterClasses"); | 
| + | 
| +exports.testFromText = function(test) | 
| +{ | 
| +  let tests = [ | 
| +    ["!asdf", CommentFilter, "comment"], | 
| +    ["asdf", RegExpFilter, "blocking"], | 
| +    ["asdf$image,~collapse", RegExpFilter, "blocking"], | 
| +    ["/asdf/", RegExpFilter, "blocking"], | 
| +    ["/asdf??+/", InvalidFilter, "invalid"], | 
| +    ["@@asdf", WhitelistFilter, "whitelist"], | 
| +    ["@@asdf$image,~collapse", WhitelistFilter, "whitelist"], | 
| +    ["@@/asdf/", WhitelistFilter, "whitelist"], | 
| +    ["@@/asdf??+/", InvalidFilter, "invalid"], | 
| +    ["##asdf", ElemHideFilter, "elemhide"], | 
| +    ["#@#asdf", ElemHideException, "elemhideexception"], | 
| +    ["foobar##asdf", ElemHideFilter, "elemhide"], | 
| +    ["foobar#@#asdf", ElemHideException, "elemhideexception"], | 
| +    ["foobar##a", ElemHideFilter, "elemhide"], | 
| +    ["foobar#@#a", ElemHideException, "elemhideexception"], | 
| + | 
| +    ["foobar#asdf", RegExpFilter, "blocking"], | 
| +    ["foobar|foobas##asdf", RegExpFilter, "blocking"], | 
| +    ["foobar##asdf{asdf}", RegExpFilter, "blocking"], | 
| +    ["foobar##", RegExpFilter, "blocking"], | 
| +    ["foobar#@#", RegExpFilter, "blocking"], | 
| +    ["asdf$foobar", InvalidFilter, "invalid"], | 
| +    ["asdf$image,foobar", InvalidFilter, "invalid"], | 
| +    ["asdf$image=foobar", RegExpFilter, "blocking"], | 
| +    ["asdf$image=foobar=xyz,~collapse", RegExpFilter, "blocking"], | 
| + | 
| +    ["##foo[-abp-properties='something']bar", InvalidFilter, "invalid"], | 
| +    ["#@#foo[-abp-properties='something']bar", ElemHideException, "elemhideexception"], | 
| +    ["example.com##foo[-abp-properties='something']bar", CSSPropertyFilter, "cssproperty"], | 
| +    ["example.com#@#foo[-abp-properties='something']bar", ElemHideException, "elemhideexception"], | 
| +    ["~example.com##foo[-abp-properties='something']bar", InvalidFilter, "invalid"], | 
| +    ["~example.com#@#foo[-abp-properties='something']bar", ElemHideException, "elemhideexception"], | 
| +    ["~example.com,~example.info##foo[-abp-properties='something']bar", InvalidFilter, "invalid"], | 
| +    ["~example.com,~example.info#@#foo[-abp-properties='something']bar", ElemHideException, "elemhideexception"], | 
| +    ["~sub.example.com,example.com##foo[-abp-properties='something']bar", CSSPropertyFilter, "cssproperty"], | 
| +    ["~sub.example.com,example.com#@#foo[-abp-properties='something']bar", ElemHideException, "elemhideexception"], | 
| +    ["example.com,~sub.example.com##foo[-abp-properties='something']bar", CSSPropertyFilter, "cssproperty"], | 
| +    ["example.com,~sub.example.com#@#foo[-abp-properties='something']bar", ElemHideException, "elemhideexception"], | 
| +    ["example.com##[-abp-properties='something']", CSSPropertyFilter, "cssproperty"], | 
| +    ["example.com#@#[-abp-properties='something']", ElemHideException, "elemhideexception"], | 
| +    ["example.com##[-abp-properties=\"something\"]", CSSPropertyFilter, "cssproperty"], | 
| +    ["example.com#@#[-abp-properties=\"something\"]", ElemHideException, "elemhideexception"], | 
| +    ["example.com##[-abp-properties=(something)]", ElemHideFilter, "elemhide"], | 
| +    ["example.com#@#[-abp-properties=(something)]", ElemHideException, "elemhideexception"], | 
| +  ]; | 
| +  for (let [text, type, typeName, location] of tests) | 
| +  { | 
| +    let filter = Filter.fromText(text); | 
| +    try | 
| +    { | 
| +      test.ok(filter instanceof Filter, "Got filter for " + text); | 
| +      test.equal(filter.text, text, "Correct filter text for " + text); | 
| +      test.ok(filter instanceof type, "Correct filter type for " + text); | 
| +      test.equal(filter.type, typeName, "Type name for " + text + " is " + typeName); | 
| +      if (type == InvalidFilter) | 
| +        test.ok(filter.reason, "Invalid filter " + text + " has a reason set"); | 
| +    } | 
| +    finally | 
| +    { | 
| +      filter.delete(); | 
| +    } | 
| +  } | 
| +  test.done(); | 
| +}; | 
| + | 
| +exports.testNormalize = function(test) | 
| +{ | 
| +  let tests = [ | 
| +    ["  foo bar ", "foobar"], | 
| +    ["foobar", "foobar"], | 
| +    [" !  comment something ", "!  comment something"], | 
| +    [" ! \n comment something ", "!  comment something"], | 
| +    [" foo , bar ## foo > bar ", "foo,bar##foo > bar"], | 
| +    [" foo , bar #@# foo > bar ", "foo,bar#@#foo > bar"], | 
| +  ]; | 
| +  for (let [text, expected] of tests) | 
| +    test.equal(Filter.normalize(text), expected); | 
| +  test.done(); | 
| +}; | 
| + | 
| +exports.testSerialize = function(test) | 
| +{ | 
| +  // Comment | 
| +  let filter = Filter.fromText("! serialize"); | 
| +  test.equal(filter.serialize(), "[Filter]\ntext=! serialize\n"); | 
| +  filter.delete(); | 
| + | 
| +  // Blocking filter | 
| +  filter = Filter.fromText("serialize"); | 
| +  test.equal(filter.serialize(), "[Filter]\ntext=serialize\n"); | 
| +  filter.disabled = true; | 
| +  test.equal(filter.serialize(), "[Filter]\ntext=serialize\ndisabled=true\n"); | 
| +  filter.disabled = false; | 
| +  filter.hitCount = 10; | 
| +  filter.lastHit = 12; | 
| +  test.equal(filter.serialize(), "[Filter]\ntext=serialize\nhitCount=10\nlastHit=12\n"); | 
| +  filter.delete(); | 
| + | 
| +  // Invalid filter | 
| +  filter = Filter.fromText("serialize$foobar"); | 
| +  test.equal(filter.serialize(), "[Filter]\ntext=serialize$foobar\n"); | 
| +  filter.delete(); | 
| + | 
| +  // Element hiding filter | 
| +  filter = Filter.fromText("example.com##serialize"); | 
| +  test.equal(filter.serialize(), "[Filter]\ntext=example.com##serialize\n"); | 
| +  filter.disabled = true; | 
| +  filter.lastHit = 5; | 
| +  test.equal(filter.serialize(), "[Filter]\ntext=example.com##serialize\ndisabled=true\nlastHit=5\n"); | 
| +  filter.delete(); | 
| + | 
| +  test.done(); | 
| +} | 
| + | 
| +exports.testActiveFilter = function(test) | 
| +{ | 
| +  let filter1 = Filter.fromText("asdf"); | 
| +  let filter1copy = Filter.fromText("asdf"); | 
| +  let filter2 = Filter.fromText("##foobar"); | 
| + | 
| +  try | 
| +  { | 
| +    test.ok(!filter1.disabled && !filter1copy.disabled && !filter2.disabled, "Filters are initially enabled"); | 
| +    filter1.disabled = true; | 
| +    test.ok(filter1.disabled, "Disabling filter works"); | 
| +    test.ok(filter1copy.disabled, "Filter copies are also disabled"); | 
| +    test.ok(!filter2.disabled, "Disabling one filter doesn't disable others"); | 
| + | 
| +    test.ok(filter1.hitCount === 0 && filter1copy.hitCount === 0 && filter2.hitCount === 0, "Filters have no hit initially"); | 
| +    filter1.hitCount = 5; | 
| +    test.equal(filter1.hitCount, 5, "Changing hit count works"); | 
| +    test.equal(filter1copy.hitCount, 5, "Hit count of filter copies is also changed"); | 
| +    test.equal(filter2.hitCount, 0, "Hit count of other filters isn't affected"); | 
| + | 
| +    test.ok(filter1.lastHit === 0 && filter1copy.lastHit === 0 && filter2.lastHit === 0, "Filters have no last hit time initially"); | 
| +    filter1.lastHit = 10; | 
| +    test.equal(filter1.lastHit, 10, "Changing last hit time works"); | 
| +    test.equal(filter1copy.lastHit, 10, "Last hit time of filter copies is also changed"); | 
| +    test.equal(filter2.lastHit, 0, "Last hit time of other filters isn't affected"); | 
| +  } | 
| +  finally | 
| +  { | 
| +    filter1.delete(); | 
| +    filter1copy.delete(); | 
| +    filter2.delete(); | 
| +  } | 
| + | 
| +  test.done(); | 
| +}; | 
| + | 
| +exports.testIsGeneric = function(test) | 
| +{ | 
| +  let tests = [ | 
| +    ["asfd", true], | 
| +    ["|http://example.com/asdf", true], | 
| +    ["||example.com/asdf", true], | 
| +    ["asfd$third-party", true], | 
| +    ["asdf$domain=com", false], | 
| +    ["asdf$domain=example.com", false], | 
| +    ["asdf$image,domain=example.com", false], | 
| +    ["asdf$~image,domain=example.com", false], | 
| +    ["asdf$third-party,domain=example.com", false], | 
| +    ["||example.com/asdf$~coLLapse,domain=example.com", false], | 
| +    ["||example.com/asdf$domain=~example.com", true], | 
| +    ["||example.com/asdf$third-party,domain=~example.com", true], | 
| +    ["asdf$domain=foo.example.com|~example.com", false], | 
| +    ["asdf$domain=foo.com|~example.com", false], | 
| +    ["asdf$domain=~foo.com|~example.com", true], | 
| +  ]; | 
| + | 
| +  for (let [text, generic] of tests) | 
| +  { | 
| +    let filter = Filter.fromText(text); | 
| +    try | 
| +    { | 
| +      test.equal(filter.isGeneric(), generic, "Filter " + text + " is generic"); | 
| +    } | 
| +    finally | 
| +    { | 
| +      filter.delete(); | 
| +    } | 
| +  } | 
| + | 
| +  test.done(); | 
| +} | 
| + | 
| +exports.testElemHideSelector = function(test) | 
| +{ | 
| +  function doTest(text, selector, selectorDomain) | 
| +  { | 
| +    let filter = Filter.fromText(text); | 
| +    try | 
| +    { | 
| +      test.equal(filter.selector, selector, "Correct selector for " + text); | 
| + | 
| +      let actualDomains = filter.selectorDomain.split(",").sort().join(","); | 
| +      let expectedDomains = selectorDomain.split(",").sort().join(","); | 
| +      test.equal(actualDomains, expectedDomains, "Correct domains list for " + text); | 
| +    } | 
| +    finally | 
| +    { | 
| +      filter.delete(); | 
| +    } | 
| +  } | 
| + | 
| +  let tests = [ | 
| +    ["##foobar", "foobar", ""], | 
| +    ["~example.com##foobar", "foobar", ""], | 
| +    ["example.com##body > div:first-child", "body > div:first-child", "example.com"], | 
| +    ["xYz,~example.com##foobar:not(whatever)", "foobar:not(whatever)","xyz"], | 
| +    ["~xyz,com,~abc.com,example.info##foobar", "foobar", "com,example.info"], | 
| +    ["foo,bar,bas,bam##foobar", "foobar", "foo,bar,bas,bam"], | 
| + | 
| +    // Good idea to test this? Maybe consider behavior undefined in this case. | 
| +    ["foo,bar,bas,~bar##foobar", "foobar", "foo,bas"], | 
| +  ]; | 
| + | 
| +  for (let [text, selector, selectorDomain] of tests) | 
| +  { | 
| +    doTest(text, selector, selectorDomain); | 
| +    doTest(text.replace("##", "#@#"), selector, selectorDomain); | 
| +  } | 
| + | 
| +  test.done(); | 
| +}; | 
| + | 
| +exports.textCSSRules = function(test) | 
| +{ | 
| +  let tests = [ | 
| +    ["foo.com##[-abp-properties='abc']", "abc", "", ""], | 
| +    ["foo.com##[-abp-properties='a\"bc']", "a\\\"bc", "", ""], | 
| +    ["foo.com##[-abp-properties=\"abc\"]", "abc", "", ""], | 
| +    ["foo.com##[-abp-properties=\"a'bc\"]", "a\\'bc", "", ""], | 
| +    ["foo.com##aaa [-abp-properties='abc'] bbb", "abc", "aaa ", " bbb"], | 
| +    ["foo.com##[-abp-properties='|background-image: url(data:*)']", "^background\\-image\\:\\ url\\(data\\:.*\\)", "", ""], | 
| +  ]; | 
| + | 
| +  for (let [text, regexp, prefix, suffix] of tests) | 
| +  { | 
| +    let filter = Filter.fromText(text); | 
| +    try | 
| +    { | 
| +      test.equal(filter.regexpString, regexp, "Regular expression of " + text); | 
| +      test.equal(filter.selectorPrefix, prefix, "Selector prefix of " + text); | 
| +      test.equal(filter.selectorSuffix, suffix, "Selector suffix of " + text); | 
| +    } | 
| +    finally | 
| +    { | 
| +      filter.delete(); | 
| +    } | 
| +  } | 
| + | 
| +  test.done(); | 
| +}; | 
|  |