diff --git a/convert.go b/conv/convert.go similarity index 50% rename from convert.go rename to conv/convert.go index fc085ae..b7238ac 100644 --- a/convert.go +++ b/conv/convert.go @@ -12,12 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package swag +package conv import ( "math" "strconv" "strings" + "unsafe" ) // same as ECMA Number.MAX_SAFE_INTEGER and Number.MIN_SAFE_INTEGER @@ -27,7 +28,7 @@ const ( epsilon float64 = 1e-9 ) -// IsFloat64AJSONInteger allow for integers [-2^53, 2^53-1] inclusive +// IsFloat64AJSONInteger allows for integers [-2^53, 2^53-1] inclusive. func IsFloat64AJSONInteger(f float64) bool { if math.IsNaN(f) || math.IsInf(f, 0) || f < minJSONFloat || f > maxJSONFloat { return false @@ -51,53 +52,77 @@ func IsFloat64AJSONInteger(f float64) bool { return diff/math.Min(fa+ga, math.MaxFloat64) < epsilon } -var evaluatesAsTrue map[string]struct{} - -func init() { - evaluatesAsTrue = map[string]struct{}{ - "true": {}, - "1": {}, - "yes": {}, - "ok": {}, - "y": {}, - "on": {}, - "selected": {}, - "checked": {}, - "t": {}, - "enabled": {}, +// ConvertFloat turns a string into a float numerical value. +func ConvertFloat[T Float](str string) (T, error) { + // NOTE: [unsafe.SizeOf] simply returns the size in bytes of the value. + // For primitive types T, the generic stencil is precompiled and this value + // is resolved at compile time, resulting in an immediate call to [strconv.ParseFloat]. + var v T + f, err := strconv.ParseFloat(str, int(unsafe.Sizeof(v))*8) + if err != nil { + return 0, err } -} -// ConvertBool turn a string into a boolean -func ConvertBool(str string) (bool, error) { - _, ok := evaluatesAsTrue[strings.ToLower(str)] - return ok, nil + return T(f), nil } -// ConvertFloat32 turn a string into a float32 -func ConvertFloat32(str string) (float32, error) { - f, err := strconv.ParseFloat(str, 32) +// ConvertInteger turns a string into a signed integer. +func ConvertInteger[T Signed](str string) (T, error) { + var v T + f, err := strconv.ParseInt(str, 10, int(unsafe.Sizeof(v))*8) if err != nil { return 0, err } - return float32(f), nil -} -// ConvertFloat64 turn a string into a float64 -func ConvertFloat64(str string) (float64, error) { - return strconv.ParseFloat(str, 64) + return T(f), nil } -// ConvertInt8 turn a string into an int8 -func ConvertInt8(str string) (int8, error) { - i, err := strconv.ParseInt(str, 10, 8) +// ConvertUinteger turns a string into an unsigned integer. +func ConvertUinteger[T Unsigned](str string) (T, error) { + var v T + f, err := strconv.ParseUint(str, 10, int(unsafe.Sizeof(v))*8) if err != nil { return 0, err } - return int8(i), nil + + return T(f), nil } -// ConvertInt16 turn a string into an int16 +// ConvertBool turns a string into a boolean. +// +// It supports a few more "true" strings than [strconv.ParseBool]: +// +// - it is not case sensitive ("trUe" or "FalsE" work) +// - "ok", "yes", "y", "on", "selected", "checked", "enabled" are all true +// - everything that is not true is false: there is never an actual error returned +func ConvertBool(str string) (bool, error) { + switch strings.ToLower(str) { + case "true", + "1", + "yes", + "ok", + "y", + "on", + "selected", + "checked", + "t", + "enabled": + return true, nil + default: + return false, nil + } +} + +// ConvertFloat32 turns a string into a float32. +func ConvertFloat32(str string) (float32, error) { return ConvertFloat[float32](str) } + +// ConvertFloat64 turns a string into a float64 +func ConvertFloat64(str string) (float64, error) { return ConvertFloat[float64](str) } + +// ConvertInt8 turns a string into an int8 +func ConvertInt8(str string) (int8, error) { return ConvertInteger[int8](str) } + +// ConvertInt16 turns a string into an int16 func ConvertInt16(str string) (int16, error) { i, err := strconv.ParseInt(str, 10, 16) if err != nil { @@ -106,7 +131,7 @@ func ConvertInt16(str string) (int16, error) { return int16(i), nil } -// ConvertInt32 turn a string into an int32 +// ConvertInt32 turns a string into an int32 func ConvertInt32(str string) (int32, error) { i, err := strconv.ParseInt(str, 10, 32) if err != nil { @@ -115,12 +140,12 @@ func ConvertInt32(str string) (int32, error) { return int32(i), nil } -// ConvertInt64 turn a string into an int64 +// ConvertInt64 turns a string into an int64 func ConvertInt64(str string) (int64, error) { return strconv.ParseInt(str, 10, 64) } -// ConvertUint8 turn a string into an uint8 +// ConvertUint8 turns a string into an uint8 func ConvertUint8(str string) (uint8, error) { i, err := strconv.ParseUint(str, 10, 8) if err != nil { @@ -129,7 +154,7 @@ func ConvertUint8(str string) (uint8, error) { return uint8(i), nil } -// ConvertUint16 turn a string into an uint16 +// ConvertUint16 turns a string into an uint16 func ConvertUint16(str string) (uint16, error) { i, err := strconv.ParseUint(str, 10, 16) if err != nil { @@ -138,7 +163,7 @@ func ConvertUint16(str string) (uint16, error) { return uint16(i), nil } -// ConvertUint32 turn a string into an uint32 +// ConvertUint32 turns a string into an uint32 func ConvertUint32(str string) (uint32, error) { i, err := strconv.ParseUint(str, 10, 32) if err != nil { @@ -147,62 +172,7 @@ func ConvertUint32(str string) (uint32, error) { return uint32(i), nil } -// ConvertUint64 turn a string into an uint64 +// ConvertUint64 turns a string into an uint64 func ConvertUint64(str string) (uint64, error) { return strconv.ParseUint(str, 10, 64) } - -// FormatBool turns a boolean into a string -func FormatBool(value bool) string { - return strconv.FormatBool(value) -} - -// FormatFloat32 turns a float32 into a string -func FormatFloat32(value float32) string { - return strconv.FormatFloat(float64(value), 'f', -1, 32) -} - -// FormatFloat64 turns a float64 into a string -func FormatFloat64(value float64) string { - return strconv.FormatFloat(value, 'f', -1, 64) -} - -// FormatInt8 turns an int8 into a string -func FormatInt8(value int8) string { - return strconv.FormatInt(int64(value), 10) -} - -// FormatInt16 turns an int16 into a string -func FormatInt16(value int16) string { - return strconv.FormatInt(int64(value), 10) -} - -// FormatInt32 turns an int32 into a string -func FormatInt32(value int32) string { - return strconv.Itoa(int(value)) -} - -// FormatInt64 turns an int64 into a string -func FormatInt64(value int64) string { - return strconv.FormatInt(value, 10) -} - -// FormatUint8 turns an uint8 into a string -func FormatUint8(value uint8) string { - return strconv.FormatUint(uint64(value), 10) -} - -// FormatUint16 turns an uint16 into a string -func FormatUint16(value uint16) string { - return strconv.FormatUint(uint64(value), 10) -} - -// FormatUint32 turns an uint32 into a string -func FormatUint32(value uint32) string { - return strconv.FormatUint(uint64(value), 10) -} - -// FormatUint64 turns an uint64 into a string -func FormatUint64(value uint64) string { - return strconv.FormatUint(value, 10) -} diff --git a/conv/convert_format_test.go b/conv/convert_format_test.go new file mode 100644 index 0000000..662e061 --- /dev/null +++ b/conv/convert_format_test.go @@ -0,0 +1,393 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package conv + +import ( + "fmt" + "io" + "math" + "math/big" + "slices" + "strconv" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var evaluatesAsTrue = map[string]struct{}{ + "true": {}, + "1": {}, + "yes": {}, + "ok": {}, + "y": {}, + "on": {}, + "selected": {}, + "checked": {}, + "t": {}, + "enabled": {}, +} + +func TestConvertBool(t *testing.T) { + for k := range evaluatesAsTrue { + r, err := ConvertBool(k) + require.NoError(t, err) + assert.True(t, r) + } + for _, k := range []string{"a", "", "0", "false", "unchecked", "anythingElse"} { + r, err := ConvertBool(k) + require.NoError(t, err) + assert.False(t, r) + } +} + +func TestFormatBool(t *testing.T) { + assert.Equal(t, "true", FormatBool(true)) + assert.Equal(t, "false", FormatBool(false)) +} + +func TestConvertFloat(t *testing.T) { + t.Run("with float32", func(t *testing.T) { + validFloats := []float32{1.0, -1, math.MaxFloat32, math.SmallestNonzeroFloat32, 0, 5.494430303} + invalidFloats := []string{"a", strconv.FormatFloat(math.MaxFloat64, 'f', -1, 64), "true", float64OverflowStr()} + + for _, f := range validFloats { + str := FormatFloat(f) + c1, err := ConvertFloat32(str) + require.NoError(t, err) + assert.InDelta(t, f, c1, 1e-6) + + c2, err := ConvertFloat[float32](str) + require.NoError(t, err) + assert.InDelta(t, c1, c2, 1e-6) + } + + for _, f := range invalidFloats { + _, err := ConvertFloat32(f) + require.Error(t, err, testErrMsg(f)) + + _, err = ConvertFloat[float32](f) + require.Error(t, err, testErrMsg(f)) + } + }) + + t.Run("with float64", func(t *testing.T) { + validFloats := []float64{1.0, -1, float64(math.MaxFloat32), float64(math.SmallestNonzeroFloat32), math.MaxFloat64, math.SmallestNonzeroFloat64, 0, 5.494430303} + invalidFloats := []string{"a", "true", float64OverflowStr()} + + for _, f := range validFloats { + str := FormatFloat(f) + c1, err := ConvertFloat64(str) + require.NoError(t, err) + assert.InDelta(t, f, c1, 1e-6) + + c2, err := ConvertFloat64(str) + require.NoError(t, err) + assert.InDelta(t, c1, c2, 1e-6) + } + + for _, f := range invalidFloats { + _, err := ConvertFloat64(f) + require.Error(t, err, testErrMsg(f)) + + _, err = ConvertFloat[float64](f) + require.Error(t, err, testErrMsg(f)) + } + }) +} + +func TestConvertInteger(t *testing.T) { + t.Run("with int8", func(t *testing.T) { + validInts := []int8{0, 1, -1, math.MaxInt8, math.MinInt8} + invalidInts := []string{"1.233", "a", "false", strconv.FormatInt(int64(math.MaxInt64), 10)} + + for _, f := range validInts { + str := FormatInteger(f) + c1, err := ConvertInt8(str) + require.NoError(t, err) + assert.Equal(t, f, c1) + + c2, err := ConvertInteger[int8](str) + require.NoError(t, err) + assert.Equal(t, c1, c2) + } + + for _, f := range invalidInts { + _, err := ConvertInt8(f) + require.Error(t, err, testErrMsg(f)) + + _, err = ConvertInteger[int8](f) + require.Error(t, err, testErrMsg(f)) + } + }) + + t.Run("with int16", func(t *testing.T) { + validInts := []int16{0, 1, -1, math.MaxInt8, math.MinInt8, math.MaxInt16, math.MinInt16} + invalidInts := []string{"1.233", "a", "false", strconv.FormatInt(int64(math.MaxInt64), 10)} + + for _, f := range validInts { + str := FormatInteger(f) + c1, err := ConvertInt16(str) + require.NoError(t, err) + assert.Equal(t, f, c1) + + c2, err := ConvertInteger[int16](str) + require.NoError(t, err) + assert.Equal(t, c1, c2) + } + + for _, f := range invalidInts { + _, err := ConvertInt16(f) + require.Error(t, err, testErrMsg(f)) + + _, err = ConvertInteger[int16](f) + require.Error(t, err, testErrMsg(f)) + } + }) + + t.Run("with int32", func(t *testing.T) { + validInts := []int32{0, 1, -1, math.MaxInt8, math.MinInt8, math.MaxInt16, math.MinInt16, math.MinInt32, math.MaxInt32} + invalidInts := []string{"1.233", "a", "false", strconv.FormatInt(int64(math.MaxInt64), 10)} + + for _, f := range validInts { + str := FormatInteger(f) + c1, err := ConvertInt32(str) + require.NoError(t, err) + assert.Equal(t, f, c1) + + c2, err := ConvertInteger[int32](str) + require.NoError(t, err) + assert.Equal(t, c1, c2) + } + + for _, f := range invalidInts { + _, err := ConvertInt32(f) + require.Error(t, err, testErrMsg(f)) + + _, err = ConvertInteger[int32](f) + require.Error(t, err, testErrMsg(f)) + } + }) + + t.Run("with int64", func(t *testing.T) { + validInts := []int64{0, 1, -1, math.MaxInt8, math.MinInt8, math.MaxInt16, math.MinInt16, math.MinInt32, math.MaxInt32, math.MaxInt64, math.MinInt64} + invalidInts := []string{"1.233", "a", "false"} + + for _, f := range validInts { + str := FormatInteger(f) + c1, err := ConvertInt64(str) + require.NoError(t, err) + assert.Equal(t, f, c1) + + c2, err := ConvertInt64(str) + require.NoError(t, err) + assert.Equal(t, c1, c2) + } + + for _, f := range invalidInts { + _, err := ConvertInt64(f) + require.Error(t, err, testErrMsg(f)) + + _, err = ConvertInteger[int64](f) + require.Error(t, err, testErrMsg(f)) + } + }) +} + +func TestConvertUinteger(t *testing.T) { + t.Run("with uint8", func(t *testing.T) { + validInts := []uint8{0, 1, math.MaxUint8} + invalidInts := []string{"1.233", "a", "false", strconv.FormatUint(math.MaxUint64, 10), "-1"} + + for _, f := range validInts { + str := FormatUinteger(f) + c1, err := ConvertUint8(str) + require.NoError(t, err) + assert.Equal(t, f, c1) + + c2, err := ConvertUinteger[uint8](str) + require.NoError(t, err) + assert.Equal(t, c1, c2) + } + + for _, f := range invalidInts { + _, err := ConvertUint8(f) + require.Error(t, err, testErrMsg(f)) + + _, err = ConvertUinteger[uint8](f) + require.Error(t, err, testErrMsg(f)) + } + }) + + t.Run("with uint16", func(t *testing.T) { + validUints := []uint16{0, 1, math.MaxUint8, math.MaxUint16} + invalidUints := []string{"1.233", "a", "false", strconv.FormatUint(math.MaxUint64, 10), strconv.FormatInt(-1, 10)} + + for _, f := range validUints { + str := FormatUinteger(f) + c1, err := ConvertUint16(str) + require.NoError(t, err) + assert.Equal(t, f, c1) + + c2, err := ConvertUinteger[uint16](str) + require.NoError(t, err) + assert.Equal(t, c1, c2) + } + + for _, f := range invalidUints { + _, err := ConvertUint16(f) + require.Error(t, err, testErrMsg(f)) + + _, err = ConvertUinteger[uint16](f) + require.Error(t, err, testErrMsg(f)) + } + }) + + t.Run("with uint32", func(t *testing.T) { + validUints := []uint32{0, 1, math.MaxUint8, math.MaxUint16, math.MaxUint32} + invalidUints := []string{"1.233", "a", "false", strconv.FormatUint(math.MaxUint64, 10), strconv.FormatInt(-1, 10)} + + for _, f := range validUints { + str := FormatUinteger(f) + c1, err := ConvertUint32(str) + require.NoError(t, err) + assert.Equal(t, f, c1) + + c2, err := ConvertUint32(str) + require.NoError(t, err) + assert.Equal(t, c1, c2) + } + + for _, f := range invalidUints { + _, err := ConvertUint32(f) + require.Error(t, err, testErrMsg(f)) + + _, err = ConvertUinteger[uint32](f) + require.Error(t, err, testErrMsg(f)) + } + }) + + t.Run("with uint64", func(t *testing.T) { + validUints := []uint64{0, 1, math.MaxUint8, math.MaxUint16, math.MaxUint32, math.MaxUint64} + invalidUints := []string{"1.233", "a", "false", strconv.FormatInt(-1, 10), uint64OverflowStr()} + + for _, f := range validUints { + str := FormatUinteger(f) + c1, err := ConvertUint64(str) + require.NoError(t, err) + assert.Equal(t, f, c1) + + c2, err := ConvertUinteger[uint64](str) + require.NoError(t, err) + assert.Equal(t, c1, c2) + } + for _, f := range invalidUints { + _, err := ConvertUint64(f) + require.Error(t, err, testErrMsg(f)) + + _, err = ConvertUinteger[uint64](f) + require.Error(t, err, testErrMsg(f)) + } + }) +} + +func TestIsFloat64AJSONInteger(t *testing.T) { + assert.False(t, IsFloat64AJSONInteger(math.Inf(1))) + assert.False(t, IsFloat64AJSONInteger(maxJSONFloat+1)) + assert.False(t, IsFloat64AJSONInteger(minJSONFloat-1)) + assert.False(t, IsFloat64AJSONInteger(math.SmallestNonzeroFloat64)) + + assert.True(t, IsFloat64AJSONInteger(1.0)) + assert.True(t, IsFloat64AJSONInteger(maxJSONFloat)) + assert.True(t, IsFloat64AJSONInteger(minJSONFloat)) + assert.True(t, IsFloat64AJSONInteger(1/0.01*67.15000001)) + assert.True(t, IsFloat64AJSONInteger(math.SmallestNonzeroFloat64/2)) + assert.True(t, IsFloat64AJSONInteger(math.SmallestNonzeroFloat64/3)) + assert.True(t, IsFloat64AJSONInteger(math.SmallestNonzeroFloat64/4)) +} + +// test utilities + +func testErrMsg(f string) string { + const ( + expectedQuote = "expected '" + errSuffix = "' to generate an error" + ) + + return expectedQuote + f + errSuffix +} + +func uint64OverflowStr() string { + var one, maxUint, overflow big.Int + one.SetUint64(1) + maxUint.SetUint64(math.MaxUint64) + overflow.Add(&maxUint, &one) + + return overflow.String() +} + +func float64OverflowStr() string { + var one, maxFloat64, overflow big.Float + one.SetFloat64(1.00) + maxFloat64.SetFloat64(math.MaxFloat64) + overflow.Add(&maxFloat64, &one) + + return overflow.String() +} + +// benchmarks +func BenchmarkConvertBool(b *testing.B) { + inputs := []string{ + "a", "t", "ok", "false", "true", "TRUE", "no", "n", "y", + } + var isTrue bool + + b.ReportAllocs() + b.ResetTimer() + + b.Run("use switch", func(b *testing.B) { + for i := 0; i < b.N; i++ { + isTrue, _ = ConvertBool(inputs[i%len(inputs)]) + } + fmt.Fprintln(io.Discard, isTrue) + }) + + b.Run("use map (previous version)", func(b *testing.B) { + previousConvertBool := func(str string) (bool, error) { + _, ok := evaluatesAsTrue[strings.ToLower(str)] + return ok, nil + } + + for i := 0; i < b.N; i++ { + isTrue, _ = previousConvertBool(inputs[i%len(inputs)]) + } + fmt.Fprintln(io.Discard, isTrue) + }) + + b.Run("use slice.Contains", func(b *testing.B) { + sliceContainsConvertBool := func(str string) (bool, error) { + return slices.Contains( + []string{"true", "1", "yes", "ok", "y", "on", "selected", "checked", "t", "enabled"}, + strings.ToLower(str), + ), nil + } + + for i := 0; i < b.N; i++ { + isTrue, _ = sliceContainsConvertBool(inputs[i%len(inputs)]) + } + fmt.Fprintln(io.Discard, isTrue) + }) +} diff --git a/conv/convert_types.go b/conv/convert_types.go new file mode 100644 index 0000000..423e866 --- /dev/null +++ b/conv/convert_types.go @@ -0,0 +1,79 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package conv + +// The original version of this file, eons ago, was taken from the aws go sdk + +// Pointer returns a pointer to the value passed in. +func Pointer[T any](v T) *T { + return &v +} + +// Value returns a shallow copy of the value of the pointer passed in. +// +// If the pointer is nil, the returned value is the zero value. +func Value[T any](v *T) T { + if v != nil { + return *v + } + + var zero T + return zero +} + +// PointerSlice converts a slice of values into a slice of pointers. +func PointerSlice[T any](src []T) []*T { + dst := make([]*T, len(src)) + for i := 0; i < len(src); i++ { + dst[i] = &(src[i]) + } + return dst +} + +// ValueSlice converts a slice of pointers into a slice of values. +// +// nil elements are zero values. +func ValueSlice[T any](src []*T) []T { + dst := make([]T, len(src)) + for i := 0; i < len(src); i++ { + if src[i] != nil { + dst[i] = *(src[i]) + } + } + return dst +} + +// PointerMap converts a map of values into a map of pointers. +func PointerMap[K comparable, T any](src map[K]T) map[K]*T { + dst := make(map[K]*T) + for k, val := range src { + v := val + dst[k] = &v + } + return dst +} + +// ValueMap converts a map of pointers into a map of values. +// +// nil elements are skipped. +func ValueMap[K comparable, T any](src map[K]*T) map[K]T { + dst := make(map[K]T) + for k, val := range src { + if val != nil { + dst[k] = *val + } + } + return dst +} diff --git a/conv/convert_types_test.go b/conv/convert_types_test.go new file mode 100644 index 0000000..49b2444 --- /dev/null +++ b/conv/convert_types_test.go @@ -0,0 +1,211 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package conv + +import ( + "reflect" + "testing" + + "github.com/go-openapi/swag/typeutils" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const ( + wantsPointer = true + wantsValue = false +) + +func TestSlice(t *testing.T) { + t.Run("with nulls, should skip null map entries", func(t *testing.T) { + require.Empty(t, ValueSlice[uint16](nil)) + + require.Len(t, ValueSlice([]*uint16{Pointer(uint16(1)), nil, Pointer(uint16(2))}), 3) + }) + + t.Run("with PointerSlice on []string", func(t *testing.T) { + testCasesStringSlice := [][]string{ + {"a", "b", "c", "d", "e"}, + {"a", "b", "", "", "e"}, + } + + for idx, in := range testCasesStringSlice { + if in == nil { + continue + } + out := PointerSlice(in) + assertValues(t, in, out, wantsPointer, idx) + + out2 := ValueSlice(out) + assertValues(t, in, out2, wantsValue, idx) + } + }) + + t.Run("with ValueSlice on []string", func(t *testing.T) { + testCasesStringValueSlice := [][]*string{ + {Pointer("a"), Pointer("b"), nil, Pointer("c")}, + } + + for idx, in := range testCasesStringValueSlice { + if in == nil { + continue + } + out := ValueSlice(in) + assertValues(t, in, out, wantsValue, idx) + + out2 := PointerSlice(out) + assertValues(t, in, out2, wantsPointer, idx) + } + }) +} + +func TestMap(t *testing.T) { + t.Run("with nulls", func(t *testing.T) { + require.Empty(t, ValueMap[string, uint16](nil)) + + require.Len(t, ValueMap(map[string]*int{"a": Pointer(1), "b": nil, "c": Pointer(2)}), 2) + }) + + t.Run("with PointerMap on map[string]string", func(t *testing.T) { + testCasesStringMap := []map[string]string{ + {"a": "1", "b": "2", "c": "3"}, + } + + for idx, in := range testCasesStringMap { + if in == nil { + continue + } + out := PointerMap(in) + assertValues(t, in, out, wantsPointer, idx) + + out2 := ValueMap(out) + assertValues(t, in, out2, wantsValue, idx) + } + }) + + t.Run("with ValueMap on map[string]bool", func(t *testing.T) { + testCasesBoolMap := []map[string]bool{ + {"a": true, "b": false, "c": true}, + } + + for idx, in := range testCasesBoolMap { + if in == nil { + continue + } + out := PointerMap(in) + assertValues(t, in, out, wantsPointer, idx) + + out2 := ValueMap(out) + assertValues(t, in, out2, wantsValue, idx) + } + }) +} + +func TestPointer(t *testing.T) { + t.Run("with Pointer on string", func(t *testing.T) { + testCasesString := []string{"a", "b", "c", "d", "e", ""} + + for idx, in := range testCasesString { + out := Pointer(in) + assertValues(t, in, out, wantsPointer, idx) + + out2 := Value(out) + assertValues(t, in, out2, wantsValue, idx) + } + assert.Zerof(t, Value[string](nil), "expected conversion from nil to return zero value") + }) + + t.Run("with Value on bool", func(t *testing.T) { + testCasesBool := []bool{true, false} + + for idx, in := range testCasesBool { + out := Pointer(in) + assertValues(t, in, out, wantsPointer, idx) + + out2 := Value(out) + assertValues(t, in, out2, wantsValue, idx) + } + assert.Zerof(t, Value[bool](nil), "expected conversion from nil to return zero value") + }) +} + +func assertSingleValue(t *testing.T, inElem, elem reflect.Value, expectPointer bool, idx int) { + require.Equalf(t, + expectPointer, (elem.Kind() == reflect.Ptr), + "unexpected expectPointer=%t value type %T at idx %d", expectPointer, elem, idx, + ) + + if inElem.Kind() == reflect.Ptr && !inElem.IsNil() { + inElem = reflect.Indirect(inElem) + } + + if elem.Kind() == reflect.Ptr && !elem.IsNil() { + elem = reflect.Indirect(elem) + } + + require.Truef(t, + (elem.Kind() == reflect.Ptr && elem.IsNil()) || + typeutils.IsZero(elem.Interface()) == (inElem.Kind() == reflect.Ptr && inElem.IsNil()) || + typeutils.IsZero(inElem.Interface()), + "unexpected nil pointer at idx %d", idx, + ) + + if !((elem.Kind() == reflect.Ptr && elem.IsNil()) || typeutils.IsZero(elem.Interface())) { + require.IsTypef(t, inElem.Interface(), elem.Interface(), + "expected in/out to match types at idx %d", idx, + ) + assert.EqualValuesf(t, inElem.Interface(), elem.Interface(), + "unexpected value at idx %d: %v", idx, elem.Interface(), + ) + } +} + +// assertValues checks equivalent representation pointer vs values for single var, slices and maps +func assertValues(t *testing.T, in, out interface{}, expectPointer bool, idx int) { + vin := reflect.ValueOf(in) + vout := reflect.ValueOf(out) + + switch vin.Kind() { //nolint:exhaustive + case reflect.Slice, reflect.Map: + require.Equalf(t, vin.Kind(), vout.Kind(), + "unexpected output type at idx %d", idx, + ) + require.Equalf(t, vin.Len(), vout.Len(), + "unexpected len at idx %d", idx, + ) + + var elem, inElem reflect.Value + for i := 0; i < vin.Len(); i++ { + switch vin.Kind() { //nolint:exhaustive + case reflect.Slice: + elem = vout.Index(i) + inElem = vin.Index(i) + case reflect.Map: + keys := vin.MapKeys() + elem = vout.MapIndex(keys[i]) + inElem = vout.MapIndex(keys[i]) + default: + } + + assertSingleValue(t, inElem, elem, expectPointer, idx) + } + + default: + inElem := vin + elem := vout + + assertSingleValue(t, inElem, elem, expectPointer, idx) + } +} diff --git a/conv/doc.go b/conv/doc.go new file mode 100644 index 0000000..d37f67c --- /dev/null +++ b/conv/doc.go @@ -0,0 +1,24 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package conv exposes utilities to convert types. +// +// Convert and Format families of functions are essentially a shorthand to `strconv` functions, +// using the decimal representation of numbers. +// +// * from string representation to value ("Convert*") and reciprocally ("Format*") +// * from pointer to value ([Value]) and reciprocally ([Pointer]) +// * from slice of values to slice of pointers ([PointerSlice]) and reciprocally ([ValueSlice]) +// * from map of values to map of pointers ([PointerMap]) and reciprocally ([ValueMap]) +package conv diff --git a/conv/format.go b/conv/format.go new file mode 100644 index 0000000..10d7d6b --- /dev/null +++ b/conv/format.go @@ -0,0 +1,43 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package conv + +import ( + "strconv" + "unsafe" +) + +// FormatInteger turns an integer type into a string. +func FormatInteger[T Signed](value T) string { + return strconv.FormatInt(int64(value), 10) +} + +// FormatUinteger turns an unsigned integer type into a string. +func FormatUinteger[T Unsigned](value T) string { + return strconv.FormatUint(uint64(value), 10) +} + +// FormatFloat turns a floating point numerical value into a string. +func FormatFloat[T Float](value T) string { + // NOTE: [unsafe.SizeOf] simply returns the size in bytes of the value. + // For primitive types T, the generic stencil is precompiled and this value + // is resolved at compile time, resulting in an immediate call to [strconv.FormatFloat]. + return strconv.FormatFloat(float64(value), 'f', -1, int(unsafe.Sizeof(value))*8) +} + +// FormatBool turns a boolean into a string. +func FormatBool(value bool) string { + return strconv.FormatBool(value) +} diff --git a/conv/type_constraints.go b/conv/type_constraints.go new file mode 100644 index 0000000..5fb92d6 --- /dev/null +++ b/conv/type_constraints.go @@ -0,0 +1,35 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package conv + +type ( + // these type constraints are redefined after golang.org/x/exp/constraints, + // because importing that package causes an undesired go upgrade. + + // Signed integer types, cf. [golang.org/x/exp/constraints.Signed] + Signed interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 + } + + // Unsigned integer types, cf. [golang.org/x/exp/constraints.Unsigned] + Unsigned interface { + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr + } + + // Float numerical types, cf. [golang.org/x/exp/constraints.Float] + Float interface { + ~float32 | ~float64 + } +) diff --git a/conv_iface.go b/conv_iface.go new file mode 100644 index 0000000..9991acb --- /dev/null +++ b/conv_iface.go @@ -0,0 +1,497 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package swag + +import ( + "time" + + "github.com/go-openapi/swag/conv" +) + +// IsFloat64AJSONInteger allows for integers [-2^53, 2^53-1] inclusive. +// +// Deprecated: use [conv.IsFloat64AJSONInteger] instead. +func IsFloat64AJSONInteger(f float64) bool { return conv.IsFloat64AJSONInteger(f) } + +// ConvertBool turns a string into a boolean. +// +// Deprecated: use [conv.ConvertBool] instead. +func ConvertBool(str string) (bool, error) { return conv.ConvertBool(str) } + +// ConvertFloat32 turns a string into a float32. +// +// Deprecated: use [conv.ConvertFloat32] instead. Alternatively, you may use the generic version [conv.ConvertFloat]. +func ConvertFloat32(str string) (float32, error) { return conv.ConvertFloat[float32](str) } + +// ConvertFloat64 turns a string into a float64. +// +// Deprecated: use [conv.ConvertFloat64] instead. Alternatively, you may use the generic version [conv.ConvertFloat]. +func ConvertFloat64(str string) (float64, error) { return conv.ConvertFloat[float64](str) } + +// ConvertInt8 turns a string into an int8. +// +// Deprecated: use [conv.ConvertInt8] instead. Alternatively, you may use the generic version [conv.ConvertInteger]. +func ConvertInt8(str string) (int8, error) { return conv.ConvertInteger[int8](str) } + +// ConvertInt16 turns a string into an int16. +// +// Deprecated: use [conv.ConvertInt16] instead. Alternatively, you may use the generic version [conv.ConvertInteger]. +func ConvertInt16(str string) (int16, error) { return conv.ConvertInteger[int16](str) } + +// ConvertInt32 turns a string into an int32. +// +// Deprecated: use [conv.ConvertInt32] instead. Alternatively, you may use the generic version [conv.ConvertInteger]. +func ConvertInt32(str string) (int32, error) { return conv.ConvertInteger[int32](str) } + +// ConvertInt64 turns a string into an int64. +// +// Deprecated: use [conv.ConvertInt64] instead. Alternatively, you may use the generic version [conv.ConvertInteger]. +func ConvertInt64(str string) (int64, error) { return conv.ConvertInteger[int64](str) } + +// ConvertUint8 turns a string into an uint8. +// +// Deprecated: use [conv.ConvertUint8] instead. Alternatively, you may use the generic version [conv.ConvertUinteger]. +func ConvertUint8(str string) (uint8, error) { return conv.ConvertUinteger[uint8](str) } + +// ConvertUint16 turns a string into an uint16. +// +// Deprecated: use [conv.ConvertUint16] instead. Alternatively, you may use the generic version [conv.ConvertUinteger]. +func ConvertUint16(str string) (uint16, error) { return conv.ConvertUinteger[uint16](str) } + +// ConvertUint32 turns a string into an uint32. +// +// Deprecated: use [conv.ConvertUint32] instead. Alternatively, you may use the generic version [conv.ConvertUinteger]. +func ConvertUint32(str string) (uint32, error) { return conv.ConvertUinteger[uint32](str) } + +// ConvertUint64 turns a string into an uint64. +// +// Deprecated: use [conv.ConvertUint64] instead. Alternatively, you may use the generic version [conv.ConvertUinteger]. +func ConvertUint64(str string) (uint64, error) { return conv.ConvertUinteger[uint64](str) } + +// FormatBool turns a boolean into a string. +// +// Deprecated: use [conv.FormatBool] instead. +func FormatBool(value bool) string { return conv.FormatBool(value) } + +// FormatFloat32 turns a float32 into a string. +// +// Deprecated: use [conv.FormatFloat] instead. +func FormatFloat32(value float32) string { return conv.FormatFloat(value) } + +// FormatFloat64 turns a float64 into a string. +// +// Deprecated: use [conv.FormatFloat] instead. +func FormatFloat64(value float64) string { return conv.FormatFloat(value) } + +// FormatInt8 turns an int8 into a string. +// +// Deprecated: use [conv.FormatInteger] instead. +func FormatInt8(value int8) string { return conv.FormatInteger(value) } + +// FormatInt16 turns an int16 into a string. +// +// Deprecated: use [conv.FormatInteger] instead. +func FormatInt16(value int16) string { return conv.FormatInteger(value) } + +// FormatInt32 turns an int32 into a string +// +// Deprecated: use [conv.FormatInteger] instead. +func FormatInt32(value int32) string { return conv.FormatInteger(value) } + +// FormatInt64 turns an int64 into a string. +// +// Deprecated: use [conv.FormatInteger] instead. +func FormatInt64(value int64) string { return conv.FormatInteger(value) } + +// FormatUint8 turns an uint8 into a string. +// +// Deprecated: use [conv.FormatUinteger] instead. +func FormatUint8(value uint8) string { return conv.FormatUinteger(value) } + +// FormatUint16 turns an uint16 into a string. +// +// Deprecated: use [conv.FormatUinteger] instead. +func FormatUint16(value uint16) string { return conv.FormatUinteger(value) } + +// FormatUint32 turns an uint32 into a string. +// +// Deprecated: use [conv.FormatUinteger] instead. +func FormatUint32(value uint32) string { return conv.FormatUinteger(value) } + +// FormatUint64 turns an uint64 into a string. +// +// Deprecated: use [conv.FormatUinteger] instead. +func FormatUint64(value uint64) string { return conv.FormatUinteger(value) } + +// String turn a pointer to of the string value passed in. +// +// Deprecated: use [conv.Pointer] instead. +func String(v string) *string { return conv.Pointer(v) } + +// StringValue turn the value of the string pointer passed in or +// "" if the pointer is nil. +// +// Deprecated: use [conv.Value] instead. +func StringValue(v *string) string { return conv.Value(v) } + +// StringSlice converts a slice of string values into a slice of string pointers. +// +// Deprecated: use [conv.PointerSlice] instead. +func StringSlice(src []string) []*string { return conv.PointerSlice(src) } + +// StringValueSlice converts a slice of string pointers into a slice of string values. +// +// Deprecated: use [conv.ValueSlice] instead. +func StringValueSlice(src []*string) []string { return conv.ValueSlice(src) } + +// StringMap converts a string map of string values into a string map of string pointers. +// +// Deprecated: use [conv.PointerMap] instead. +func StringMap(src map[string]string) map[string]*string { return conv.PointerMap(src) } + +// StringValueMap converts a string map of string pointers into a string map of string values. +// +// Deprecated: use [conv.ValueMap] instead. +func StringValueMap(src map[string]*string) map[string]string { return conv.ValueMap(src) } + +// Bool turn a pointer to of the bool value passed in. +// +// Deprecated: use [conv.Pointer] instead. +func Bool(v bool) *bool { return conv.Pointer(v) } + +// BoolValue turn the value of the bool pointer passed in or false if the pointer is nil. +// +// Deprecated: use [conv.Value] instead. +func BoolValue(v *bool) bool { return conv.Value(v) } + +// BoolSlice converts a slice of bool values into a slice of bool pointers. +// +// Deprecated: use [conv.PointerSlice] instead. +func BoolSlice(src []bool) []*bool { return conv.PointerSlice(src) } + +// BoolValueSlice converts a slice of bool pointers into a slice of bool values. +// +// Deprecated: use [conv.ValueSlice] instead. +func BoolValueSlice(src []*bool) []bool { return conv.ValueSlice(src) } + +// BoolMap converts a string map of bool values into a string map of bool pointers. +// +// Deprecated: use [conv.PointerMap] instead. +func BoolMap(src map[string]bool) map[string]*bool { return conv.PointerMap(src) } + +// BoolValueMap converts a string map of bool pointers into a string map of bool values. +// +// Deprecated: use [conv.ValueMap] instead. +func BoolValueMap(src map[string]*bool) map[string]bool { return conv.ValueMap(src) } + +// Int turn a pointer to of the int value passed in. +// +// Deprecated: use [conv.Pointer] instead. +func Int(v int) *int { return conv.Pointer(v) } + +// IntValue turn the value of the int pointer passed in or 0 if the pointer is nil. +// +// Deprecated: use [conv.Value] instead. +func IntValue(v *int) int { return conv.Value(v) } + +// IntSlice converts a slice of int values into a slice of int pointers. +// +// Deprecated: use [conv.PointerSlice] instead. +func IntSlice(src []int) []*int { return conv.PointerSlice(src) } + +// IntValueSlice converts a slice of int pointers into a slice of int values. +// +// Deprecated: use [conv.ValueSlice] instead. +func IntValueSlice(src []*int) []int { return conv.ValueSlice(src) } + +// IntMap converts a string map of int values into a string map of int pointers. +// +// Deprecated: use [conv.PointerMap] instead. +func IntMap(src map[string]int) map[string]*int { return conv.PointerMap(src) } + +// IntValueMap converts a string map of int pointers into a string map of int values. +// +// Deprecated: use [conv.ValueMap] instead. +func IntValueMap(src map[string]*int) map[string]int { return conv.ValueMap(src) } + +// Int32 turn a pointer to of the int32 value passed in. +// +// Deprecated: use [conv.Pointer] instead. +func Int32(v int32) *int32 { return conv.Pointer(v) } + +// Int32Value turn the value of the int32 pointer passed in or 0 if the pointer is nil. +// +// Deprecated: use [conv.Value] instead. +func Int32Value(v *int32) int32 { return conv.Value(v) } + +// Int32Slice converts a slice of int32 values into a slice of int32 pointers. +// +// Deprecated: use [conv.PointerSlice] instead. +func Int32Slice(src []int32) []*int32 { return conv.PointerSlice(src) } + +// Int32ValueSlice converts a slice of int32 pointers into a slice of int32 values. +// +// Deprecated: use [conv.ValueSlice] instead. +func Int32ValueSlice(src []*int32) []int32 { return conv.ValueSlice(src) } + +// Int32Map converts a string map of int32 values into a string map of int32 pointers. +// +// Deprecated: use [conv.PointerMap] instead. +func Int32Map(src map[string]int32) map[string]*int32 { return conv.PointerMap(src) } + +// Int32ValueMap converts a string map of int32 pointers into a string map of int32 values. +// +// Deprecated: use [conv.ValueMap] instead. +func Int32ValueMap(src map[string]*int32) map[string]int32 { return conv.ValueMap(src) } + +// Int64 turn a pointer to of the int64 value passed in. +// +// Deprecated: use [conv.Pointer] instead. +func Int64(v int64) *int64 { return conv.Pointer(v) } + +// Int64Value turn the value of the int64 pointer passed in or 0 if the pointer is nil. +// +// Deprecated: use [conv.Value] instead. +func Int64Value(v *int64) int64 { return conv.Value(v) } + +// Int64Slice converts a slice of int64 values into a slice of int64 pointers. +// +// Deprecated: use [conv.PointerSlice] instead. +func Int64Slice(src []int64) []*int64 { return conv.PointerSlice(src) } + +// Int64ValueSlice converts a slice of int64 pointers into a slice of int64 values. +// +// Deprecated: use [conv.ValueSlice] instead. +func Int64ValueSlice(src []*int64) []int64 { return conv.ValueSlice(src) } + +// Int64Map converts a string map of int64 values into a string map of int64 pointers. +// +// Deprecated: use [conv.PointerMap] instead. +func Int64Map(src map[string]int64) map[string]*int64 { return conv.PointerMap(src) } + +// Int64ValueMap converts a string map of int64 pointers into a string map of int64 values. +// +// Deprecated: use [conv.ValueMap] instead. +func Int64ValueMap(src map[string]*int64) map[string]int64 { return conv.ValueMap(src) } + +// Uint16 turn a pointer to of the uint16 value passed in. +// +// Deprecated: use [conv.Pointer] instead. +func Uint16(v uint16) *uint16 { return conv.Pointer(v) } + +// Uint16Value turn the value of the uint16 pointer passed in or 0 if the pointer is nil. +// +// Deprecated: use [conv.Value] instead. +func Uint16Value(v *uint16) uint16 { return conv.Value(v) } + +// Uint16Slice converts a slice of uint16 values into a slice of uint16 pointers. +// +// Deprecated: use [conv.PointerSlice] instead. +func Uint16Slice(src []uint16) []*uint16 { return conv.PointerSlice(src) } + +// Uint16ValueSlice converts a slice of uint16 pointers into a slice of uint16 values. +// +// Deprecated: use [conv.ValueSlice] instead. +func Uint16ValueSlice(src []*uint16) []uint16 { return conv.ValueSlice(src) } + +// Uint16Map converts a string map of uint16 values into a string map of uint16 pointers. +// +// Deprecated: use [conv.PointerMap] instead. +func Uint16Map(src map[string]uint16) map[string]*uint16 { return conv.PointerMap(src) } + +// Uint16ValueMap converts a string map of uint16 pointers into a string map of uint16 values. +// +// Deprecated: use [conv.ValueMap] instead. +func Uint16ValueMap(src map[string]*uint16) map[string]uint16 { return conv.ValueMap(src) } + +// Uint turn a pointer to of the uint value passed in. +// +// Deprecated: use [conv.Pointer] instead. +func Uint(v uint) *uint { return conv.Pointer(v) } + +// UintValue turn the value of the uint pointer passed in or 0 if the pointer is nil. +// +// Deprecated: use [conv.Value] instead. +func UintValue(v *uint) uint { return conv.Value(v) } + +// UintSlice converts a slice of uint values into a slice of uint pointers. +// +// Deprecated: use [conv.PointerSlice] instead. +func UintSlice(src []uint) []*uint { return conv.PointerSlice(src) } + +// UintValueSlice converts a slice of uint pointers into a slice of uint values. +// +// Deprecated: use [conv.ValueSlice] instead. +func UintValueSlice(src []*uint) []uint { return conv.ValueSlice(src) } + +// UintMap converts a string map of uint values into a string map of uint pointers. +// +// Deprecated: use [conv.PointerMap] instead. +func UintMap(src map[string]uint) map[string]*uint { return conv.PointerMap(src) } + +// UintValueMap converts a string map of uint pointers into a string map of uint values. +// +// Deprecated: use [conv.ValueMap] instead. +func UintValueMap(src map[string]*uint) map[string]uint { return conv.ValueMap(src) } + +// Uint32 turn a pointer to of the uint32 value passed in. +// +// Deprecated: use [conv.Pointer] instead. +func Uint32(v uint32) *uint32 { return conv.Pointer(v) } + +// Uint32Value turn the value of the uint32 pointer passed in or 0 if the pointer is nil. +// +// Deprecated: use [conv.Value] instead. +func Uint32Value(v *uint32) uint32 { return conv.Value(v) } + +// Uint32Slice converts a slice of uint32 values into a slice of uint32 pointers. +// +// Deprecated: use [conv.PointerSlice] instead. +func Uint32Slice(src []uint32) []*uint32 { return conv.PointerSlice(src) } + +// Uint32ValueSlice converts a slice of uint32 pointers into a slice of uint32 values. +// +// Deprecated: use [conv.ValueSlice] instead. +func Uint32ValueSlice(src []*uint32) []uint32 { return conv.ValueSlice(src) } + +// Uint32Map converts a string map of uint32 values into a string map of uint32 pointers. +// +// Deprecated: use [conv.PointerMap] instead. +func Uint32Map(src map[string]uint32) map[string]*uint32 { return conv.PointerMap(src) } + +// Uint32ValueMap converts a string map of uint32 pointers into a string map of uint32 values. +// +// Deprecated: use [conv.ValueMap] instead. +func Uint32ValueMap(src map[string]*uint32) map[string]uint32 { return conv.ValueMap(src) } + +// Uint64 turn a pointer to of the uint64 value passed in. +// +// Deprecated: use [conv.Pointer] instead. +func Uint64(v uint64) *uint64 { return conv.Pointer(v) } + +// Uint64Value turn the value of the uint64 pointer passed in or 0 if the pointer is nil. +// +// Deprecated: use [conv.Value] instead. +func Uint64Value(v *uint64) uint64 { return conv.Value(v) } + +// Uint64Slice converts a slice of uint64 values into a slice of uint64 pointers. +// +// Deprecated: use [conv.PointerSlice] instead. +func Uint64Slice(src []uint64) []*uint64 { return conv.PointerSlice(src) } + +// Uint64ValueSlice converts a slice of uint64 pointers into a slice of uint64 values. +// +// Deprecated: use [conv.ValueSlice] instead. +func Uint64ValueSlice(src []*uint64) []uint64 { return conv.ValueSlice(src) } + +// Uint64Map converts a string map of uint64 values into a string map of uint64 pointers. +// +// Deprecated: use [conv.PointerMap] instead. +func Uint64Map(src map[string]uint64) map[string]*uint64 { return conv.PointerMap(src) } + +// Uint64ValueMap converts a string map of uint64 pointers into a string map of uint64 values. +// +// Deprecated: use [conv.ValueMap] instead. +func Uint64ValueMap(src map[string]*uint64) map[string]uint64 { return conv.ValueMap(src) } + +// Float32 turn a pointer to of the float32 value passed in. +// +// Deprecated: use [conv.Pointer] instead. +func Float32(v float32) *float32 { return conv.Pointer(v) } + +// Float32Value turn the value of the float32 pointer passed in or 0 if the pointer is nil. +// +// Deprecated: use [conv.Value] instead. +func Float32Value(v *float32) float32 { return conv.Value(v) } + +// Float32Slice converts a slice of float32 values into a slice of float32 pointers. +// +// Deprecated: use [conv.PointerSlice] instead. +func Float32Slice(src []float32) []*float32 { return conv.PointerSlice(src) } + +// Float32ValueSlice converts a slice of float32 pointers into a slice of float32 values. +// +// Deprecated: use [conv.ValueSlice] instead. +func Float32ValueSlice(src []*float32) []float32 { return conv.ValueSlice(src) } + +// Float32Map converts a string map of float32 values into a string map of float32 pointers. +// +// Deprecated: use [conv.PointerMap] instead. +func Float32Map(src map[string]float32) map[string]*float32 { return conv.PointerMap(src) } + +// Float32ValueMap converts a string map of float32 pointers into a string map of float32 values. +// +// Deprecated: use [conv.ValueMap] instead. +func Float32ValueMap(src map[string]*float32) map[string]float32 { return conv.ValueMap(src) } + +// Float64 turn a pointer to of the float64 value passed in. +// +// Deprecated: use [conv.Pointer] instead. +func Float64(v float64) *float64 { return conv.Pointer(v) } + +// Float64Value turn the value of the float64 pointer passed in or 0 if the pointer is nil. +// +// Deprecated: use [conv.Value] instead. +func Float64Value(v *float64) float64 { return conv.Value(v) } + +// Float64Slice converts a slice of float64 values into a slice of float64 pointers. +// +// Deprecated: use [conv.PointerSlice] instead. +func Float64Slice(src []float64) []*float64 { return conv.PointerSlice(src) } + +// Float64ValueSlice converts a slice of float64 pointers into a slice of float64 values. +// +// Deprecated: use [conv.ValueSlice] instead. +func Float64ValueSlice(src []*float64) []float64 { return conv.ValueSlice(src) } + +// Float64Map converts a string map of float64 values into a string map of float64 pointers. +// +// Deprecated: use [conv.PointerMap] instead. +func Float64Map(src map[string]float64) map[string]*float64 { return conv.PointerMap(src) } + +// Float64ValueMap converts a string map of float64 pointers into a string map of float64 values. +// +// Deprecated: use [conv.ValueMap] instead. +func Float64ValueMap(src map[string]*float64) map[string]float64 { return conv.ValueMap(src) } + +// Time turn a pointer to of the time.Time value passed in. +// +// Deprecated: use [conv.Pointer] instead. +func Time(v time.Time) *time.Time { return conv.Pointer(v) } + +// TimeValue turn the value of the time.Time pointer passed in or time.Time{} if the pointer is nil. +// +// Deprecated: use [conv.Value] instead. +func TimeValue(v *time.Time) time.Time { return conv.Value(v) } + +// TimeSlice converts a slice of time.Time values into a slice of time.Time pointers. +// +// Deprecated: use [conv.PointerSlice] instead. +func TimeSlice(src []time.Time) []*time.Time { return conv.PointerSlice(src) } + +// TimeValueSlice converts a slice of time.Time pointers into a slice of time.Time values +// +// Deprecated: use [conv.ValueSlice] instead. +func TimeValueSlice(src []*time.Time) []time.Time { return conv.ValueSlice(src) } + +// TimeMap converts a string map of time.Time values into a string map of time.Time pointers. +// +// Deprecated: use [conv.PointerMap] instead. +func TimeMap(src map[string]time.Time) map[string]*time.Time { return conv.PointerMap(src) } + +// TimeValueMap converts a string map of time.Time pointers into a string map of time.Time values. +// +// Deprecated: use [conv.ValueMap] instead. +func TimeValueMap(src map[string]*time.Time) map[string]time.Time { return conv.ValueMap(src) } diff --git a/conv_iface_test.go b/conv_iface_test.go new file mode 100644 index 0000000..e103b19 --- /dev/null +++ b/conv_iface_test.go @@ -0,0 +1,140 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package swag + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestConvIface(t *testing.T) { + const epsilon = 1e-6 + + t.Run("deprecated Convert functions should work", func(t *testing.T) { + // only check happy path - more comprehensive testing is carried out inside the called packag + assert.True(t, IsFloat64AJSONInteger(1.00)) + + b, err := ConvertBool("true") + require.NoError(t, err) + assert.True(t, b) + + f32, err := ConvertFloat32("1.05") + require.NoError(t, err) + assert.InDelta(t, float32(1.05), f32, epsilon) + + f64, err := ConvertFloat64("1.05") + require.NoError(t, err) + assert.InDelta(t, float32(1.05), f64, epsilon) + + i8, err := ConvertInt8("2") + require.NoError(t, err) + assert.Equal(t, int8(2), i8) + + i16, err := ConvertInt16("2") + require.NoError(t, err) + assert.Equal(t, int16(2), i16) + + i32, err := ConvertInt32("2") + require.NoError(t, err) + assert.Equal(t, int32(2), i32) + + i64, err := ConvertInt64("2") + require.NoError(t, err) + assert.Equal(t, int64(2), i64) + + u8, err := ConvertUint8("2") + require.NoError(t, err) + assert.Equal(t, uint8(2), u8) + + u16, err := ConvertUint16("2") + require.NoError(t, err) + assert.Equal(t, uint16(2), u16) + + u32, err := ConvertUint32("2") + require.NoError(t, err) + assert.Equal(t, uint32(2), u32) + + u64, err := ConvertUint64("2") + require.NoError(t, err) + assert.Equal(t, uint64(2), u64) + }) + + t.Run("deprecated Format functions should work", func(t *testing.T) { + assert.Equal(t, "true", FormatBool(true)) + assert.Equal(t, "1.05", FormatFloat32(1.05)) + assert.Equal(t, "1.05", FormatFloat64(1.05)) + assert.Equal(t, "1", FormatInt8(1)) + assert.Equal(t, "1", FormatInt16(1)) + assert.Equal(t, "1", FormatInt32(1)) + assert.Equal(t, "1", FormatInt64(1)) + assert.Equal(t, "1", FormatUint8(1)) + assert.Equal(t, "1", FormatUint16(1)) + assert.Equal(t, "1", FormatUint32(1)) + assert.Equal(t, "1", FormatUint64(1)) + }) + + t.Run("deprecated pointer functions should work", func(t *testing.T) { + assert.Equal(t, "a", StringValue(String("a"))) + assert.EqualValues(t, []string{"a"}, StringValueSlice(StringSlice([]string{"a"}))) + assert.EqualValues(t, map[string]string{"1": "a"}, StringValueMap(StringMap(map[string]string{"1": "a"}))) + + assert.True(t, BoolValue(Bool(true))) + assert.EqualValues(t, []bool{true}, BoolValueSlice(BoolSlice([]bool{true}))) + assert.EqualValues(t, map[string]bool{"1": true}, BoolValueMap(BoolMap(map[string]bool{"1": true}))) + + assert.Equal(t, 1, IntValue(Int(1))) + assert.EqualValues(t, []int{1}, IntValueSlice(IntSlice([]int{1}))) + assert.EqualValues(t, map[string]int{"1": 1}, IntValueMap(IntMap(map[string]int{"1": 1}))) + + assert.Equal(t, int32(1), Int32Value(Int32(1))) + assert.EqualValues(t, []int32{1}, Int32ValueSlice(Int32Slice([]int32{1}))) + assert.EqualValues(t, map[string]int32{"1": 1}, Int32ValueMap(Int32Map(map[string]int32{"1": 1}))) + + assert.Equal(t, int64(1), Int64Value(Int64(1))) + assert.EqualValues(t, []int64{1}, Int64ValueSlice(Int64Slice([]int64{1}))) + assert.EqualValues(t, map[string]int64{"1": 1}, Int64ValueMap(Int64Map(map[string]int64{"1": 1}))) + + assert.Equal(t, uint16(1), Uint16Value(Uint16(1))) + assert.EqualValues(t, []uint16{1}, Uint16ValueSlice(Uint16Slice([]uint16{1}))) + assert.EqualValues(t, map[string]uint16{"1": 1}, Uint16ValueMap(Uint16Map(map[string]uint16{"1": 1}))) + + assert.Equal(t, uint32(1), Uint32Value(Uint32(1))) + assert.EqualValues(t, []uint32{1}, Uint32ValueSlice(Uint32Slice([]uint32{1}))) + assert.EqualValues(t, map[string]uint32{"1": 1}, Uint32ValueMap(Uint32Map(map[string]uint32{"1": 1}))) + + assert.Equal(t, uint64(1), Uint64Value(Uint64(1))) + assert.EqualValues(t, []uint64{1}, Uint64ValueSlice(Uint64Slice([]uint64{1}))) + assert.EqualValues(t, map[string]uint64{"1": 1}, Uint64ValueMap(Uint64Map(map[string]uint64{"1": 1}))) + + assert.Equal(t, uint(1), UintValue(Uint(1))) + assert.EqualValues(t, []uint{1}, UintValueSlice(UintSlice([]uint{1}))) + assert.EqualValues(t, map[string]uint{"1": 1}, UintValueMap(UintMap(map[string]uint{"1": 1}))) + + assert.InDelta(t, float32(1.00), Float32Value(Float32(1.00)), epsilon) + assert.EqualValues(t, []float32{1.00}, Float32ValueSlice(Float32Slice([]float32{1.00}))) + assert.EqualValues(t, map[string]float32{"1": 1.00}, Float32ValueMap(Float32Map(map[string]float32{"1": 1.00}))) + + assert.InDelta(t, float64(1.00), Float64Value(Float64(1)), epsilon) + assert.EqualValues(t, []float64{1.00}, Float64ValueSlice(Float64Slice([]float64{1.00}))) + assert.EqualValues(t, map[string]float64{"1": 1.00}, Float64ValueMap(Float64Map(map[string]float64{"1": 1.00}))) + + assert.Equal(t, time.Unix(0, 0), TimeValue(Time(time.Unix(0, 0)))) + assert.EqualValues(t, []time.Time{time.Unix(0, 0)}, TimeValueSlice(TimeSlice([]time.Time{time.Unix(0, 0)}))) + assert.EqualValues(t, map[string]time.Time{"1": time.Unix(0, 0)}, TimeValueMap(TimeMap(map[string]time.Time{"1": time.Unix(0, 0)}))) + }) +} diff --git a/convert_test.go b/convert_test.go deleted file mode 100644 index dc5c09b..0000000 --- a/convert_test.go +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package swag - -import ( - "math" - "strconv" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func errMsg(f string) string { - const ( - expectedQuote = "expected '" - errSuffix = "' to generate an error" - ) - - return expectedQuote + f + errSuffix -} - -// These are really dumb tests - -func TestConvertBool(t *testing.T) { - for k := range evaluatesAsTrue { - r, err := ConvertBool(k) - require.NoError(t, err) - assert.True(t, r) - } - for _, k := range []string{"a", "", "0", "false", "unchecked"} { - r, err := ConvertBool(k) - require.NoError(t, err) - assert.False(t, r) - } -} - -func TestConvertFloat32(t *testing.T) { - validFloats := []float32{1.0, -1, math.MaxFloat32, math.SmallestNonzeroFloat32, 0, 5.494430303} - invalidFloats := []string{"a", strconv.FormatFloat(math.MaxFloat64, 'f', -1, 64), "true"} - - for _, f := range validFloats { - c, err := ConvertFloat32(FormatFloat32(f)) - require.NoError(t, err) - assert.InDelta(t, f, c, 1e-6) - } - for _, f := range invalidFloats { - _, err := ConvertFloat32(f) - require.Error(t, err, errMsg(f)) - } -} - -func TestConvertFloat64(t *testing.T) { - validFloats := []float64{1.0, -1, float64(math.MaxFloat32), float64(math.SmallestNonzeroFloat32), math.MaxFloat64, math.SmallestNonzeroFloat64, 0, 5.494430303} - invalidFloats := []string{"a", "true"} - - for _, f := range validFloats { - c, err := ConvertFloat64(FormatFloat64(f)) - require.NoError(t, err) - assert.InDelta(t, f, c, 1e-6) - } - for _, f := range invalidFloats { - _, err := ConvertFloat64(f) - require.Error(t, err, errMsg(f)) - } -} - -func TestConvertInt8(t *testing.T) { - validInts := []int8{0, 1, -1, math.MaxInt8, math.MinInt8} - invalidInts := []string{"1.233", "a", "false", strconv.FormatInt(int64(math.MaxInt64), 10)} - - for _, f := range validInts { - c, err := ConvertInt8(FormatInt8(f)) - require.NoError(t, err) - assert.EqualValues(t, f, c) - } - for _, f := range invalidInts { - _, err := ConvertInt8(f) - require.Error(t, err, errMsg(f)) - } -} - -func TestConvertInt16(t *testing.T) { - validInts := []int16{0, 1, -1, math.MaxInt8, math.MinInt8, math.MaxInt16, math.MinInt16} - invalidInts := []string{"1.233", "a", "false", strconv.FormatInt(int64(math.MaxInt64), 10)} - - for _, f := range validInts { - c, err := ConvertInt16(FormatInt16(f)) - require.NoError(t, err) - assert.EqualValues(t, f, c) - } - for _, f := range invalidInts { - _, err := ConvertInt16(f) - require.Error(t, err, errMsg(f)) - } -} - -func TestConvertInt32(t *testing.T) { - validInts := []int32{0, 1, -1, math.MaxInt8, math.MinInt8, math.MaxInt16, math.MinInt16, math.MinInt32, math.MaxInt32} - invalidInts := []string{"1.233", "a", "false", strconv.FormatInt(int64(math.MaxInt64), 10)} - - for _, f := range validInts { - c, err := ConvertInt32(FormatInt32(f)) - require.NoError(t, err) - assert.EqualValues(t, f, c) - } - for _, f := range invalidInts { - _, err := ConvertInt32(f) - require.Error(t, err, errMsg(f)) - } -} - -func TestConvertInt64(t *testing.T) { - validInts := []int64{0, 1, -1, math.MaxInt8, math.MinInt8, math.MaxInt16, math.MinInt16, math.MinInt32, math.MaxInt32, math.MaxInt64, math.MinInt64} - invalidInts := []string{"1.233", "a", "false"} - - for _, f := range validInts { - c, err := ConvertInt64(FormatInt64(f)) - require.NoError(t, err) - assert.EqualValues(t, f, c) - } - for _, f := range invalidInts { - _, err := ConvertInt64(f) - require.Error(t, err, errMsg(f)) - } -} - -func TestConvertUint8(t *testing.T) { - validInts := []uint8{0, 1, math.MaxUint8} - invalidInts := []string{"1.233", "a", "false", strconv.FormatUint(math.MaxUint64, 10)} - - for _, f := range validInts { - c, err := ConvertUint8(FormatUint8(f)) - require.NoError(t, err) - assert.EqualValues(t, f, c) - } - for _, f := range invalidInts { - _, err := ConvertUint8(f) - require.Error(t, err, errMsg(f)) - } -} - -func TestConvertUint16(t *testing.T) { - validUints := []uint16{0, 1, math.MaxUint8, math.MaxUint16} - invalidUints := []string{"1.233", "a", "false", strconv.FormatUint(math.MaxUint64, 10)} - - for _, f := range validUints { - c, err := ConvertUint16(FormatUint16(f)) - require.NoError(t, err) - assert.EqualValues(t, f, c) - } - for _, f := range invalidUints { - _, err := ConvertUint16(f) - require.Error(t, err, errMsg(f)) - } -} - -func TestConvertUint32(t *testing.T) { - validUints := []uint32{0, 1, math.MaxUint8, math.MaxUint16, math.MaxUint32} - invalidUints := []string{"1.233", "a", "false", strconv.FormatUint(math.MaxUint64, 10)} - - for _, f := range validUints { - c, err := ConvertUint32(FormatUint32(f)) - require.NoError(t, err) - assert.EqualValues(t, f, c) - } - for _, f := range invalidUints { - _, err := ConvertUint32(f) - require.Error(t, err, errMsg(f)) - } -} - -func TestConvertUint64(t *testing.T) { - validUints := []uint64{0, 1, math.MaxUint8, math.MaxUint16, math.MaxUint32, math.MaxUint64} - invalidUints := []string{"1.233", "a", "false"} - - for _, f := range validUints { - c, err := ConvertUint64(FormatUint64(f)) - require.NoError(t, err) - assert.EqualValues(t, f, c) - } - for _, f := range invalidUints { - _, err := ConvertUint64(f) - require.Error(t, err, errMsg(f)) - } -} - -func TestIsFloat64AJSONInteger(t *testing.T) { - assert.False(t, IsFloat64AJSONInteger(math.Inf(1))) - assert.False(t, IsFloat64AJSONInteger(maxJSONFloat+1)) - - assert.False(t, IsFloat64AJSONInteger(minJSONFloat-1)) - assert.True(t, IsFloat64AJSONInteger(1.0)) - assert.True(t, IsFloat64AJSONInteger(maxJSONFloat)) - assert.True(t, IsFloat64AJSONInteger(minJSONFloat)) - assert.True(t, IsFloat64AJSONInteger(1/0.01*67.15000001)) - assert.False(t, IsFloat64AJSONInteger(math.SmallestNonzeroFloat64)) - assert.True(t, IsFloat64AJSONInteger(math.SmallestNonzeroFloat64/2)) - assert.True(t, IsFloat64AJSONInteger(math.SmallestNonzeroFloat64/3)) - assert.True(t, IsFloat64AJSONInteger(math.SmallestNonzeroFloat64/4)) -} - -func TestFormatBool(t *testing.T) { - assert.Equal(t, "true", FormatBool(true)) - assert.Equal(t, "false", FormatBool(false)) -} diff --git a/convert_types.go b/convert_types.go deleted file mode 100644 index c49cc47..0000000 --- a/convert_types.go +++ /dev/null @@ -1,730 +0,0 @@ -package swag - -import "time" - -// This file was taken from the aws go sdk - -// String returns a pointer to of the string value passed in. -func String(v string) *string { - return &v -} - -// StringValue returns the value of the string pointer passed in or -// "" if the pointer is nil. -func StringValue(v *string) string { - if v != nil { - return *v - } - return "" -} - -// StringSlice converts a slice of string values into a slice of -// string pointers -func StringSlice(src []string) []*string { - dst := make([]*string, len(src)) - for i := 0; i < len(src); i++ { - dst[i] = &(src[i]) - } - return dst -} - -// StringValueSlice converts a slice of string pointers into a slice of -// string values -func StringValueSlice(src []*string) []string { - dst := make([]string, len(src)) - for i := 0; i < len(src); i++ { - if src[i] != nil { - dst[i] = *(src[i]) - } - } - return dst -} - -// StringMap converts a string map of string values into a string -// map of string pointers -func StringMap(src map[string]string) map[string]*string { - dst := make(map[string]*string) - for k, val := range src { - v := val - dst[k] = &v - } - return dst -} - -// StringValueMap converts a string map of string pointers into a string -// map of string values -func StringValueMap(src map[string]*string) map[string]string { - dst := make(map[string]string) - for k, val := range src { - if val != nil { - dst[k] = *val - } - } - return dst -} - -// Bool returns a pointer to of the bool value passed in. -func Bool(v bool) *bool { - return &v -} - -// BoolValue returns the value of the bool pointer passed in or -// false if the pointer is nil. -func BoolValue(v *bool) bool { - if v != nil { - return *v - } - return false -} - -// BoolSlice converts a slice of bool values into a slice of -// bool pointers -func BoolSlice(src []bool) []*bool { - dst := make([]*bool, len(src)) - for i := 0; i < len(src); i++ { - dst[i] = &(src[i]) - } - return dst -} - -// BoolValueSlice converts a slice of bool pointers into a slice of -// bool values -func BoolValueSlice(src []*bool) []bool { - dst := make([]bool, len(src)) - for i := 0; i < len(src); i++ { - if src[i] != nil { - dst[i] = *(src[i]) - } - } - return dst -} - -// BoolMap converts a string map of bool values into a string -// map of bool pointers -func BoolMap(src map[string]bool) map[string]*bool { - dst := make(map[string]*bool) - for k, val := range src { - v := val - dst[k] = &v - } - return dst -} - -// BoolValueMap converts a string map of bool pointers into a string -// map of bool values -func BoolValueMap(src map[string]*bool) map[string]bool { - dst := make(map[string]bool) - for k, val := range src { - if val != nil { - dst[k] = *val - } - } - return dst -} - -// Int returns a pointer to of the int value passed in. -func Int(v int) *int { - return &v -} - -// IntValue returns the value of the int pointer passed in or -// 0 if the pointer is nil. -func IntValue(v *int) int { - if v != nil { - return *v - } - return 0 -} - -// IntSlice converts a slice of int values into a slice of -// int pointers -func IntSlice(src []int) []*int { - dst := make([]*int, len(src)) - for i := 0; i < len(src); i++ { - dst[i] = &(src[i]) - } - return dst -} - -// IntValueSlice converts a slice of int pointers into a slice of -// int values -func IntValueSlice(src []*int) []int { - dst := make([]int, len(src)) - for i := 0; i < len(src); i++ { - if src[i] != nil { - dst[i] = *(src[i]) - } - } - return dst -} - -// IntMap converts a string map of int values into a string -// map of int pointers -func IntMap(src map[string]int) map[string]*int { - dst := make(map[string]*int) - for k, val := range src { - v := val - dst[k] = &v - } - return dst -} - -// IntValueMap converts a string map of int pointers into a string -// map of int values -func IntValueMap(src map[string]*int) map[string]int { - dst := make(map[string]int) - for k, val := range src { - if val != nil { - dst[k] = *val - } - } - return dst -} - -// Int32 returns a pointer to of the int32 value passed in. -func Int32(v int32) *int32 { - return &v -} - -// Int32Value returns the value of the int32 pointer passed in or -// 0 if the pointer is nil. -func Int32Value(v *int32) int32 { - if v != nil { - return *v - } - return 0 -} - -// Int32Slice converts a slice of int32 values into a slice of -// int32 pointers -func Int32Slice(src []int32) []*int32 { - dst := make([]*int32, len(src)) - for i := 0; i < len(src); i++ { - dst[i] = &(src[i]) - } - return dst -} - -// Int32ValueSlice converts a slice of int32 pointers into a slice of -// int32 values -func Int32ValueSlice(src []*int32) []int32 { - dst := make([]int32, len(src)) - for i := 0; i < len(src); i++ { - if src[i] != nil { - dst[i] = *(src[i]) - } - } - return dst -} - -// Int32Map converts a string map of int32 values into a string -// map of int32 pointers -func Int32Map(src map[string]int32) map[string]*int32 { - dst := make(map[string]*int32) - for k, val := range src { - v := val - dst[k] = &v - } - return dst -} - -// Int32ValueMap converts a string map of int32 pointers into a string -// map of int32 values -func Int32ValueMap(src map[string]*int32) map[string]int32 { - dst := make(map[string]int32) - for k, val := range src { - if val != nil { - dst[k] = *val - } - } - return dst -} - -// Int64 returns a pointer to of the int64 value passed in. -func Int64(v int64) *int64 { - return &v -} - -// Int64Value returns the value of the int64 pointer passed in or -// 0 if the pointer is nil. -func Int64Value(v *int64) int64 { - if v != nil { - return *v - } - return 0 -} - -// Int64Slice converts a slice of int64 values into a slice of -// int64 pointers -func Int64Slice(src []int64) []*int64 { - dst := make([]*int64, len(src)) - for i := 0; i < len(src); i++ { - dst[i] = &(src[i]) - } - return dst -} - -// Int64ValueSlice converts a slice of int64 pointers into a slice of -// int64 values -func Int64ValueSlice(src []*int64) []int64 { - dst := make([]int64, len(src)) - for i := 0; i < len(src); i++ { - if src[i] != nil { - dst[i] = *(src[i]) - } - } - return dst -} - -// Int64Map converts a string map of int64 values into a string -// map of int64 pointers -func Int64Map(src map[string]int64) map[string]*int64 { - dst := make(map[string]*int64) - for k, val := range src { - v := val - dst[k] = &v - } - return dst -} - -// Int64ValueMap converts a string map of int64 pointers into a string -// map of int64 values -func Int64ValueMap(src map[string]*int64) map[string]int64 { - dst := make(map[string]int64) - for k, val := range src { - if val != nil { - dst[k] = *val - } - } - return dst -} - -// Uint16 returns a pointer to of the uint16 value passed in. -func Uint16(v uint16) *uint16 { - return &v -} - -// Uint16Value returns the value of the uint16 pointer passed in or -// 0 if the pointer is nil. -func Uint16Value(v *uint16) uint16 { - if v != nil { - return *v - } - - return 0 -} - -// Uint16Slice converts a slice of uint16 values into a slice of -// uint16 pointers -func Uint16Slice(src []uint16) []*uint16 { - dst := make([]*uint16, len(src)) - for i := 0; i < len(src); i++ { - dst[i] = &(src[i]) - } - - return dst -} - -// Uint16ValueSlice converts a slice of uint16 pointers into a slice of -// uint16 values -func Uint16ValueSlice(src []*uint16) []uint16 { - dst := make([]uint16, len(src)) - - for i := 0; i < len(src); i++ { - if src[i] != nil { - dst[i] = *(src[i]) - } - } - - return dst -} - -// Uint16Map converts a string map of uint16 values into a string -// map of uint16 pointers -func Uint16Map(src map[string]uint16) map[string]*uint16 { - dst := make(map[string]*uint16) - - for k, val := range src { - v := val - dst[k] = &v - } - - return dst -} - -// Uint16ValueMap converts a string map of uint16 pointers into a string -// map of uint16 values -func Uint16ValueMap(src map[string]*uint16) map[string]uint16 { - dst := make(map[string]uint16) - - for k, val := range src { - if val != nil { - dst[k] = *val - } - } - - return dst -} - -// Uint returns a pointer to of the uint value passed in. -func Uint(v uint) *uint { - return &v -} - -// UintValue returns the value of the uint pointer passed in or -// 0 if the pointer is nil. -func UintValue(v *uint) uint { - if v != nil { - return *v - } - return 0 -} - -// UintSlice converts a slice of uint values into a slice of -// uint pointers -func UintSlice(src []uint) []*uint { - dst := make([]*uint, len(src)) - for i := 0; i < len(src); i++ { - dst[i] = &(src[i]) - } - return dst -} - -// UintValueSlice converts a slice of uint pointers into a slice of -// uint values -func UintValueSlice(src []*uint) []uint { - dst := make([]uint, len(src)) - for i := 0; i < len(src); i++ { - if src[i] != nil { - dst[i] = *(src[i]) - } - } - return dst -} - -// UintMap converts a string map of uint values into a string -// map of uint pointers -func UintMap(src map[string]uint) map[string]*uint { - dst := make(map[string]*uint) - for k, val := range src { - v := val - dst[k] = &v - } - return dst -} - -// UintValueMap converts a string map of uint pointers into a string -// map of uint values -func UintValueMap(src map[string]*uint) map[string]uint { - dst := make(map[string]uint) - for k, val := range src { - if val != nil { - dst[k] = *val - } - } - return dst -} - -// Uint32 returns a pointer to of the uint32 value passed in. -func Uint32(v uint32) *uint32 { - return &v -} - -// Uint32Value returns the value of the uint32 pointer passed in or -// 0 if the pointer is nil. -func Uint32Value(v *uint32) uint32 { - if v != nil { - return *v - } - return 0 -} - -// Uint32Slice converts a slice of uint32 values into a slice of -// uint32 pointers -func Uint32Slice(src []uint32) []*uint32 { - dst := make([]*uint32, len(src)) - for i := 0; i < len(src); i++ { - dst[i] = &(src[i]) - } - return dst -} - -// Uint32ValueSlice converts a slice of uint32 pointers into a slice of -// uint32 values -func Uint32ValueSlice(src []*uint32) []uint32 { - dst := make([]uint32, len(src)) - for i := 0; i < len(src); i++ { - if src[i] != nil { - dst[i] = *(src[i]) - } - } - return dst -} - -// Uint32Map converts a string map of uint32 values into a string -// map of uint32 pointers -func Uint32Map(src map[string]uint32) map[string]*uint32 { - dst := make(map[string]*uint32) - for k, val := range src { - v := val - dst[k] = &v - } - return dst -} - -// Uint32ValueMap converts a string map of uint32 pointers into a string -// map of uint32 values -func Uint32ValueMap(src map[string]*uint32) map[string]uint32 { - dst := make(map[string]uint32) - for k, val := range src { - if val != nil { - dst[k] = *val - } - } - return dst -} - -// Uint64 returns a pointer to of the uint64 value passed in. -func Uint64(v uint64) *uint64 { - return &v -} - -// Uint64Value returns the value of the uint64 pointer passed in or -// 0 if the pointer is nil. -func Uint64Value(v *uint64) uint64 { - if v != nil { - return *v - } - return 0 -} - -// Uint64Slice converts a slice of uint64 values into a slice of -// uint64 pointers -func Uint64Slice(src []uint64) []*uint64 { - dst := make([]*uint64, len(src)) - for i := 0; i < len(src); i++ { - dst[i] = &(src[i]) - } - return dst -} - -// Uint64ValueSlice converts a slice of uint64 pointers into a slice of -// uint64 values -func Uint64ValueSlice(src []*uint64) []uint64 { - dst := make([]uint64, len(src)) - for i := 0; i < len(src); i++ { - if src[i] != nil { - dst[i] = *(src[i]) - } - } - return dst -} - -// Uint64Map converts a string map of uint64 values into a string -// map of uint64 pointers -func Uint64Map(src map[string]uint64) map[string]*uint64 { - dst := make(map[string]*uint64) - for k, val := range src { - v := val - dst[k] = &v - } - return dst -} - -// Uint64ValueMap converts a string map of uint64 pointers into a string -// map of uint64 values -func Uint64ValueMap(src map[string]*uint64) map[string]uint64 { - dst := make(map[string]uint64) - for k, val := range src { - if val != nil { - dst[k] = *val - } - } - return dst -} - -// Float32 returns a pointer to of the float32 value passed in. -func Float32(v float32) *float32 { - return &v -} - -// Float32Value returns the value of the float32 pointer passed in or -// 0 if the pointer is nil. -func Float32Value(v *float32) float32 { - if v != nil { - return *v - } - - return 0 -} - -// Float32Slice converts a slice of float32 values into a slice of -// float32 pointers -func Float32Slice(src []float32) []*float32 { - dst := make([]*float32, len(src)) - - for i := 0; i < len(src); i++ { - dst[i] = &(src[i]) - } - - return dst -} - -// Float32ValueSlice converts a slice of float32 pointers into a slice of -// float32 values -func Float32ValueSlice(src []*float32) []float32 { - dst := make([]float32, len(src)) - - for i := 0; i < len(src); i++ { - if src[i] != nil { - dst[i] = *(src[i]) - } - } - - return dst -} - -// Float32Map converts a string map of float32 values into a string -// map of float32 pointers -func Float32Map(src map[string]float32) map[string]*float32 { - dst := make(map[string]*float32) - - for k, val := range src { - v := val - dst[k] = &v - } - - return dst -} - -// Float32ValueMap converts a string map of float32 pointers into a string -// map of float32 values -func Float32ValueMap(src map[string]*float32) map[string]float32 { - dst := make(map[string]float32) - - for k, val := range src { - if val != nil { - dst[k] = *val - } - } - - return dst -} - -// Float64 returns a pointer to of the float64 value passed in. -func Float64(v float64) *float64 { - return &v -} - -// Float64Value returns the value of the float64 pointer passed in or -// 0 if the pointer is nil. -func Float64Value(v *float64) float64 { - if v != nil { - return *v - } - return 0 -} - -// Float64Slice converts a slice of float64 values into a slice of -// float64 pointers -func Float64Slice(src []float64) []*float64 { - dst := make([]*float64, len(src)) - for i := 0; i < len(src); i++ { - dst[i] = &(src[i]) - } - return dst -} - -// Float64ValueSlice converts a slice of float64 pointers into a slice of -// float64 values -func Float64ValueSlice(src []*float64) []float64 { - dst := make([]float64, len(src)) - for i := 0; i < len(src); i++ { - if src[i] != nil { - dst[i] = *(src[i]) - } - } - return dst -} - -// Float64Map converts a string map of float64 values into a string -// map of float64 pointers -func Float64Map(src map[string]float64) map[string]*float64 { - dst := make(map[string]*float64) - for k, val := range src { - v := val - dst[k] = &v - } - return dst -} - -// Float64ValueMap converts a string map of float64 pointers into a string -// map of float64 values -func Float64ValueMap(src map[string]*float64) map[string]float64 { - dst := make(map[string]float64) - for k, val := range src { - if val != nil { - dst[k] = *val - } - } - return dst -} - -// Time returns a pointer to of the time.Time value passed in. -func Time(v time.Time) *time.Time { - return &v -} - -// TimeValue returns the value of the time.Time pointer passed in or -// time.Time{} if the pointer is nil. -func TimeValue(v *time.Time) time.Time { - if v != nil { - return *v - } - return time.Time{} -} - -// TimeSlice converts a slice of time.Time values into a slice of -// time.Time pointers -func TimeSlice(src []time.Time) []*time.Time { - dst := make([]*time.Time, len(src)) - for i := 0; i < len(src); i++ { - dst[i] = &(src[i]) - } - return dst -} - -// TimeValueSlice converts a slice of time.Time pointers into a slice of -// time.Time values -func TimeValueSlice(src []*time.Time) []time.Time { - dst := make([]time.Time, len(src)) - for i := 0; i < len(src); i++ { - if src[i] != nil { - dst[i] = *(src[i]) - } - } - return dst -} - -// TimeMap converts a string map of time.Time values into a string -// map of time.Time pointers -func TimeMap(src map[string]time.Time) map[string]*time.Time { - dst := make(map[string]*time.Time) - for k, val := range src { - v := val - dst[k] = &v - } - return dst -} - -// TimeValueMap converts a string map of time.Time pointers into a string -// map of time.Time values -func TimeValueMap(src map[string]*time.Time) map[string]time.Time { - dst := make(map[string]time.Time) - for k, val := range src { - if val != nil { - dst[k] = *val - } - } - return dst -} diff --git a/convert_types_test.go b/convert_types_test.go deleted file mode 100644 index 0e41bc0..0000000 --- a/convert_types_test.go +++ /dev/null @@ -1,840 +0,0 @@ -// Copyright 2015 go-swagger maintainers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package swag - -import ( - "reflect" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestStringSlice(t *testing.T) { - testCasesStringSlice := [][]string{ - {"a", "b", "c", "d", "e"}, - {"a", "b", "", "", "e"}, - } - - for idx, in := range testCasesStringSlice { - if in == nil { - continue - } - out := StringSlice(in) - assertValues(t, in, out, true, idx) - - out2 := StringValueSlice(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestStringValueSlice(t *testing.T) { - testCasesStringValueSlice := [][]*string{ - {String("a"), String("b"), nil, String("c")}, - } - - for idx, in := range testCasesStringValueSlice { - if in == nil { - continue - } - out := StringValueSlice(in) - assertValues(t, in, out, false, idx) - - out2 := StringSlice(out) - assertValues(t, in, out2, true, idx) - } -} - -func TestStringMap(t *testing.T) { - testCasesStringMap := []map[string]string{ - {"a": "1", "b": "2", "c": "3"}, - } - - for idx, in := range testCasesStringMap { - if in == nil { - continue - } - out := StringMap(in) - assertValues(t, in, out, true, idx) - - out2 := StringValueMap(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestBoolSlice(t *testing.T) { - testCasesBoolSlice := [][]bool{ - {true, true, false, false}, - } - - for idx, in := range testCasesBoolSlice { - if in == nil { - continue - } - out := BoolSlice(in) - assertValues(t, in, out, true, idx) - - out2 := BoolValueSlice(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestBoolValueSlice(t *testing.T) { - testCasesBoolValueSlice := [][]*bool{ - {Bool(true), Bool(true), Bool(false), Bool(false)}, - } - - for idx, in := range testCasesBoolValueSlice { - if in == nil { - continue - } - out := BoolValueSlice(in) - assertValues(t, in, out, false, idx) - - out2 := BoolSlice(out) - assertValues(t, in, out2, true, idx) - } -} - -func TestBoolMap(t *testing.T) { - testCasesBoolMap := []map[string]bool{ - {"a": true, "b": false, "c": true}, - } - - for idx, in := range testCasesBoolMap { - if in == nil { - continue - } - out := BoolMap(in) - assertValues(t, in, out, true, idx) - - out2 := BoolValueMap(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestIntSlice(t *testing.T) { - testCasesIntSlice := [][]int{ - {1, 2, 3, 4}, - } - - for idx, in := range testCasesIntSlice { - if in == nil { - continue - } - out := IntSlice(in) - assertValues(t, in, out, true, idx) - - out2 := IntValueSlice(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestIntValueSlice(t *testing.T) { - testCasesIntValueSlice := [][]*int{ - {Int(1), Int(2), Int(3), Int(4)}, - } - - for idx, in := range testCasesIntValueSlice { - if in == nil { - continue - } - out := IntValueSlice(in) - assertValues(t, in, out, false, idx) - - out2 := IntSlice(out) - assertValues(t, in, out2, true, idx) - } -} - -func TestIntMap(t *testing.T) { - testCasesIntMap := []map[string]int{ - {"a": 3, "b": 2, "c": 1}, - } - - for idx, in := range testCasesIntMap { - if in == nil { - continue - } - out := IntMap(in) - assertValues(t, in, out, true, idx) - - out2 := IntValueMap(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestInt64Slice(t *testing.T) { - testCasesInt64Slice := [][]int64{ - {1, 2, 3, 4}, - } - - for idx, in := range testCasesInt64Slice { - if in == nil { - continue - } - out := Int64Slice(in) - assertValues(t, in, out, true, idx) - - out2 := Int64ValueSlice(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestInt64ValueSlice(t *testing.T) { - testCasesInt64ValueSlice := [][]*int64{ - {Int64(1), Int64(2), Int64(3), Int64(4)}, - } - - for idx, in := range testCasesInt64ValueSlice { - if in == nil { - continue - } - out := Int64ValueSlice(in) - assertValues(t, in, out, false, idx) - - out2 := Int64Slice(out) - assertValues(t, in, out2, true, idx) - } -} - -func TestInt64Map(t *testing.T) { - testCasesInt64Map := []map[string]int64{ - {"a": 3, "b": 2, "c": 1}, - } - - for idx, in := range testCasesInt64Map { - if in == nil { - continue - } - out := Int64Map(in) - assertValues(t, in, out, true, idx) - - out2 := Int64ValueMap(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestFloat32Slice(t *testing.T) { - testCasesFloat32Slice := [][]float32{ - {1, 2, 3, 4}, - } - - for idx, in := range testCasesFloat32Slice { - if in == nil { - continue - } - - out := Float32Slice(in) - assertValues(t, in, out, true, idx) - - out2 := Float32ValueSlice(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestFloat64Slice(t *testing.T) { - testCasesFloat64Slice := [][]float64{ - {1, 2, 3, 4}, - } - - for idx, in := range testCasesFloat64Slice { - if in == nil { - continue - } - out := Float64Slice(in) - assertValues(t, in, out, true, idx) - - out2 := Float64ValueSlice(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestUintSlice(t *testing.T) { - testCasesUintSlice := [][]uint{ - {1, 2, 3, 4}, - } - - for idx, in := range testCasesUintSlice { - if in == nil { - continue - } - out := UintSlice(in) - assertValues(t, in, out, true, idx) - - out2 := UintValueSlice(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestUintValueSlice(t *testing.T) { - testCasesUintValueSlice := [][]*uint{} - - for idx, in := range testCasesUintValueSlice { - if in == nil { - continue - } - out := UintValueSlice(in) - assertValues(t, in, out, true, idx) - - out2 := UintSlice(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestUintMap(t *testing.T) { - testCasesUintMap := []map[string]uint{ - {"a": 3, "b": 2, "c": 1}, - } - - for idx, in := range testCasesUintMap { - if in == nil { - continue - } - out := UintMap(in) - assertValues(t, in, out, true, idx) - - out2 := UintValueMap(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestUint16Slice(t *testing.T) { - testCasesUint16Slice := [][]uint16{ - {1, 2, 3, 4}, - } - - for idx, in := range testCasesUint16Slice { - if in == nil { - continue - } - - out := Uint16Slice(in) - assertValues(t, in, out, true, idx) - - out2 := Uint16ValueSlice(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestUint16ValueSlice(t *testing.T) { - testCasesUint16ValueSlice := [][]*uint16{} - - for idx, in := range testCasesUint16ValueSlice { - if in == nil { - continue - } - - out := Uint16ValueSlice(in) - assertValues(t, in, out, true, idx) - - out2 := Uint16Slice(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestUint16Map(t *testing.T) { - testCasesUint16Map := []map[string]uint16{ - {"a": 3, "b": 2, "c": 1}, - } - - for idx, in := range testCasesUint16Map { - if in == nil { - continue - } - - out := Uint16Map(in) - assertValues(t, in, out, true, idx) - - out2 := Uint16ValueMap(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestUint64Slice(t *testing.T) { - testCasesUint64Slice := [][]uint64{ - {1, 2, 3, 4}, - } - - for idx, in := range testCasesUint64Slice { - if in == nil { - continue - } - out := Uint64Slice(in) - assertValues(t, in, out, true, idx) - - out2 := Uint64ValueSlice(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestUint64ValueSlice(t *testing.T) { - testCasesUint64ValueSlice := [][]*uint64{} - - for idx, in := range testCasesUint64ValueSlice { - if in == nil { - continue - } - out := Uint64ValueSlice(in) - assertValues(t, in, out, true, idx) - - out2 := Uint64Slice(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestUint64Map(t *testing.T) { - testCasesUint64Map := []map[string]uint64{ - {"a": 3, "b": 2, "c": 1}, - } - - for idx, in := range testCasesUint64Map { - if in == nil { - continue - } - out := Uint64Map(in) - assertValues(t, in, out, true, idx) - - out2 := Uint64ValueMap(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestFloat32ValueSlice(t *testing.T) { - testCasesFloat32ValueSlice := [][]*float32{} - - for idx, in := range testCasesFloat32ValueSlice { - if in == nil { - continue - } - - out := Float32ValueSlice(in) - assertValues(t, in, out, true, idx) - - out2 := Float32Slice(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestFloat32Map(t *testing.T) { - testCasesFloat32Map := []map[string]float32{ - {"a": 3, "b": 2, "c": 1}, - } - - for idx, in := range testCasesFloat32Map { - if in == nil { - continue - } - - out := Float32Map(in) - assertValues(t, in, out, true, idx) - - out2 := Float32ValueMap(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestFloat64ValueSlice(t *testing.T) { - testCasesFloat64ValueSlice := [][]*float64{} - - for idx, in := range testCasesFloat64ValueSlice { - if in == nil { - continue - } - out := Float64ValueSlice(in) - assertValues(t, in, out, true, idx) - - out2 := Float64Slice(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestFloat64Map(t *testing.T) { - testCasesFloat64Map := []map[string]float64{ - {"a": 3, "b": 2, "c": 1}, - } - - for idx, in := range testCasesFloat64Map { - if in == nil { - continue - } - out := Float64Map(in) - assertValues(t, in, out, true, idx) - - out2 := Float64ValueMap(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestTimeSlice(t *testing.T) { - testCasesTimeSlice := [][]time.Time{ - {time.Now(), time.Now().AddDate(100, 0, 0)}, - } - - for idx, in := range testCasesTimeSlice { - if in == nil { - continue - } - out := TimeSlice(in) - assertValues(t, in, out, true, idx) - - out2 := TimeValueSlice(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestTimeValueSlice(t *testing.T) { - testCasesTimeValueSlice := [][]*time.Time{ - {Time(time.Now()), Time(time.Now().AddDate(100, 0, 0))}, - } - - for idx, in := range testCasesTimeValueSlice { - if in == nil { - continue - } - out := TimeValueSlice(in) - assertValues(t, in, out, false, idx) - - out2 := TimeSlice(out) - assertValues(t, in, out2, true, idx) - } -} - -func TestTimeMap(t *testing.T) { - testCasesTimeMap := []map[string]time.Time{ - {"a": time.Now().AddDate(-100, 0, 0), "b": time.Now()}, - } - - for idx, in := range testCasesTimeMap { - if in == nil { - continue - } - out := TimeMap(in) - assertValues(t, in, out, true, idx) - - out2 := TimeValueMap(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestInt32Slice(t *testing.T) { - testCasesInt32Slice := [][]int32{ - {1, 2, 3, 4}, - } - - for idx, in := range testCasesInt32Slice { - if in == nil { - continue - } - out := Int32Slice(in) - assertValues(t, in, out, true, idx) - - out2 := Int32ValueSlice(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestInt32ValueSlice(t *testing.T) { - testCasesInt32ValueSlice := [][]*int32{ - {Int32(1), Int32(2), Int32(3), Int32(4)}, - } - - for idx, in := range testCasesInt32ValueSlice { - if in == nil { - continue - } - out := Int32ValueSlice(in) - assertValues(t, in, out, false, idx) - - out2 := Int32Slice(out) - assertValues(t, in, out2, true, idx) - } -} - -func TestInt32Map(t *testing.T) { - testCasesInt32Map := []map[string]int32{ - {"a": 3, "b": 2, "c": 1}, - } - - for idx, in := range testCasesInt32Map { - if in == nil { - continue - } - out := Int32Map(in) - assertValues(t, in, out, true, idx) - - out2 := Int32ValueMap(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestUint32Slice(t *testing.T) { - testCasesUint32Slice := [][]uint32{ - {1, 2, 3, 4}, - } - - for idx, in := range testCasesUint32Slice { - if in == nil { - continue - } - out := Uint32Slice(in) - assertValues(t, in, out, true, idx) - - out2 := Uint32ValueSlice(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestUint32ValueSlice(t *testing.T) { - testCasesUint32ValueSlice := [][]*uint32{ - {Uint32(1), Uint32(2), Uint32(3), Uint32(4)}, - } - - for idx, in := range testCasesUint32ValueSlice { - if in == nil { - continue - } - out := Uint32ValueSlice(in) - assertValues(t, in, out, false, idx) - - out2 := Uint32Slice(out) - assertValues(t, in, out2, true, idx) - } -} - -func TestUint32Map(t *testing.T) { - testCasesUint32Map := []map[string]uint32{ - {"a": 3, "b": 2, "c": 1}, - } - - for idx, in := range testCasesUint32Map { - if in == nil { - continue - } - out := Uint32Map(in) - assertValues(t, in, out, true, idx) - - out2 := Uint32ValueMap(out) - assertValues(t, in, out2, false, idx) - } -} - -func TestStringValue(t *testing.T) { - testCasesString := []string{"a", "b", "c", "d", "e", ""} - - for idx, in := range testCasesString { - out := String(in) - assertValues(t, in, out, true, idx) - - out2 := StringValue(out) - assertValues(t, in, out2, false, idx) - } - assert.Zerof(t, StringValue(nil), "expected conversion from nil to return zero value") -} - -func TestBoolValue(t *testing.T) { - testCasesBool := []bool{true, false} - - for idx, in := range testCasesBool { - out := Bool(in) - assertValues(t, in, out, true, idx) - - out2 := BoolValue(out) - assertValues(t, in, out2, false, idx) - } - assert.Zerof(t, BoolValue(nil), "expected conversion from nil to return zero value") -} - -func TestIntValue(t *testing.T) { - testCasesInt := []int{1, 2, 3, 0} - - for idx, in := range testCasesInt { - out := Int(in) - assertValues(t, in, out, true, idx) - - out2 := IntValue(out) - assertValues(t, in, out2, false, idx) - } - assert.Zerof(t, IntValue(nil), "expected conversion from nil to return zero value") -} - -func TestInt32Value(t *testing.T) { - testCasesInt32 := []int32{1, 2, 3, 0} - - for idx, in := range testCasesInt32 { - out := Int32(in) - assertValues(t, in, out, true, idx) - - out2 := Int32Value(out) - assertValues(t, in, out2, false, idx) - } - assert.Zerof(t, Int32Value(nil), "expected conversion from nil to return zero value") -} - -func TestInt64Value(t *testing.T) { - testCasesInt64 := []int64{1, 2, 3, 0} - - for idx, in := range testCasesInt64 { - out := Int64(in) - assertValues(t, in, out, true, idx) - - out2 := Int64Value(out) - assertValues(t, in, out2, false, idx) - } - assert.Zerof(t, Int64Value(nil), "expected conversion from nil to return zero value") -} - -func TestUintValue(t *testing.T) { - testCasesUint := []uint{1, 2, 3, 0} - - for idx, in := range testCasesUint { - out := Uint(in) - assertValues(t, in, out, true, idx) - - out2 := UintValue(out) - assertValues(t, in, out2, false, idx) - } - assert.Zerof(t, UintValue(nil), "expected conversion from nil to return zero value") -} - -func TestUint32Value(t *testing.T) { - testCasesUint32 := []uint32{1, 2, 3, 0} - - for idx, in := range testCasesUint32 { - out := Uint32(in) - assertValues(t, in, out, true, idx) - - out2 := Uint32Value(out) - assertValues(t, in, out2, false, idx) - } - assert.Zerof(t, Uint32Value(nil), "expected conversion from nil to return zero value") -} - -func TestUint64Value(t *testing.T) { - testCasesUint64 := []uint64{1, 2, 3, 0} - - for idx, in := range testCasesUint64 { - out := Uint64(in) - assertValues(t, in, out, true, idx) - - out2 := Uint64Value(out) - assertValues(t, in, out2, false, idx) - } - assert.Zerof(t, Uint64Value(nil), "expected conversion from nil to return zero value") -} - -func TestFloat32Value(t *testing.T) { - testCasesFloat32 := []float32{1, 2, 3, 0} - - for idx, in := range testCasesFloat32 { - out := Float32(in) - assertValues(t, in, out, true, idx) - - out2 := Float32Value(out) - assertValues(t, in, out2, false, idx) - } - - assert.Zerof(t, Float32Value(nil), "expected conversion from nil to return zero value") -} - -func TestFloat64Value(t *testing.T) { - testCasesFloat64 := []float64{1, 2, 3, 0} - - for idx, in := range testCasesFloat64 { - out := Float64(in) - assertValues(t, in, out, true, idx) - - out2 := Float64Value(out) - assertValues(t, in, out2, false, idx) - } - assert.Zerof(t, Float64Value(nil), "expected conversion from nil to return zero value") -} - -func TestTimeValue(t *testing.T) { - testCasesTime := []time.Time{ - time.Now().AddDate(-100, 0, 0), time.Now(), - } - - for idx, in := range testCasesTime { - out := Time(in) - assertValues(t, in, out, true, idx) - - out2 := TimeValue(out) - assertValues(t, in, out2, false, idx) - } - assert.Zerof(t, TimeValue(nil), "expected conversion from nil to return zero value") -} - -func assertSingleValue(t *testing.T, inElem, elem reflect.Value, expectPointer bool, idx int) { - require.Equalf(t, - expectPointer, (elem.Kind() == reflect.Ptr), - "unexpected expectPointer=%t value type", expectPointer, - ) - - if inElem.Kind() == reflect.Ptr && !inElem.IsNil() { - inElem = reflect.Indirect(inElem) - } - - if elem.Kind() == reflect.Ptr && !elem.IsNil() { - elem = reflect.Indirect(elem) - } - - require.Truef(t, - (elem.Kind() == reflect.Ptr && elem.IsNil()) || - IsZero(elem.Interface()) == (inElem.Kind() == reflect.Ptr && inElem.IsNil()) || - IsZero(inElem.Interface()), - "unexpected nil pointer at idx %d", idx, - ) - - if !((elem.Kind() == reflect.Ptr && elem.IsNil()) || IsZero(elem.Interface())) { - require.IsTypef(t, inElem.Interface(), elem.Interface(), "Expected in/out to match types") - assert.EqualValuesf(t, inElem.Interface(), elem.Interface(), "Unexpected value at idx %d: %v", idx, elem.Interface()) - } -} - -// assertValues checks equivalent representation pointer vs values for single var, slices and maps -func assertValues(t *testing.T, in, out interface{}, expectPointer bool, idx int) { - vin := reflect.ValueOf(in) - vout := reflect.ValueOf(out) - - switch vin.Kind() { //nolint:exhaustive - case reflect.Slice, reflect.Map: - require.Equalf(t, vin.Kind(), vout.Kind(), "Unexpected output type at idx %d", idx) - require.Equalf(t, vin.Len(), vout.Len(), "Unexpected len at idx %d", idx) - - var elem, inElem reflect.Value - for i := 0; i < vin.Len(); i++ { - switch vin.Kind() { //nolint:exhaustive - case reflect.Slice: - elem = vout.Index(i) - inElem = vin.Index(i) - case reflect.Map: - keys := vin.MapKeys() - elem = vout.MapIndex(keys[i]) - inElem = vout.MapIndex(keys[i]) - default: - } - - assertSingleValue(t, inElem, elem, expectPointer, idx) - } - - default: - inElem := vin - elem := vout - - assertSingleValue(t, inElem, elem, expectPointer, idx) - } -} diff --git a/doc.go b/doc.go index 55094cb..eb9bf81 100644 --- a/doc.go +++ b/doc.go @@ -12,20 +12,24 @@ // See the License for the specific language governing permissions and // limitations under the License. -/* -Package swag contains a bunch of helper functions for go-openapi and go-swagger projects. - -You may also use it standalone for your projects. - - - convert between value and pointers for builtin types - - convert from string to builtin types (wraps strconv) - - fast json concatenation - - search in path - - load from file or http - - name mangling - -This repo has only few dependencies outside of the standard library: - - - YAML utilities depend on gopkg.in/yaml.v2 -*/ +// Package swag contains a bunch of helper functions for go-openapi and go-swagger projects. +// +// You may also use it standalone for your projects. +// +// Here is what is inside: +// +// Sub-package conv: +// - convert between value and pointers for builtin types +// - convert from string to builtin types (wraps strconv) +// +// Package swag: +// - fast json concatenation +// - search in path +// - load from file or http +// - name mangling +// +// This repo has a few dependencies outside of the standard library: +// +// - YAML utilities depend on [gopkg.in/yaml.v3] +// - JSON utilities depend on [mailru/easyjson] package swag diff --git a/errors.go b/errors.go index 6c67fbf..ac35f60 100644 --- a/errors.go +++ b/errors.go @@ -1,3 +1,17 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package swag type swagError string diff --git a/file_test.go b/file_test.go index b2bed79..41f76cd 100644 --- a/file_test.go +++ b/file_test.go @@ -1,3 +1,17 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package swag import ( diff --git a/split_test.go b/split_test.go index b8574bc..063900d 100644 --- a/split_test.go +++ b/split_test.go @@ -1,3 +1,17 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package swag import ( diff --git a/string_bytes.go b/string_bytes.go index 90745d5..6af9419 100644 --- a/string_bytes.go +++ b/string_bytes.go @@ -1,3 +1,17 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package swag import "unsafe" diff --git a/typeutils/types.go b/typeutils/types.go new file mode 100644 index 0000000..a60ca9a --- /dev/null +++ b/typeutils/types.go @@ -0,0 +1,45 @@ +package typeutils + +import "reflect" + +type zeroable interface { + IsZero() bool +} + +// IsZero returns true when the value passed into the function is a zero value. +// This allows for safer checking of interface values. +func IsZero(data interface{}) bool { + v := reflect.ValueOf(data) + // check for nil data + switch v.Kind() { //nolint:exhaustive + case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: + if v.IsNil() { + return true + } + } + + // check for things that have an IsZero method instead + if vv, ok := data.(zeroable); ok { + return vv.IsZero() + } + + // continue with slightly more complex reflection + switch v.Kind() { //nolint:exhaustive + case reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Struct, reflect.Array: + return reflect.DeepEqual(data, reflect.Zero(v.Type()).Interface()) + case reflect.Invalid: + return true + default: + return false + } +} diff --git a/typeutils/types_test.go b/typeutils/types_test.go new file mode 100644 index 0000000..72eaad0 --- /dev/null +++ b/typeutils/types_test.go @@ -0,0 +1,111 @@ +package typeutils + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +type SimpleZeroes struct { + ID string + Name string +} +type ZeroesWithTime struct { + Time time.Time +} + +type dummyZeroable struct { + zero bool +} + +func (d dummyZeroable) IsZero() bool { + return d.zero +} + +func TestIsZero(t *testing.T) { + var strs [5]string + var strss []string + var a int + var b int8 + var c int16 + var d int32 + var e int64 + var f uint + var g uint8 + var h uint16 + var i uint32 + var j uint64 + var k map[string]string + var l interface{} + var m *SimpleZeroes + var n string + var o SimpleZeroes + var p ZeroesWithTime + var q time.Time + var z bool + data := []struct { + Data interface{} + Expected bool + }{ + {a, true}, + {b, true}, + {c, true}, + {d, true}, + {e, true}, + {f, true}, + {g, true}, + {h, true}, + {i, true}, + {j, true}, + {k, true}, + {l, true}, + {m, true}, + {n, true}, + {o, true}, + {p, true}, + {q, true}, + {strss, true}, + {strs, true}, + {"", true}, + {nil, true}, + {1, false}, + {0, true}, + {int8(1), false}, + {int8(0), true}, + {int16(1), false}, + {int16(0), true}, + {int32(1), false}, + {int32(0), true}, + {int64(1), false}, + {int64(0), true}, + {uint(1), false}, + {uint(0), true}, + {uint8(1), false}, + {uint8(0), true}, + {uint16(1), false}, + {uint16(0), true}, + {uint32(1), false}, + {uint32(0), true}, + {uint64(1), false}, + {uint64(0), true}, + {0.0, true}, + {0.1, false}, + {float32(0.0), true}, + {float32(0.1), false}, + {float64(0.0), true}, + {float64(0.1), false}, + {[...]string{}, true}, + {[...]string{"hello"}, false}, + {[]string(nil), true}, + {[]string{"a"}, false}, + {&dummyZeroable{true}, true}, + {&dummyZeroable{false}, false}, + {(*dummyZeroable)(nil), true}, + {z, true}, + } + + for _, it := range data { + assert.Equalf(t, it.Expected, IsZero(it.Data), "expected %#v, but got %#v", it.Expected, it.Data) + } +} diff --git a/typeutils_iface.go b/typeutils_iface.go new file mode 100644 index 0000000..b104a80 --- /dev/null +++ b/typeutils_iface.go @@ -0,0 +1,23 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package swag + +import "github.com/go-openapi/swag/typeutils" + +// IsZero returns true when the value passed into the function is a zero value. +// This allows for safer checking of interface values. +// +// Deprecated: use [typeutils.IsZero] instead. +func IsZero(data interface{}) bool { return typeutils.IsZero(data) } diff --git a/typeutils_iface_test.go b/typeutils_iface_test.go new file mode 100644 index 0000000..73a1371 --- /dev/null +++ b/typeutils_iface_test.go @@ -0,0 +1,28 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package swag + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestTypeUtilsIface(t *testing.T) { + t.Run("deprecated type utility functions should work", func(t *testing.T) { + // only check happy path - more comprehensive testing is carried out inside the called packag + require.True(t, IsZero(0)) + }) +} diff --git a/util.go b/util.go index 99be5cc..65328f4 100644 --- a/util.go +++ b/util.go @@ -15,7 +15,6 @@ package swag import ( - "reflect" "strings" "unicode" "unicode/utf8" @@ -308,48 +307,6 @@ func ContainsStringsCI(coll []string, item string) bool { return false } -type zeroable interface { - IsZero() bool -} - -// IsZero returns true when the value passed into the function is a zero value. -// This allows for safer checking of interface values. -func IsZero(data interface{}) bool { - v := reflect.ValueOf(data) - // check for nil data - switch v.Kind() { //nolint:exhaustive - case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice: - if v.IsNil() { - return true - } - } - - // check for things that have an IsZero method instead - if vv, ok := data.(zeroable); ok { - return vv.IsZero() - } - - // continue with slightly more complex reflection - switch v.Kind() { //nolint:exhaustive - case reflect.String: - return v.Len() == 0 - case reflect.Bool: - return !v.Bool() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return v.Uint() == 0 - case reflect.Float32, reflect.Float64: - return v.Float() == 0 - case reflect.Struct, reflect.Array: - return reflect.DeepEqual(data, reflect.Zero(v.Type()).Interface()) - case reflect.Invalid: - return true - default: - return false - } -} - // CommandLineOptionsGroup represents a group of user-defined command line options type CommandLineOptionsGroup struct { ShortDescription string diff --git a/util_benchmark_test.go b/util_benchmark_test.go index f393af0..daa8230 100644 --- a/util_benchmark_test.go +++ b/util_benchmark_test.go @@ -1,3 +1,17 @@ +// Copyright 2015 go-swagger maintainers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package swag import (