Refactor exif related test suite

* Use more specific pytest markers that automagically skip the tests
* Split requirements into multiple files
* Make exif related fixtures available for the complete test suite
This commit is contained in:
karlch 2021-01-03 11:15:47 +01:00
parent 78d9cd7ffd
commit c661d40de3
12 changed files with 82 additions and 42 deletions

View File

@ -37,7 +37,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
toxenv: [pyqt513, pyqt514, pyqt515-cov, no_optionals, lint, packaging, mypy]
toxenv: [pyqt513, pyqt514, pyqt515-cov, piexif, noexif, lint, packaging, mypy]
fail-fast: false
steps:
- uses: actions/checkout@v2.3.4

View File

@ -0,0 +1 @@
piexif==1.1.3

View File

@ -1,11 +1,13 @@
[pytest]
testpaths = tests
addopts = --no-flaky-report
addopts = --no-flaky-report --strict-markers
faulthandler_timeout = 30
markers =
current: Mark tests during development
imageformats: Require retrieving images from the web to test additional formats
optional: Require optional dependencies
no_optional: Require optional dependencies to NOT be installed
exif: Require exif support
piexif: Require piexif
pyexiv2: Require pyexiv2
noexif: Requires exif support NOT to be available
ci: Run test only on ci
ci_skip: Skip test on ci

View File

@ -12,6 +12,8 @@ import urllib.request
import pytest
from vimiv.imutils import exif
CI = "CI" in os.environ
@ -20,25 +22,46 @@ PLATFORM_MARKERS = (
("ci", CI, "Only run on ci"),
("ci_skip", not CI, "Skipped on ci"),
)
EXIF_MARKERS = (
("exif", exif.has_exif_support, "Only run with exif support"),
("noexif", not exif.has_exif_support, "Only run without exif support"),
("pyexiv2", exif.pyexiv2 is not None, "Only run with pyexiv2"),
("piexif", exif.piexif is not None, "Only run with piexif"),
)
# fmt: on
def apply_platform_markers(item):
"""Apply markers that skip tests depending on the current platform."""
for marker_name, fulfilled, reason in PLATFORM_MARKERS:
apply_markers_helper(item, PLATFORM_MARKERS)
def apply_exif_markers(item):
"""Apply markers that skip tests depending on specific exif support."""
if os.path.basename(item.fspath) in ("test_exif.py",):
for marker_name in "exif", "pyexiv2", "piexif":
marker = getattr(pytest.mark, marker_name)
item.add_marker(marker)
apply_markers_helper(item, EXIF_MARKERS)
def apply_markers_helper(item, markers):
"""Helper function to apply an iterable of markers to a test item."""
for marker_name, fulfilled, reason in markers:
marker = item.get_closest_marker(marker_name)
if not marker or fulfilled:
continue
skipif = pytest.mark.skipif(
not fulfilled, *marker.args, reason=reason, **marker.kwargs
)
item.add_marker(skipif)
if marker is not None:
skipif = pytest.mark.skipif(
not fulfilled, *marker.args, reason=reason, **marker.kwargs
)
item.add_marker(skipif)
def pytest_collection_modifyitems(items):
"""Handle custom markers via pytest hook."""
for item in items:
apply_platform_markers(item)
apply_exif_markers(item)
@pytest.fixture
@ -140,3 +163,30 @@ def _retrieve_file_from_web(url: str, path: str) -> None:
def tmpdir():
"""Override tmpdir to raise a ValueError."""
raise ValueError("Use the 'tmp_path' fixture instead of 'tmpdir'")
@pytest.fixture()
def piexif(monkeypatch):
"""Pytest fixture to ensure only piexif is available."""
monkeypatch.setattr(exif, "pyexiv2", None)
@pytest.fixture()
def noexif(monkeypatch, piexif):
"""Pytest fixture to ensure no exif library is available."""
monkeypatch.setattr(exif, "piexif", None)
@pytest.fixture()
def add_exif_information():
"""Fixture to retrieve a helper function that adds exif content to an image."""
def add_exif_information_impl(path: str, content):
assert exif.piexif is not None, "piexif required to add exif information"
exif_dict = exif.piexif.load(path)
for ifd, ifd_dict in content.items():
for key, value in ifd_dict.items():
exif_dict[ifd][key] = value
exif.piexif.insert(exif.piexif.dump(exif_dict), path)
return add_exif_information_impl

View File

@ -33,14 +33,9 @@ def handler():
@bdd.when("I add exif information")
def add_exif_information(handler, exif_content):
def add_exif_information_bdd(add_exif_information, handler, exif_content):
assert piexif is not None, "piexif required to add exif information"
path = handler._path
exif_dict = piexif.load(path)
for ifd, ifd_dict in exif_content.items():
for key, value in ifd_dict.items():
exif_dict[ifd][key] = value
# Wait for thumbnail creation so we don't interfere with the current reading by
# adding more bytes
utils.Pool.wait(5000)
piexif.insert(piexif.dump(exif_dict), path)
add_exif_information(handler._path, exif_content)

View File

@ -1,4 +1,4 @@
@optional
@exif
Feature: Metadata widget displaying image exif information
Scenario: Show metadata widget

View File

@ -11,7 +11,7 @@ Feature: Write an image to disk
| new_path.png |
| new_path.tiff |
@optional
@exif
Scenario: Write image preserving exif information
Given I open any image
When I add exif information

View File

@ -1,6 +1,6 @@
@no_optional
Feature: Ensure the application works correctly without optional dependencies
@noexif
Scenario: No metadata command
Given I open any image
When I run metadata

View File

@ -17,18 +17,6 @@ def exif_handler(request):
yield request.param
@pytest.fixture()
def piexif(monkeypatch):
"""Pytest fixture to ensure only piexif is available."""
monkeypatch.setattr(exif, "pyexiv2", None)
@pytest.fixture()
def noexif(monkeypatch, piexif):
"""Pytest fixture to ensure no exif library is available."""
monkeypatch.setattr(exif, "piexif", None)
def test_check_exif_dependency():
default = None
assert exif.check_exif_dependancy(default) == default

View File

@ -26,7 +26,6 @@ def no_exif_support(monkeypatch):
monkeypatch.setattr(version, "piexif", None)
@pytest.mark.optional
def test_svg_support_info():
assert "svg support: true" in version.info().lower()
@ -35,7 +34,7 @@ def test_no_svg_support_info(no_svg_support):
assert "svg support: false" in version.info().lower()
@pytest.mark.optional
@pytest.mark.piexif
def test_exif_support_info():
assert piexif.VERSION in version.info()

18
tox.ini
View File

@ -1,5 +1,5 @@
[tox]
envlist = pyqt-cov,no_optionals,lint,packaging,mypy
envlist = pyqt-cov,piexif,noexif,lint,packaging,mypy
# Standard test suite using pytest
[testenv]
@ -9,7 +9,8 @@ passenv = PYTHONPATH CI USER HOME XDG_* DISPLAY
basepython = {env:PYTHON:python3}
deps =
-r{toxinidir}/misc/requirements/requirements_tests.txt
-r{toxinidir}/misc/requirements/requirements_optional.txt
-r{toxinidir}/misc/requirements/requirements_pyexiv2.txt
-r{toxinidir}/misc/requirements/requirements_piexif.txt
pyqt: -r{toxinidir}/misc/requirements/requirements.txt
pyqt59: PyQt5==5.9.2
pyqt510: PyQt5==5.10.1
@ -21,15 +22,20 @@ deps =
cov: -r{toxinidir}/misc/requirements/requirements_cov.txt
commands_pre = {envpython} scripts/maybe_build_cextension.py
commands = pytest -m "not no_optional" {posargs}
commands = pytest {posargs}
# Test suite without optional dependencies
[testenv:no_optionals]
# Test suite using piexif
[testenv:piexif]
deps =
-r{toxinidir}/misc/requirements/requirements.txt
-r{toxinidir}/misc/requirements/requirements_tests.txt
-r{toxinidir}/misc/requirements/requirements_piexif.txt
commands = pytest -m "not optional" {posargs}
# Test suite without optional dependencies
[testenv:noexif]
deps =
-r{toxinidir}/misc/requirements/requirements.txt
-r{toxinidir}/misc/requirements/requirements_tests.txt
# Linters and checkers for the source code
[testenv:lint]