|
5 | 5 | import sys |
6 | 6 | import xml.etree.ElementTree as ET |
7 | 7 | from pathlib import Path |
| 8 | +from textwrap import dedent |
8 | 9 |
|
9 | 10 | import pytest |
10 | 11 |
|
@@ -694,14 +695,78 @@ def test_summary_in_output_zero_lines(do_branch): |
694 | 695 |
|
695 | 696 |
|
696 | 697 | @pytest.mark.parametrize("json_flag", ["", "--json"]) |
697 | | -def test_fail_under(json_flag): |
| 698 | +def test_fail_under(tmp_path, json_flag): |
698 | 699 | p = subprocess.run(f"{sys.executable} -m slipcover {json_flag} --fail-under 100 tests/branch.py".split(), check=False) |
699 | 700 | assert 0 == p.returncode |
700 | 701 |
|
701 | | - p = subprocess.run(f"{sys.executable} -m slipcover {json_flag} --branch --fail-under 83 tests/branch.py".split(), check=False) |
| 702 | + p = subprocess.run(f"{sys.executable} -m slipcover {json_flag} --branch --fail-under 85 tests/branch.py".split(), check=False) |
702 | 703 | assert 0 == p.returncode |
703 | 704 |
|
704 | | - p = subprocess.run(f"{sys.executable} -m slipcover {json_flag} --branch --fail-under 84 tests/branch.py".split(), check=False) |
| 705 | + p = subprocess.run(f"{sys.executable} -m slipcover {json_flag} --branch --fail-under 86 tests/branch.py".split(), check=False) |
| 706 | + assert 2 == p.returncode |
| 707 | + |
| 708 | + p = subprocess.run(f"{sys.executable} -m slipcover --branch --fail-under 93 -m pytest tests/pyt.py".split(), check=False) |
| 709 | + assert 0 == p.returncode |
| 710 | + |
| 711 | + p = subprocess.run(f"{sys.executable} -m slipcover --branch --fail-under 94 -m pytest tests/pyt.py".split(), check=False) |
| 712 | + assert 2 == p.returncode |
| 713 | + |
| 714 | + |
| 715 | +def test_fail_under_precedence_with_nonzero_exit(tmp_path): |
| 716 | + """When the script/pytest run itself fails (nonzero SystemExit) AND |
| 717 | + coverage is below the fail-under threshold, coverage failure (RC 2) |
| 718 | + takes precedence. But when coverage is fine, the run's own nonzero |
| 719 | + exit code must be preserved, not silently replaced with 0. |
| 720 | + """ |
| 721 | + script = tmp_path / "script.py" |
| 722 | + script.write_text(dedent("""\ |
| 723 | + def foo(x): |
| 724 | + if x: |
| 725 | + return 1 |
| 726 | + return 2 |
| 727 | + foo(0) |
| 728 | + raise SystemExit(3) |
| 729 | + """)) |
| 730 | + |
| 731 | + # coverage is fine (line 3 "return 1" never runs, but threshold is low) -- |
| 732 | + # the script's own exit code (3) must be preserved |
| 733 | + p = subprocess.run(f"{sys.executable} -m slipcover --fail-under 1 {script}".split(), check=False) |
| 734 | + assert 3 == p.returncode |
| 735 | + |
| 736 | + # coverage is below threshold -- fail-under (2) must override the |
| 737 | + # script's own exit code |
| 738 | + p = subprocess.run(f"{sys.executable} -m slipcover --fail-under 100 {script}".split(), check=False) |
| 739 | + assert 2 == p.returncode |
| 740 | + |
| 741 | + |
| 742 | +def test_fail_under_precedence_with_failing_pytest_run(tmp_path): |
| 743 | + """Same precedence check as test_fail_under_precedence_with_nonzero_exit, |
| 744 | + but through the `-m pytest` path with a genuinely failing test (pytest's |
| 745 | + own SystemExit(1)), rather than a script raising SystemExit directly. |
| 746 | + """ |
| 747 | + test_file = tmp_path / "test_mod.py" |
| 748 | + test_file.write_text(dedent("""\ |
| 749 | + def foo(x): |
| 750 | + if x: |
| 751 | + return 1 |
| 752 | + return 2 |
| 753 | +
|
| 754 | + def test_fail(): |
| 755 | + assert foo(0) == 2 |
| 756 | + assert False |
| 757 | + """)) |
| 758 | + |
| 759 | + # coverage is fine -- pytest's own failure exit code (1) must be preserved |
| 760 | + p = subprocess.run( |
| 761 | + [sys.executable, '-m', 'slipcover', '--fail-under', '1', '-m', 'pytest', test_file.name], |
| 762 | + cwd=str(tmp_path), check=False) |
| 763 | + assert 1 == p.returncode |
| 764 | + |
| 765 | + # coverage is below threshold -- fail-under (2) must override pytest's |
| 766 | + # own exit code |
| 767 | + p = subprocess.run( |
| 768 | + [sys.executable, '-m', 'slipcover', '--fail-under', '100', '-m', 'pytest', test_file.name], |
| 769 | + cwd=str(tmp_path), check=False) |
705 | 770 | assert 2 == p.returncode |
706 | 771 |
|
707 | 772 |
|
|
0 commit comments