Skip to content

Commit 2252669

Browse files
Added CLI flag coverage and E2E pipeline integration tests
1 parent fae996b commit 2252669

2 files changed

Lines changed: 745 additions & 2 deletions

File tree

tests/test_cli.py

Lines changed: 382 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
"""Unit tests to verify CLI behavior for codemeta generation."""
1+
"""Unit tests verifying CLI argument handling and dispatch."""
22

33
import importlib
44
from unittest.mock import MagicMock
55

66
cli_module = importlib.import_module("rsmetacheck.cli")
77

8-
98
REPO_URL = "https://github.com/SoftwareUnderstanding/sw-metadata-bot"
109

1110

@@ -70,3 +69,384 @@ def test_cli_without_generate_codemeta_keeps_default_behavior(monkeypatch, tmp_p
7069
assert "-c" not in command
7170

7271
run_analysis_mock.assert_called_once()
72+
73+
74+
def test_cli_skip_somef_bypasses_somef_execution(monkeypatch, tmp_path):
75+
"""--skip-somef should call run_analysis directly without running SoMEF."""
76+
somef_file = tmp_path / "somef_output.json"
77+
somef_file.write_text("{}")
78+
79+
run_analysis_mock = MagicMock()
80+
ensure_somef_mock = MagicMock()
81+
82+
monkeypatch.setattr(
83+
"sys.argv",
84+
[
85+
"rsmetacheck",
86+
"--input",
87+
str(somef_file),
88+
"--skip-somef",
89+
],
90+
)
91+
monkeypatch.setattr(cli_module, "ensure_somef_configured", ensure_somef_mock)
92+
monkeypatch.setattr(cli_module, "run_analysis", run_analysis_mock)
93+
94+
cli_module.cli()
95+
96+
ensure_somef_mock.assert_not_called()
97+
run_analysis_mock.assert_called_once()
98+
99+
100+
def test_cli_skip_somef_with_missing_file_skips_and_warns(monkeypatch, capsys):
101+
"""--skip-somef with a missing file should print a warning and skip."""
102+
run_analysis_mock = MagicMock()
103+
104+
monkeypatch.setattr(
105+
"sys.argv",
106+
[
107+
"rsmetacheck",
108+
"--input",
109+
"/nonexistent/file.json",
110+
"--skip-somef",
111+
],
112+
)
113+
monkeypatch.setattr(cli_module, "run_analysis", run_analysis_mock)
114+
115+
cli_module.cli()
116+
117+
captured = capsys.readouterr()
118+
assert "Warning: File not found" in captured.out
119+
120+
121+
def test_cli_verbose_flag_passed_to_run_analysis(monkeypatch, tmp_path):
122+
"""--verbose should be forwarded to run_analysis."""
123+
somef_file = tmp_path / "somef_output.json"
124+
somef_file.write_text("{}")
125+
126+
run_analysis_mock = MagicMock()
127+
128+
monkeypatch.setattr(
129+
"sys.argv",
130+
[
131+
"rsmetacheck",
132+
"--input",
133+
str(somef_file),
134+
"--skip-somef",
135+
"--verbose",
136+
],
137+
)
138+
monkeypatch.setattr(cli_module, "run_analysis", run_analysis_mock)
139+
140+
cli_module.cli()
141+
142+
call_kwargs = run_analysis_mock.call_args.kwargs
143+
assert call_kwargs.get("verbose") is True
144+
145+
146+
def test_cli_verbose_defaults_to_false(monkeypatch, tmp_path):
147+
"""Default is verbose=False when --verbose is not provided."""
148+
somef_file = tmp_path / "somef_output.json"
149+
somef_file.write_text("{}")
150+
151+
run_analysis_mock = MagicMock()
152+
153+
monkeypatch.setattr(
154+
"sys.argv",
155+
[
156+
"rsmetacheck",
157+
"--input",
158+
str(somef_file),
159+
"--skip-somef",
160+
],
161+
)
162+
monkeypatch.setattr(cli_module, "run_analysis", run_analysis_mock)
163+
164+
cli_module.cli()
165+
166+
call_kwargs = run_analysis_mock.call_args.kwargs
167+
assert call_kwargs.get("verbose") is False
168+
169+
170+
def test_cli_branch_passed_to_somef(monkeypatch, tmp_path):
171+
"""-b / --branch should be forwarded to the somef command."""
172+
somef_output_dir = tmp_path / "somef_outputs"
173+
174+
run_analysis_mock = MagicMock()
175+
subprocess_run_mock = MagicMock()
176+
177+
monkeypatch.setattr(
178+
"sys.argv",
179+
[
180+
"rsmetacheck",
181+
"--input",
182+
REPO_URL,
183+
"--somef-output",
184+
str(somef_output_dir),
185+
"-b",
186+
"develop",
187+
],
188+
)
189+
monkeypatch.setattr(cli_module, "ensure_somef_configured", lambda: True)
190+
monkeypatch.setattr(cli_module, "run_analysis", run_analysis_mock)
191+
monkeypatch.setattr("rsmetacheck.run_somef.subprocess.run", subprocess_run_mock)
192+
193+
cli_module.cli()
194+
195+
command = subprocess_run_mock.call_args.args[0]
196+
assert "-b" in command
197+
assert "develop" in command
198+
199+
200+
def test_cli_threshold_passed_to_somef(monkeypatch, tmp_path):
201+
"""--threshold should be forwarded to the somef command."""
202+
somef_output_dir = tmp_path / "somef_outputs"
203+
204+
run_analysis_mock = MagicMock()
205+
subprocess_run_mock = MagicMock()
206+
207+
monkeypatch.setattr(
208+
"sys.argv",
209+
[
210+
"rsmetacheck",
211+
"--input",
212+
REPO_URL,
213+
"--somef-output",
214+
str(somef_output_dir),
215+
"--threshold",
216+
"0.5",
217+
],
218+
)
219+
monkeypatch.setattr(cli_module, "ensure_somef_configured", lambda: True)
220+
monkeypatch.setattr(cli_module, "run_analysis", run_analysis_mock)
221+
monkeypatch.setattr("rsmetacheck.run_somef.subprocess.run", subprocess_run_mock)
222+
223+
cli_module.cli()
224+
225+
command = subprocess_run_mock.call_args.args[0]
226+
assert "-t" in command
227+
assert "0.5" in command
228+
229+
230+
def test_cli_notes_output_passed_to_run_analysis(monkeypatch, tmp_path):
231+
"""--notes-output should be forwarded to run_analysis."""
232+
somef_file = tmp_path / "somef_output.json"
233+
somef_file.write_text("{}")
234+
notes_path = tmp_path / "notes.json"
235+
236+
run_analysis_mock = MagicMock()
237+
238+
monkeypatch.setattr(
239+
"sys.argv",
240+
[
241+
"rsmetacheck",
242+
"--input",
243+
str(somef_file),
244+
"--skip-somef",
245+
"--notes-output",
246+
str(notes_path),
247+
],
248+
)
249+
monkeypatch.setattr(cli_module, "run_analysis", run_analysis_mock)
250+
251+
cli_module.cli()
252+
253+
call_kwargs = run_analysis_mock.call_args.kwargs
254+
assert call_kwargs.get("notes_output") == str(notes_path)
255+
256+
257+
def test_cli_custom_pitfalls_output_dir(monkeypatch, tmp_path):
258+
"""--pitfalls-output should be forwarded to run_analysis."""
259+
somef_file = tmp_path / "somef_output.json"
260+
somef_file.write_text("{}")
261+
pitfalls_dir = tmp_path / "custom_pitfalls"
262+
263+
run_analysis_mock = MagicMock()
264+
265+
monkeypatch.setattr(
266+
"sys.argv",
267+
[
268+
"rsmetacheck",
269+
"--input",
270+
str(somef_file),
271+
"--skip-somef",
272+
"--pitfalls-output",
273+
str(pitfalls_dir),
274+
],
275+
)
276+
monkeypatch.setattr(cli_module, "run_analysis", run_analysis_mock)
277+
278+
cli_module.cli()
279+
280+
call_args = run_analysis_mock.call_args.args
281+
assert str(call_args[1]) == str(pitfalls_dir)
282+
283+
284+
def test_cli_custom_analysis_output_path(monkeypatch, tmp_path):
285+
"""--analysis-output should be forwarded to run_analysis."""
286+
somef_file = tmp_path / "somef_output.json"
287+
somef_file.write_text("{}")
288+
analysis_file = tmp_path / "custom_summary.json"
289+
290+
run_analysis_mock = MagicMock()
291+
292+
monkeypatch.setattr(
293+
"sys.argv",
294+
[
295+
"rsmetacheck",
296+
"--input",
297+
str(somef_file),
298+
"--skip-somef",
299+
"--analysis-output",
300+
str(analysis_file),
301+
],
302+
)
303+
monkeypatch.setattr(cli_module, "run_analysis", run_analysis_mock)
304+
305+
cli_module.cli()
306+
307+
call_args = run_analysis_mock.call_args.args
308+
assert str(call_args[2]) == str(analysis_file)
309+
310+
311+
def test_cli_custom_somef_output_dir(monkeypatch, tmp_path):
312+
"""--somef-output should be forwarded to run_somef_single."""
313+
somef_output_dir = tmp_path / "custom_somef"
314+
315+
run_analysis_mock = MagicMock()
316+
run_somef_single_mock = MagicMock()
317+
318+
monkeypatch.setattr(
319+
"sys.argv",
320+
[
321+
"rsmetacheck",
322+
"--input",
323+
REPO_URL,
324+
"--somef-output",
325+
str(somef_output_dir),
326+
],
327+
)
328+
monkeypatch.setattr(cli_module, "ensure_somef_configured", lambda: True)
329+
monkeypatch.setattr(cli_module, "run_analysis", run_analysis_mock)
330+
monkeypatch.setattr(cli_module, "run_somef_single", run_somef_single_mock)
331+
332+
cli_module.cli()
333+
334+
call_args = run_somef_single_mock.call_args.args
335+
assert str(call_args[1]) == str(somef_output_dir)
336+
337+
338+
def test_cli_input_url_triggers_run_somef_single(monkeypatch):
339+
"""An HTTP URL as --input should trigger run_somef_single."""
340+
run_analysis_mock = MagicMock()
341+
run_somef_single_mock = MagicMock()
342+
run_somef_batch_mock = MagicMock()
343+
344+
monkeypatch.setattr(
345+
"sys.argv",
346+
[
347+
"rsmetacheck",
348+
"--input",
349+
REPO_URL,
350+
],
351+
)
352+
monkeypatch.setattr(cli_module, "ensure_somef_configured", lambda: True)
353+
monkeypatch.setattr(cli_module, "run_analysis", run_analysis_mock)
354+
monkeypatch.setattr(cli_module, "run_somef_single", run_somef_single_mock)
355+
monkeypatch.setattr(cli_module, "run_somef_batch", run_somef_batch_mock)
356+
357+
cli_module.cli()
358+
359+
run_somef_single_mock.assert_called_once()
360+
run_somef_batch_mock.assert_not_called()
361+
362+
363+
def test_cli_input_file_triggers_run_somef_batch(monkeypatch, tmp_path):
364+
"""A JSON file as --input should trigger run_somef_batch."""
365+
batch_file = tmp_path / "repos.json"
366+
batch_file.write_text('{"repositories": ["https://github.com/a/b"]}')
367+
368+
run_analysis_mock = MagicMock()
369+
run_somef_single_mock = MagicMock()
370+
run_somef_batch_mock = MagicMock()
371+
372+
monkeypatch.setattr(
373+
"sys.argv",
374+
[
375+
"rsmetacheck",
376+
"--input",
377+
str(batch_file),
378+
],
379+
)
380+
monkeypatch.setattr(cli_module, "ensure_somef_configured", lambda: True)
381+
monkeypatch.setattr(cli_module, "run_analysis", run_analysis_mock)
382+
monkeypatch.setattr(cli_module, "run_somef_single", run_somef_single_mock)
383+
monkeypatch.setattr(cli_module, "run_somef_batch", run_somef_batch_mock)
384+
385+
cli_module.cli()
386+
387+
run_somef_single_mock.assert_not_called()
388+
run_somef_batch_mock.assert_called_once()
389+
390+
391+
def test_cli_invalid_input_warns(monkeypatch, capsys):
392+
"""Invalid input (not URL, not existing file) should produce a warning."""
393+
run_analysis_mock = MagicMock()
394+
395+
monkeypatch.setattr(
396+
"sys.argv",
397+
[
398+
"rsmetacheck",
399+
"--input",
400+
"just-a-string-not-a-url-or-file",
401+
],
402+
)
403+
monkeypatch.setattr(cli_module, "ensure_somef_configured", lambda: True)
404+
monkeypatch.setattr(cli_module, "run_analysis", run_analysis_mock)
405+
406+
cli_module.cli()
407+
408+
captured = capsys.readouterr()
409+
assert "Skipping invalid input" in captured.out
410+
411+
412+
def test_cli_multiple_inputs_triggers_multiple_calls(monkeypatch, tmp_path):
413+
"""Multiple --input values should each be processed."""
414+
batch_file = tmp_path / "repos.json"
415+
batch_file.write_text('{"repositories": ["https://github.com/a/b"]}')
416+
417+
run_analysis_mock = MagicMock()
418+
run_somef_single_mock = MagicMock()
419+
run_somef_batch_mock = MagicMock()
420+
421+
monkeypatch.setattr(
422+
"sys.argv",
423+
[
424+
"rsmetacheck",
425+
"--input",
426+
REPO_URL,
427+
str(batch_file),
428+
],
429+
)
430+
monkeypatch.setattr(cli_module, "ensure_somef_configured", lambda: True)
431+
monkeypatch.setattr(cli_module, "run_analysis", run_analysis_mock)
432+
monkeypatch.setattr(cli_module, "run_somef_single", run_somef_single_mock)
433+
monkeypatch.setattr(cli_module, "run_somef_batch", run_somef_batch_mock)
434+
435+
cli_module.cli()
436+
437+
run_somef_single_mock.assert_called_once()
438+
run_somef_batch_mock.assert_called_once()
439+
440+
441+
def test_cli_input_required(monkeypatch):
442+
"""CLI should fail if --input is not provided."""
443+
monkeypatch.setattr(
444+
"sys.argv",
445+
["rsmetacheck"],
446+
)
447+
448+
try:
449+
cli_module.cli()
450+
assert False, "Expected SystemExit"
451+
except SystemExit:
452+
pass

0 commit comments

Comments
 (0)