Skip to content

Commit

Permalink
Replace scripts/test_klippy.py with py.test
Browse files Browse the repository at this point in the history
  • Loading branch information
kageurufu committed Dec 22, 2024
1 parent 23be61f commit c8b686a
Show file tree
Hide file tree
Showing 7 changed files with 314 additions and 9 deletions.
7 changes: 7 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,12 @@ ignore = [

[tool.uv]
dev-dependencies = [
"pytest-xdist>=3.6.1",
"pytest>=8.3.4",
"ruff>=0.8.4",
]

[tool.pytest.ini_options]
testpaths = [
'test',
]
11 changes: 3 additions & 8 deletions scripts/ci-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,6 @@ fi
# Verify klippy host software
######################################################################

start_test klippy "Test klippy import (Python3)"
# I'm leaving this with klippy/klippy.py so we test that compatibility
$PYTHON klippy/klippy.py --import-test
finish_test klippy "Test klippy import (Python3)"

start_test klippy "Test invoke klippy (Python3)"
$PYTHON scripts/test_klippy.py -d ${DICTDIR} test/klippy/*.test
finish_test klippy "Test invoke klippy (Python3)"
start_test klippy "py.test suite"
py.test --dictdir "${DICTDIR}"
finish_test klippy "py.test suite"
9 changes: 9 additions & 0 deletions scripts/requirements_dev.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
# This file was autogenerated by uv via the following command:
# uv export -o scripts/requirements_dev.txt --only-dev --no-hashes
colorama==0.4.6 ; sys_platform == 'win32'
exceptiongroup==1.2.2 ; python_full_version < '3.11'
execnet==2.1.1
iniconfig==2.0.0
packaging==24.2
pluggy==1.5.0
pytest==8.3.4
pytest-xdist==3.6.1
ruff==0.8.4
tomli==2.2.1 ; python_full_version < '3.11'
157 changes: 157 additions & 0 deletions test/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
from __future__ import annotations

import pytest
import pathlib
import subprocess
import sys
import tempfile
import shutil


@pytest.fixture(autouse=True)
def _ensure_klippy_imports():
root = pathlib.Path().parent.parent.parent
if str(root) not in sys.path:
sys.path.insert(0, str(root))


def pytest_addoption(parser):
parser.addoption("--dictdir", action="store", default="dict")


def pytest_collect_file(parent, file_path):
if file_path.suffix == ".test":
return KlippyTest.from_parent(parent, path=file_path)


class KlippyTest(pytest.File):
def relative_path(self, *parts, root=None):
if not root:
root = self.path.parent
return root.joinpath(*parts).resolve().relative_to(self.path.cwd())

def collect(self):
dict_path = pathlib.Path.cwd() / self.config.getoption("dictdir")

with self.path.open("r", encoding="utf-8") as test_file:
multi_test = False
should_fail = False
gcode = []
config_file = None
dictionaries = []

for line in test_file:
parts = line.strip().split()

if not parts or line.strip().startswith("#"):
continue

elif parts[0] == "SHOULD_FAIL":
should_fail = True

elif parts[0] == "GCODE":
with self.relative_path(parts[1]).open(
"r", encoding="utf-8"
) as fp:
gcode = fp.readlines()

elif parts[0] == "DICTIONARY":
dictionaries = [
str(self.relative_path(parts[1], root=dict_path))
]
for mcu_path in parts[2:]:
mcu, fname = mcu_path.split("=", maxsplit=1)
dictionaries.append(
f"{mcu}={self.relative_path(fname, root=dict_path)}"
)

elif parts[0] == "CONFIG":
if config_file and not multi_test:
multi_test = True
yield KlippyTestItem.from_parent(
self,
name=str(config_file),
gcode=gcode,
config_file=config_file,
dictionaries=list(dictionaries),
should_fail=should_fail,
)

config_file = self.relative_path(parts[1])

if multi_test:
yield KlippyTestItem.from_parent(
self,
name=str(config_file),
gcode=gcode,
config_file=config_file,
dictionaries=list(dictionaries),
should_fail=should_fail,
)

else:
gcode.append(line.strip())

if not multi_test:
yield KlippyTestItem.from_parent(
self,
name=str(config_file),
gcode=gcode,
config_file=config_file,
dictionaries=list(dictionaries),
should_fail=should_fail,
)


class KlippyTestItem(pytest.Item):
def __init__(
self,
*,
config_file: pathlib.Path,
dictionaries: list[str],
gcode: list[str],
should_fail: bool = False,
**kwargs,
):
super().__init__(**kwargs)

self.config_file = config_file
self.dictionaries = dictionaries
self.gcode = gcode

if should_fail:
self.add_marker(pytest.mark.xfail)

def setup(self):
self.tmp_dir = pathlib.Path(tempfile.mkdtemp())

def teardown(self):
shutil.rmtree(self.tmp_dir, ignore_errors=True)

def runtest(self):
gcode_file = self.tmp_dir.joinpath("_test_.gcode")
output_file = self.tmp_dir.joinpath("_test_.output")

gcode_file.write_text("\n".join(self.gcode))

args = [sys.executable, "-m", "klippy", str(self.config_file)]
args.extend(["-i", str(gcode_file)])
args.extend(["-o", str(output_file)])
args.extend(["-v"])

for df in self.dictionaries:
args.extend(["-d", df])

subprocess.run(args, check=True, text=True, stderr=subprocess.STDOUT)

def repr_failure(self, excinfo, style=None):
if isinstance(excinfo.value, subprocess.CalledProcessError):
return "\n".join(
[
f"Error in {self.name}",
f" Config File: {self.config_file}",
f" Dictionaries: {', '.join(self.dictionaries)}",
]
)

return super().repr_failure(excinfo=excinfo, style=style)
Empty file added test/klippy/conftest.py
Empty file.
8 changes: 8 additions & 0 deletions test/test_imports.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import pytest


def test_import_extra():
from klippy import import_test

with pytest.raises(SystemExit):
import_test()
Loading

0 comments on commit c8b686a

Please sign in to comment.