Skip to content

Commit 1b9ec1d

Browse files
committed
Add tests for jesd basic webui interfaces
Signed-off-by: Travis F. Collins <travis.collins@analog.com>
1 parent b000c82 commit 1b9ec1d

1 file changed

Lines changed: 234 additions & 0 deletions

File tree

tests/tools/test_jesdbasic.py

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
"""Streamlit testing for Basic JESD204 Calculator page."""
2+
3+
import pathlib
4+
import sys
5+
import time
6+
7+
from streamlit.testing.v1 import AppTest
8+
9+
app_path = (
10+
pathlib.Path(__file__).parent.parent.parent
11+
/ "adijif"
12+
/ "tools"
13+
/ "explorer"
14+
)
15+
app_file_path = app_path / "main.py"
16+
17+
sys.path.append(str(app_path))
18+
19+
20+
def navigate_to_jesdbasic(at: AppTest) -> AppTest:
21+
"""Navigate the sidebar to the Basic JESD204 Calculator page."""
22+
sb = at.sidebar
23+
for item in sb.radio:
24+
if item.label == "Select a Tool":
25+
item.set_value("Basic JESD204 Calculator").run()
26+
break
27+
time.sleep(0.5)
28+
return at
29+
30+
31+
def test_jesdbasic_page_loads() -> None:
32+
"""Test that the Basic JESD204 Calculator page loads without errors."""
33+
at = AppTest.from_file(app_file_path).run()
34+
navigate_to_jesdbasic(at)
35+
36+
assert not at.exception
37+
assert len(at.title) > 0
38+
assert at.title[0].value == "Basic JESD204 Calculator"
39+
40+
41+
def test_jesdbasic_default_inputs_present() -> None:
42+
"""Test that default input widgets are present with expected defaults."""
43+
at = AppTest.from_file(app_file_path).run()
44+
navigate_to_jesdbasic(at)
45+
46+
labels = {ni.label: ni for ni in at.number_input}
47+
assert "L (number of lanes)" in labels, "L input not found"
48+
assert "M (number of converters)" in labels, "M input not found"
49+
assert "Np (Bits per sample)" in labels, "Np input not found"
50+
51+
assert labels["L (number of lanes)"].value == 4
52+
assert labels["M (number of converters)"].value == 4
53+
assert labels["Np (Bits per sample)"].value == 16
54+
55+
assert not at.exception
56+
57+
58+
def test_jesdbasic_jesd_class_selector() -> None:
59+
"""Test that the JESD204 Class selector is present with correct options."""
60+
at = AppTest.from_file(app_file_path).run()
61+
navigate_to_jesdbasic(at)
62+
63+
class_sel = None
64+
for sb in at.selectbox:
65+
if sb.label == "JESD204 Class":
66+
class_sel = sb
67+
break
68+
69+
assert class_sel is not None, "JESD204 Class selectbox not found"
70+
assert "JESD204B" in class_sel.options
71+
assert "JESD204C" in class_sel.options
72+
assert class_sel.value == "JESD204B"
73+
74+
assert not at.exception
75+
76+
77+
def test_jesdbasic_clock_ref_sample_rate_mode() -> None:
78+
"""Test that Sample Rate mode shows the Sample Rate input."""
79+
at = AppTest.from_file(app_file_path).run()
80+
navigate_to_jesdbasic(at)
81+
82+
# Default mode is Sample Rate — verify the sample rate input is visible
83+
labels = [ni.label for ni in at.number_input]
84+
assert any("Sample Rate" in lbl for lbl in labels), (
85+
"Sample Rate input not found in default mode"
86+
)
87+
88+
assert not at.exception
89+
90+
91+
def test_jesdbasic_clock_ref_lane_rate_mode() -> None:
92+
"""Test that switching to Lane Rate mode shows the Lane Rate input."""
93+
at = AppTest.from_file(app_file_path).run()
94+
navigate_to_jesdbasic(at)
95+
96+
for sb in at.selectbox:
97+
if sb.label == "Clock Reference Source":
98+
sb.set_value("Lane Rate").run()
99+
break
100+
101+
labels = [ni.label for ni in at.number_input]
102+
assert any("Lane Rate" in lbl for lbl in labels), (
103+
"Lane Rate input not found after switching Clock Reference Source"
104+
)
105+
106+
assert not at.exception
107+
108+
109+
def test_jesdbasic_output_table_present() -> None:
110+
"""Test that the Derived Parameters table is rendered."""
111+
at = AppTest.from_file(app_file_path).run()
112+
navigate_to_jesdbasic(at)
113+
114+
assert len(at.table) > 0, "Output table not found"
115+
116+
# Table should contain Lane Rate and Core Clock rows
117+
table_df = at.table[0].value
118+
params = list(table_df["Parameter"])
119+
assert "Lane Rate (Gbps)" in params, (
120+
"Lane Rate row missing from output table"
121+
)
122+
assert "Core Clock (MHz)" in params, (
123+
"Core Clock row missing from output table"
124+
)
125+
126+
assert not at.exception
127+
128+
129+
def test_jesdbasic_lane_rate_calculation_sample_rate_mode() -> None:
130+
"""Test lane rate calculation in Sample Rate mode with known values."""
131+
at = AppTest.from_file(app_file_path).run()
132+
navigate_to_jesdbasic(at)
133+
134+
# Set known values: L=4, M=4, Np=16, Sample Rate=1e8 SPS, JESD204B
135+
# Expected lane rate = (4 * 16 * 1e8 * 10/8) / 4 / 1e9 = 2.0 Gbps
136+
for ni in at.number_input:
137+
if ni.label == "Sample Rate (SPS)":
138+
ni.set_value(1e8).run()
139+
break
140+
141+
assert not at.exception
142+
table_df = at.table[0].value
143+
row = table_df[table_df["Parameter"] == "Lane Rate (Gbps)"]
144+
assert len(row) == 1
145+
assert abs(float(row["Value"].iloc[0]) - 2.0) < 1e-6
146+
147+
148+
def test_jesdbasic_sample_rate_calculation_lane_rate_mode() -> None:
149+
"""Test sample rate calculation in Lane Rate mode with known values."""
150+
at = AppTest.from_file(app_file_path).run()
151+
navigate_to_jesdbasic(at)
152+
153+
for sb in at.selectbox:
154+
if sb.label == "Clock Reference Source":
155+
sb.set_value("Lane Rate").run()
156+
break
157+
158+
# Set lane rate to 10 Gbps with defaults L=4, M=4, Np=16, JESD204B
159+
# Expected sample rate = (10e9 * 4) / (4 * 16 * 10/8) / 1e6 = 500 MSPS
160+
for ni in at.number_input:
161+
if ni.label == "Lane Rate (Gbps)":
162+
ni.set_value(10.0).run()
163+
break
164+
165+
assert not at.exception
166+
table_df = at.table[0].value
167+
row = table_df[table_df["Parameter"] == "Sample Rate (MSPS)"]
168+
assert len(row) == 1
169+
assert abs(float(row["Value"].iloc[0]) - 500.0) < 1e-6
170+
171+
172+
def test_jesdbasic_jesd204c_encoding() -> None:
173+
"""Test that switching to JESD204C uses 66/64 encoding factor."""
174+
at = AppTest.from_file(app_file_path).run()
175+
navigate_to_jesdbasic(at)
176+
177+
for sb in at.selectbox:
178+
if sb.label == "JESD204 Class":
179+
sb.set_value("JESD204C").run()
180+
break
181+
182+
assert not at.exception
183+
184+
# With L=4, M=4, Np=16, SR=1e8, JESD204C (66/64 encoding):
185+
# lane rate = (4 * 16 * 1e8 * 66/64) / 4 / 1e9 = 1.65625 Gbps
186+
for ni in at.number_input:
187+
if ni.label == "Sample Rate (SPS)":
188+
ni.set_value(1e8).run()
189+
break
190+
191+
assert not at.exception
192+
table_df = at.table[0].value
193+
row = table_df[table_df["Parameter"] == "Lane Rate (Gbps)"]
194+
assert len(row) == 1
195+
expected = (4 * 16 * 1e8 * 66 / 64) / 4 / 1e9
196+
assert abs(float(row["Value"].iloc[0]) - expected) < 1e-6
197+
198+
199+
def test_jesdbasic_core_clock_jesd204b() -> None:
200+
"""Test core clock calculation for JESD204B."""
201+
at = AppTest.from_file(app_file_path).run()
202+
navigate_to_jesdbasic(at)
203+
204+
for ni in at.number_input:
205+
if ni.label == "Sample Rate (SPS)":
206+
ni.set_value(1e8).run()
207+
break
208+
209+
assert not at.exception
210+
211+
# With lane rate = 2.0 Gbps, JESD204B core clock = 2.0 / 40 * 1e3 = 50 MHz
212+
table_df = at.table[0].value
213+
row = table_df[table_df["Parameter"] == "Core Clock (MHz)"]
214+
assert len(row) == 1
215+
assert abs(float(row["Value"].iloc[0]) - 50.0) < 1e-6
216+
217+
218+
def test_jesdbasic_no_exception_on_param_changes() -> None:
219+
"""Test that changing L, M, Np inputs produces no exceptions."""
220+
at = AppTest.from_file(app_file_path).run()
221+
navigate_to_jesdbasic(at)
222+
223+
for label, value in [
224+
("L (number of lanes)", 8),
225+
("M (number of converters)", 2),
226+
("Np (Bits per sample)", 12),
227+
]:
228+
for ni in at.number_input:
229+
if ni.label == label:
230+
ni.set_value(value).run()
231+
assert not at.exception, (
232+
f"Exception when setting {label}={value}"
233+
)
234+
break

0 commit comments

Comments
 (0)