| LEFT | RIGHT | 
|---|
| 1 # This file is part of Adblock Plus <https://adblockplus.org/>, | 1 # This file is part of Adblock Plus <https://adblockplus.org/>, | 
| 2 # Copyright (C) 2006-2017 eyeo GmbH | 2 # Copyright (C) 2006-present eyeo GmbH | 
| 3 # | 3 # | 
| 4 # Adblock Plus is free software: you can redistribute it and/or modify | 4 # Adblock Plus is free software: you can redistribute it and/or modify | 
| 5 # it under the terms of the GNU General Public License version 3 as | 5 # it under the terms of the GNU General Public License version 3 as | 
| 6 # published by the Free Software Foundation. | 6 # published by the Free Software Foundation. | 
| 7 # | 7 # | 
| 8 # Adblock Plus is distributed in the hope that it will be useful, | 8 # Adblock Plus is distributed in the hope that it will be useful, | 
| 9 # but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 # but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| 10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
| 11 # GNU General Public License for more details. | 11 # GNU General Public License for more details. | 
| 12 # | 12 # | 
| 13 # You should have received a copy of the GNU General Public License | 13 # You should have received a copy of the GNU General Public License | 
| 14 # along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 14 # along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
| 15 | 15 | 
| 16 from __future__ import unicode_literals | 16 from __future__ import unicode_literals | 
| 17 | 17 | 
| 18 import pytest | 18 import pytest | 
| 19 | 19 | 
| 20 from abp.filters import parse_line, parse_filterlist | 20 from abp.filters import ( | 
| 21 from abp.filters.parser import InvalidLine, Comment, Metadata, ParseError | 21     parse_line, parse_filterlist, ParseError, | 
|  | 22     SELECTOR_TYPE as ST, FILTER_ACTION as FA, FILTER_OPTION as OPT, | 
|  | 23 ) | 
|  | 24 from abp.filters.parser import Comment, Metadata | 
| 22 | 25 | 
| 23 | 26 | 
| 24 def test_parse_empty(): | 27 def test_parse_empty(): | 
| 25     line = parse_line('    ') | 28     line = parse_line('    ') | 
| 26     assert line.type == 'emptyline' | 29     assert line.type == 'emptyline' | 
| 27 | 30 | 
| 28 | 31 | 
| 29 @pytest.mark.parametrize('filter_text, expected', { | 32 @pytest.mark.parametrize('filter_text, expected', { | 
| 30     '||example.com/banner.gif$image,~match-case,domain=abc.com|~def.org': { | 33     # Blocking filters with patterns and regexps and blocking exceptions. | 
|  | 34     '*asdf*d**dd*': { | 
|  | 35         'selector': {'type': ST.URL_PATTERN, 'value': '*asdf*d**dd*'}, | 
|  | 36         'action': FA.BLOCK, | 
|  | 37     }, | 
|  | 38     '@@|*asd|f*d**dd*|': { | 
|  | 39         'selector': {'type': ST.URL_PATTERN, 'value': '|*asd|f*d**dd*|'}, | 
|  | 40         'action': FA.ALLOW, | 
|  | 41     }, | 
|  | 42     '/ddd|f?a[s]d/': { | 
|  | 43         'selector': {'type': ST.URL_REGEXP, 'value': 'ddd|f?a[s]d'}, | 
|  | 44         'action': FA.BLOCK, | 
|  | 45     }, | 
|  | 46     '@@/ddd|f?a[s]d/': { | 
|  | 47         'selector': {'type': ST.URL_REGEXP, 'value': 'ddd|f?a[s]d'}, | 
|  | 48         'action': FA.ALLOW, | 
|  | 49     }, | 
|  | 50     # Blocking filters with some options. | 
|  | 51     'bla$match-case,~script,domain=foo.com|~bar.com,sitekey=foo': { | 
|  | 52         'selector': {'type': ST.URL_PATTERN, 'value': 'bla'}, | 
|  | 53         'action': FA.BLOCK, | 
|  | 54         'options': [ | 
|  | 55             (OPT.MATCH_CASE, True), | 
|  | 56             (OPT.SCRIPT, False), | 
|  | 57             (OPT.DOMAIN, [('foo.com', True), ('bar.com', False)]), | 
|  | 58             (OPT.SITEKEY, ['foo']), | 
|  | 59         ], | 
|  | 60     }, | 
|  | 61     '@@http://bla$~script,~other,sitekey=foo|bar': { | 
|  | 62         'selector': {'type': ST.URL_PATTERN, 'value': 'http://bla'}, | 
|  | 63         'action': FA.ALLOW, | 
|  | 64         'options': [ | 
|  | 65             (OPT.SCRIPT, False), | 
|  | 66             (OPT.OTHER, False), | 
|  | 67             (OPT.SITEKEY, ['foo', 'bar']), | 
|  | 68         ], | 
|  | 69     }, | 
|  | 70     # Element hiding filters and exceptions. | 
|  | 71     '##ddd': { | 
|  | 72         'selector': {'type': ST.CSS, 'value': 'ddd'}, | 
|  | 73         'action': FA.HIDE, | 
|  | 74         'options': [], | 
|  | 75     }, | 
|  | 76     '#@#body > div:first-child': { | 
|  | 77         'selector': {'type': ST.CSS, 'value': 'body > div:first-child'}, | 
|  | 78         'action': FA.SHOW, | 
|  | 79         'options': [], | 
|  | 80     }, | 
|  | 81     'foo,~bar##ddd': { | 
|  | 82         'options': [(OPT.DOMAIN, [('foo', True), ('bar', False)])], | 
|  | 83     }, | 
|  | 84     # Element hiding emulation filters (extended CSS). | 
|  | 85     'foo,~bar#?#:-abp-properties(abc)': { | 
|  | 86         'selector': {'type': ST.XCSS, 'value': ':-abp-properties(abc)'}, | 
|  | 87         'action': FA.HIDE, | 
|  | 88         'options': [(OPT.DOMAIN, [('foo', True), ('bar', False)])], | 
|  | 89     }, | 
|  | 90     'foo.com#?#aaa :-abp-properties(abc) bbb': { | 
| 31         'selector': { | 91         'selector': { | 
| 32             'type': 'url-pattern', | 92             'type': ST.XCSS, | 
| 33             'value': '||example.com/banner.gif', | 93             'value': 'aaa :-abp-properties(abc) bbb' | 
| 34         }, |  | 
| 35         'action': 'block', |  | 
| 36         'options': { |  | 
| 37             'match-case': False, |  | 
| 38             'types-none': True, |  | 
| 39             'types-include': ['image'], |  | 
| 40             'domains-none': True, |  | 
| 41             'domains-include': ['abc.com'], |  | 
| 42             'domains-exclude': ['def.org'], |  | 
| 43         }, | 94         }, | 
| 44     }, | 95     }, | 
| 45     '/ab?c\\.com/$image': { | 96     '#?#:-abp-properties(|background-image: url(data:*))': { | 
| 46         'selector': {'type': 'url-regexp', 'value': 'ab?c\\.com'}, | 97         'selector': { | 
| 47         'action': 'block', | 98             'type': ST.XCSS, | 
| 48         'options': { | 99             'value': ':-abp-properties(|background-image: url(data:*))' | 
| 49             'types-none': True, |  | 
| 50             'types-include': ['image'], |  | 
| 51         }, | 100         }, | 
| 52     }, | 101         'options': [], | 
| 53     'abc$~image': { |  | 
| 54         'selector': {'type': 'url-pattern', 'value': 'abc'}, |  | 
| 55         'action': 'block', |  | 
| 56         'options': { |  | 
| 57             'types-exclude': ['image'], |  | 
| 58         }, |  | 
| 59     }, |  | 
| 60     '@@||example.com/good.gif': { |  | 
| 61         'selector': {'type': 'url-pattern', 'value': '||example.com/good.gif'}, |  | 
| 62         'action': 'allow', |  | 
| 63         'options': {}, |  | 
| 64     }, |  | 
| 65     '@@/ab?c\\.com/': { |  | 
| 66         'selector': {'type': 'url-regexp', 'value': 'ab?c\\.com'}, |  | 
| 67         'action': 'allow', |  | 
| 68         'options': {}, |  | 
| 69     }, |  | 
| 70     'abc.com,cdf.com##div#ad1': { |  | 
| 71         'selector': {'type': 'css', 'value': 'div#ad1'}, |  | 
| 72         'action': 'hide', |  | 
| 73         'options': { |  | 
| 74             'domains-none': True, |  | 
| 75             'domains-include': ['abc.com', 'cdf.com'], |  | 
| 76         }, |  | 
| 77     }, |  | 
| 78     '#@#div#ad1': { |  | 
| 79         'selector': {'type': 'css', 'value': 'div#ad1'}, |  | 
| 80         'action': 'show', |  | 
| 81         'options': {}, |  | 
| 82     }, |  | 
| 83     'abc.com,~cdf.abc.com#@##ad1': { |  | 
| 84         'selector': {'type': 'css', 'value': '#ad1'}, |  | 
| 85         'action': 'show', |  | 
| 86         'options': { |  | 
| 87             'domains-none': True, |  | 
| 88             'domains-include': ['abc.com'], |  | 
| 89             'domains-exclude': ['cdf.abc.com'], |  | 
| 90         }, |  | 
| 91     }, |  | 
| 92     # Exception with a site key. |  | 
| 93     '@@||abc.com/ad?$subdocument,sitekey=foo': { |  | 
| 94         'selector': {'type': 'url-pattern', 'value': '||abc.com/ad?'}, |  | 
| 95         'action': 'allow', |  | 
| 96         'options': { |  | 
| 97             'types-none': True, |  | 
| 98             'types-include': ['subdocument'], |  | 
| 99             'sitekeys': ['foo'] |  | 
| 100         }, |  | 
| 101     }, |  | 
| 102     # Element hiding filter using old (a.k.a. simple) syntax. |  | 
| 103     'abc.com#div(foo)(name=bar)(value=baz)': { |  | 
| 104         'selector': { |  | 
| 105             'type': 'abp-simple', |  | 
| 106             'value': 'div(foo)(name=bar)(value=baz)', |  | 
| 107         }, |  | 
| 108         'action': 'hide', |  | 
| 109         'options': { |  | 
| 110             'domains-none': True, |  | 
| 111             'domains-include': ['abc.com'], |  | 
| 112         }, |  | 
| 113     }, |  | 
| 114     # Exclude all types with "x|~x" trick. |  | 
| 115     'x$image,~image': {'options': {'types-none': True}}, |  | 
| 116     # More tricky combos of type flags. |  | 
| 117     'x$~image,image': {'options': {}}, |  | 
| 118     'x$~image,image,~image': {'options': {'types-exclude': ['image']}}, |  | 
| 119     'x$image,~image,image': { |  | 
| 120         'options': {'types-none': True, 'types-include': ['image']}, |  | 
| 121     }, | 102     }, | 
| 122 }.items()) | 103 }.items()) | 
| 123 def test_parse_filters(filter_text, expected): | 104 def test_parse_filters(filter_text, expected): | 
| 124     """Parametric test for filter parsing""" | 105     """Parametric test for filter parsing""" | 
| 125     parsed = parse_line(filter_text) | 106     parsed = parse_line(filter_text) | 
| 126     assert parsed.type == 'filter' | 107     assert parsed.type == 'filter' | 
| 127     assert parsed.text == filter_text | 108     assert parsed.text == filter_text | 
| 128     for attribute, expected_value in expected.items(): | 109     for attribute, expected_value in expected.items(): | 
| 129         assert getattr(parsed, attribute) == expected_value | 110         assert getattr(parsed, attribute) == expected_value | 
| 130 | 111 | 
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 167 def test_parse_bad_header(): | 148 def test_parse_bad_header(): | 
| 168     with pytest.raises(ParseError): | 149     with pytest.raises(ParseError): | 
| 169         parse_line('[Adblock 1.1]') | 150         parse_line('[Adblock 1.1]') | 
| 170 | 151 | 
| 171 | 152 | 
| 172 def test_parse_filterlist(): | 153 def test_parse_filterlist(): | 
| 173     result = parse_filterlist(['! foo', '! Title: bar']) | 154     result = parse_filterlist(['! foo', '! Title: bar']) | 
| 174     assert list(result) == [Comment('foo'), Metadata('Title', 'bar')] | 155     assert list(result) == [Comment('foo'), Metadata('Title', 'bar')] | 
| 175 | 156 | 
| 176 | 157 | 
| 177 def test_invalid_lines(): | 158 def test_exception_timing(): | 
| 178     result = parse_filterlist([ | 159     result = parse_filterlist(['! good line', '%bad line%']) | 
| 179         '[Bad header]', | 160     assert next(result) == Comment('good line') | 
| 180         '! Good comment', | 161     with pytest.raises(ParseError): | 
| 181         '%Bad instruction%', | 162         next(result) | 
| 182     ]) |  | 
| 183     assert list(result) == [ |  | 
| 184         InvalidLine('[Bad header]', 'Malformed header'), |  | 
| 185         Comment('Good comment'), |  | 
| 186         InvalidLine('%Bad instruction%', 'Unrecognized instruction'), |  | 
| 187     ] |  | 
| LEFT | RIGHT | 
|---|