Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions e2e_projects/my_lib/src/my_lib/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,7 @@ def divide(a: int, b: int):
),
)
raise Exception(f'Cannot divide if {b=} cannot be 0!!!')

def write_into_file(path: str):
with open(path, 'w') as file:
file.write("Hello")
10 changes: 10 additions & 0 deletions e2e_projects/my_lib/tests/test_my_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,13 @@ def test_private_class_classmethod():
def test_divide():
with pytest.raises(Exception, match='.*cannot be 0!!!'):
divide(1, 0)

def test_tmp_dir_switch(tmpdir):
"""Verify that mutmut works with the tmpdir fixture"""
# change to tmp directory
with tmpdir.as_cwd():
write_into_file("foo.txt")

with open("foo.txt", "r", encoding='utf-8') as file:
data = file.read()
assert "Hello" in data
4 changes: 2 additions & 2 deletions src/mutmut/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@
def record_trampoline_hit(name: str, caller: str | None = None) -> None:
assert not name.startswith("src."), "Failed trampoline hit. Module name starts with `src.`, which is invalid"

source_paths = [p.resolve(strict=True) for p in Config.get().source_paths]
mutated_source_paths = Config.get().resolved_mutated_source_paths

if Config.get().max_stack_depth != -1:
f = inspect.currentframe()
Expand All @@ -132,7 +132,7 @@ def record_trampoline_hit(name: str, caller: str | None = None) -> None:
if "pytest" in filename or "hammett" in filename or "unittest" in filename:
break
file_path = Path(filename).resolve(strict=True)
if any(path in file_path.parents for path in source_paths):
if any(path in file_path.parents for path in mutated_source_paths):
# only include stack frames of user-code; exclude mutmut and 3rd library stack frames
c -= 1

Expand Down
5 changes: 5 additions & 0 deletions src/mutmut/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ def _load_config() -> Config:
source_paths = [Path(path) for path in s("source_paths", [])]
source_paths = source_paths or paths_to_mutate or [Path(path) for path in _guess_source_paths()]

# We resolve at startup, s.t. we are still in the current working directory (and no tests modified the directory)
resolved_mutated_source_paths = [Path.cwd().resolve(strict=True) / "mutants" / p for p in source_paths]

tests_dir = s("tests_dir", [])
if tests_dir:
warnings.warn(
Expand Down Expand Up @@ -135,6 +138,7 @@ def _load_config() -> Config:
debug=s("debug", False),
mutate_only_covered_lines=s("mutate_only_covered_lines", False),
source_paths=source_paths,
resolved_mutated_source_paths=resolved_mutated_source_paths,
pytest_add_cli_args=s("pytest_add_cli_args", []),
pytest_add_cli_args_test_selection=pytest_add_cli_args_test_selection,
timeout_multiplier=s("timeout_multiplier", 15.0),
Expand Down Expand Up @@ -164,6 +168,7 @@ class Config:
max_stack_depth: int
debug: bool
source_paths: list[Path]
resolved_mutated_source_paths: list[Path]
pytest_add_cli_args: list[str]
pytest_add_cli_args_test_selection: list[str]
mutate_only_covered_lines: bool
Expand Down
10 changes: 10 additions & 0 deletions tests/e2e/test_e2e_my_lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,16 @@ def test_my_lib_result_snapshot():
"my_lib.xǁ_PrivateClassǁget_question__mutmut_3": 0,
"my_lib.xǁ_PrivateClassǁget_answer__mutmut_1": 0,
"my_lib.x_divide__mutmut_1": 1,
"my_lib.x_write_into_file__mutmut_1": 1,
"my_lib.x_write_into_file__mutmut_2": 1,
"my_lib.x_write_into_file__mutmut_3": 1,
"my_lib.x_write_into_file__mutmut_4": 1,
"my_lib.x_write_into_file__mutmut_5": 1,
"my_lib.x_write_into_file__mutmut_6": 1,
"my_lib.x_write_into_file__mutmut_7": 1,
"my_lib.x_write_into_file__mutmut_8": 0,
"my_lib.x_write_into_file__mutmut_9": 1,
"my_lib.x_write_into_file__mutmut_10": 1,
}
}
)
3 changes: 3 additions & 0 deletions tests/mutation/test_mutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -1226,6 +1226,7 @@ def test_record_trampoline_hit_records_caller(monkeypatch):
cfg = Mock(spec=Config)
cfg.max_stack_depth = -1
cfg.source_paths = []
cfg.resolved_mutated_source_paths = []
cfg.track_dependencies = True
monkeypatch.setattr(Config, "get", lambda: cfg)

Expand All @@ -1244,6 +1245,7 @@ def test_record_trampoline_hit_skips_caller_when_disabled(monkeypatch):
cfg = Mock(spec=Config)
cfg.max_stack_depth = -1
cfg.source_paths = []
cfg.resolved_mutated_source_paths = []
cfg.track_dependencies = False
monkeypatch.setattr(Config, "get", lambda: cfg)

Expand Down Expand Up @@ -1318,6 +1320,7 @@ def _config_for_invalidation(**overrides):
max_stack_depth=-1,
debug=False,
source_paths=[pathlib.Path("src")],
resolved_mutated_source_paths=[(pathlib.Path("mutants") / "src").absolute()],
pytest_add_cli_args=[],
pytest_add_cli_args_test_selection=[],
mutate_only_covered_lines=False,
Expand Down
1 change: 1 addition & 0 deletions tests/test_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def _get_config(only_mutate: list[str], do_not_mutate: list[str]) -> Config:
max_stack_depth=-1,
debug=False,
source_paths=[],
resolved_mutated_source_paths=[],
pytest_add_cli_args=[],
pytest_add_cli_args_test_selection=[],
mutate_only_covered_lines=False,
Expand Down
Loading