diff --git a/internal/common/common.go b/internal/common/common.go index c4ca9fa..5444db5 100644 --- a/internal/common/common.go +++ b/internal/common/common.go @@ -27,12 +27,55 @@ func GetAnyAsInt(value any) (int, bool) { return int(byteValue), true } - floatValue, ok := value.(float64) + float32Value, ok := value.(float32) if ok { - if floatValue != math.Floor(floatValue) { + if float64(float32Value) != math.Floor(float64(float32Value)) { return 0, false } - return int(floatValue), true + return int(float32Value), true + } + + float64Value, ok := value.(float64) + if ok { + if float64Value != math.Floor(float64Value) { + return 0, false + } + return int(float64Value), true + } + return 0, false +} + +func GetAnyAsByte(value any) (byte, bool) { + + byteValue, ok := value.(byte) + if ok { + return byte(byteValue), true + } + + intValue, ok := value.(int) + if ok { + return byte(intValue), true + } + + uintValue, ok := value.(uint) + if ok { + return byte(uintValue), true + } + + float32Value, ok := value.(float32) + if ok { + if float64(float32Value) != math.Floor(float64(float32Value)) { + return 0, false + } + return byte(float32Value), true + } + + float64Value, ok := value.(float64) + if ok { + if float64Value != math.Floor(float64Value) { + return 0, false + } + return byte(float64Value), true } return 0, false } @@ -46,39 +89,11 @@ func GetAnyAsByteSlice(value any) ([]byte, bool) { result := make([]byte, v.Len()) for i := 0; i < v.Len(); i++ { elem := v.Index(i).Interface() - byteValue, ok := elem.(byte) - if ok { - result[i] = byteValue - continue + elemValue, ok := GetAnyAsByte(elem) + if !ok { + return nil, false } - uintValue, ok := elem.(uint) - if ok { - if uintValue > 255 { - return nil, false - } - result[i] = byte(uintValue) - continue - } - intValue, ok := elem.(int) - if ok { - if intValue < 0 || intValue > 255 { - return nil, false - } - result[i] = byte(intValue) - continue - } - floatValue, ok := elem.(float64) - if ok { - if floatValue != math.Floor(floatValue) { - return nil, false - } - if floatValue < 0 || floatValue > 255 { - return nil, false - } - result[i] = byte(floatValue) - continue - } - return nil, false + result[i] = elemValue } return result, true } @@ -92,30 +107,11 @@ func GetAnyAsIntSlice(value any) ([]int, bool) { result := make([]int, v.Len()) for i := 0; i < v.Len(); i++ { elem := v.Index(i).Interface() - byteValue, ok := elem.(byte) - if ok { - result[i] = int(byteValue) - continue + elemInt, ok := GetAnyAsInt(elem) + if !ok { + return nil, false } - uintValue, ok := elem.(uint) - if ok { - result[i] = int(uintValue) - continue - } - intValue, ok := elem.(int) - if ok { - result[i] = int(intValue) - continue - } - floatValue, ok := elem.(float64) - if ok { - if floatValue != math.Floor(floatValue) { - return nil, false - } - result[i] = int(floatValue) - continue - } - return nil, false + result[i] = elemInt } return result, true } diff --git a/internal/common/common_test.go b/internal/common/common_test.go new file mode 100644 index 0000000..28286fe --- /dev/null +++ b/internal/common/common_test.go @@ -0,0 +1,216 @@ +package common_test + +import ( + "slices" + "testing" + + "github.com/jwetzell/showbridge-go/internal/common" +) + +func TestGoodGetAnyAsInt(t *testing.T) { + testCases := []struct { + name string + value any + typedValue int + }{ + { + name: "int", + value: int(42), + typedValue: 42, + }, + { + name: "uint", + value: uint(42), + typedValue: 42, + }, + { + name: "float32 without decimal", + value: float32(42.0), + typedValue: 42, + }, + { + name: "float64 without decimal", + value: float64(42.0), + typedValue: 42, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + value, ok := common.GetAnyAsInt(testCase.value) + if !ok { + t.Fatalf("GetAnyAsInt expected to succeed but failed") + } + if value != testCase.typedValue { + t.Fatalf("GetAnyAsInt expected got %d, expected %d", value, testCase.typedValue) + } + }) + } +} + +func TestBadGetAnyAsInt(t *testing.T) { + testCases := []struct { + name string + value any + }{ + { + name: "string", + value: "value", + }, + { + name: "float with decimal", + value: 1.5, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + value, ok := common.GetAnyAsInt(testCase.value) + if ok { + t.Fatalf("GetAnyAsInt expected to fail but succeeded, got: %v", value) + } + }) + } +} + +func TestGoodGetAnyAsByteSlice(t *testing.T) { + testCases := []struct { + name string + value any + typedValue []byte + }{ + { + name: "byte slice", + value: []byte{1, 2, 3}, + typedValue: []byte{1, 2, 3}, + }, + { + name: "int slice", + value: []int{1, 2, 3}, + typedValue: []byte{1, 2, 3}, + }, + { + name: "uint slice", + value: []uint{1, 2, 3}, + typedValue: []byte{1, 2, 3}, + }, + { + name: "float32 without decimal slice", + value: []float32{1, 2, 3}, + typedValue: []byte{1, 2, 3}, + }, + { + name: "float64 without decimal slice", + value: []float64{1, 2, 3}, + typedValue: []byte{1, 2, 3}, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + value, ok := common.GetAnyAsByteSlice(testCase.value) + if !ok { + t.Fatalf("GetAnyAsByteSlice expected to succeed but failed") + } + if !slices.Equal(value, testCase.typedValue) { + t.Fatalf("GetAnyAsByteSlice expected got %d, expected %d", value, testCase.typedValue) + } + }) + } +} + +func TestBadGetAnyAsByteSlice(t *testing.T) { + testCases := []struct { + name string + value any + }{ + { + name: "not a slice", + value: "value", + }, + { + name: "not a int slice", + value: []any{"value1", 2}, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + value, ok := common.GetAnyAsByteSlice(testCase.value) + if ok { + t.Fatalf("GetAnyAsByteSlice expected to fail but succeeded, got: %v", value) + } + }) + } +} + +func TestGoodGetAnyAsIntSlice(t *testing.T) { + testCases := []struct { + name string + value any + typedValue []int + }{ + { + name: "int slice", + value: []int{1, 2, 3}, + typedValue: []int{1, 2, 3}, + }, + { + name: "byte slice", + value: []byte{1, 2, 3}, + typedValue: []int{1, 2, 3}, + }, + { + name: "uint slice", + value: []uint{1, 2, 3}, + typedValue: []int{1, 2, 3}, + }, + { + name: "float32 without decimal slice", + value: []float32{1, 2, 3}, + typedValue: []int{1, 2, 3}, + }, + { + name: "float64 without decimal slice", + value: []float64{1, 2, 3}, + typedValue: []int{1, 2, 3}, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + value, ok := common.GetAnyAsIntSlice(testCase.value) + if !ok { + t.Fatalf("GetAnyAsIntSlice expected to succeed but failed") + } + if !slices.Equal(value, testCase.typedValue) { + t.Fatalf("GetAnyAsIntSlice expected got %d, expected %d", value, testCase.typedValue) + } + }) + } +} + +func TestBadGetAnyAsIntSlice(t *testing.T) { + testCases := []struct { + name string + value any + }{ + { + name: "not a slice", + value: "value", + }, + { + name: "not a int slice", + value: []any{"value1", 2}, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + value, ok := common.GetAnyAsIntSlice(testCase.value) + if ok { + t.Fatalf("GetAnyAsIntSlice expected to fail but succeeded, got: %v", value) + } + }) + } +}