@@ -228,3 +228,174 @@ func TestComputeSavings_Mixed(t *testing.T) {
228228 // Cost increase: 0.2 cores * $0.031/hr * 730 hrs = $4.53
229229 assert .Equal (t , "$4.53" , savings .EstimatedMonthlyCostIncrease )
230230}
231+
232+ // --- Defense-in-depth parsing helpers ---
233+
234+ func TestParseFloat64_ValidValue (t * testing.T ) {
235+ assert .Equal (t , 3.5 , parseFloat64 ("3.5" , 1.0 ))
236+ }
237+
238+ func TestParseFloat64_EmptyReturnsFallback (t * testing.T ) {
239+ assert .Equal (t , 1.0 , parseFloat64 ("" , 1.0 ))
240+ }
241+
242+ func TestParseFloat64_NaNReturnsFallback (t * testing.T ) {
243+ assert .Equal (t , 1.0 , parseFloat64 ("NaN" , 1.0 ))
244+ }
245+
246+ func TestParseFloat64_InfReturnsFallback (t * testing.T ) {
247+ assert .Equal (t , 1.0 , parseFloat64 ("Inf" , 1.0 ))
248+ }
249+
250+ func TestParseFloat64_NegativeInfReturnsFallback (t * testing.T ) {
251+ assert .Equal (t , 1.0 , parseFloat64 ("-Inf" , 1.0 ))
252+ }
253+
254+ func TestParseFloat64_NegativeReturnsFallback (t * testing.T ) {
255+ assert .Equal (t , 1.0 , parseFloat64 ("-0.5" , 1.0 ))
256+ }
257+
258+ func TestParseFloat64_ZeroReturnsFallback (t * testing.T ) {
259+ assert .Equal (t , 1.0 , parseFloat64 ("0" , 1.0 ))
260+ }
261+
262+ func TestParseFloat64_ExceedsMaxReturnsFallback (t * testing.T ) {
263+ assert .Equal (t , 1.0 , parseFloat64 ("11.0" , 1.0 ))
264+ }
265+
266+ func TestParseFloat64_BoundaryMaxAccepted (t * testing.T ) {
267+ assert .Equal (t , 10.0 , parseFloat64 ("10.0" , 1.0 ))
268+ }
269+
270+ func TestParseFloat64_InvalidStringReturnsFallback (t * testing.T ) {
271+ assert .Equal (t , 1.0 , parseFloat64 ("abc" , 1.0 ))
272+ }
273+
274+ func TestParseFloat64Ratio_ValidValue (t * testing.T ) {
275+ assert .Equal (t , 2.5 , parseFloat64Ratio ("2.5" ))
276+ }
277+
278+ func TestParseFloat64Ratio_EmptyReturnsZero (t * testing.T ) {
279+ assert .Equal (t , 0.0 , parseFloat64Ratio ("" ))
280+ }
281+
282+ func TestParseFloat64Ratio_NaNReturnsZero (t * testing.T ) {
283+ assert .Equal (t , 0.0 , parseFloat64Ratio ("NaN" ))
284+ }
285+
286+ func TestParseFloat64Ratio_InfReturnsZero (t * testing.T ) {
287+ assert .Equal (t , 0.0 , parseFloat64Ratio ("Inf" ))
288+ }
289+
290+ func TestParseFloat64Ratio_NegativeReturnsZero (t * testing.T ) {
291+ assert .Equal (t , 0.0 , parseFloat64Ratio ("-1.0" ))
292+ }
293+
294+ func TestParseFloat64Ratio_ExceedsMaxReturnsZero (t * testing.T ) {
295+ assert .Equal (t , 0.0 , parseFloat64Ratio ("1001" ))
296+ }
297+
298+ func TestParseFloat64Ratio_BoundaryMaxAccepted (t * testing.T ) {
299+ assert .Equal (t , 1000.0 , parseFloat64Ratio ("1000" ))
300+ }
301+
302+ func TestParseOverheadPercent_ValidValue (t * testing.T ) {
303+ assert .Equal (t , 20.0 , parseOverheadPercent ("20" , 15.0 ))
304+ }
305+
306+ func TestParseOverheadPercent_EmptyReturnsFallback (t * testing.T ) {
307+ assert .Equal (t , 15.0 , parseOverheadPercent ("" , 15.0 ))
308+ }
309+
310+ func TestParseOverheadPercent_NaNReturnsFallback (t * testing.T ) {
311+ assert .Equal (t , 15.0 , parseOverheadPercent ("NaN" , 15.0 ))
312+ }
313+
314+ func TestParseOverheadPercent_InfReturnsFallback (t * testing.T ) {
315+ assert .Equal (t , 15.0 , parseOverheadPercent ("Inf" , 15.0 ))
316+ }
317+
318+ func TestParseOverheadPercent_NegativeReturnsFallback (t * testing.T ) {
319+ assert .Equal (t , 15.0 , parseOverheadPercent ("-5" , 15.0 ))
320+ }
321+
322+ func TestParseOverheadPercent_ZeroIsValid (t * testing.T ) {
323+ assert .Equal (t , 0.0 , parseOverheadPercent ("0" , 15.0 ))
324+ }
325+
326+ func TestParseOverheadPercent_ExceedsMaxReturnsFallback (t * testing.T ) {
327+ assert .Equal (t , 15.0 , parseOverheadPercent ("901" , 15.0 ))
328+ }
329+
330+ func TestParseFloat64NonNeg_ValidValue (t * testing.T ) {
331+ assert .Equal (t , 0.5 , parseFloat64NonNeg ("0.5" , 0.1 ))
332+ }
333+
334+ func TestParseFloat64NonNeg_EmptyReturnsFallback (t * testing.T ) {
335+ assert .Equal (t , 0.1 , parseFloat64NonNeg ("" , 0.1 ))
336+ }
337+
338+ func TestParseFloat64NonNeg_NaNReturnsFallback (t * testing.T ) {
339+ assert .Equal (t , 0.1 , parseFloat64NonNeg ("NaN" , 0.1 ))
340+ }
341+
342+ func TestParseFloat64NonNeg_InfReturnsFallback (t * testing.T ) {
343+ assert .Equal (t , 0.1 , parseFloat64NonNeg ("Inf" , 0.1 ))
344+ }
345+
346+ func TestParseFloat64NonNeg_NegativeReturnsFallback (t * testing.T ) {
347+ assert .Equal (t , 0.1 , parseFloat64NonNeg ("-0.5" , 0.1 ))
348+ }
349+
350+ func TestParseFloat64NonNeg_ZeroIsValid (t * testing.T ) {
351+ assert .Equal (t , 0.0 , parseFloat64NonNeg ("0" , 0.1 ))
352+ }
353+
354+ func TestParseFloat64NonNeg_ExceedsOneCapsAtOne (t * testing.T ) {
355+ assert .Equal (t , 1.0 , parseFloat64NonNeg ("5.0" , 0.1 ))
356+ }
357+
358+ func TestParseFloat64NonNeg_ExactlyOneIsValid (t * testing.T ) {
359+ assert .Equal (t , 1.0 , parseFloat64NonNeg ("1.0" , 0.1 ))
360+ }
361+
362+ func TestScaleLimits_NormalCase (t * testing.T ) {
363+ // Current limit 1000m with request 500m gives ratio 2.0.
364+ // New request 250m * 2.0 = 500m new limit.
365+ result := scaleLimits (
366+ resource .MustParse ("500m" ),
367+ resource .MustParse ("1000m" ),
368+ resource .MustParse ("250m" ),
369+ )
370+ expected := resource .MustParse ("500m" )
371+ assert .True (t , result .Cmp (expected ) == 0 , "expected %s, got %s" , expected .String (), result .String ())
372+ }
373+
374+ func TestScaleLimits_ZeroRequestReturnsZero (t * testing.T ) {
375+ result := scaleLimits (
376+ resource .MustParse ("0" ),
377+ resource .MustParse ("1000m" ),
378+ resource .MustParse ("250m" ),
379+ )
380+ assert .True (t , result .IsZero ())
381+ }
382+
383+ func TestScaleLimits_ZeroLimitReturnsZero (t * testing.T ) {
384+ result := scaleLimits (
385+ resource .MustParse ("500m" ),
386+ resource .MustParse ("0" ),
387+ resource .MustParse ("250m" ),
388+ )
389+ assert .True (t , result .IsZero ())
390+ }
391+
392+ func TestScaleLimits_EqualRequestAndLimit (t * testing.T ) {
393+ // Ratio is 1.0 so new limit equals new request.
394+ result := scaleLimits (
395+ resource .MustParse ("500m" ),
396+ resource .MustParse ("500m" ),
397+ resource .MustParse ("300m" ),
398+ )
399+ expected := resource .MustParse ("300m" )
400+ assert .True (t , result .Cmp (expected ) == 0 , "expected %s, got %s" , expected .String (), result .String ())
401+ }
0 commit comments