From 16ac3baf2e5a153c4a6d78be746e9a4ac79a4681 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Thu, 1 Oct 2015 23:11:48 +0200 Subject: [PATCH] configtypes: Handle invalid escapes in regexes. --- qutebrowser/config/configtypes.py | 21 +++++++++---- tests/unit/config/test_configtypes.py | 43 +++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/qutebrowser/config/configtypes.py b/qutebrowser/config/configtypes.py index aa61dfa5d..c15de3d0f 100644 --- a/qutebrowser/config/configtypes.py +++ b/qutebrowser/config/configtypes.py @@ -26,6 +26,7 @@ import codecs import os.path import itertools import collections +import warnings from PyQt5.QtCore import QUrl from PyQt5.QtGui import QColor, QFont @@ -45,11 +46,21 @@ BOOLEAN_STATES = {'1': True, 'yes': True, 'true': True, 'on': True, def _validate_regex(pattern, flags): - try: - re.compile(pattern, flags) - except re.error as e: - raise configexc.ValidationError(pattern, "must be a valid regex - " + - str(e)) + with warnings.catch_warnings(record=True) as recorded_warnings: + warnings.simplefilter('always') + try: + re.compile(pattern, flags) + except re.error as e: + raise configexc.ValidationError( + pattern, "must be a valid regex - " + str(e)) + + for w in recorded_warnings: + if (issubclass(w.category, DeprecationWarning) and + str(w.message).startswith('bad escape')): + raise configexc.ValidationError( + pattern, "must be a valid regex - " + str(w.message)) + else: + warnings.warn(w.message) class ValidValues: diff --git a/tests/unit/config/test_configtypes.py b/tests/unit/config/test_configtypes.py index d6ba61d2a..a6d328ea4 100644 --- a/tests/unit/config/test_configtypes.py +++ b/tests/unit/config/test_configtypes.py @@ -23,6 +23,7 @@ import collections import itertools import os.path import base64 +import warnings import pytest from PyQt5.QtCore import QUrl @@ -1064,6 +1065,22 @@ class TestRegex: with pytest.raises(configexc.ValidationError): klass().validate(val) + @pytest.mark.parametrize('val', [ + r'foo\Xbar', + r'foo\Cbar', + ]) + def test_validate_maybe_valid(self, klass, val): + """Those values are valid on some Python versions (and systems?). + + On others, they raise a DeprecationWarning because of an invalid + escape. This tests makes sure this gets translated to a + ValidationError. + """ + try: + klass().validate(val) + except configexc.ValidationError: + pass + @pytest.mark.parametrize('val, expected', [ (r'foobar', RegexEq(r'foobar')), ('', None), @@ -1071,6 +1088,16 @@ class TestRegex: def test_transform_empty(self, klass, val, expected): assert klass().transform(val) == expected + @pytest.mark.parametrize('warning', [ + Warning('foo'), DeprecationWarning('foo'), + ]) + def test_passed_warnings(self, mocker, klass, warning): + m = mocker.patch('qutebrowser.config.configtypes.re') + m.compile.side_effect = lambda *args: warnings.warn(warning) + m.error = re.error + with pytest.raises(type(warning)): + klass().validate('foo') + class TestRegexList: @@ -1097,6 +1124,22 @@ class TestRegexList: with pytest.raises(configexc.ValidationError): klass().validate(val) + @pytest.mark.parametrize('val', [ + r'foo\Xbar', + r'foo\Cbar', + ]) + def test_validate_maybe_valid(self, klass, val): + """Those values are valid on some Python versions (and systems?). + + On others, they raise a DeprecationWarning because of an invalid + escape. This tests makes sure this gets translated to a + ValidationError. + """ + try: + klass().validate(val) + except configexc.ValidationError: + pass + @pytest.mark.parametrize('val, expected', [ ('foo', [RegexEq('foo')]), ('foo,bar,baz', [RegexEq('foo'), RegexEq('bar'),