Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix int/float conversion to bool #2893

Merged
merged 14 commits into from
Jan 22, 2019
Merged
15 changes: 9 additions & 6 deletions types/conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,14 @@ func Convert(from Val, toID TypeID) (Val, error) {
case StringID, DefaultID:
*res = vc
case BoolID:
val, err := strconv.ParseBool(vc)
if err != nil {
return to, err
*res = false
if vc != "" {
val, err := strconv.ParseBool(vc)
if err != nil {
return to, err
}
*res = bool(val)
}
*res = bool(val)
case DateTimeID:
t, err := ParseTime(vc)
if err != nil {
Expand Down Expand Up @@ -162,7 +165,7 @@ func Convert(from Val, toID TypeID) (Val, error) {
case FloatID:
*res = float64(vc)
case BoolID:
*res = bool(vc != 1)
*res = bool(vc != 0)
case StringID, DefaultID:
*res = string(strconv.FormatInt(vc, 10))
case DateTimeID:
Expand Down Expand Up @@ -194,7 +197,7 @@ func Convert(from Val, toID TypeID) (Val, error) {
}
*res = int64(vc)
case BoolID:
*res = bool(vc != 1)
*res = bool(vc != 0)
case StringID, DefaultID:
*res = string(strconv.FormatFloat(float64(vc), 'G', -1, 64))
case DateTimeID:
Expand Down
108 changes: 108 additions & 0 deletions types/conversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
package types

import (
"math"
"reflect"
"strings"
"testing"
"time"

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

func TestSameConversionString(t *testing.T) {
Expand Down Expand Up @@ -161,6 +164,111 @@ func TestConvertToPassword(t *testing.T) {
}
}

func TestConvertIntToBool(t *testing.T) {
tests := []struct {
in Val
out Val
}{
{in: Val{Tid: IntID, Value: []byte{3, 0, 0, 0, 0, 0, 0, 0}}, out: Val{Tid: BoolID, Value: true}},
{in: Val{Tid: IntID, Value: []byte{253, 255, 255, 255, 255, 255, 255, 255}}, out: Val{Tid: BoolID, Value: true}},
{in: Val{Tid: IntID, Value: []byte{0, 0, 0, 0, 0, 0, 0, 0}}, out: Val{Tid: BoolID, Value: false}},
}
for _, tc := range tests {
out, err := Convert(tc.in, BoolID)
require.NoError(t, err)
require.EqualValues(t, tc.out, out)
}
}

func TestConvertFloatToBool(t *testing.T) {
tests := []struct {
n float64
in Val
out Val
}{
{n: 3.0, in: Val{Tid: FloatID, Value: []byte{7, 95, 152, 76, 21, 140, 11, 64}}, out: Val{Tid: BoolID, Value: true}},
{n: -3.5, in: Val{Tid: FloatID, Value: []byte{0, 0, 0, 0, 0, 0, 12, 192}}, out: Val{Tid: BoolID, Value: true}},
{n: 0, in: Val{Tid: FloatID, Value: []byte{0, 0, 0, 0, 0, 0, 0, 0}}, out: Val{Tid: BoolID, Value: false}},
{n: math.NaN(), in: Val{Tid: FloatID, Value: []byte{1, 0, 0, 0, 0, 0, 248, 127}}, out: Val{Tid: BoolID, Value: true}},
{n: math.Inf(1), in: Val{Tid: FloatID, Value: []byte{0, 0, 0, 0, 0, 0, 240, 127}}, out: Val{Tid: BoolID, Value: true}},
{n: math.Inf(-1), in: Val{Tid: FloatID, Value: []byte{0, 0, 0, 0, 0, 0, 240, 255}}, out: Val{Tid: BoolID, Value: true}},
}
for _, tc := range tests {
out, err := Convert(tc.in, BoolID)
require.NoError(t, err)
require.EqualValues(t, tc.out, out, "%f should be %t", tc.n, tc.out.Value)
}
}

func TestConvertStringToBool(t *testing.T) {
tests := []struct {
in Val
out Val
fail bool
}{
{in: Val{Tid: StringID, Value: []byte("1")}, out: Val{Tid: BoolID, Value: true}},
{in: Val{Tid: StringID, Value: []byte("true")}, out: Val{Tid: BoolID, Value: true}},
{in: Val{Tid: StringID, Value: []byte("True")}, out: Val{Tid: BoolID, Value: true}},
{in: Val{Tid: StringID, Value: []byte("T")}, out: Val{Tid: BoolID, Value: true}},
{in: Val{Tid: StringID, Value: []byte("F")}, out: Val{Tid: BoolID, Value: false}},
{in: Val{Tid: StringID, Value: []byte("0")}, out: Val{Tid: BoolID, Value: false}},
{in: Val{Tid: StringID, Value: []byte("false")}, out: Val{Tid: BoolID, Value: false}},
{in: Val{Tid: StringID, Value: []byte("False")}, out: Val{Tid: BoolID, Value: false}},
{in: Val{Tid: StringID, Value: []byte("srfrog")}, fail: true},
{in: Val{Tid: StringID, Value: []byte("")}, out: Val{Tid: BoolID, Value: false}},
{in: Val{Tid: StringID, Value: []byte("3")}, fail: true},
{in: Val{Tid: StringID, Value: []byte("-3")}, fail: true},
}
for _, tc := range tests {
out, err := Convert(tc.in, BoolID)
if tc.fail {
require.Error(t, err)
continue
}
require.NoError(t, err)
require.EqualValues(t, tc.out, out)
}
}

func TestConvertDateTimeToBool(t *testing.T) {
val, err := time.Now().MarshalBinary()
require.NoError(t, err)
in := Val{Tid: DateTimeID, Value: val}
_, err = Convert(in, BoolID)
require.Error(t, err)
require.EqualError(t, err, "Cannot convert datetime to type bool")
}

func TestConvertBoolToDateTime(t *testing.T) {
in := Val{Tid: BoolID, Value: []byte{1}}
_, err := Convert(in, DateTimeID)
require.Error(t, err)
require.EqualError(t, err, "Cannot convert bool to type datetime")
}

func TestConvertBoolToInt(t *testing.T) {
tests := []struct {
in Val
out Val
failure string
}{
{in: Val{Tid: BoolID, Value: []byte{1}}, out: Val{Tid: IntID, Value: int64(1)}},
{in: Val{Tid: BoolID, Value: []byte{0}}, out: Val{Tid: IntID, Value: int64(0)}},
{in: Val{Tid: BoolID, Value: []byte{3}},
failure: "Invalid value for bool 3"},
}
for _, tc := range tests {
out, err := Convert(tc.in, IntID)
if tc.failure != "" {
require.Error(t, err)
require.EqualError(t, err, tc.failure)
continue
}
require.NoError(t, err)
require.EqualValues(t, tc.out, out)
}
}

/*
func TestSameConversionFloat(t *testing.T) {
data := []struct {
Expand Down