Skip to content

Commit f2079c2

Browse files
frenzymadnessclaude
andcommitted
Extract rpm_patches helper to reduce repetition in tests
The 18-line patch block for rpm constants was duplicated across every test method in both the unit and integration test files. Extract it into an rpm_patches(mock_ts) context manager and switch all call sites to use it. Use parentheses instead of backslashes to wrap the multi-patch block inside the helper (PEP 8 preferred style). Also fix the unit test module docstring which incorrectly said "actual RPM files" when it always uses mocks. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
1 parent 33a51d3 commit f2079c2

2 files changed

Lines changed: 62 additions & 199 deletions

File tree

tests/integration/test_rpm_checking.py

Lines changed: 30 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
Tests the complete workflow of checking RPM files for reverse dependency conflicts.
55
"""
66

7+
from contextlib import contextmanager
78
from unittest.mock import Mock, mock_open, patch
89
from fedora_revdep_check import FedoraRevDepChecker
910
from tests.fixtures.mock_packages import MockPackage, MockBase
@@ -32,6 +33,30 @@ def __getitem__(self, key):
3233
return self.data.get(key)
3334

3435

36+
@contextmanager
37+
def rpm_patches(mock_ts):
38+
"""Context manager providing all rpm module patches needed for tests."""
39+
with (patch('rpm.TransactionSet', return_value=mock_ts),
40+
patch('rpm._RPMVSF_NOSIGNATURES', 0),
41+
patch('rpm._RPMVSF_NODIGESTS', 0),
42+
patch('rpm.RPMTAG_NAME', 1000),
43+
patch('rpm.RPMTAG_VERSION', 1001),
44+
patch('rpm.RPMTAG_RELEASE', 1002),
45+
patch('rpm.RPMTAG_ARCH', 1022),
46+
patch('rpm.RPMTAG_EPOCH', 1003),
47+
patch('rpm.RPMTAG_SOURCERPM', 1044),
48+
patch('rpm.RPMTAG_SOURCEPACKAGE', 1106),
49+
patch('rpm.RPMTAG_PROVIDENAME', 1047),
50+
patch('rpm.RPMTAG_PROVIDEFLAGS', 1113),
51+
patch('rpm.RPMTAG_PROVIDEVERSION', 1048),
52+
patch('rpm.RPMSENSE_EQUAL', 8),
53+
patch('rpm.RPMSENSE_GREATER', 4),
54+
patch('rpm.RPMSENSE_LESS', 2),
55+
patch('os.path.exists', return_value=True),
56+
patch('builtins.open', mock_open())):
57+
yield
58+
59+
3560
class TestCheckRPMFiles:
3661
"""Test check_rpm_files() integration."""
3762

@@ -84,24 +109,7 @@ def test_check_rpm_files_no_conflicts(self):
84109
mock_ts = Mock()
85110
mock_ts.hdrFromFdno = Mock(return_value=mock_header)
86111

87-
with patch('rpm.TransactionSet', return_value=mock_ts), \
88-
patch('rpm._RPMVSF_NOSIGNATURES', 0), \
89-
patch('rpm._RPMVSF_NODIGESTS', 0), \
90-
patch('rpm.RPMTAG_NAME', 1000), \
91-
patch('rpm.RPMTAG_VERSION', 1001), \
92-
patch('rpm.RPMTAG_RELEASE', 1002), \
93-
patch('rpm.RPMTAG_ARCH', 1022), \
94-
patch('rpm.RPMTAG_EPOCH', 1003), \
95-
patch('rpm.RPMTAG_SOURCERPM', 1044), \
96-
patch('rpm.RPMTAG_SOURCEPACKAGE', 1106), \
97-
patch('rpm.RPMTAG_PROVIDENAME', 1047), \
98-
patch('rpm.RPMTAG_PROVIDEFLAGS', 1113), \
99-
patch('rpm.RPMTAG_PROVIDEVERSION', 1048), \
100-
patch('rpm.RPMSENSE_EQUAL', 8), \
101-
patch('rpm.RPMSENSE_GREATER', 4), \
102-
patch('rpm.RPMSENSE_LESS', 2), \
103-
patch('os.path.exists', return_value=True), \
104-
patch('builtins.open', mock_open()):
112+
with rpm_patches(mock_ts):
105113

106114
result = checker.check_rpm_files(['/tmp/pytest.rpm'])
107115

@@ -159,24 +167,7 @@ def test_check_rpm_files_with_conflicts(self):
159167
mock_ts = Mock()
160168
mock_ts.hdrFromFdno = Mock(return_value=mock_header)
161169

162-
with patch('rpm.TransactionSet', return_value=mock_ts), \
163-
patch('rpm._RPMVSF_NOSIGNATURES', 0), \
164-
patch('rpm._RPMVSF_NODIGESTS', 0), \
165-
patch('rpm.RPMTAG_NAME', 1000), \
166-
patch('rpm.RPMTAG_VERSION', 1001), \
167-
patch('rpm.RPMTAG_RELEASE', 1002), \
168-
patch('rpm.RPMTAG_ARCH', 1022), \
169-
patch('rpm.RPMTAG_EPOCH', 1003), \
170-
patch('rpm.RPMTAG_SOURCERPM', 1044), \
171-
patch('rpm.RPMTAG_SOURCEPACKAGE', 1106), \
172-
patch('rpm.RPMTAG_PROVIDENAME', 1047), \
173-
patch('rpm.RPMTAG_PROVIDEFLAGS', 1113), \
174-
patch('rpm.RPMTAG_PROVIDEVERSION', 1048), \
175-
patch('rpm.RPMSENSE_EQUAL', 8), \
176-
patch('rpm.RPMSENSE_GREATER', 4), \
177-
patch('rpm.RPMSENSE_LESS', 2), \
178-
patch('os.path.exists', return_value=True), \
179-
patch('builtins.open', mock_open()):
170+
with rpm_patches(mock_ts):
180171

181172
result = checker.check_rpm_files(['/tmp/jupyterlab.rpm'])
182173

@@ -240,24 +231,7 @@ def test_check_rpm_files_with_epoch(self):
240231
mock_ts = Mock()
241232
mock_ts.hdrFromFdno = Mock(return_value=mock_header)
242233

243-
with patch('rpm.TransactionSet', return_value=mock_ts), \
244-
patch('rpm._RPMVSF_NOSIGNATURES', 0), \
245-
patch('rpm._RPMVSF_NODIGESTS', 0), \
246-
patch('rpm.RPMTAG_NAME', 1000), \
247-
patch('rpm.RPMTAG_VERSION', 1001), \
248-
patch('rpm.RPMTAG_RELEASE', 1002), \
249-
patch('rpm.RPMTAG_ARCH', 1022), \
250-
patch('rpm.RPMTAG_EPOCH', 1003), \
251-
patch('rpm.RPMTAG_SOURCERPM', 1044), \
252-
patch('rpm.RPMTAG_SOURCEPACKAGE', 1106), \
253-
patch('rpm.RPMTAG_PROVIDENAME', 1047), \
254-
patch('rpm.RPMTAG_PROVIDEFLAGS', 1113), \
255-
patch('rpm.RPMTAG_PROVIDEVERSION', 1048), \
256-
patch('rpm.RPMSENSE_EQUAL', 8), \
257-
patch('rpm.RPMSENSE_GREATER', 4), \
258-
patch('rpm.RPMSENSE_LESS', 2), \
259-
patch('os.path.exists', return_value=True), \
260-
patch('builtins.open', mock_open()):
234+
with rpm_patches(mock_ts):
261235

262236
result = checker.check_rpm_files(['/tmp/sphinx.rpm'])
263237

@@ -313,24 +287,7 @@ def test_check_rpm_files_skips_same_srpm(self):
313287
mock_ts = Mock()
314288
mock_ts.hdrFromFdno = Mock(return_value=mock_header)
315289

316-
with patch('rpm.TransactionSet', return_value=mock_ts), \
317-
patch('rpm._RPMVSF_NOSIGNATURES', 0), \
318-
patch('rpm._RPMVSF_NODIGESTS', 0), \
319-
patch('rpm.RPMTAG_NAME', 1000), \
320-
patch('rpm.RPMTAG_VERSION', 1001), \
321-
patch('rpm.RPMTAG_RELEASE', 1002), \
322-
patch('rpm.RPMTAG_ARCH', 1022), \
323-
patch('rpm.RPMTAG_EPOCH', 1003), \
324-
patch('rpm.RPMTAG_SOURCERPM', 1044), \
325-
patch('rpm.RPMTAG_SOURCEPACKAGE', 1106), \
326-
patch('rpm.RPMTAG_PROVIDENAME', 1047), \
327-
patch('rpm.RPMTAG_PROVIDEFLAGS', 1113), \
328-
patch('rpm.RPMTAG_PROVIDEVERSION', 1048), \
329-
patch('rpm.RPMSENSE_EQUAL', 8), \
330-
patch('rpm.RPMSENSE_GREATER', 4), \
331-
patch('rpm.RPMSENSE_LESS', 2), \
332-
patch('os.path.exists', return_value=True), \
333-
patch('builtins.open', mock_open()):
290+
with rpm_patches(mock_ts):
334291

335292
result = checker.check_rpm_files(['/tmp/micropipenv.rpm'])
336293

@@ -387,24 +344,7 @@ def test_check_rpm_files_already_broken(self):
387344
mock_ts = Mock()
388345
mock_ts.hdrFromFdno = Mock(return_value=mock_header)
389346

390-
with patch('rpm.TransactionSet', return_value=mock_ts), \
391-
patch('rpm._RPMVSF_NOSIGNATURES', 0), \
392-
patch('rpm._RPMVSF_NODIGESTS', 0), \
393-
patch('rpm.RPMTAG_NAME', 1000), \
394-
patch('rpm.RPMTAG_VERSION', 1001), \
395-
patch('rpm.RPMTAG_RELEASE', 1002), \
396-
patch('rpm.RPMTAG_ARCH', 1022), \
397-
patch('rpm.RPMTAG_EPOCH', 1003), \
398-
patch('rpm.RPMTAG_SOURCERPM', 1044), \
399-
patch('rpm.RPMTAG_SOURCEPACKAGE', 1106), \
400-
patch('rpm.RPMTAG_PROVIDENAME', 1047), \
401-
patch('rpm.RPMTAG_PROVIDEFLAGS', 1113), \
402-
patch('rpm.RPMTAG_PROVIDEVERSION', 1048), \
403-
patch('rpm.RPMSENSE_EQUAL', 8), \
404-
patch('rpm.RPMSENSE_GREATER', 4), \
405-
patch('rpm.RPMSENSE_LESS', 2), \
406-
patch('os.path.exists', return_value=True), \
407-
patch('builtins.open', mock_open()):
347+
with rpm_patches(mock_ts):
408348

409349
result = checker.check_rpm_files(['/tmp/library.rpm'])
410350

tests/unit/test_rpm_reading.py

Lines changed: 32 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
"""
22
Unit tests for RPM file reading functionality.
33
4-
Tests the read_rpm_provides() method which reads provides from actual RPM files.
4+
Tests the read_rpm_provides() method using mocked RPM headers (no real RPM files).
55
"""
66

77
import pytest
8+
from contextlib import contextmanager
89
from unittest.mock import Mock, mock_open, patch
910
from fedora_revdep_check import FedoraRevDepChecker
1011

@@ -32,6 +33,30 @@ def __getitem__(self, key):
3233
return self.data.get(key)
3334

3435

36+
@contextmanager
37+
def rpm_patches(mock_ts):
38+
"""Context manager providing all rpm module patches needed for tests."""
39+
with (patch('rpm.TransactionSet', return_value=mock_ts),
40+
patch('rpm._RPMVSF_NOSIGNATURES', 0),
41+
patch('rpm._RPMVSF_NODIGESTS', 0),
42+
patch('rpm.RPMTAG_NAME', 1000),
43+
patch('rpm.RPMTAG_VERSION', 1001),
44+
patch('rpm.RPMTAG_RELEASE', 1002),
45+
patch('rpm.RPMTAG_ARCH', 1022),
46+
patch('rpm.RPMTAG_EPOCH', 1003),
47+
patch('rpm.RPMTAG_SOURCERPM', 1044),
48+
patch('rpm.RPMTAG_SOURCEPACKAGE', 1106),
49+
patch('rpm.RPMTAG_PROVIDENAME', 1047),
50+
patch('rpm.RPMTAG_PROVIDEFLAGS', 1113),
51+
patch('rpm.RPMTAG_PROVIDEVERSION', 1048),
52+
patch('rpm.RPMSENSE_EQUAL', 8),
53+
patch('rpm.RPMSENSE_GREATER', 4),
54+
patch('rpm.RPMSENSE_LESS', 2),
55+
patch('os.path.exists', return_value=True),
56+
patch('builtins.open', mock_open())):
57+
yield
58+
59+
3560
class TestReadRPMProvides:
3661
"""Test read_rpm_provides() method."""
3762

@@ -66,24 +91,7 @@ def test_read_single_rpm_file(self, checker):
6691
mock_ts = Mock()
6792
mock_ts.hdrFromFdno = Mock(return_value=mock_header)
6893

69-
with patch('rpm.TransactionSet', return_value=mock_ts), \
70-
patch('rpm._RPMVSF_NOSIGNATURES', 0), \
71-
patch('rpm._RPMVSF_NODIGESTS', 0), \
72-
patch('rpm.RPMTAG_NAME', 1000), \
73-
patch('rpm.RPMTAG_VERSION', 1001), \
74-
patch('rpm.RPMTAG_RELEASE', 1002), \
75-
patch('rpm.RPMTAG_ARCH', 1022), \
76-
patch('rpm.RPMTAG_EPOCH', 1003), \
77-
patch('rpm.RPMTAG_SOURCERPM', 1044), \
78-
patch('rpm.RPMTAG_SOURCEPACKAGE', 1106), \
79-
patch('rpm.RPMTAG_PROVIDENAME', 1047), \
80-
patch('rpm.RPMTAG_PROVIDEFLAGS', 1113), \
81-
patch('rpm.RPMTAG_PROVIDEVERSION', 1048), \
82-
patch('rpm.RPMSENSE_EQUAL', 8), \
83-
patch('rpm.RPMSENSE_GREATER', 4), \
84-
patch('rpm.RPMSENSE_LESS', 2), \
85-
patch('os.path.exists', return_value=True), \
86-
patch('builtins.open', mock_open()):
94+
with rpm_patches(mock_ts):
8795

8896
result = checker.read_rpm_provides(['/tmp/test.rpm'])
8997

@@ -128,24 +136,7 @@ def test_read_multiple_rpm_files(self, checker):
128136
mock_ts = Mock()
129137
mock_ts.hdrFromFdno = Mock(side_effect=[mock_header1, mock_header2])
130138

131-
with patch('rpm.TransactionSet', return_value=mock_ts), \
132-
patch('rpm._RPMVSF_NOSIGNATURES', 0), \
133-
patch('rpm._RPMVSF_NODIGESTS', 0), \
134-
patch('rpm.RPMTAG_NAME', 1000), \
135-
patch('rpm.RPMTAG_VERSION', 1001), \
136-
patch('rpm.RPMTAG_RELEASE', 1002), \
137-
patch('rpm.RPMTAG_ARCH', 1022), \
138-
patch('rpm.RPMTAG_EPOCH', 1003), \
139-
patch('rpm.RPMTAG_SOURCERPM', 1044), \
140-
patch('rpm.RPMTAG_SOURCEPACKAGE', 1106), \
141-
patch('rpm.RPMTAG_PROVIDENAME', 1047), \
142-
patch('rpm.RPMTAG_PROVIDEFLAGS', 1113), \
143-
patch('rpm.RPMTAG_PROVIDEVERSION', 1048), \
144-
patch('rpm.RPMSENSE_EQUAL', 8), \
145-
patch('rpm.RPMSENSE_GREATER', 4), \
146-
patch('rpm.RPMSENSE_LESS', 2), \
147-
patch('os.path.exists', return_value=True), \
148-
patch('builtins.open', mock_open()):
139+
with rpm_patches(mock_ts):
149140

150141
result = checker.read_rpm_provides(['/tmp/test1.rpm', '/tmp/test2.rpm'])
151142

@@ -176,24 +167,7 @@ def test_skip_source_rpm(self, checker):
176167
mock_ts = Mock()
177168
mock_ts.hdrFromFdno = Mock(return_value=mock_header)
178169

179-
with patch('rpm.TransactionSet', return_value=mock_ts), \
180-
patch('rpm._RPMVSF_NOSIGNATURES', 0), \
181-
patch('rpm._RPMVSF_NODIGESTS', 0), \
182-
patch('rpm.RPMTAG_NAME', 1000), \
183-
patch('rpm.RPMTAG_VERSION', 1001), \
184-
patch('rpm.RPMTAG_RELEASE', 1002), \
185-
patch('rpm.RPMTAG_ARCH', 1022), \
186-
patch('rpm.RPMTAG_EPOCH', 1003), \
187-
patch('rpm.RPMTAG_SOURCERPM', 1044), \
188-
patch('rpm.RPMTAG_SOURCEPACKAGE', 1106), \
189-
patch('rpm.RPMTAG_PROVIDENAME', 1047), \
190-
patch('rpm.RPMTAG_PROVIDEFLAGS', 1113), \
191-
patch('rpm.RPMTAG_PROVIDEVERSION', 1048), \
192-
patch('rpm.RPMSENSE_EQUAL', 8), \
193-
patch('rpm.RPMSENSE_GREATER', 4), \
194-
patch('rpm.RPMSENSE_LESS', 2), \
195-
patch('os.path.exists', return_value=True), \
196-
patch('builtins.open', mock_open()):
170+
with rpm_patches(mock_ts):
197171

198172
result = checker.read_rpm_provides(['/tmp/test.src.rpm'])
199173

@@ -222,24 +196,7 @@ def test_skip_bundled_provides(self, checker):
222196
mock_ts = Mock()
223197
mock_ts.hdrFromFdno = Mock(return_value=mock_header)
224198

225-
with patch('rpm.TransactionSet', return_value=mock_ts), \
226-
patch('rpm._RPMVSF_NOSIGNATURES', 0), \
227-
patch('rpm._RPMVSF_NODIGESTS', 0), \
228-
patch('rpm.RPMTAG_NAME', 1000), \
229-
patch('rpm.RPMTAG_VERSION', 1001), \
230-
patch('rpm.RPMTAG_RELEASE', 1002), \
231-
patch('rpm.RPMTAG_ARCH', 1022), \
232-
patch('rpm.RPMTAG_EPOCH', 1003), \
233-
patch('rpm.RPMTAG_SOURCERPM', 1044), \
234-
patch('rpm.RPMTAG_SOURCEPACKAGE', 1106), \
235-
patch('rpm.RPMTAG_PROVIDENAME', 1047), \
236-
patch('rpm.RPMTAG_PROVIDEFLAGS', 1113), \
237-
patch('rpm.RPMTAG_PROVIDEVERSION', 1048), \
238-
patch('rpm.RPMSENSE_EQUAL', 8), \
239-
patch('rpm.RPMSENSE_GREATER', 4), \
240-
patch('rpm.RPMSENSE_LESS', 2), \
241-
patch('os.path.exists', return_value=True), \
242-
patch('builtins.open', mock_open()):
199+
with rpm_patches(mock_ts):
243200

244201
result = checker.read_rpm_provides(['/tmp/myapp.rpm'])
245202

@@ -274,24 +231,7 @@ def test_mixed_source_packages_error(self, checker):
274231
mock_ts = Mock()
275232
mock_ts.hdrFromFdno = Mock(side_effect=[mock_header1, mock_header2])
276233

277-
with patch('rpm.TransactionSet', return_value=mock_ts), \
278-
patch('rpm._RPMVSF_NOSIGNATURES', 0), \
279-
patch('rpm._RPMVSF_NODIGESTS', 0), \
280-
patch('rpm.RPMTAG_NAME', 1000), \
281-
patch('rpm.RPMTAG_VERSION', 1001), \
282-
patch('rpm.RPMTAG_RELEASE', 1002), \
283-
patch('rpm.RPMTAG_ARCH', 1022), \
284-
patch('rpm.RPMTAG_EPOCH', 1003), \
285-
patch('rpm.RPMTAG_SOURCERPM', 1044), \
286-
patch('rpm.RPMTAG_SOURCEPACKAGE', 1106), \
287-
patch('rpm.RPMTAG_PROVIDENAME', 1047), \
288-
patch('rpm.RPMTAG_PROVIDEFLAGS', 1113), \
289-
patch('rpm.RPMTAG_PROVIDEVERSION', 1048), \
290-
patch('rpm.RPMSENSE_EQUAL', 8), \
291-
patch('rpm.RPMSENSE_GREATER', 4), \
292-
patch('rpm.RPMSENSE_LESS', 2), \
293-
patch('os.path.exists', return_value=True), \
294-
patch('builtins.open', mock_open()):
234+
with rpm_patches(mock_ts):
295235

296236
with pytest.raises(ValueError, match="multiple source packages"):
297237
checker.read_rpm_provides(['/tmp/test1.rpm', '/tmp/test2.rpm'])
@@ -318,24 +258,7 @@ def test_rpm_without_epoch(self, checker):
318258
mock_ts = Mock()
319259
mock_ts.hdrFromFdno = Mock(return_value=mock_header)
320260

321-
with patch('rpm.TransactionSet', return_value=mock_ts), \
322-
patch('rpm._RPMVSF_NOSIGNATURES', 0), \
323-
patch('rpm._RPMVSF_NODIGESTS', 0), \
324-
patch('rpm.RPMTAG_NAME', 1000), \
325-
patch('rpm.RPMTAG_VERSION', 1001), \
326-
patch('rpm.RPMTAG_RELEASE', 1002), \
327-
patch('rpm.RPMTAG_ARCH', 1022), \
328-
patch('rpm.RPMTAG_EPOCH', 1003), \
329-
patch('rpm.RPMTAG_SOURCERPM', 1044), \
330-
patch('rpm.RPMTAG_SOURCEPACKAGE', 1106), \
331-
patch('rpm.RPMTAG_PROVIDENAME', 1047), \
332-
patch('rpm.RPMTAG_PROVIDEFLAGS', 1113), \
333-
patch('rpm.RPMTAG_PROVIDEVERSION', 1048), \
334-
patch('rpm.RPMSENSE_EQUAL', 8), \
335-
patch('rpm.RPMSENSE_GREATER', 4), \
336-
patch('rpm.RPMSENSE_LESS', 2), \
337-
patch('os.path.exists', return_value=True), \
338-
patch('builtins.open', mock_open()):
261+
with rpm_patches(mock_ts):
339262

340263
result = checker.read_rpm_provides(['/tmp/test.rpm'])
341264

0 commit comments

Comments
 (0)