2024-05-01 17:59:11 -07:00
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
import pathlib
|
|
|
|
|
|
|
|
import _pytest.terminal
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
_pytest.terminal._color_for_type['incompatible'] = 'red'
|
|
|
|
_pytest.terminal._color_for_type['passable'] = 'yellow'
|
|
|
|
_pytest.terminal._color_for_type['compatible'] = 'green'
|
|
|
|
_pytest.terminal._color_for_type['exact'] = 'green'
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.hookimpl
|
|
|
|
def pytest_report_teststatus(report, config):
|
|
|
|
"""Customizes the reporting of test statuses."""
|
|
|
|
if report.when != 'call':
|
|
|
|
return None
|
|
|
|
|
|
|
|
if isinstance(report, pytest.CollectReport) or report.outcome in ('skipped'):
|
|
|
|
return None
|
|
|
|
|
|
|
|
props = dict(report.user_properties)
|
|
|
|
ahash = props.get('ahash:', -1)
|
|
|
|
dhash = props.get('dhash:', -1)
|
|
|
|
phash = props.get('phash:', -1)
|
2024-08-04 17:21:58 -07:00
|
|
|
report.wasxfail = f'reason: {ahash},{dhash},{phash}'
|
|
|
|
if ahash == dhash == phash == 0 or ahash == dhash == phash == -1:
|
2024-05-01 17:59:11 -07:00
|
|
|
if report.outcome == 'failed':
|
2024-08-04 17:21:58 -07:00
|
|
|
return 'failed', 'F', ('FAIL', {'red': True})
|
2024-05-01 17:59:11 -07:00
|
|
|
return 'exact', 'E', ('EXACT', {'green': True})
|
2024-08-04 17:21:58 -07:00
|
|
|
if (ahash <= 4 and dhash <= 4 and phash <= 4) and 0 in (ahash, dhash, phash):
|
2024-05-01 17:59:11 -07:00
|
|
|
return 'compatible', 'C', ('COMPATIBLE', {'green': True})
|
2024-08-04 17:21:58 -07:00
|
|
|
if ahash <= 8 and dhash <= 8 and phash <= 8:
|
|
|
|
return 'passable', 'P', ('PASSABLE', {'yellow': True})
|
|
|
|
|
|
|
|
return 'incompatible', 'I', ('INCOMPATIBLE', {'red': True})
|
2024-05-01 17:59:11 -07:00
|
|
|
|
|
|
|
|
|
|
|
def pytest_terminal_summary(terminalreporter, exitstatus, config):
|
|
|
|
incompatible = terminalreporter._get_reports_to_display('incompatible')
|
|
|
|
passable = terminalreporter._get_reports_to_display('passable')
|
|
|
|
compatible = terminalreporter._get_reports_to_display('compatible')
|
|
|
|
exact = terminalreporter._get_reports_to_display('exact')
|
|
|
|
total = len(incompatible) + len(passable) + len(compatible) + len(exact)
|
|
|
|
if total < 1:
|
|
|
|
return
|
|
|
|
incompatible_percent = int((len(incompatible)/total)*100)
|
|
|
|
passable_percent = int((len(passable)/total)*100)
|
|
|
|
compatible_percent = int((len(compatible)/total)*100)
|
|
|
|
exact_percent = int((len(exact)/total)*100)
|
|
|
|
final_percent = ((len(exact)+len(compatible))/total)*100
|
|
|
|
|
|
|
|
parts = (
|
|
|
|
(f'incompatible: {incompatible_percent:02d}%', {'red': True}),
|
|
|
|
(f'passable: {passable_percent:02d}%', {'yellow': True}),
|
|
|
|
(f'compatible: {compatible_percent:02d}%', {'green': True}),
|
|
|
|
(f'exact: {exact_percent:02d}%', {'green': True}),
|
|
|
|
(
|
|
|
|
f'final: {final_percent:02.2f}%', {
|
|
|
|
'green' if final_percent > 80 else 'red': True,
|
|
|
|
},
|
|
|
|
),
|
|
|
|
)
|
|
|
|
line_parts = []
|
|
|
|
for text, markup in parts:
|
|
|
|
with_markup = terminalreporter._tw.markup(text, **markup)
|
|
|
|
line_parts.append(with_markup)
|
|
|
|
msg = ', '.join(line_parts)
|
|
|
|
terminalreporter.write_line(msg)
|
|
|
|
|
|
|
|
|
|
|
|
def pytest_addoption(parser):
|
|
|
|
parser.addoption(
|
|
|
|
'--hasher', default='go run ./hashImage -file {}', help="The commandline image hasher to test ('go run ./hashImage -file {}')",
|
|
|
|
)
|
|
|
|
parser.addoption(
|
2024-08-04 17:21:58 -07:00
|
|
|
'--image-dir', nargs='+', default='_examples/images', help='The file path to a directory of images to test',
|
2024-05-01 17:59:11 -07:00
|
|
|
)
|
|
|
|
parser.addoption(
|
2024-08-04 17:21:58 -07:00
|
|
|
'--skip-invalid-image', action='store_true', help="skip images that can't be decoded",
|
2024-05-01 17:59:11 -07:00
|
|
|
)
|
2024-08-04 17:21:58 -07:00
|
|
|
parser.addoption(
|
|
|
|
'--recurse', action='store_true', help='recursively load images',
|
|
|
|
)
|
|
|
|
parser.addoption('--only-files', help='Only add files containing the specified string eg "--only-files thumb"')
|
|
|
|
|
|
|
|
|
|
|
|
def get_images(path: pathlib.Path, recurse: bool, /, limit: str = '') -> list[str]:
|
|
|
|
files = []
|
|
|
|
cwd = pathlib.Path('').absolute()
|
|
|
|
for p in pathlib.Path(path).iterdir():
|
|
|
|
if p.is_dir():
|
|
|
|
if recurse:
|
|
|
|
files.extend(get_images(p, recurse, limit=limit))
|
|
|
|
continue
|
|
|
|
if limit and limit not in str(p):
|
|
|
|
continue
|
|
|
|
p = p.absolute()
|
|
|
|
if p.is_relative_to(cwd):
|
|
|
|
files.append(str(p.relative_to(cwd)))
|
|
|
|
else:
|
|
|
|
files.append(str(p.absolute()))
|
|
|
|
return files
|
2024-05-01 17:59:11 -07:00
|
|
|
|
|
|
|
|
|
|
|
def pytest_generate_tests(metafunc):
|
|
|
|
if 'file' in metafunc.fixturenames:
|
|
|
|
file = metafunc.config.getoption('--image-dir')
|
|
|
|
files = []
|
2024-08-04 17:21:58 -07:00
|
|
|
limit = metafunc.config.getoption('--only-files')
|
|
|
|
for f in file:
|
|
|
|
files.extend(get_images(f, metafunc.config.getoption('--recurse'), limit=limit))
|
2024-05-01 17:59:11 -07:00
|
|
|
metafunc.parametrize('file', files)
|