mirror of
https://github.com/freedomofpress/dangerzone.git
synced 2025-04-28 18:02:38 +02:00

Add the following two methods in the isolation provider: 1. `.is_available()`: Mainly used for the Container isolation provider, it specifies whether the container runtime is up and running. May be used in the future by other similar providers. 2. `.should_wait_install()`: Whether the isolation provider takes a while to be installed. Should be `True` only for the Container isolation provider, for the time being.
593 lines
20 KiB
Python
593 lines
20 KiB
Python
import os
|
|
import pathlib
|
|
import platform
|
|
import shutil
|
|
import time
|
|
from typing import List
|
|
|
|
from pytest import MonkeyPatch, fixture
|
|
from pytest_mock import MockerFixture
|
|
from pytest_subprocess import FakeProcess
|
|
from pytestqt.qtbot import QtBot
|
|
|
|
from dangerzone.document import Document
|
|
from dangerzone.gui import MainWindow
|
|
from dangerzone.gui import main_window as main_window_module
|
|
from dangerzone.gui import updater as updater_module
|
|
from dangerzone.gui.logic import DangerzoneGui
|
|
|
|
# import Pyside related objects from here to avoid duplicating import logic.
|
|
from dangerzone.gui.main_window import (
|
|
ContentWidget,
|
|
InstallContainerThread,
|
|
QtCore,
|
|
QtGui,
|
|
WaitingWidgetContainer,
|
|
)
|
|
from dangerzone.gui.updater import UpdateReport, UpdaterThread
|
|
from dangerzone.isolation_provider.container import (
|
|
Container,
|
|
NoContainerTechException,
|
|
NotAvailableContainerTechException,
|
|
)
|
|
from dangerzone.isolation_provider.dummy import Dummy
|
|
|
|
from .test_updater import assert_report_equal, default_updater_settings
|
|
|
|
##
|
|
# Widget Fixtures
|
|
##
|
|
|
|
|
|
@fixture
|
|
def content_widget(qtbot: QtBot, mocker: MockerFixture) -> ContentWidget:
|
|
# Setup
|
|
mock_app = mocker.MagicMock()
|
|
dummy = mocker.MagicMock()
|
|
dz = DangerzoneGui(mock_app, dummy)
|
|
w = ContentWidget(dz)
|
|
qtbot.addWidget(w)
|
|
return w
|
|
|
|
|
|
def drag_files_event(mocker: MockerFixture, files: List[str]) -> QtGui.QDropEvent:
|
|
ev = mocker.MagicMock(spec=QtGui.QDropEvent)
|
|
ev.accept.return_value = True
|
|
|
|
urls = [QtCore.QUrl.fromLocalFile(x) for x in files]
|
|
ev.mimeData.return_value.has_urls.return_value = True
|
|
ev.mimeData.return_value.urls.return_value = urls
|
|
return ev
|
|
|
|
|
|
@fixture
|
|
def drag_valid_files_event(
|
|
mocker: MockerFixture, sample_doc: str, sample_pdf: str
|
|
) -> QtGui.QDropEvent:
|
|
return drag_files_event(mocker, [sample_doc, sample_pdf])
|
|
|
|
|
|
@fixture
|
|
def drag_1_invalid_file_event(
|
|
mocker: MockerFixture, sample_doc: str, tmp_path: pathlib.Path
|
|
) -> QtGui.QDropEvent:
|
|
unsupported_file_path = tmp_path / "file.unsupported"
|
|
shutil.copy(sample_doc, unsupported_file_path)
|
|
return drag_files_event(mocker, [str(unsupported_file_path)])
|
|
|
|
|
|
@fixture
|
|
def drag_1_invalid_and_2_valid_files_event(
|
|
mocker: MockerFixture, tmp_path: pathlib.Path, sample_doc: str, sample_pdf: str
|
|
) -> QtGui.QDropEvent:
|
|
unsupported_file_path = tmp_path / "file.unsupported"
|
|
shutil.copy(sample_doc, unsupported_file_path)
|
|
return drag_files_event(
|
|
mocker, [sample_doc, sample_pdf, str(unsupported_file_path)]
|
|
)
|
|
|
|
|
|
@fixture
|
|
def drag_text_event(mocker: MockerFixture) -> QtGui.QDropEvent:
|
|
ev = mocker.MagicMock()
|
|
ev.accept.return_value = True
|
|
ev.mimeData.return_value.has_urls.return_value = False
|
|
return ev
|
|
|
|
|
|
def test_default_menu(
|
|
qtbot: QtBot,
|
|
updater: UpdaterThread,
|
|
) -> None:
|
|
"""Check that the default menu entries are in order."""
|
|
updater.dangerzone.settings.set("updater_check", True)
|
|
|
|
window = MainWindow(updater.dangerzone)
|
|
menu_actions = window.hamburger_button.menu().actions()
|
|
assert len(menu_actions) == 3
|
|
|
|
toggle_updates_action = menu_actions[0]
|
|
assert toggle_updates_action.text() == "Check for updates"
|
|
assert toggle_updates_action.isChecked()
|
|
|
|
separator = menu_actions[1]
|
|
assert separator.isSeparator()
|
|
|
|
exit_action = menu_actions[2]
|
|
assert exit_action.text() == "Exit"
|
|
|
|
toggle_updates_action.trigger()
|
|
assert not toggle_updates_action.isChecked()
|
|
assert updater.dangerzone.settings.get("updater_check") is False
|
|
|
|
|
|
def test_no_update(
|
|
qtbot: QtBot,
|
|
updater: UpdaterThread,
|
|
monkeypatch: MonkeyPatch,
|
|
mocker: MockerFixture,
|
|
) -> None:
|
|
"""Test that when no update has been detected, the user is not alerted."""
|
|
# Check that when no update is detected, e.g., due to update cooldown, an empty
|
|
# report is received that does not affect the menu entries.
|
|
curtime = int(time.time())
|
|
updater.dangerzone.settings.set("updater_check", True)
|
|
updater.dangerzone.settings.set("updater_errors", 9)
|
|
updater.dangerzone.settings.set("updater_last_check", curtime)
|
|
|
|
expected_settings = default_updater_settings()
|
|
expected_settings["updater_check"] = True
|
|
expected_settings["updater_errors"] = 0 # errors must be cleared
|
|
expected_settings["updater_last_check"] = curtime
|
|
|
|
window = MainWindow(updater.dangerzone)
|
|
window.register_update_handler(updater.finished)
|
|
handle_updates_spy = mocker.spy(window, "handle_updates")
|
|
|
|
menu_actions_before = window.hamburger_button.menu().actions()
|
|
|
|
with qtbot.waitSignal(updater.finished):
|
|
updater.start()
|
|
|
|
# Check that the callback function gets an empty report.
|
|
handle_updates_spy.assert_called_once()
|
|
assert_report_equal(handle_updates_spy.call_args.args[0], UpdateReport())
|
|
|
|
# Check that the menu entries remain exactly the same.
|
|
menu_actions_after = window.hamburger_button.menu().actions()
|
|
assert menu_actions_before == menu_actions_after
|
|
|
|
# Check that any previous update errors are cleared.
|
|
assert updater.dangerzone.settings.get_updater_settings() == expected_settings
|
|
|
|
|
|
def test_update_detected(
|
|
qtbot: QtBot,
|
|
qt_updater: UpdaterThread,
|
|
monkeypatch: MonkeyPatch,
|
|
mocker: MockerFixture,
|
|
) -> None:
|
|
"""Test that a newly detected version leads to a notification to the user."""
|
|
|
|
qt_updater.dangerzone.settings.set("updater_check", True)
|
|
qt_updater.dangerzone.settings.set("updater_last_check", 0)
|
|
qt_updater.dangerzone.settings.set("updater_errors", 9)
|
|
|
|
# Make requests.get().json() return the following dictionary.
|
|
mock_upstream_info = {"tag_name": "99.9.9", "body": "changelog"}
|
|
mocker.patch("dangerzone.gui.updater.requests.get")
|
|
requests_mock = updater_module.requests.get
|
|
requests_mock().status_code = 200 # type: ignore [call-arg]
|
|
requests_mock().json.return_value = mock_upstream_info # type: ignore [attr-defined, call-arg]
|
|
|
|
window = MainWindow(qt_updater.dangerzone)
|
|
window.register_update_handler(qt_updater.finished)
|
|
handle_updates_spy = mocker.spy(window, "handle_updates")
|
|
load_svg_spy = mocker.spy(main_window_module, "load_svg_image")
|
|
|
|
menu_actions_before = window.hamburger_button.menu().actions()
|
|
|
|
with qtbot.waitSignal(qt_updater.finished):
|
|
qt_updater.start()
|
|
|
|
menu_actions_after = window.hamburger_button.menu().actions()
|
|
|
|
# Check that the callback function gets an update report.
|
|
handle_updates_spy.assert_called_once()
|
|
assert_report_equal(
|
|
handle_updates_spy.call_args.args[0], UpdateReport("99.9.9", "<p>changelog</p>")
|
|
)
|
|
|
|
# Check that the settings have been updated properly.
|
|
expected_settings = default_updater_settings()
|
|
expected_settings["updater_check"] = True
|
|
expected_settings["updater_last_check"] = qt_updater.dangerzone.settings.get(
|
|
"updater_last_check"
|
|
)
|
|
expected_settings["updater_latest_version"] = "99.9.9"
|
|
expected_settings["updater_latest_changelog"] = "<p>changelog</p>"
|
|
expected_settings["updater_errors"] = 0
|
|
assert qt_updater.dangerzone.settings.get_updater_settings() == expected_settings
|
|
|
|
# Check that the hamburger icon has changed with the expected SVG image.
|
|
assert load_svg_spy.call_count == 2
|
|
assert load_svg_spy.call_args_list[0].args[0] == "hamburger_menu_update_success.svg"
|
|
assert (
|
|
load_svg_spy.call_args_list[1].args[0]
|
|
== "hamburger_menu_update_dot_available.svg"
|
|
)
|
|
|
|
# Check that new menu entries have been added.
|
|
menu_actions_after = window.hamburger_button.menu().actions()
|
|
assert len(menu_actions_after) == 5
|
|
assert menu_actions_after[2:] == menu_actions_before
|
|
|
|
success_action = menu_actions_after[0]
|
|
assert success_action.text() == "New version available"
|
|
|
|
separator = menu_actions_after[1]
|
|
assert separator.isSeparator()
|
|
|
|
# Check that clicking in the new menu entry, opens a dialog.
|
|
update_dialog_spy = mocker.spy(main_window_module, "UpdateDialog")
|
|
|
|
def check_dialog() -> None:
|
|
dialog = qt_updater.dangerzone.app.activeWindow()
|
|
|
|
update_dialog_spy.assert_called_once()
|
|
kwargs = update_dialog_spy.call_args.kwargs
|
|
assert "99.9.9" in kwargs["title"]
|
|
assert "dangerzone.rocks" in kwargs["intro_msg"]
|
|
assert not kwargs["middle_widget"].toggle_button.isChecked()
|
|
collapsible_box = kwargs["middle_widget"]
|
|
text_browser = (
|
|
collapsible_box.layout().itemAt(1).widget().layout().itemAt(0).widget()
|
|
)
|
|
assert collapsible_box.toggle_button.text() == "What's New?"
|
|
assert text_browser.toPlainText() == "changelog"
|
|
|
|
height_initial = dialog.sizeHint().height()
|
|
width_initial = dialog.sizeHint().width()
|
|
|
|
# Collapse the "What's New" section and ensure that the dialog's height
|
|
# increases.
|
|
with qtbot.waitSignal(collapsible_box.toggle_animation.finished):
|
|
collapsible_box.toggle_button.click()
|
|
|
|
assert dialog.sizeHint().height() > height_initial
|
|
assert dialog.sizeHint().width() == width_initial
|
|
|
|
# Uncollapse the "What's New" section, and ensure that the dialog's height gets
|
|
# back to the original value.
|
|
with qtbot.waitSignal(collapsible_box.toggle_animation.finished):
|
|
collapsible_box.toggle_button.click()
|
|
|
|
assert dialog.sizeHint().height() == height_initial
|
|
assert dialog.sizeHint().width() == width_initial
|
|
|
|
dialog.close()
|
|
|
|
QtCore.QTimer.singleShot(500, check_dialog)
|
|
success_action.trigger()
|
|
|
|
# FIXME: We should check the content of the dialog here.
|
|
|
|
|
|
def test_update_error(
|
|
qtbot: QtBot,
|
|
qt_updater: UpdaterThread,
|
|
monkeypatch: MonkeyPatch,
|
|
mocker: MockerFixture,
|
|
) -> None:
|
|
"""Test that an error during an update check leads to a notification to the user."""
|
|
# Test 1 - Check that the first error does not notify the user.
|
|
qt_updater.dangerzone.settings.set("updater_check", True)
|
|
qt_updater.dangerzone.settings.set("updater_last_check", 0)
|
|
qt_updater.dangerzone.settings.set("updater_errors", 0)
|
|
|
|
# Make requests.get() return an errorthe following dictionary.
|
|
mocker.patch("dangerzone.gui.updater.requests.get")
|
|
requests_mock = updater_module.requests.get
|
|
requests_mock.side_effect = Exception("failed") # type: ignore [attr-defined]
|
|
|
|
window = MainWindow(qt_updater.dangerzone)
|
|
window.register_update_handler(qt_updater.finished)
|
|
handle_updates_spy = mocker.spy(window, "handle_updates")
|
|
load_svg_spy = mocker.spy(main_window_module, "load_svg_image")
|
|
|
|
menu_actions_before = window.hamburger_button.menu().actions()
|
|
|
|
with qtbot.waitSignal(qt_updater.finished):
|
|
qt_updater.start()
|
|
|
|
menu_actions_after = window.hamburger_button.menu().actions()
|
|
|
|
# Check that the callback function gets an update report.
|
|
handle_updates_spy.assert_called_once()
|
|
assert "failed" in handle_updates_spy.call_args.args[0].error
|
|
|
|
# Check that the settings have been updated properly.
|
|
expected_settings = default_updater_settings()
|
|
expected_settings["updater_check"] = True
|
|
expected_settings["updater_last_check"] = qt_updater.dangerzone.settings.get(
|
|
"updater_last_check"
|
|
)
|
|
expected_settings["updater_errors"] += 1
|
|
assert qt_updater.dangerzone.settings.get_updater_settings() == expected_settings
|
|
|
|
# Check that the hamburger icon has not changed.
|
|
assert load_svg_spy.call_count == 0
|
|
|
|
# Check that no menu entries have been added.
|
|
assert menu_actions_before == menu_actions_after
|
|
|
|
# Test 2 - Check that the second error does not notify the user either.
|
|
qt_updater.dangerzone.settings.set("updater_last_check", 0)
|
|
with qtbot.waitSignal(qt_updater.finished):
|
|
qt_updater.start()
|
|
|
|
assert load_svg_spy.call_count == 0
|
|
|
|
# Check that the settings have been updated properly.
|
|
expected_settings["updater_errors"] += 1
|
|
expected_settings["updater_last_check"] = qt_updater.dangerzone.settings.get(
|
|
"updater_last_check"
|
|
)
|
|
assert qt_updater.dangerzone.settings.get_updater_settings() == expected_settings
|
|
|
|
# Check that no menu entries have been added.
|
|
assert menu_actions_before == menu_actions_after
|
|
|
|
# Test 3 - Check that a third error shows a new menu entry.
|
|
qt_updater.dangerzone.settings.set("updater_last_check", 0)
|
|
with qtbot.waitSignal(qt_updater.finished):
|
|
qt_updater.start()
|
|
|
|
menu_actions_after = window.hamburger_button.menu().actions()
|
|
assert len(menu_actions_after) == 5
|
|
assert menu_actions_after[2:] == menu_actions_before
|
|
|
|
# Check that the hamburger icon has changed with the expected SVG image.
|
|
assert load_svg_spy.call_count == 2
|
|
assert load_svg_spy.call_args_list[0].args[0] == "hamburger_menu_update_error.svg"
|
|
assert (
|
|
load_svg_spy.call_args_list[1].args[0] == "hamburger_menu_update_dot_error.svg"
|
|
)
|
|
|
|
error_action = menu_actions_after[0]
|
|
assert error_action.text() == "Update error"
|
|
|
|
separator = menu_actions_after[1]
|
|
assert separator.isSeparator()
|
|
|
|
# Check that clicking in the new menu entry, opens a dialog.
|
|
update_dialog_spy = mocker.spy(main_window_module, "UpdateDialog")
|
|
|
|
def check_dialog() -> None:
|
|
dialog = qt_updater.dangerzone.app.activeWindow()
|
|
|
|
update_dialog_spy.assert_called_once()
|
|
kwargs = update_dialog_spy.call_args.kwargs
|
|
assert kwargs["title"] == "Update check error"
|
|
assert "Something went wrong" in kwargs["intro_msg"]
|
|
assert "dangerzone.rocks" in kwargs["intro_msg"]
|
|
assert not kwargs["middle_widget"].toggle_button.isChecked()
|
|
collapsible_box = kwargs["middle_widget"]
|
|
text_browser = (
|
|
collapsible_box.layout().itemAt(1).widget().layout().itemAt(0).widget()
|
|
)
|
|
assert collapsible_box.toggle_button.text() == "Error Details"
|
|
assert "Encountered an exception" in text_browser.toPlainText()
|
|
assert "failed" in text_browser.toPlainText()
|
|
|
|
dialog.close()
|
|
|
|
QtCore.QTimer.singleShot(500, check_dialog)
|
|
error_action.trigger()
|
|
|
|
|
|
##
|
|
# Document Selection tests
|
|
##
|
|
|
|
|
|
def test_change_document_button(
|
|
content_widget: ContentWidget,
|
|
qtbot: QtBot,
|
|
mocker: MockerFixture,
|
|
sample_pdf: str,
|
|
sample_doc: str,
|
|
tmp_path: pathlib.Path,
|
|
) -> None:
|
|
# Setup first doc selection
|
|
file_dialog_mock = mocker.MagicMock()
|
|
file_dialog_mock.selectedFiles.return_value = (sample_pdf,)
|
|
content_widget.doc_selection_widget.file_dialog = file_dialog_mock
|
|
|
|
# Select first file
|
|
with qtbot.waitSignal(content_widget.documents_added):
|
|
qtbot.mouseClick(
|
|
content_widget.doc_selection_widget.dangerous_doc_button,
|
|
QtCore.Qt.MouseButton.LeftButton,
|
|
)
|
|
file_dialog_mock.accept()
|
|
|
|
# Setup doc change
|
|
shutil.copy(sample_doc, tmp_path)
|
|
tmp_sample_doc = tmp_path / os.path.basename(sample_doc)
|
|
file_dialog_mock.selectedFiles.return_value = (tmp_sample_doc,)
|
|
|
|
# When clicking on "select docs" button
|
|
with qtbot.waitSignal(content_widget.documents_added):
|
|
qtbot.mouseClick(
|
|
content_widget.settings_widget.change_selection_button,
|
|
QtCore.Qt.MouseButton.LeftButton,
|
|
)
|
|
file_dialog_mock.accept()
|
|
|
|
# Then two dialogs should have been open
|
|
assert file_dialog_mock.exec.call_count == 2
|
|
assert file_dialog_mock.selectedFiles.call_count == 2
|
|
|
|
# Then the final document should be only the second one
|
|
docs = [
|
|
doc.input_filename
|
|
for doc in content_widget.dangerzone.get_unconverted_documents()
|
|
]
|
|
assert len(docs) == 1
|
|
assert docs[0] == str(tmp_sample_doc)
|
|
|
|
|
|
def test_drop_valid_documents(
|
|
content_widget: ContentWidget,
|
|
drag_valid_files_event: QtGui.QDropEvent,
|
|
qtbot: QtBot,
|
|
) -> None:
|
|
with qtbot.waitSignal(
|
|
content_widget.doc_selection_wrapper.documents_selected,
|
|
check_params_cb=lambda x: len(x) == 2 and isinstance(x[0], Document),
|
|
):
|
|
content_widget.doc_selection_wrapper.dropEvent(drag_valid_files_event)
|
|
|
|
|
|
def test_drop_text(
|
|
content_widget: ContentWidget,
|
|
drag_text_event: QtGui.QDropEvent,
|
|
qtbot: QtBot,
|
|
) -> None:
|
|
with qtbot.assertNotEmitted(
|
|
content_widget.doc_selection_wrapper.documents_selected
|
|
):
|
|
content_widget.doc_selection_wrapper.dropEvent(drag_text_event)
|
|
|
|
|
|
def test_drop_1_invalid_doc(
|
|
content_widget: ContentWidget,
|
|
drag_1_invalid_file_event: QtGui.QDropEvent,
|
|
qtbot: QtBot,
|
|
) -> None:
|
|
with qtbot.assertNotEmitted(
|
|
content_widget.doc_selection_wrapper.documents_selected
|
|
):
|
|
content_widget.doc_selection_wrapper.dropEvent(drag_1_invalid_file_event)
|
|
|
|
|
|
def test_drop_1_invalid_2_valid_documents(
|
|
content_widget: ContentWidget,
|
|
drag_1_invalid_and_2_valid_files_event: QtGui.QDropEvent,
|
|
qtbot: QtBot,
|
|
monkeypatch: MonkeyPatch,
|
|
) -> None:
|
|
# If we accept to continue
|
|
monkeypatch.setattr(
|
|
content_widget.doc_selection_wrapper, "prompt_continue_without", lambda x: True
|
|
)
|
|
|
|
# Then the 2 valid docs will be selected
|
|
with qtbot.waitSignal(
|
|
content_widget.doc_selection_wrapper.documents_selected,
|
|
check_params_cb=lambda x: len(x) == 2 and isinstance(x[0], Document),
|
|
):
|
|
content_widget.doc_selection_wrapper.dropEvent(
|
|
drag_1_invalid_and_2_valid_files_event
|
|
)
|
|
|
|
# If we refuse to continue
|
|
monkeypatch.setattr(
|
|
content_widget.doc_selection_wrapper, "prompt_continue_without", lambda x: False
|
|
)
|
|
|
|
# Then no docs will be selected
|
|
with qtbot.assertNotEmitted(
|
|
content_widget.doc_selection_wrapper.documents_selected,
|
|
):
|
|
content_widget.doc_selection_wrapper.dropEvent(
|
|
drag_1_invalid_and_2_valid_files_event
|
|
)
|
|
|
|
|
|
def test_not_available_container_tech_exception(
|
|
qtbot: QtBot, mocker: MockerFixture
|
|
) -> None:
|
|
# Setup
|
|
mock_app = mocker.MagicMock()
|
|
dummy = Dummy()
|
|
fn = mocker.patch.object(dummy, "is_available")
|
|
fn.side_effect = NotAvailableContainerTechException(
|
|
"podman", "podman image ls logs"
|
|
)
|
|
|
|
dz = DangerzoneGui(mock_app, dummy)
|
|
widget = WaitingWidgetContainer(dz)
|
|
qtbot.addWidget(widget)
|
|
|
|
# Assert that the error is displayed in the GUI
|
|
if platform.system() in ["Darwin", "Windows"]:
|
|
assert "Dangerzone requires Docker Desktop" in widget.label.text()
|
|
else:
|
|
assert "Podman is installed but cannot run properly" in widget.label.text()
|
|
|
|
assert "podman image ls logs" in widget.traceback.toPlainText()
|
|
|
|
|
|
def test_no_container_tech_exception(qtbot: QtBot, mocker: MockerFixture) -> None:
|
|
# Setup
|
|
mock_app = mocker.MagicMock()
|
|
dummy = mocker.MagicMock()
|
|
|
|
# Raise
|
|
dummy.is_available.side_effect = NoContainerTechException("podman")
|
|
|
|
dz = DangerzoneGui(mock_app, dummy)
|
|
widget = WaitingWidgetContainer(dz)
|
|
qtbot.addWidget(widget)
|
|
|
|
# Assert that the error is displayed in the GUI
|
|
if platform.system() in ["Darwin", "Windows"]:
|
|
assert "Dangerzone requires Docker Desktop" in widget.label.text()
|
|
else:
|
|
assert "Dangerzone requires Podman" in widget.label.text()
|
|
|
|
|
|
def test_installation_failure_exception(qtbot: QtBot, mocker: MockerFixture) -> None:
|
|
"""Ensures that if an exception is raised during image installation,
|
|
it is shown in the GUI.
|
|
"""
|
|
# Setup install to raise an exception
|
|
mock_app = mocker.MagicMock()
|
|
dummy = mocker.MagicMock(spec=Container)
|
|
dummy.install.side_effect = RuntimeError("Error during install")
|
|
|
|
dz = DangerzoneGui(mock_app, dummy)
|
|
|
|
# Mock the InstallContainerThread to call the original run method instead of
|
|
# starting a new thread
|
|
mocker.patch.object(InstallContainerThread, "start", InstallContainerThread.run)
|
|
widget = WaitingWidgetContainer(dz)
|
|
qtbot.addWidget(widget)
|
|
|
|
assert dummy.install.call_count == 1
|
|
|
|
assert "Error during install" in widget.traceback.toPlainText()
|
|
assert "RuntimeError" in widget.traceback.toPlainText()
|
|
|
|
|
|
def test_installation_failure_return_false(qtbot: QtBot, mocker: MockerFixture) -> None:
|
|
"""Ensures that if the installation returns False, the error is shown in the GUI."""
|
|
# Setup install to return False
|
|
mock_app = mocker.MagicMock()
|
|
dummy = mocker.MagicMock(spec=Container)
|
|
dummy.install.return_value = False
|
|
|
|
dz = DangerzoneGui(mock_app, dummy)
|
|
|
|
# Mock the InstallContainerThread to call the original run method instead of
|
|
# starting a new thread
|
|
mocker.patch.object(InstallContainerThread, "start", InstallContainerThread.run)
|
|
widget = WaitingWidgetContainer(dz)
|
|
qtbot.addWidget(widget)
|
|
|
|
assert dummy.install.call_count == 1
|
|
|
|
assert "the following error occured" in widget.label.text()
|
|
assert "The image cannot be found" in widget.traceback.toPlainText()
|