Coverage for tests / test_widget_rendering.py: 99%

68 statements  

« prev     ^ index     » next       coverage.py v7.13.3, created at 2026-02-03 15:41 +0000

1import sys 

2 

3import types 

4import json 

5import pytest 

6 

7from tadkit.utils.ui import sanitize_default, WidgetFactory 

8 

9 

10# ===================================================== 

11# 1. Tests for sanitize_default 

12# ===================================================== 

13@pytest.mark.parametrize( 

14 "default,min_val,max_val,ptype,closed,expected", 

15 [ 

16 (5, 0, 10, int, "both", 5), # within range 

17 (-5, 0, 10, int, "both", 0), # below min -> clamp 

18 (15, 0, 10, int, "both", 10), # above max -> clamp 

19 (0, 0, 10, int, "right", 1), # closed=right shifts up 

20 (10, 0, 10, int, "left", 9), # closed=left shifts down 

21 (None, 0, 10, int, "both", 0), # None -> default to 0 

22 (0.5, 0.0, 1.0, float, "both", 0.5), # float ok 

23 (-0.5, 0.0, 1.0, float, "both", 0.0), # clamp float min 

24 (1.5, 0.0, 1.0, float, "both", 1.0), # clamp float max 

25 ], 

26) 

27def test_sanitize_default(default, min_val, max_val, ptype, closed, expected): 

28 result = sanitize_default(default, min_val, max_val, ptype, closed) 

29 assert ( 

30 abs(result - expected) < 1e-10 

31 if isinstance(result, float) 

32 else result == expected 

33 ) 

34 

35 

36def test_sanitize_default_allow_none(): 

37 assert sanitize_default(None, 0, 10, int, allow_none=True) is None 

38 

39 

40# ===================================================== 

41# 2. Tests for WidgetFactory (no_ui) 

42# ===================================================== 

43@pytest.fixture 

44def wf_no_ui(): 

45 return WidgetFactory(frontend="no_ui") 

46 

47 

48def test_make_numeric_no_ui(wf_no_ui): 

49 widget = wf_no_ui.make_numeric("Age", 25, 0, 100, int, "Age in years") 

50 assert widget["type"] == "number" 

51 assert widget["default"] == 25 

52 assert widget["min"] == 0 

53 assert widget["max"] == 100 

54 

55 

56def test_make_dropdown_no_ui(wf_no_ui): 

57 widget = wf_no_ui.make_dropdown("Color", ["red", "blue"], "blue", "Pick a color") 

58 assert widget["type"] == "dropdown" 

59 assert "blue" in widget["options"] 

60 

61 

62def test_make_text_no_ui(wf_no_ui): 

63 widget = wf_no_ui.make_text("Name", "Alice", "User name") 

64 assert widget["type"] == "text" 

65 assert widget["default"] == "Alice" 

66 

67 

68def test_make_dict_no_ui(wf_no_ui): 

69 d = {"a": 1} 

70 widget = wf_no_ui.make_dict("Config", d, "Settings dict") 

71 assert widget["type"] == "dict" 

72 assert widget["default"] == d 

73 

74 

75# ===================================================== 

76# 3. Tests for WidgetFactory (ipywidgets mocked) 

77# ===================================================== 

78@pytest.fixture 

79def wf_ipywidgets(monkeypatch): 

80 # Mock ipywidgets 

81 class DummyWidget: 

82 def __init__(self, **kwargs): 

83 self.kwargs = kwargs 

84 

85 class DummyLayout: 

86 def __init__(self, **kwargs): 

87 self.kwargs = kwargs 

88 

89 mock_widgets = types.SimpleNamespace( 

90 BoundedIntText=DummyWidget, 

91 BoundedFloatText=DummyWidget, 

92 Dropdown=DummyWidget, 

93 Text=DummyWidget, 

94 Textarea=DummyWidget, 

95 Layout=DummyLayout, 

96 ) 

97 monkeypatch.setitem(sys.modules, "ipywidgets", mock_widgets) 

98 return WidgetFactory(frontend="ipywidgets") 

99 

100 

101def test_make_numeric_ipywidgets(wf_ipywidgets): 

102 widget = wf_ipywidgets.make_numeric("Num", 5, 0, 10, int, "desc") 

103 assert hasattr(widget, "kwargs") 

104 assert widget.kwargs["value"] == 5 

105 

106 

107def test_make_dropdown_ipywidgets(wf_ipywidgets): 

108 widget = wf_ipywidgets.make_dropdown("Choice", ["a", "b"], "a", "desc") 

109 assert "value" in widget.kwargs 

110 assert widget.kwargs["value"] == "a" 

111 

112 

113# ===================================================== 

114# 4. Tests for WidgetFactory (Streamlit mocked) 

115# ===================================================== 

116@pytest.fixture 

117def wf_streamlit(monkeypatch): 

118 mock_st = types.SimpleNamespace( 

119 number_input=lambda **kw: kw, 

120 selectbox=lambda *a, **kw: kw, 

121 text_input=lambda *a, **kw: kw, 

122 text_area=lambda *a, **kw: kw, 

123 ) 

124 monkeypatch.setitem(sys.modules, "streamlit", mock_st) 

125 return WidgetFactory(frontend="st") 

126 

127 

128def test_make_numeric_streamlit(wf_streamlit): 

129 widget = wf_streamlit.make_numeric("Num", 5, 0, 10, int, "desc") 

130 assert "value" in widget 

131 assert widget["value"] == 5 

132 

133 

134def test_make_text_streamlit(wf_streamlit): 

135 widget = wf_streamlit.make_text("Name", "Bob", "desc") 

136 assert widget["value"] == "Bob" 

137 

138 

139def test_make_dict_streamlit(wf_streamlit): 

140 widget = wf_streamlit.make_dict("Config", {"x": 1}, "desc") 

141 assert "value" in widget 

142 json.loads(widget["value"]) # should be valid JSON