Skip to content

Commit 7d77ba2

Browse files
committed
Add some basic smoke tests
These just check that the basic functions are working
1 parent 411cf09 commit 7d77ba2

1 file changed

Lines changed: 182 additions & 0 deletions

File tree

tests/test_smoke.py

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
import msprime
2+
import pytest
3+
4+
import tskit_arg_visualizer as argviz
5+
6+
7+
def _example_d3arg():
8+
ts = msprime.sim_ancestry(
9+
samples=4,
10+
sequence_length=100,
11+
recombination_rate=1e-2,
12+
record_full_arg=True,
13+
ploidy=1,
14+
random_seed=123,
15+
)
16+
return ts, argviz.D3ARG.from_ts(ts)
17+
18+
19+
class TestRenderingSmoke:
20+
def test_draw_returns_drawinfo_without_opening_browser(self, monkeypatch):
21+
_, d3arg = _example_d3arg()
22+
23+
# Keep test non-interactive while still exercising HTML generation path.
24+
monkeypatch.setattr(argviz, "display", lambda *_args, **_kwargs: None)
25+
26+
info = d3arg.draw(
27+
width=320,
28+
height=240,
29+
tree_highlighting=False,
30+
show_mutations=False,
31+
is_notebook=True,
32+
)
33+
34+
assert isinstance(info, argviz.DrawInfo)
35+
# Width/height may be adjusted internally (e.g., axis/title spacing),
36+
# so only assert broad sanity constraints here.
37+
assert float(info.width) >= 320
38+
assert float(info.height) >= 240
39+
assert info.uid.startswith("arg_")
40+
41+
included_nodes = info.included.nodes
42+
assert isinstance(included_nodes, list)
43+
assert len(included_nodes) > 0
44+
assert set(included_nodes).issubset(set(d3arg.nodes["id"]))
45+
46+
def test_draw_nodes_returns_drawinfo_without_opening_browser(self, monkeypatch):
47+
_, d3arg = _example_d3arg()
48+
49+
monkeypatch.setattr(argviz, "display", lambda *_args, **_kwargs: None)
50+
51+
info = d3arg.draw_nodes(
52+
seed_nodes=[d3arg.sample_order[0]],
53+
depth=1,
54+
width=320,
55+
height=240,
56+
tree_highlighting=False,
57+
show_mutations=False,
58+
is_notebook=True,
59+
)
60+
61+
assert isinstance(info, argviz.DrawInfo)
62+
assert float(info.width) >= 320
63+
assert float(info.height) >= 240
64+
assert info.uid.startswith("arg_")
65+
66+
included_nodes = info.included.nodes
67+
assert isinstance(included_nodes, list)
68+
assert len(included_nodes) > 0
69+
assert set(included_nodes).issubset(set(d3arg.nodes["id"]))
70+
71+
def test_draw_genome_bar_smoke_notebook_mode(self, monkeypatch):
72+
_, d3arg = _example_d3arg()
73+
74+
monkeypatch.setattr(argviz, "display", lambda *_args, **_kwargs: None)
75+
76+
result = d3arg.draw_genome_bar(
77+
width=320,
78+
show_mutations=True,
79+
is_notebook=True,
80+
)
81+
assert result is None
82+
83+
84+
class TestGraphSubsetSmoke:
85+
def test_from_ts_and_subset_graph_smoke(self):
86+
ts, d3arg = _example_d3arg()
87+
88+
assert d3arg.num_samples == ts.num_samples
89+
assert not d3arg.nodes.empty
90+
assert not d3arg.edges.empty
91+
92+
subset = d3arg.subset_graph(seed_nodes=[d3arg.sample_order[0]], depth=1)
93+
assert not subset.nodes.empty
94+
assert not subset.edges.empty
95+
96+
node_ids = set(subset.nodes["id"].tolist())
97+
assert set(subset.edges["source"]).issubset(node_ids)
98+
assert set(subset.edges["target"]).issubset(node_ids)
99+
assert set(subset.mutations["edge"]).issubset(set(subset.edges["id"]))
100+
101+
102+
class TestSecondaryPositionUtilities:
103+
def test_extract_x_positions_from_json_smoke(self):
104+
arg_no_labels = {
105+
"width": 500,
106+
"y_axis": {"include_labels": False},
107+
"data": {
108+
"nodes": [
109+
{"id": 1, "x": 50},
110+
{"id": 2, "x": 450},
111+
]
112+
},
113+
}
114+
pos_no_labels = argviz.extract_x_positions_from_json(arg_no_labels)
115+
assert pos_no_labels[1] == pytest.approx(0.0)
116+
assert pos_no_labels[2] == pytest.approx(1.0)
117+
118+
arg_with_labels = {
119+
"width": 500,
120+
"y_axis": {"include_labels": True},
121+
"data": {
122+
"nodes": [
123+
{"id": 1, "x": 150},
124+
{"id": 2, "x": 450},
125+
]
126+
},
127+
}
128+
pos_with_labels = argviz.extract_x_positions_from_json(arg_with_labels)
129+
assert pos_with_labels[1] == pytest.approx(0.0)
130+
assert pos_with_labels[2] == pytest.approx(1.0)
131+
132+
def test_calculate_evenly_distributed_positions_smoke(self):
133+
positions = argviz.calculate_evenly_distributed_positions(
134+
num_elements=5, start=0, end=1, round_to=3
135+
)
136+
assert len(positions) == 5
137+
assert positions[0] == 0
138+
assert positions[-1] == 1
139+
assert positions == sorted(positions)
140+
141+
midpoint = argviz.calculate_evenly_distributed_positions(
142+
num_elements=1, start=10, end=20, round_to=3
143+
)
144+
assert midpoint == [15.0]
145+
146+
def test_convert_time_to_position_monotonic_in_time_scale(self):
147+
y_shift = 7
148+
height = 200
149+
y_for_recent = argviz.convert_time_to_position(
150+
t=0,
151+
min_time=0,
152+
max_time=10,
153+
scale="time",
154+
unique_times=[0, 5, 10],
155+
h_spacing=0.5,
156+
height=height,
157+
y_shift=y_shift,
158+
)
159+
y_for_ancient = argviz.convert_time_to_position(
160+
t=10,
161+
min_time=0,
162+
max_time=10,
163+
scale="time",
164+
unique_times=[0, 5, 10],
165+
h_spacing=0.5,
166+
height=height,
167+
y_shift=y_shift,
168+
)
169+
assert y_for_ancient < y_for_recent
170+
171+
def test_convert_time_to_position_rank_requires_known_time(self):
172+
with pytest.raises(RuntimeError):
173+
argviz.convert_time_to_position(
174+
t=3,
175+
min_time=0,
176+
max_time=10,
177+
scale="rank",
178+
unique_times=[0, 1, 2],
179+
h_spacing=0.5,
180+
height=100,
181+
y_shift=0,
182+
)

0 commit comments

Comments
 (0)