diff --git a/tests/helpers/test_helper_utils.py b/tests/helpers/test_helper_utils.py new file mode 100644 index 000000000..9a9ff0111 --- /dev/null +++ b/tests/helpers/test_helper_utils.py @@ -0,0 +1,48 @@ +# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: + +# Copyright 2015 Florian Bruhin (The Compiler) +# +# This file is part of qutebrowser. +# +# qutebrowser is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# qutebrowser is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with qutebrowser. If not, see . + + +import pytest + +from helpers import utils + + +@pytest.mark.parametrize('val1, val2', [ + ({'a': 1}, {'a': 1}), + ({'a': 1, 'b': 2}, {'a': 1}), + ({'a': [1, 2, 3]}, {'a': [1]}), + ({'a': [1, 2, 3]}, {'a': [..., 2]}), + (1.0, 1.00000001), +]) +def test_partial_compare_equal(val1, val2): + assert utils.partial_compare(val1, val2) + + +@pytest.mark.parametrize('val1, val2', [ + ({'a': 1}, {'a': 2}), + ({'a': 1}, {'b': 1}), + ({'a': 1, 'b': 2}, {'a': 2}), + ({'a': [1]}, {'a': [1, 2, 3]}), + ({'a': [1]}, {'a': [2, 3, 4]}), + ([1], {1: 2}), + ({1: 1}, {1: [1]}), + ({'a': [1, 2, 3]}, {'a': [..., 3]}), +]) +def test_partial_compare_not_equal(val1, val2): + assert not utils.partial_compare(val1, val2) diff --git a/tests/helpers/utils.py b/tests/helpers/utils.py new file mode 100644 index 000000000..bca8f7c08 --- /dev/null +++ b/tests/helpers/utils.py @@ -0,0 +1,78 @@ +# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et: + +# Copyright 2015 Florian Bruhin (The Compiler) +# +# This file is part of qutebrowser. +# +# qutebrowser is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# qutebrowser is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with qutebrowser. If not, see . + +"""Partial comparison of dicts/lists.""" + + +def _partial_compare_dict(val1, val2): + for key in val2: + if key not in val1: + print("Key {!r} is in second dict but not in first!".format(key)) + return False + if not partial_compare(val1[key], val2[key]): + print("Comparison failed for {!r} and {!r}!".format( + val1[key], val2[key])) + return False + return True + + +def _partial_compare_list(val1, val2): + if len(val1) < len(val2): + print("Second list is longer than first list -> False!") + return False + for item1, item2 in zip(val1, val2): + if not partial_compare(item1, item2): + return False + return True + + +def partial_compare(val1, val2): + """Do a partial comparison between the given values. + + For dicts, keys in val2 are checked, others are ignored. + For lists, entries at the positions in val2 are checked, others ignored. + For other values, == is used. + + This happens recursively. + """ + print() + print("Comparing\n {!r}\nto\n {!r}".format(val1, val2)) + + if val2 is Ellipsis: + print("Ignoring ellipsis comparison") + return True + elif type(val1) != type(val2): + print("Different types ({}, {}) -> False".format( + type(val1), type(val2))) + return False + + if isinstance(val2, dict): + print("Comparing as dicts") + equal = _partial_compare_dict(val1, val2) + elif isinstance(val2, list): + print("Comparing as lists") + equal = _partial_compare_list(val1, val2) + elif isinstance(val2, float): + print("Doing float comparison") + equal = abs(val1 - val2) < 0.00001 + else: + print("Comparing via ==") + equal = val1 == val2 + print("---> {}".format(equal)) + return equal diff --git a/tests/integration/features/conftest.py b/tests/integration/features/conftest.py index 35599d98a..722537b32 100644 --- a/tests/integration/features/conftest.py +++ b/tests/integration/features/conftest.py @@ -1,7 +1,11 @@ +import re import logging +import yaml import pytest_bdd as bdd +from helpers import utils + @bdd.given(bdd.parsers.parse("I set {sect} -> {opt} to {value}")) def set_setting(quteproc, sect, opt, value): @@ -53,3 +57,21 @@ def expect_error(quteproc, httpbin, category, message): quteproc.mark_expected(category='message', loglevel=category_to_loglevel[category], message=message) + + +@bdd.then(bdd.parsers.parse("The session should look like:\n{expected}")) +def compare_session(quteproc, tmpdir, expected): + session = tmpdir / 'session.yml' + quteproc.send_cmd(':session-save "{}"'.format(session)) + quteproc.wait_for(category='message', loglevel=logging.INFO, + message='Saved session {}.'.format(session)) + + # Translate ... to ellipsis in YAML. + loader = yaml.SafeLoader(expected) + loader.add_constructor('!ellipsis', lambda loader, node: ...) + loader.add_implicit_resolver('!ellipsis', re.compile('\.\.\.'), None) + + data = yaml.load(session.read()) + expected = loader.get_data() + + assert utils.partial_compare(data, expected)