127 lines
3.9 KiB
Python
127 lines
3.9 KiB
Python
from pathlib import Path
|
|
from types import SimpleNamespace
|
|
|
|
from PyQt6.QtCore import QSettings
|
|
from PyQt6.QtWidgets import (
|
|
QApplication,
|
|
QWidget,
|
|
)
|
|
import pyqtgraph as pg
|
|
import pytest
|
|
from pytestqt.qtbot import QtBot
|
|
|
|
from piker import config
|
|
|
|
|
|
@pytest.fixture(scope='module')
|
|
def module_qapp(
|
|
qapp: QApplication,
|
|
|
|
) -> QApplication:
|
|
'''
|
|
Pin pytest-qt's session application for this test module.
|
|
|
|
'''
|
|
return qapp
|
|
|
|
|
|
def test_ui_state_is_process_isolated_and_restored(
|
|
isolated_ui_state: SimpleNamespace,
|
|
module_qapp: QApplication,
|
|
pytestconfig: pytest.Config,
|
|
qtbot: QtBot,
|
|
|
|
) -> None:
|
|
'''
|
|
Prove imports and one UI test cannot reach user config state.
|
|
|
|
Previously `qapp_args` assigned `XDG_CONFIG_HOME` only after
|
|
Piker was imported, so `piker.config` cached real user paths
|
|
before Qt setup. This test verifies every cached path starts
|
|
below the process-owned temporary XDG root, then redirects those
|
|
globals and writes both a file and `QSettings` key. The fixture's
|
|
exact-state teardown proves those mutations disappear while its
|
|
process sentinels survive for the next test.
|
|
|
|
'''
|
|
state: SimpleNamespace = isolated_ui_state
|
|
assert module_qapp is state.qapp
|
|
assert QApplication.instance() is state.qapp
|
|
if pytestconfig.getoption('headless'):
|
|
assert state.qapp.platformName() == 'offscreen'
|
|
assert config._click_config_dir.is_relative_to(
|
|
state.process_config_home,
|
|
)
|
|
assert config._config_dir.is_relative_to(
|
|
state.process_config_home,
|
|
)
|
|
assert config._watchlists_data_path.is_relative_to(
|
|
state.process_config_home,
|
|
)
|
|
|
|
widget: QWidget = QWidget()
|
|
qtbot.addWidget(widget)
|
|
widget.show()
|
|
|
|
owned_dir: Path = state.test_config_dir
|
|
config._click_config_dir = owned_dir
|
|
config._config_dir = owned_dir
|
|
config._watchlists_data_path = owned_dir / 'watchlists.json'
|
|
(owned_dir / 'owned').write_text('remove-me', encoding='utf-8')
|
|
|
|
settings: QSettings = QSettings('pikers', 'piker')
|
|
settings.setFallbacksEnabled(False)
|
|
settings_path: Path = Path(settings.fileName())
|
|
assert settings_path.is_relative_to(state.process_config_home)
|
|
assert settings.value(state.preexisting_setting) == 'keep-me'
|
|
settings.setValue(state.owned_setting, 'remove-me')
|
|
settings.sync()
|
|
|
|
|
|
def test_ui_state_reuses_qapp_without_previous_test_leaks(
|
|
isolated_ui_state: SimpleNamespace,
|
|
module_qapp: QApplication,
|
|
qtbot: QtBot,
|
|
|
|
) -> None:
|
|
'''
|
|
Prove repeated tests reuse Qt without inheriting mutable state.
|
|
|
|
A session `QApplication` can retain widgets, settings and
|
|
PyQtGraph's `ViewBox.AllViews` entries from an earlier test. This
|
|
test runs after the mutation case, verifies the same application
|
|
and preserved process sentinel but no test-owned key, then
|
|
creates a real named `PlotWidget` and mutates Qt/PyQtGraph
|
|
options. Normal pytest-qt widget closure plus the isolation
|
|
fixture's registry assertions prove the second test also leaves
|
|
no state behind.
|
|
|
|
'''
|
|
state: SimpleNamespace = isolated_ui_state
|
|
assert module_qapp is state.qapp
|
|
assert QApplication.instance() is state.qapp
|
|
|
|
settings: QSettings = QSettings('pikers', 'piker')
|
|
settings.setFallbacksEnabled(False)
|
|
assert settings.value(state.preexisting_setting) == 'keep-me'
|
|
assert not settings.contains(state.owned_setting)
|
|
assert state.preexisting_config.read_text(
|
|
encoding='utf-8',
|
|
) == 'keep-me'
|
|
assert list(state.test_config_dir.iterdir()) == []
|
|
|
|
plot: pg.PlotWidget = pg.PlotWidget(name='pytest-owned-view')
|
|
qtbot.addWidget(plot)
|
|
plot.show()
|
|
assert pg.ViewBox.NamedViews['pytest-owned-view'] is (
|
|
plot.plotItem.vb
|
|
)
|
|
|
|
pg.setConfigOption(
|
|
'antialias',
|
|
not pg.getConfigOption('antialias'),
|
|
)
|
|
state.qapp.setQuitOnLastWindowClosed(
|
|
not state.qapp.quitOnLastWindowClosed(),
|
|
)
|