1package component
2
3import (
4 "testing"
5
6 layoutmocks "github.com/bnema/dumber/internal/ui/layout/mocks"
7 "github.com/stretchr/testify/assert"
8)
9
10func TestCalculateModalDimensions_NilParent(t *testing.T) {
11 cfg := ModalSizeConfig{
12 WidthPct: 0.6,
13 MaxWidth: 600,
14 TopMarginPct: 0.15,
15 FallbackWidth: 800,
16 FallbackHeight: 600,
17 }
18
19 width, marginTop := CalculateModalDimensions(nil, cfg)
20
21 // Should use fallback values
22 expectedWidth := int(float64(cfg.FallbackWidth) * cfg.WidthPct)
23 expectedMargin := int(float64(cfg.FallbackHeight) * cfg.TopMarginPct)
24
25 assert.Equal(t, expectedWidth, width)
26 assert.Equal(t, expectedMargin, marginTop)
27}
28
29func TestCalculateModalDimensions_ZeroAllocatedSize(t *testing.T) {
30 cfg := ModalSizeConfig{
31 WidthPct: 0.5,
32 MaxWidth: 500,
33 TopMarginPct: 0.2,
34 FallbackWidth: 1000,
35 FallbackHeight: 800,
36 }
37
38 parent := layoutmocks.NewMockOverlayWidget(t)
39 parent.EXPECT().GetAllocatedWidth().Return(0)
40 parent.EXPECT().GetAllocatedHeight().Return(0)
41
42 width, marginTop := CalculateModalDimensions(parent, cfg)
43
44 // Should use fallback values when allocated size is 0
45 expectedWidth := int(float64(cfg.FallbackWidth) * cfg.WidthPct)
46 expectedMargin := int(float64(cfg.FallbackHeight) * cfg.TopMarginPct)
47
48 assert.Equal(t, expectedWidth, width)
49 assert.Equal(t, expectedMargin, marginTop)
50}
51
52func TestCalculateModalDimensions_WidthCapped(t *testing.T) {
53 cfg := ModalSizeConfig{
54 WidthPct: 0.8,
55 MaxWidth: 600,
56 TopMarginPct: 0.1,
57 FallbackWidth: 800,
58 FallbackHeight: 600,
59 }
60
61 parent := layoutmocks.NewMockOverlayWidget(t)
62 parent.EXPECT().GetAllocatedWidth().Return(1920) // Large screen
63 parent.EXPECT().GetAllocatedHeight().Return(1080)
64
65 width, marginTop := CalculateModalDimensions(parent, cfg)
66
67 // 0.8 * 1920 = 1536, but capped at MaxWidth 600
68 assert.Equal(t, cfg.MaxWidth, width)
69 assert.Equal(t, int(float64(1080)*cfg.TopMarginPct), marginTop)
70}
71
72func TestCalculateModalDimensions_WidthPercentage(t *testing.T) {
73 cfg := ModalSizeConfig{
74 WidthPct: 0.6,
75 MaxWidth: 1000, // High cap, won't be hit
76 TopMarginPct: 0.15,
77 FallbackWidth: 800,
78 FallbackHeight: 600,
79 }
80
81 parent := layoutmocks.NewMockOverlayWidget(t)
82 parent.EXPECT().GetAllocatedWidth().Return(800)
83 parent.EXPECT().GetAllocatedHeight().Return(600)
84
85 width, marginTop := CalculateModalDimensions(parent, cfg)
86
87 assert.Equal(t, 480, width)
88 assert.Equal(t, 90, marginTop)
89}
90
91func TestCalculateModalDimensions_FixedWidthAndTopMargin(t *testing.T) {
92 cfg := ModalSizeConfig{
93 WidthPct: 0.8,
94 MaxWidth: 600,
95 TopMarginPct: 0.2,
96 FallbackWidth: 1000,
97 FallbackHeight: 800,
98 FixedWidth: 800,
99 FixedTopMargin: 0,
100 UseFixedTopMargin: true,
101 }
102
103 parent := layoutmocks.NewMockOverlayWidget(t)
104 parent.EXPECT().GetAllocatedWidth().Return(1920)
105 parent.EXPECT().GetAllocatedHeight().Return(1080)
106
107 width, marginTop := CalculateModalDimensions(parent, cfg)
108
109 assert.Equal(t, 800, width)
110 assert.Equal(t, 0, marginTop)
111}
112
113func TestResolveModalSizeConfig_MergesDefaultsAndOverrides(t *testing.T) {
114 defaults := OmniboxSizeDefaults
115 override := ModalSizeConfig{
116 FixedWidth: 800,
117 FixedTopMargin: 0,
118 UseFixedTopMargin: true,
119 }
120
121 resolved := ResolveModalSizeConfig(override, defaults)
122
123 assert.InDelta(t, defaults.WidthPct, resolved.WidthPct, 0)
124 assert.Equal(t, defaults.MaxWidth, resolved.MaxWidth)
125 assert.Equal(t, defaults.FallbackWidth, resolved.FallbackWidth)
126 assert.Equal(t, defaults.FallbackHeight, resolved.FallbackHeight)
127 assert.Equal(t, 800, resolved.FixedWidth)
128 assert.True(t, resolved.UseFixedTopMargin)
129 assert.Equal(t, 0, resolved.FixedTopMargin)
130}
131
132func TestScaleValue_DefaultScale(t *testing.T) {
133 // When scale is 0 or negative, should default to 1.0
134 assert.Equal(t, 50, ScaleValue(50, 0))
135 assert.Equal(t, 50, ScaleValue(50, -1.0))
136}
137
138func TestScaleValue_NormalScale(t *testing.T) {
139 assert.Equal(t, 50, ScaleValue(50, 1.0))
140}
141
142func TestScaleValue_Scaling(t *testing.T) {
143 // 1.5x scale
144 assert.Equal(t, 75, ScaleValue(50, 1.5))
145 // 2x scale
146 assert.Equal(t, 100, ScaleValue(50, 2.0))
147 // 1.2x scale (common UI scale)
148 assert.Equal(t, 60, ScaleValue(50, 1.2))
149}
150
151func TestMeasureWidgetHeight_NilWidget(t *testing.T) {
152 height := MeasureWidgetHeight(nil, 100)
153 assert.Equal(t, 0, height)
154}
155
156func TestDefaultRowHeights_Values(t *testing.T) {
157 // Ensure defaults are sensible
158 assert.Positive(t, DefaultRowHeights.Standard)
159 assert.Positive(t, DefaultRowHeights.Compact)
160 assert.Positive(t, DefaultRowHeights.Divider)
161 // Standard should be larger than compact
162 assert.Greater(t, DefaultRowHeights.Standard, DefaultRowHeights.Compact)
163}
164
165func TestOmniboxSizeDefaults_Values(t *testing.T) {
166 assert.InDelta(t, 0.8, OmniboxSizeDefaults.WidthPct, 0.0001)
167 assert.Equal(t, 800, OmniboxSizeDefaults.MaxWidth)
168 assert.InDelta(t, 0.2, OmniboxSizeDefaults.TopMarginPct, 0.0001)
169 assert.Equal(t, 600, OmniboxSizeDefaults.FallbackHeight)
170}
171
172func TestSessionManagerSizeDefaults_Values(t *testing.T) {
173 assert.Greater(t, SessionManagerSizeDefaults.WidthPct, 0.0)
174 assert.LessOrEqual(t, SessionManagerSizeDefaults.WidthPct, 1.0)
175 assert.Positive(t, SessionManagerSizeDefaults.MaxWidth)
176 assert.Greater(t, SessionManagerSizeDefaults.TopMarginPct, 0.0)
177 assert.LessOrEqual(t, SessionManagerSizeDefaults.TopMarginPct, 1.0)
178}
179
180func TestPermissionPopupSizeDefaults_Values(t *testing.T) {
181 assert.Greater(t, PermissionPopupSizeDefaults.WidthPct, 0.0)
182 assert.LessOrEqual(t, PermissionPopupSizeDefaults.WidthPct, 1.0)
183 assert.Positive(t, PermissionPopupSizeDefaults.MaxWidth)
184 assert.Greater(t, PermissionPopupSizeDefaults.TopMarginPct, 0.0)
185 assert.LessOrEqual(t, PermissionPopupSizeDefaults.TopMarginPct, 1.0)
186 assert.Equal(t, 300, PermissionPopupSizeDefaults.FallbackHeight)
187}
188
189func TestListDisplayDefaults_Values(t *testing.T) {
190 assert.Positive(t, OmniboxListDefaults.MaxVisibleRows)
191 assert.Positive(t, OmniboxListDefaults.MaxResults)
192 assert.Positive(t, SessionManagerListDefaults.MaxVisibleRows)
193 assert.Positive(t, SessionManagerListDefaults.MaxResults)
194}
195
196func TestEffectiveMaxRows(t *testing.T) {
197 sizeCfg := ModalSizeConfig{TopMarginPct: 0.2}
198 defaults := ListDisplayDefaults{
199 MaxVisibleRows: 10,
200 MaxResults: 10,
201 SmallMaxVisibleRows: 5,
202 }
203
204 tests := []struct {
205 name string
206 parentHeight int
207 rowHeight int
208 want int
209 }{
210 {
211 name: "tall pane returns MaxVisibleRows",
212 parentHeight: 1200,
213 rowHeight: 72,
214 want: 10,
215 },
216 {
217 name: "short pane returns SmallMaxVisibleRows",
218 parentHeight: 800,
219 rowHeight: 72,
220 want: 5,
221 },
222 {
223 name: "zero parentHeight returns MaxVisibleRows",
224 parentHeight: 0,
225 rowHeight: 72,
226 want: 10,
227 },
228 {
229 name: "zero rowHeight returns MaxVisibleRows",
230 parentHeight: 800,
231 rowHeight: 0,
232 want: 10,
233 },
234 {
235 name: "negative parentHeight returns MaxVisibleRows",
236 parentHeight: -100,
237 rowHeight: 72,
238 want: 10,
239 },
240 {
241 name: "exact fit returns MaxVisibleRows",
242 parentHeight: 1150, // available = 1150 - 230 - 144 = 776, needed = 720
243 rowHeight: 72,
244 want: 10,
245 },
246 {
247 name: "boundary: available equals needed still fits",
248 parentHeight: 1080, // available = 1080 - 216 - 144 = 720, needed = 720 → fits
249 rowHeight: 72,
250 want: 10,
251 },
252 {
253 name: "boundary: one pixel under triggers small",
254 parentHeight: 1079, // available = 1079 - 215 - 144 = 720, needed = 720 → check
255 rowHeight: 72,
256 want: 10, // int(1079*0.2) = 215, 1079-215-144 = 720 → still fits
257 },
258 {
259 name: "just below boundary triggers small",
260 parentHeight: 1078, // available = 1078 - 215 - 144 = 719, needed = 720 → doesn't fit
261 rowHeight: 72,
262 want: 5,
263 },
264 }
265
266 for _, tt := range tests {
267 t.Run(tt.name, func(t *testing.T) {
268 got := EffectiveMaxRows(tt.parentHeight, tt.rowHeight, sizeCfg, defaults)
269 assert.Equal(t, tt.want, got)
270 })
271 }
272}
273
274func TestEffectiveMaxRows_NoAdaptation(t *testing.T) {
275 sizeCfg := ModalSizeConfig{TopMarginPct: 0.2}
276 defaults := ListDisplayDefaults{
277 MaxVisibleRows: 10,
278 MaxResults: 10,
279 SmallMaxVisibleRows: 0, // adaptation disabled
280 }
281
282 // Even with a short pane, should return MaxVisibleRows when SmallMaxVisibleRows is 0
283 got := EffectiveMaxRows(500, 72, sizeCfg, defaults)
284 assert.Equal(t, 10, got)
285}