Skip to content

Commit

Permalink
Test settings button
Browse files Browse the repository at this point in the history
  • Loading branch information
gselzer committed Sep 8, 2022
1 parent 65f4133 commit 3a5a5c1
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 22 deletions.
12 changes: 9 additions & 3 deletions src/napari_imagej/widgets/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ def __init__(self, viewer: Viewer):

self.clicked.connect(self._update_settings)
self.setting_change.connect(self._notify_settings_change)
self.setting_change.connect(self._write_settings)

def _update_settings(self):
args = {}
Expand All @@ -319,9 +320,6 @@ def _update_settings(self):

if any_changed:
self.setting_change.emit()
output = settings.dump()
with open(settings.user_config_path(), "w") as f:
f.write(output)

def _notify_settings_change(self):
"""
Expand All @@ -333,3 +331,11 @@ def _notify_settings_change(self):
"Please restart napari for napari-imagej settings changes to take effect!"
)
msg.exec()

def _write_settings(self):
"""
Writes settings to a local configuration YAML file
"""
output = settings.dump()
with open(settings.user_config_path(), "w") as f:
f.write(output)
4 changes: 4 additions & 0 deletions tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ def DoubleArray(self):
def EuclideanSpace(self):
return "net.imglib2.EuclideanSpace"

@JavaClasses.blocking_import
def ImageDisplay(self):
return "net.imagej.display.ImageDisplay"

@JavaClasses.blocking_import
def ItemIO(self):
return "org.scijava.ItemIO"
Expand Down
126 changes: 107 additions & 19 deletions tests/widgets/test_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
"""
import numpy
import pytest
import yaml
from napari import Viewer
from napari.layers import Image, Layer
from napari.viewer import current_viewer
from qtpy.QtCore import QRunnable, Qt, QThreadPool
from qtpy.QtGui import QPixmap
from qtpy.QtWidgets import QApplication, QHBoxLayout, QMessageBox

from napari_imagej.java import JavaClasses, running_headless
from napari_imagej import settings
from napari_imagej.java import running_headless
from napari_imagej.widgets import menu
from napari_imagej.widgets.menu import (
FromIJButton,
Expand All @@ -20,23 +22,7 @@
ToIJButton,
)
from napari_imagej.widgets.resources import resource_path


class JavaClassesTest(JavaClasses):
"""
Here we override JavaClasses to get extra test imports
"""

@JavaClasses.blocking_import
def ArrayImgs(self):
return "net.imglib2.img.array.ArrayImgs"

@JavaClasses.blocking_import
def ImageDisplay(self):
return "net.imagej.display.ImageDisplay"


jc = JavaClassesTest()
from tests.utils import jc


@pytest.fixture(autouse=True)
Expand All @@ -46,10 +32,14 @@ def napari_mocker(viewer: Viewer):
# REQUEST_VALUES MOCK
oldfunc = menu.request_values

def newfunc(values=(), title="", **kwargs):
def newfunc(values={}, title="", **kwargs):
values.update(kwargs)
results = {}
# Solve each parameter
for name, options in kwargs.items():
if "value" in options:
results[name] = options["value"]
continue
if "choices" in options["options"]:
if options["annotation"] == Layer:
results[name] = viewer.layers[0]
Expand All @@ -70,6 +60,19 @@ def newfunc(values=(), title="", **kwargs):
menu.request_values = oldfunc


@pytest.fixture(autouse=True)
def settings_wrapper():
# Obtain prior user settings
with open(settings.user_config_path(), "r") as f:
existing_settings = f.read()

yield

# Restore prior user settings
with open(settings.user_config_path(), "w") as f:
f.write(existing_settings)


@pytest.fixture(autouse=True)
def clean_layers_and_Displays(asserter, ij, viewer: Viewer):
"""Fixture to remove image data from napari and ImageJ2"""
Expand Down Expand Up @@ -144,6 +147,7 @@ def test_GUIButton_layout_headful(qtbot, asserter, ij, gui_widget: NapariImageJM
)
def test_GUIButton_layout_headless(asserter, gui_widget: NapariImageJMenu):
"""Tests headless-specific settings of GUIButton"""
# Wait until the JVM starts to test settings
button: GUIButton = gui_widget.gui_button

expected: QPixmap = QPixmap(resource_path("imagej2-16x16-flat-disabled"))
Expand Down Expand Up @@ -281,3 +285,87 @@ def test_data_choosers(asserter, qtbot, ij, gui_widget_chooser):

# Assert that the data is now in napari
asserter(lambda: 2 == len(button_to.viewer.layers))


def test_settings_no_change(gui_widget: NapariImageJMenu):
"""Ensure that no changes are made when there is no change from the defaults"""
button: SettingsButton = gui_widget.settings_button

# First record the old settings
old_yaml = [(k, v.get()) for k, v in settings.items()]

# Then update the settings, but select all defaults
button._update_settings()
# Then record the new settings and compare
new_yaml = [(k, v.get()) for k, v in settings.items()]
assert new_yaml == old_yaml


def test_settings_change(asserter, gui_widget: NapariImageJMenu):
"""Change imagej_directory_or_endpoint and ensure that the settings change"""
button: SettingsButton = gui_widget.settings_button

# REQUEST_VALUES MOCK
oldfunc = menu.request_values

key = "imagej_directory_or_endpoint"
old_value = settings[key]
new_value = "foo"

assert old_value != new_value

def newfunc(values={}, title="", **kwargs):
results = {}
# Solve each parameter
for name, options in values.items():
if name == "imagej_directory_or_endpoint":
results[name] = new_value
continue
elif "value" in options:
results[name] = options["value"]
continue

# Otherwise, we don't know how to solve that parameter
raise NotImplementedError()
return results

menu.request_values = newfunc

# # Start the handler in a new thread
class Handler(QRunnable):

# Test popup when running headlessly
def run(self) -> None:
asserter(lambda: isinstance(QApplication.activeWindow(), QMessageBox))
msg = QApplication.activeWindow()
expected_text = (
"Please restart napari for napari-imagej settings "
"changes to take effect!"
)
if expected_text != msg.text():
self._passed = False
return
ok_button = msg.button(QMessageBox.Ok)
ok_button.clicked.emit()
asserter(lambda: QApplication.activeModalWidget() is not msg)
self._passed = True

def passed(self) -> bool:
return self._passed

runnable = Handler()
QThreadPool.globalInstance().start(runnable)

# Trigger the button
button._update_settings()

# Wait for the popup to be handled
asserter(QThreadPool.globalInstance().waitForDone)
assert runnable.passed()

menu.request_values = oldfunc

# Assert a change in the settings
assert settings[key].get() == new_value
with open(settings.user_config_path(), "r") as stream:
assert yaml.safe_load(stream)[key] == new_value

0 comments on commit 3a5a5c1

Please sign in to comment.