Skip to content

Commit

Permalink
adding StringOrFloat64
Browse files Browse the repository at this point in the history
moving CPULimit to use new type, added tests around all Or types and fixed regex to allow all floats to be used as Or types
  • Loading branch information
luthermonson committed Aug 9, 2023
1 parent 263c9df commit 0e07d02
Show file tree
Hide file tree
Showing 2 changed files with 324 additions and 18 deletions.
66 changes: 48 additions & 18 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package proxmox

import (
"encoding/json"
"fmt"
"math"
"regexp"
"strconv"
"strings"
Expand All @@ -11,7 +13,7 @@ import (
)

var (
numericRegex = regexp.MustCompile(`\d`)
isFloat = regexp.MustCompile(`^[0-9.]*$`)
)

type Credentials struct {
Expand Down Expand Up @@ -283,13 +285,13 @@ type VirtualMachineConfig struct {
Acpi int `json:"acpi,omitempty"`

// Qemu CPU specs
Sockets int `json:"sockets,omitempty"`
Cores int `json:"cores,omitempty"`
CPU string `json:"cpu,omitempty"`
CPULimit float32 `json:"cpulimit,omitempty"`
CPUUnits int `json:"cpuunits,omitempty"`
Vcpus int `json:"vcpus,omitempty"`
Affinity string `json:"affinity,omitempty"`
Sockets int `json:"sockets,omitempty"`
Cores int `json:"cores,omitempty"`
CPU string `json:"cpu,omitempty"`
CPULimit StringOrFloat64 `json:"cpulimit,omitempty"`
CPUUnits int `json:"cpuunits,omitempty"`
Vcpus int `json:"vcpus,omitempty"`
Affinity string `json:"affinity,omitempty"`

// Qemu memory specs
Numa int `json:"numa,omitempty"`
Expand Down Expand Up @@ -671,37 +673,65 @@ type StringOrInt int

func (d *StringOrInt) UnmarshalJSON(b []byte) error {
str := strings.Replace(string(b), "\"", "", -1)

numeric := numericRegex.MatchString(str)
if !numeric {
if str == "" {
*d = StringOrInt(0)
return nil
}

parsed, err := strconv.ParseUint(str, 0, 64)
if !isFloat.MatchString(str) {
return fmt.Errorf("failed to match %s: %s", isFloat.String(), str)
}

parsed, err := strconv.ParseFloat(str, 64)
if err != nil {
return err
}
*d = StringOrInt(parsed)

*d = StringOrInt(math.Trunc(parsed)) // truncate to make an int
return nil
}

type StringOrUint64 uint64

func (d *StringOrUint64) UnmarshalJSON(b []byte) error {
str := strings.Replace(string(b), "\"", "", -1)

numeric := numericRegex.MatchString(str)
if !numeric {
if str == "" {
*d = StringOrUint64(0)
return nil
}

parsed, err := strconv.ParseUint(str, 0, 64)
if !isFloat.MatchString(str) {
return fmt.Errorf("failed to match %s: %s", isFloat.String(), str)
}

parsed, err := strconv.ParseFloat(str, 64)
if err != nil {
return err
}

*d = StringOrUint64(math.Trunc(parsed)) // truncate to make an int

return nil
}

type StringOrFloat64 float64

func (d *StringOrFloat64) UnmarshalJSON(b []byte) error {
str := strings.Replace(string(b), "\"", "", -1)
if str == "" {
*d = StringOrFloat64(0)
return nil
}

if !isFloat.MatchString(str) {
return fmt.Errorf("failed to match %s: %s", isFloat.String(), str)
}

parsed, err := strconv.ParseFloat(str, 64)
if err != nil {
return err
}
*d = StringOrUint64(parsed)
*d = StringOrFloat64(parsed)
return nil
}

Expand Down
276 changes: 276 additions & 0 deletions types_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
package proxmox

import (
"encoding/json"
"errors"
"fmt"
"testing"

"github.com/stretchr/testify/assert"
)

func TestStringOrUint64(t *testing.T) {
cases := []struct {
input interface{}
expected StringOrUint64
err error
}{
{
"",
StringOrUint64(0),
nil,
}, {
"0",
StringOrUint64(0),
nil,
}, {
0,
StringOrUint64(0),
nil,
}, {
"00",
StringOrUint64(0),
nil,
}, {
"0.0",
StringOrUint64(0),
nil,
}, {
"1",
StringOrUint64(1),
nil,
}, {
1,
StringOrUint64(1),
nil,
}, {
"1.0",
StringOrUint64(1),
nil,
}, {
1.0,
StringOrUint64(1),
nil,
}, {
01,
StringOrUint64(1),
nil,
}, {
"01.0",
StringOrUint64(1),
nil,
}, {
01.0,
StringOrUint64(1),
nil,
}, {
0.1,
StringOrUint64(0),
nil,
}, {
"bad-parse-1234-value", // parse error
StringOrUint64(0),
errors.New("failed to match ^[0-9.]*$: bad-parse-1234-value"),
},
}

type s struct {
Value StringOrUint64
}

for _, test := range cases {
var value string
switch v := test.input.(type) {
case string:
value = fmt.Sprintf("\"%s\"", v)
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
value = fmt.Sprintf("%d", v)
default:
value = fmt.Sprintf("%f", v)
}
m := `{
"value": ` + value + `
}
`
var unmarshall s
assert.Equal(t, test.err, json.Unmarshal([]byte(m), &unmarshall))
assert.Equal(t, test.expected, unmarshall.Value)
}
}

func TestStringOrFloat64(t *testing.T) {
cases := []struct {
input interface{}
expected StringOrFloat64
err error
}{
{
"",
StringOrFloat64(0),
nil,
}, {
"0",
StringOrFloat64(0),
nil,
}, {
0,
StringOrFloat64(0),
nil,
}, {
"00",
StringOrFloat64(0),
nil,
}, {
"0.0",
StringOrFloat64(0),
nil,
}, {
"1",
StringOrFloat64(1),
nil,
}, {
1,
StringOrFloat64(1),
nil,
}, {
"1.0",
StringOrFloat64(1),
nil,
}, {
1.0,
StringOrFloat64(1),
nil,
}, {
01,
StringOrFloat64(1),
nil,
}, {
"01.0",
StringOrFloat64(1),
nil,
}, {
01.0,
StringOrFloat64(1),
nil,
}, {
0.1,
StringOrFloat64(0.1),
nil,
}, {
"bad-parse-1234-value", // parse error
StringOrFloat64(0),
errors.New("failed to match ^[0-9.]*$: bad-parse-1234-value"),
},
}

type s struct {
Value StringOrFloat64
}

for _, test := range cases {
var value string
switch v := test.input.(type) {
case string:
value = fmt.Sprintf("\"%s\"", v)
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
value = fmt.Sprintf("%d", v)
default:
value = fmt.Sprintf("%f", v)
}
m := `{
"value": ` + value + `
}
`
var unmarshall s
assert.Equal(t, test.err, json.Unmarshal([]byte(m), &unmarshall))
assert.Equal(t, test.expected, unmarshall.Value)
}
}
func TestStringOrInt(t *testing.T) {
cases := []struct {
input interface{}
expected StringOrInt
err error
}{
{
"",
StringOrInt(0),
nil,
}, {
"0",
StringOrInt(0),
nil,
}, {
0,
StringOrInt(0),
nil,
}, {
"00",
StringOrInt(0),
nil,
}, {
"0.0",
StringOrInt(0),
nil,
}, {
"1",
StringOrInt(1),
nil,
}, {
1,
StringOrInt(1),
nil,
}, {
"1.0",
StringOrInt(1),
nil,
}, {
1.0,
StringOrInt(1),
nil,
}, {
01,
StringOrInt(1),
nil,
}, {
"01.0",
StringOrInt(1),
nil,
}, {
01.0,
StringOrInt(1),
nil,
}, {
0.1,
StringOrInt(0),
nil,
}, {
"bad-parse-1234-value", // parse error
StringOrInt(0),
errors.New("failed to match ^[0-9.]*$: bad-parse-1234-value"),
},
}

type s struct {
Value StringOrInt
}

for _, test := range cases {
var value string
switch v := test.input.(type) {
case string:
value = fmt.Sprintf("\"%s\"", v)
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
value = fmt.Sprintf("%d", v)
default:
value = fmt.Sprintf("%f", v)
}
m := `{
"value": ` + value + `
}
`
var unmarshall s
assert.Equal(t, test.err, json.Unmarshal([]byte(m), &unmarshall))
assert.Equal(t, test.expected, unmarshall.Value)
}
}

0 comments on commit 0e07d02

Please sign in to comment.