diff --git a/meshchatx.rsm b/meshchatx.rsm index 5b0847f0..6d932af4 100644 Binary files a/meshchatx.rsm and b/meshchatx.rsm differ diff --git a/pyproject.toml b/pyproject.toml index f1e0835b..69863c4e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -129,9 +129,31 @@ parallel = true [tool.mutmut] paths_to_mutate = ["meshchatx/src/backend/"] +# mutmut copies only paths_to_mutate into mutants/, then pytest runs from that +# directory. meshchatx/ then shadows the installed package as a namespace +# package, so these non-backend modules must be copied too. +also_copy = [ + "meshchatx/__init__.py", + "meshchatx/android_codec2.py", + "meshchatx/android_push_bridge.py", + "meshchatx/meshchat.py", + "meshchatx/pycodec2_ctypes.py", + "meshchatx/repository_http_standalone.py", + "meshchatx/src/__init__.py", + "meshchatx/src/build_meta.py", + "meshchatx/src/env_utils.py", + "meshchatx/src/path_utils.py", + "meshchatx/src/ssl_self_signed.py", + "meshchatx/src/version.py", +] +pytest_add_cli_args = [ + "-m", + "not integration and not long_running and not eect and not lxst_real and not live_validation", +] pytest_add_cli_args_test_selection = [ "tests/backend/", "--ignore=tests/backend/test_performance_hotpaths.py", "--ignore=tests/backend/test_memory_profiling.py", "--ignore=tests/backend/test_performance_bottlenecks.py", + "--ignore=tests/backend/eect", ] diff --git a/tests/backend/test_mutmut_also_copy.py b/tests/backend/test_mutmut_also_copy.py new file mode 100644 index 00000000..270fc54a --- /dev/null +++ b/tests/backend/test_mutmut_also_copy.py @@ -0,0 +1,47 @@ +# SPDX-License-Identifier: 0BSD + +"""mutmut mutants/ must include meshchatx modules outside src/backend.""" + +from __future__ import annotations + +import tomllib +from pathlib import Path + + +def _root() -> Path: + return Path(__file__).resolve().parents[2] + + +def _mutmut_config() -> dict: + data = tomllib.loads((_root() / "pyproject.toml").read_text(encoding="utf-8")) + return data["tool"]["mutmut"] + + +def _also_copy_covers(rel: Path, also_copy: list[str]) -> bool: + rel_s = rel.as_posix() + for item in also_copy: + normalized = item.rstrip("/") + if rel_s == item or rel_s == normalized: + return True + if rel_s.startswith(normalized + "/"): + return True + return False + + +def test_mutmut_also_copy_covers_package_modules_outside_backend(): + also_copy = list(_mutmut_config().get("also_copy", [])) + root = _root() + required = sorted( + path + for path in ( + list((root / "meshchatx").glob("*.py")) + + list((root / "meshchatx" / "src").glob("*.py")) + ) + if path.name != "_build_meta_baked.py" + ) + missing = [ + path.relative_to(root).as_posix() + for path in required + if not _also_copy_covers(path.relative_to(root), also_copy) + ] + assert missing == []