Add unit tests for coerceUint64 and FlexInt.UnmarshalJSON

45 test cases covering:
- FlexInt: integer/float/string parsing, truncation behavior, error cases
- coerceUint64: nil, float64 (including NaN/Inf), int/int32/int64,
  uint32/uint64, json.Number, string parsing (whitespace, null, quotes,
  commas, scientific notation), unsupported types

Coverage: 20.5% -> 22.6%
This commit is contained in:
rcourtman 2025-11-30 02:17:52 +00:00
parent 6267554b74
commit ae3ffc0355

View file

@ -3,6 +3,7 @@ package proxmox
import (
"encoding/json"
"fmt"
"math"
"testing"
)
@ -246,6 +247,326 @@ func TestMemoryStatusUnmarshalFlexibleValues(t *testing.T) {
}
}
func TestFlexIntUnmarshalJSON(t *testing.T) {
tests := []struct {
name string
input string
want FlexInt
wantErr bool
}{
{
name: "integer",
input: "42",
want: FlexInt(42),
},
{
name: "zero",
input: "0",
want: FlexInt(0),
},
{
name: "negative integer",
input: "-10",
want: FlexInt(-10),
},
{
name: "float truncates",
input: "1.5",
want: FlexInt(1),
},
{
name: "float 2.9 truncates",
input: "2.9",
want: FlexInt(2),
},
{
name: "string integer",
input: `"123"`,
want: FlexInt(123),
},
{
name: "string float",
input: `"1.5"`,
want: FlexInt(1),
},
{
name: "string float 3.7",
input: `"3.7"`,
want: FlexInt(3),
},
{
name: "large integer",
input: "1000000",
want: FlexInt(1000000),
},
{
name: "invalid string",
input: `"not a number"`,
wantErr: true,
},
{
name: "empty string",
input: `""`,
wantErr: true,
},
{
name: "invalid json",
input: `{invalid}`,
wantErr: true,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
var f FlexInt
err := f.UnmarshalJSON([]byte(tc.input))
if tc.wantErr {
if err == nil {
t.Fatalf("expected error, got nil")
}
return
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if f != tc.want {
t.Fatalf("got %d, want %d", f, tc.want)
}
})
}
}
func TestCoerceUint64(t *testing.T) {
tests := []struct {
name string
field string
value interface{}
want uint64
wantErr bool
}{
// nil handling
{
name: "nil returns zero",
field: "test",
value: nil,
want: 0,
},
// float64 handling
{
name: "float64 positive",
field: "test",
value: float64(100.0),
want: 100,
},
{
name: "float64 rounds",
field: "test",
value: float64(100.6),
want: 101,
},
{
name: "float64 negative returns zero",
field: "test",
value: float64(-10),
want: 0,
},
{
name: "float64 zero",
field: "test",
value: float64(0),
want: 0,
},
{
name: "float64 NaN returns error",
field: "test",
value: math.NaN(),
wantErr: true,
},
{
name: "float64 positive infinity returns error",
field: "test",
value: math.Inf(1),
wantErr: true,
},
// int handling
{
name: "int positive",
field: "test",
value: int(42),
want: 42,
},
{
name: "int negative returns zero",
field: "test",
value: int(-5),
want: 0,
},
{
name: "int zero",
field: "test",
value: int(0),
want: 0,
},
// int64 handling
{
name: "int64 positive",
field: "test",
value: int64(1000000000000),
want: 1000000000000,
},
{
name: "int64 negative returns zero",
field: "test",
value: int64(-100),
want: 0,
},
// int32 handling
{
name: "int32 positive",
field: "test",
value: int32(12345),
want: 12345,
},
{
name: "int32 negative returns zero",
field: "test",
value: int32(-1),
want: 0,
},
// uint32 handling
{
name: "uint32",
field: "test",
value: uint32(4294967295),
want: 4294967295,
},
// uint64 handling
{
name: "uint64",
field: "test",
value: uint64(18446744073709551615),
want: 18446744073709551615,
},
// json.Number handling
{
name: "json.Number integer",
field: "test",
value: json.Number("12345"),
want: 12345,
},
{
name: "json.Number float",
field: "test",
value: json.Number("123.45"),
want: 123,
},
// string handling
{
name: "string integer",
field: "test",
value: "12345",
want: 12345,
},
{
name: "string with whitespace",
field: "test",
value: " 12345 ",
want: 12345,
},
{
name: "string empty",
field: "test",
value: "",
want: 0,
},
{
name: "string null",
field: "test",
value: "null",
want: 0,
},
{
name: "string NULL uppercase",
field: "test",
value: "NULL",
want: 0,
},
{
name: "string with quotes",
field: "test",
value: `"12345"`,
want: 12345,
},
{
name: "string with single quotes",
field: "test",
value: `'12345'`,
want: 12345,
},
{
name: "string with commas",
field: "test",
value: "1,000,000",
want: 1000000,
},
{
name: "string float notation",
field: "test",
value: "123.45",
want: 123,
},
{
name: "string scientific notation",
field: "test",
value: "1e6",
want: 1000000,
},
{
name: "string scientific notation uppercase",
field: "test",
value: "1E6",
want: 1000000,
},
{
name: "string invalid",
field: "test",
value: "not a number",
wantErr: true,
},
// unsupported type
{
name: "unsupported type bool",
field: "test",
value: true,
wantErr: true,
},
{
name: "unsupported type slice",
field: "test",
value: []int{1, 2, 3},
wantErr: true,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got, err := coerceUint64(tc.field, tc.value)
if tc.wantErr {
if err == nil {
t.Fatalf("expected error, got nil")
}
return
}
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got != tc.want {
t.Fatalf("got %d, want %d", got, tc.want)
}
})
}
}
// TestMemoryStatusEffectiveAvailable_RegressionIssue435 tests the specific scenarios
// reported in GitHub issue #435 where memory calculations incorrectly included cache/buffers
func TestMemoryStatusEffectiveAvailable_RegressionIssue435(t *testing.T) {