summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Bruhin <me@the-compiler.org>2023-06-12 23:16:30 +0200
committerFlorian Bruhin <me@the-compiler.org>2023-06-12 23:34:27 +0200
commiteeb39d633004c00f21749b964cdf5b0d66ae371c (patch)
treebec6d909f57fd01abee48344c2a1d0f54e94e66c
parent7fb2a2568e43af3f9b3164df9b908795c9a343d6 (diff)
downloadqutebrowser-eeb39d633004c00f21749b964cdf5b0d66ae371c.tar.gz
qutebrowser-eeb39d633004c00f21749b964cdf5b0d66ae371c.zip
qt: Add tests for machinery
-rw-r--r--tests/unit/test_qt_machinery.py171
1 files changed, 171 insertions, 0 deletions
diff --git a/tests/unit/test_qt_machinery.py b/tests/unit/test_qt_machinery.py
new file mode 100644
index 000000000..ffbb39543
--- /dev/null
+++ b/tests/unit/test_qt_machinery.py
@@ -0,0 +1,171 @@
+# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
+
+# Copyright 2021 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
+#
+# 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 <https://www.gnu.org/licenses/>.
+
+"""Test qutebrowser.qt.machinery."""
+
+import sys
+import argparse
+import typing
+from typing import Any, Optional
+
+import pytest
+
+from qutebrowser.qt import machinery
+
+
+def test_unavailable_is_importerror():
+ with pytest.raises(ImportError):
+ raise machinery.Unavailable()
+
+
+@pytest.fixture
+def modules():
+ """Return a dict of modules to import-patch, all unavailable by default."""
+ return dict.fromkeys(machinery.WRAPPERS, False)
+
+
+def test_autoselect_none_available(
+ stubs: Any,
+ modules: dict[str, bool],
+ monkeypatch: pytest.MonkeyPatch,
+):
+ stubs.ImportFake(modules, monkeypatch).patch()
+
+ message = "No Qt wrapper found, tried PyQt6, PyQt5"
+ with pytest.raises(machinery.Error, match=message):
+ machinery._autoselect_wrapper()
+
+
+@pytest.mark.parametrize(
+ "available, expected",
+ [
+ (["PyQt6"], "PyQt6"),
+ (["PyQt5"], "PyQt5"),
+ (["PyQt5", "PyQt6"], "PyQt6"),
+ ],
+)
+def test_autoselect(
+ stubs: Any,
+ modules: dict[str, bool],
+ available: list[str],
+ expected: str,
+ monkeypatch: pytest.MonkeyPatch,
+):
+ for wrapper in available:
+ modules[wrapper] = True
+ stubs.ImportFake(modules, monkeypatch).patch()
+ assert machinery._autoselect_wrapper() == expected
+
+
+@pytest.mark.parametrize(
+ "args, env, expected",
+ [
+ # Defaults with no overrides
+ (None, None, "PyQt5"),
+ (argparse.Namespace(qt_wrapper=None), None, "PyQt5"),
+ # Only argument given
+ (argparse.Namespace(qt_wrapper="PyQt6"), None, "PyQt6"),
+ (argparse.Namespace(qt_wrapper="PyQt5"), None, "PyQt5"),
+ # Only environment variable given
+ (None, "PyQt6", "PyQt6"),
+ (None, "PyQt5", "PyQt5"),
+ # Both given
+ (argparse.Namespace(qt_wrapper="PyQt5"), "PyQt6", "PyQt5"),
+ (argparse.Namespace(qt_wrapper="PyQt6"), "PyQt5", "PyQt6"),
+ (argparse.Namespace(qt_wrapper="PyQt6"), "PyQt6", "PyQt6"),
+ ],
+)
+def test_select_wrapper(
+ args: Optional[argparse.Namespace],
+ env: Optional[str],
+ expected: str,
+ monkeypatch: pytest.MonkeyPatch,
+):
+ if env is None:
+ monkeypatch.delenv("QUTE_QT_WRAPPER", raising=False)
+ else:
+ monkeypatch.setenv("QUTE_QT_WRAPPER", env)
+
+ assert machinery._select_wrapper(args) == expected
+
+
+def test_init_multiple_implicit(monkeypatch: pytest.MonkeyPatch):
+ monkeypatch.setattr(machinery, "_initialized", True)
+ machinery.init()
+ machinery.init()
+
+
+def test_init_multiple_explicit(monkeypatch: pytest.MonkeyPatch):
+ monkeypatch.setattr(machinery, "_initialized", True)
+ machinery.init()
+
+ with pytest.raises(
+ machinery.Error, match=r"init\(\) already called before application init"
+ ):
+ machinery.init(args=argparse.Namespace(qt_wrapper="PyQt6"))
+
+
+def test_init_after_qt_import(monkeypatch: pytest.MonkeyPatch):
+ monkeypatch.setattr(machinery, "_initialized", False)
+ with pytest.raises(machinery.Error, match="Py.* already imported"):
+ machinery.init()
+
+
+@pytest.mark.parametrize(
+ "selected_wrapper, true_vars",
+ [
+ ("PyQt6", ["USE_PYQT6", "IS_QT6", "IS_PYQT"]),
+ ("PyQt5", ["USE_PYQT5", "IS_QT5", "IS_PYQT"]),
+ ("PySide6", ["USE_PYSIDE6", "IS_QT6", "IS_PYSIDE"]),
+ ],
+)
+def test_init_properly(
+ monkeypatch: pytest.MonkeyPatch, selected_wrapper: str, true_vars: str
+):
+ for wrapper in machinery.WRAPPERS:
+ monkeypatch.delitem(sys.modules, wrapper, raising=False)
+
+ monkeypatch.setattr(machinery, "_initialized", False)
+
+ bool_vars = [
+ "USE_PYQT5",
+ "USE_PYQT6",
+ "USE_PYSIDE6",
+ "IS_QT5",
+ "IS_QT6",
+ "IS_PYQT",
+ "IS_PYSIDE",
+ ]
+ # Make sure we didn't forget anything that's declared in the module.
+ # Not sure if this is a good idea. Might remove it in the future if it breaks.
+ assert set(typing.get_type_hints(machinery).keys()) == set(bool_vars) | {"WRAPPER"}
+
+ for var in ["WRAPPER"] + bool_vars:
+ monkeypatch.delattr(machinery, var)
+
+ monkeypatch.setattr(machinery, "_select_wrapper", lambda args: selected_wrapper)
+
+ machinery.init()
+ assert machinery.WRAPPER == selected_wrapper
+
+ expected_vars = dict.fromkeys(bool_vars, False)
+ expected_vars.update(dict.fromkeys(true_vars, True))
+ actual_vars = {var: getattr(machinery, var) for var in bool_vars}
+
+ assert expected_vars == actual_vars