Skip to content

Commit 58f6bb4

Browse files
committed
test(cli): update test suites to reflect modern typer subcommand syntax
1 parent d5279eb commit 58f6bb4

3 files changed

Lines changed: 182 additions & 151 deletions

File tree

tests/test_cli.py

Lines changed: 142 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
1-
"""Smoke tests for CLI entry-points (main() functions via sys.argv monkeypatching)."""
1+
"""Smoke tests for CLI entry-points via Typer CliRunner."""
22

33
import shutil
4-
import sys
5-
import warnings
64

75
import pandas as pd
86
import pytest
7+
from typer.testing import CliRunner
98

10-
from krakenparser.counts.convert2csv import main as convert2csv_main
11-
from krakenparser.counts.processing_script import main as processing_main
12-
from krakenparser.counts.split_mpa import main as split_mpa_main
13-
from krakenparser.mpa.mpa_table import main as mpa_table_main
14-
from krakenparser.mpa.transform2mpa import main as transform2mpa_main
15-
from krakenparser.pipeline import main as pipeline_main
16-
from krakenparser.stats.diversity import main as diversity_main
17-
from krakenparser.stats.relabund import main as relabund_main
9+
from krakenparser.counts.convert2csv import app as convert2csv_app
10+
from krakenparser.counts.processing_script import app as processing_app
11+
from krakenparser.counts.split_mpa import app as split_mpa_app
12+
from krakenparser.mpa.mpa_table import app as mpa_table_app
13+
from krakenparser.mpa.transform2mpa import app as transform2mpa_app
14+
from krakenparser.pipeline import app as pipeline_app
15+
from krakenparser.stats.diversity import app as diversity_app
16+
from krakenparser.stats.relabund import app as relabund_app
1817

1918
_MPA_A = "#Classification\tsample1\nd__Bacteria|s__Pseudomonas_aeruginosa\t300\n"
2019
_MPA_B = "#Classification\tsample2\nd__Bacteria|s__Pseudomonas_aeruginosa\t100\n"
@@ -26,80 +25,102 @@
2625
)
2726

2827

28+
@pytest.fixture
29+
def runner():
30+
return CliRunner()
31+
32+
2933
# ---------------------------------------------------------------------------
3034
# convert2csv
3135
# ---------------------------------------------------------------------------
3236

3337

34-
def test_convert2csv_main(counts_txt_file, tmp_path, monkeypatch):
35-
out = tmp_path / "out.csv"
36-
monkeypatch.setattr(
37-
sys, "argv", ["c2c", "-i", str(counts_txt_file), "-o", str(out)]
38+
def test_convert2csv_no_args_shows_help(runner):
39+
result = runner.invoke(convert2csv_app, [])
40+
assert result.exit_code == 0
41+
assert "Usage" in result.output
42+
43+
44+
def test_convert2csv_missing_one_option(runner, tmp_path):
45+
result = runner.invoke(convert2csv_app, ["-i", str(tmp_path / "x.txt")])
46+
assert result.exit_code == 1
47+
assert "Missing required options" in result.output
48+
49+
50+
def test_convert2csv_file_not_found(runner, tmp_path):
51+
result = runner.invoke(
52+
convert2csv_app,
53+
["-i", str(tmp_path / "ghost.txt"), "-o", str(tmp_path / "out.csv")],
3854
)
39-
convert2csv_main()
40-
assert out.exists()
55+
assert result.exit_code == 1
56+
assert "Error" in result.output
4157

4258

4359
# ---------------------------------------------------------------------------
4460
# processing_script
4561
# ---------------------------------------------------------------------------
4662

4763

48-
def test_processing_main(tmp_path, monkeypatch):
49-
source = tmp_path / "COMBINED.txt"
50-
source.write_text("#Classification\tsample1.kreport\n")
51-
dest = tmp_path / "counts.txt"
52-
dest.write_text("s__Pseudomonas_aeruginosa\t100\n")
53-
monkeypatch.setattr(sys, "argv", ["ps", "-i", str(source), "-o", str(dest)])
54-
processing_main()
64+
def test_processing_no_args_shows_help(runner):
65+
result = runner.invoke(processing_app, [])
66+
assert result.exit_code == 0
67+
assert "Usage" in result.output
68+
69+
70+
def test_processing_missing_one_option(runner, tmp_path):
71+
result = runner.invoke(processing_app, ["-i", str(tmp_path / "x.txt")])
72+
assert result.exit_code == 1
73+
assert "Missing required options" in result.output
74+
75+
76+
def test_processing_file_not_found(runner, tmp_path):
77+
result = runner.invoke(
78+
processing_app,
79+
["-i", str(tmp_path / "ghost.txt"), "-o", str(tmp_path / "dest.txt")],
80+
)
81+
assert result.exit_code == 1
82+
assert "Error" in result.output
5583

5684

5785
# ---------------------------------------------------------------------------
5886
# split_mpa
5987
# ---------------------------------------------------------------------------
6088

6189

62-
def test_split_mpa_main(tmp_path, monkeypatch):
63-
combined = tmp_path / "COMBINED.txt"
64-
combined.write_text(_COMBINED_MPA)
65-
out = tmp_path / "out"
66-
monkeypatch.setattr(sys, "argv", ["sm", "-i", str(combined), "-o", str(out)])
67-
split_mpa_main()
68-
assert (out / "txt" / "counts_species.txt").exists()
90+
def test_split_mpa_no_args_shows_help(runner):
91+
result = runner.invoke(split_mpa_app, [])
92+
assert result.exit_code == 0
93+
assert "Usage" in result.output
6994

7095

71-
def test_split_mpa_main_viruses_only(tmp_path, monkeypatch):
72-
combined = tmp_path / "COMBINED.txt"
73-
combined.write_text(_COMBINED_MPA + "d__Viruses|s__Virus_X\t5\t3\n")
74-
out = tmp_path / "out"
75-
monkeypatch.setattr(
76-
sys, "argv", ["sm", "-i", str(combined), "-o", str(out), "--viruses-only"]
77-
)
78-
split_mpa_main()
96+
def test_split_mpa_missing_one_option(runner, tmp_path):
97+
result = runner.invoke(split_mpa_app, ["-i", str(tmp_path / "x.txt")])
98+
assert result.exit_code == 1
99+
assert "Missing required options" in result.output
79100

80101

81-
def test_split_mpa_main_keep_human(tmp_path, monkeypatch):
82-
combined = tmp_path / "COMBINED.txt"
83-
combined.write_text(_COMBINED_MPA)
84-
out = tmp_path / "out"
85-
monkeypatch.setattr(
86-
sys, "argv", ["sm", "-i", str(combined), "-o", str(out), "--keep-human"]
102+
def test_split_mpa_file_not_found(runner, tmp_path):
103+
result = runner.invoke(
104+
split_mpa_app,
105+
["-i", str(tmp_path / "ghost.txt"), "-o", str(tmp_path / "out")],
87106
)
88-
split_mpa_main()
107+
assert result.exit_code == 1
108+
assert "Error" in result.output
89109

90110

91111
# ---------------------------------------------------------------------------
92112
# mpa_table
93113
# ---------------------------------------------------------------------------
94114

95115

96-
def test_mpa_table_main(tmp_path, monkeypatch):
116+
def test_mpa_table_main(tmp_path, runner):
97117
a, b = tmp_path / "a.MPA.TXT", tmp_path / "b.MPA.TXT"
98118
a.write_text(_MPA_A)
99119
b.write_text(_MPA_B)
100120
out = tmp_path / "COMBINED.txt"
101-
monkeypatch.setattr(sys, "argv", ["mt", "-i", str(a), str(b), "-o", str(out)])
102-
mpa_table_main()
121+
122+
result = runner.invoke(mpa_table_app, ["-i", str(a), "-i", str(b), "-o", str(out)])
123+
assert result.exit_code == 0
103124
assert out.exists()
104125

105126

@@ -108,22 +129,23 @@ def test_mpa_table_main(tmp_path, monkeypatch):
108129
# ---------------------------------------------------------------------------
109130

110131

111-
def test_transform2mpa_main_single(kreport_file, tmp_path, monkeypatch):
132+
def test_transform2mpa_main_single(kreport_file, tmp_path, runner):
112133
out = tmp_path / "out.MPA.TXT"
113-
monkeypatch.setattr(sys, "argv", ["t2m", "-r", str(kreport_file), "-o", str(out)])
114-
transform2mpa_main()
134+
result = runner.invoke(transform2mpa_app, ["-r", str(kreport_file), "-o", str(out)])
135+
assert result.exit_code == 0
115136
assert out.exists()
116137

117138

118-
def test_transform2mpa_main_batch(kreport_file, tmp_path, monkeypatch):
139+
def test_transform2mpa_main_batch(kreport_file, tmp_path, runner):
119140
kreports_dir = tmp_path / "kreports"
120141
kreports_dir.mkdir()
121142
shutil.copy(kreport_file, kreports_dir / kreport_file.name)
122143
out_dir = tmp_path / "mpa_out"
123-
monkeypatch.setattr(
124-
sys, "argv", ["t2m", "-i", str(kreports_dir), "-o", str(out_dir)]
144+
145+
result = runner.invoke(
146+
transform2mpa_app, ["-i", str(kreports_dir), "-o", str(out_dir)]
125147
)
126-
transform2mpa_main()
148+
assert result.exit_code == 0
127149
assert out_dir.is_dir()
128150

129151

@@ -132,78 +154,91 @@ def test_transform2mpa_main_batch(kreport_file, tmp_path, monkeypatch):
132154
# ---------------------------------------------------------------------------
133155

134156

135-
def test_diversity_main_with_seed(counts_csv_file, tmp_path, monkeypatch):
136-
out_dir = tmp_path / "div"
137-
monkeypatch.setattr(
138-
sys,
139-
"argv",
140-
[
141-
"div",
142-
"-i",
143-
str(counts_csv_file),
144-
"-o",
145-
str(out_dir),
146-
"-d",
147-
"1000",
148-
"-s",
149-
"42",
150-
],
157+
def test_diversity_no_args_shows_help(runner):
158+
result = runner.invoke(diversity_app, [])
159+
assert result.exit_code == 0
160+
assert "Usage" in result.output
161+
162+
163+
def test_diversity_missing_one_option(runner, tmp_path):
164+
result = runner.invoke(diversity_app, ["-o", str(tmp_path / "out")])
165+
assert result.exit_code == 1
166+
assert "Missing required options" in result.output
167+
168+
169+
def test_diversity_file_not_found(runner, tmp_path):
170+
result = runner.invoke(
171+
diversity_app,
172+
["-i", str(tmp_path / "ghost.csv"), "-o", str(tmp_path / "out")],
151173
)
152-
diversity_main()
153-
assert (out_dir / "alpha_div.csv").exists()
174+
assert result.exit_code == 1
175+
assert "Error" in result.output
154176

155177

156-
def test_diversity_main_no_seed(counts_csv_file, tmp_path, monkeypatch):
178+
def test_diversity_not_enough_samples_for_beta(runner, tmp_path):
179+
csv_in = tmp_path / "single.csv"
180+
pd.DataFrame({"Taxon_A": [100], "Taxon_B": [200]}, index=["S1"]).to_csv(csv_in)
157181
out_dir = tmp_path / "div"
158-
monkeypatch.setattr(
159-
sys,
160-
"argv",
161-
["div", "-i", str(counts_csv_file), "-o", str(out_dir), "-d", "1000"],
182+
result = runner.invoke(
183+
diversity_app,
184+
["-i", str(csv_in), "-o", str(out_dir), "-d", "50"],
162185
)
163-
diversity_main()
186+
assert result.exit_code == 1
187+
assert "Error" in result.output
164188

165189

166190
# ---------------------------------------------------------------------------
167191
# relabund
168192
# ---------------------------------------------------------------------------
169193

170194

171-
def test_relabund_main(counts_csv_file, tmp_path, monkeypatch):
172-
out = tmp_path / "ra.csv"
173-
monkeypatch.setattr(sys, "argv", ["ra", "-i", str(counts_csv_file), "-o", str(out)])
174-
relabund_main()
175-
assert out.exists()
195+
def test_relabund_no_args_shows_help(runner):
196+
result = runner.invoke(relabund_app, [])
197+
assert result.exit_code == 0
198+
assert "Usage" in result.output
176199

177200

178-
def test_relabund_main_with_other_threshold(counts_csv_file, tmp_path, monkeypatch):
179-
out = tmp_path / "ra.csv"
180-
monkeypatch.setattr(
181-
sys, "argv", ["ra", "-i", str(counts_csv_file), "-o", str(out), "-O", "50"]
182-
)
183-
relabund_main()
201+
def test_relabund_missing_one_option(runner, tmp_path):
202+
result = runner.invoke(relabund_app, ["-i", str(tmp_path / "x.csv")])
203+
assert result.exit_code == 1
204+
assert "Missing required options" in result.output
184205

185206

186-
def test_relabund_warns_zero_abundance_sample(tmp_path):
187-
df = pd.DataFrame(
188-
{"Sample_id": ["S1", "S2"], "Taxon_A": [0, 100], "Taxon_B": [0, 200]}
207+
def test_relabund_file_not_found(runner, tmp_path):
208+
result = runner.invoke(
209+
relabund_app,
210+
["-i", str(tmp_path / "ghost.csv"), "-o", str(tmp_path / "out.csv")],
189211
)
190-
csv_in = tmp_path / "counts.csv"
191-
df.to_csv(csv_in, index=False)
192-
out = tmp_path / "ra.csv"
193-
with warnings.catch_warnings(record=True) as caught:
194-
warnings.simplefilter("always")
195-
from krakenparser.stats.relabund import calculate_rel_abund
196-
197-
calculate_rel_abund(str(csv_in), str(out))
198-
assert any("zero total abundance" in str(w.message) for w in caught)
212+
assert result.exit_code == 1
213+
assert "Error" in result.output
199214

200215

201216
# ---------------------------------------------------------------------------
202217
# pipeline (error paths only — success path covered by test_full_pipeline.py)
203218
# ---------------------------------------------------------------------------
204219

205220

206-
def test_pipeline_main_missing_input_exits(tmp_path, monkeypatch):
207-
monkeypatch.setattr(sys, "argv", ["pipeline", "-i", str(tmp_path / "ghost")])
208-
with pytest.raises(SystemExit):
209-
pipeline_main()
221+
def test_pipeline_no_mpa_files(runner, tmp_path):
222+
empty_dir = tmp_path / "kreports"
223+
empty_dir.mkdir()
224+
result = runner.invoke(pipeline_app, ["-i", str(empty_dir)])
225+
assert result.exit_code == 1
226+
assert "Error" in result.output
227+
228+
229+
def test_pipeline_file_exists_error(runner, tmp_path, kreport_file):
230+
kreports_dir = tmp_path / "kreports"
231+
kreports_dir.mkdir()
232+
shutil.copy(kreport_file, kreports_dir / kreport_file.name)
233+
234+
runner.invoke(pipeline_app, ["-i", str(kreports_dir), "--overwrite"])
235+
236+
result = runner.invoke(pipeline_app, ["-i", str(kreports_dir)])
237+
assert result.exit_code == 1
238+
assert "Error" in result.output
239+
240+
241+
def test_pipeline_missing_input_dir(runner, tmp_path):
242+
result = runner.invoke(pipeline_app, ["-i", str(tmp_path / "ghost")])
243+
assert result.exit_code == 1
244+
assert "Error" in result.output

tests/test_full_pipeline.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def test_full_pipeline_end_to_end(demo_run):
3131
run_dir = demo_run["run_dir"]
3232
kreports_path = run_dir / "kreports"
3333

34-
run_pipeline(str(kreports_path))
34+
run_pipeline(kreports_path)
3535

3636
# Assert each rank-level CSV exists and is non-empty
3737
ranks = ["phylum", "class", "order", "family", "genus", "species"]
@@ -59,17 +59,17 @@ def test_pipeline_overwrite_protection(demo_run):
5959
run_dir = demo_run["run_dir"]
6060
kreports_path = run_dir / "kreports"
6161

62-
run_pipeline(str(kreports_path))
62+
run_pipeline(kreports_path)
6363

6464
# Second run without --overwrite must raise (library function, not sys.exit)
6565
with pytest.raises(FileExistsError):
66-
run_pipeline(str(kreports_path))
66+
run_pipeline(kreports_path)
6767

6868

6969
def test_pipeline_overwrite_flag(demo_run):
7070
run_dir = demo_run["run_dir"]
7171
kreports_path = run_dir / "kreports"
7272

73-
run_pipeline(str(kreports_path))
73+
run_pipeline(kreports_path)
7474
# Second run with overwrite=True must succeed
75-
run_pipeline(str(kreports_path), overwrite=True)
75+
run_pipeline(kreports_path, overwrite=True)

0 commit comments

Comments
 (0)