Skip to content

Commit 59754ba

Browse files
committed
more comprehensive tests of main
1 parent 8fc107d commit 59754ba

File tree

2 files changed

+140
-29
lines changed

2 files changed

+140
-29
lines changed

src/rattlesnake/cicd/report_pytest.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,12 @@ def get_coverage_metric(coverage_file: Path) -> CoverageMetric:
5555
root = tree.getroot()
5656
lines_valid = int(root.attrib["lines-valid"])
5757
lines_covered = int(root.attrib["lines-covered"])
58-
_coverage = (
59-
float(root.attrib["line-rate"]) * 100
60-
) # not used because we calculate it ourselves
6158
cm = CoverageMetric(
6259
lines_valid=lines_valid,
6360
lines_covered=lines_covered,
6461
) # overwrite default
65-
except:
66-
print("No valid attributes found.")
62+
except (FileNotFoundError, ET.ParseError, KeyError) as e:
63+
print(f"Error processing coverage file: {e}")
6764

6865
return cm
6966

tests/test_report_pytest.py

Lines changed: 138 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
pytest --cov=src/rattlesnake --cov-report=html --cov-report=xml --cov-report=term-misssing
99
"""
1010

11-
import types
1211
from pathlib import Path
12+
import types
1313
from typing import Final
1414

1515
import pytest
@@ -18,6 +18,7 @@
1818
CoverageMetric,
1919
get_coverage_metric,
2020
get_report_html,
21+
main,
2122
run_pytest_report,
2223
)
2324

@@ -71,11 +72,47 @@ def test_get_coverage_metrics_bad_attributes():
7172
assert result.coverage == 0.0
7273

7374

75+
def test_get_coverage_metric_file_not_found():
76+
"""Tests that get_coverage_metric handles a non-existent file."""
77+
fin = Path("non_existent_file.xml")
78+
result = get_coverage_metric(fin)
79+
expected = CoverageMetric(lines_valid=0, lines_covered=0)
80+
assert result.lines_valid == expected.lines_valid
81+
assert result.lines_covered == expected.lines_covered
82+
assert result.coverage == expected.coverage
83+
84+
85+
def test_get_report_html():
86+
"""Test get_report_html with minimal valid inputs.
87+
88+
Ensures generated HTML includes expected static and dynamic content
89+
like report title, coverage, and summary.
90+
"""
91+
coverage_metric = CoverageMetric(lines_valid=200, lines_covered=150)
92+
report = get_report_html(
93+
coverage_metric=coverage_metric,
94+
timestamp="20250815_211112_UTC",
95+
run_id="123",
96+
ref_name="main",
97+
github_sha="abc123def456",
98+
github_repo="testuser/testrepo",
99+
)
100+
101+
assert "<!DOCTYPE html>" in report
102+
assert "Pytest Report" in report
103+
assert "Coverage: 75.00%" in report
104+
assert "<strong>Lines Covered:</strong> 150" in report
105+
assert "<strong>Total Lines:</strong> 200" in report
106+
assert 'href="https://github.com/testuser/testrepo/actions/runs/123"' in report
107+
assert 'href="https://github.com/testuser/testrepo/tree/main"' in report
108+
assert 'href="https://github.com/testuser/testrepo/commit/abc123def456"' in report
109+
110+
74111
def test_run_pytest_report():
75112
"""Tests the main report creation."""
76113

77114
function_debug: Final[bool] = (
78-
True # set to True to avoid deleting the temporary output file
115+
False # set to True to avoid deleting the temporary output file
79116
)
80117

81118
fin = Path(__file__).parent / "files" / "coverage_output_20250807_241800_UTC.xml"
@@ -124,25 +161,102 @@ def test_run_pytest_report():
124161
print(f"Retained output file: {fout}")
125162

126163

127-
# def test_main_success(monkeypatch, capsys):
128-
# """Test the main function for a successful run."""
129-
# mock_args = types.SimpleNamespace(
130-
# input_file="dummy_input.tx",
131-
# output_file="dummy_output.html",
132-
# timestamp="20250818_123456_UTC",
133-
# run_id="123",
134-
# ref_name="main",
135-
# github_sha="abc",
136-
# github_repo="user/repo",
137-
# )
138-
139-
# monkeypatch.setattr("argparse.ArgumentParser.parse_args", lambda self: mock_args)
140-
# monkeypatch.setattr(
141-
# "rattlesnake.cicd.report_pytest.run_pytest_report",
142-
# lambda *args, **kwargs: CoverageMetric(100, 80),
143-
# )
144-
145-
# breakpoint()
146-
# main()
147-
# captured = capsys.readouterr()
148-
# assert "Coverage report generated successfully" in captured.out
164+
def test_main_success(monkeypatch, capsys):
165+
"""Test the main function for a successful run."""
166+
mock_args = types.SimpleNamespace(
167+
input_file="dummy_input.xml",
168+
output_file="dummy_output.html",
169+
timestamp="20240101_120000_UTC",
170+
run_id="123",
171+
ref_name="main",
172+
github_sha="abc",
173+
github_repo="owner/repo",
174+
)
175+
176+
monkeypatch.setattr("argparse.ArgumentParser.parse_args", lambda self: mock_args)
177+
monkeypatch.setattr(
178+
"rattlesnake.cicd.report_pytest.run_pytest_report",
179+
lambda *args, **kwargs: CoverageMetric(lines_valid=100, lines_covered=85),
180+
)
181+
182+
main()
183+
captured = capsys.readouterr()
184+
assert "✅ Pytest HTML report generated: dummy_output.html" in captured.out
185+
assert "📊 - valid lines of code: 100" in captured.out
186+
assert "🔍 - lines covered: 85" in captured.out
187+
assert "🎉 - coverage: 85.0" in captured.out
188+
189+
190+
def test_main_file_not_found(monkeypatch, capsys):
191+
"""Test the main function when the input file is not found."""
192+
mock_args = types.SimpleNamespace(
193+
input_file="non_existent.xml",
194+
output_file="dummy_output.html",
195+
timestamp="20240101_120000_UTC",
196+
run_id="123",
197+
ref_name="main",
198+
github_sha="abc",
199+
github_repo="owner/repo",
200+
)
201+
202+
monkeypatch.setattr("argparse.ArgumentParser.parse_args", lambda self: mock_args)
203+
monkeypatch.setattr(
204+
"rattlesnake.cicd.report_pytest.run_pytest_report",
205+
lambda *args, **kwargs: exec('raise FileNotFoundError("File not found")'),
206+
)
207+
208+
exit_code = main()
209+
assert exit_code == 1
210+
211+
captured = capsys.readouterr()
212+
assert "❌ Error: The input file 'non_existent.xml' was not found." in captured.out
213+
214+
215+
def test_main_io_error(monkeypatch, capsys):
216+
"""Test the main function when an IOError occurs."""
217+
mock_args = types.SimpleNamespace(
218+
input_file="dummy_input.xml",
219+
output_file="dummy_output.html",
220+
timestamp="20240101_120000_UTC",
221+
run_id="123",
222+
ref_name="main",
223+
github_sha="abc",
224+
github_repo="owner/repo",
225+
)
226+
227+
monkeypatch.setattr("argparse.ArgumentParser.parse_args", lambda self: mock_args)
228+
monkeypatch.setattr(
229+
"rattlesnake.cicd.report_pytest.run_pytest_report",
230+
lambda *args, **kwargs: exec('raise IOError("Permission denied")'),
231+
)
232+
233+
exit_code = main()
234+
assert exit_code == 1
235+
236+
captured = capsys.readouterr()
237+
assert "❌ I/O error occurred: Permission denied" in captured.out
238+
239+
240+
def test_main_unexpected_error(monkeypatch, capsys):
241+
"""Test the main function for an unexpected error."""
242+
mock_args = types.SimpleNamespace(
243+
input_file="dummy_input.xml",
244+
output_file="dummy_output.html",
245+
timestamp="20240101_120000_UTC",
246+
run_id="123",
247+
ref_name="main",
248+
github_sha="abc",
249+
github_repo="owner/repo",
250+
)
251+
252+
monkeypatch.setattr("argparse.ArgumentParser.parse_args", lambda self: mock_args)
253+
monkeypatch.setattr(
254+
"rattlesnake.cicd.report_pytest.run_pytest_report",
255+
lambda *args, **kwargs: exec('raise Exception("Something went wrong")'),
256+
)
257+
258+
exit_code = main()
259+
assert exit_code == 1
260+
261+
captured = capsys.readouterr()
262+
assert "❌ An unexpected error occurred: Something went wrong" in captured.out

0 commit comments

Comments
 (0)