From 64bcc4cf2a3fbc616e4ab99f0e9de5cbad9a9bbb Mon Sep 17 00:00:00 2001 From: srfrog Date: Mon, 14 Jan 2019 11:36:10 -0700 Subject: [PATCH 01/11] fix conversion from int/float to bool to make zero equal to false --- types/conversion.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/types/conversion.go b/types/conversion.go index 50ca4389adb..f75af56373e 100644 --- a/types/conversion.go +++ b/types/conversion.go @@ -162,7 +162,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: @@ -194,7 +194,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: From ebf223921dee44d62f534aecaaa8fd1b2ed00ea8 Mon Sep 17 00:00:00 2001 From: srfrog Date: Mon, 14 Jan 2019 13:14:47 -0700 Subject: [PATCH 02/11] added tests for int/float -> bool conversion --- types/conversion_test.go | 108 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/types/conversion_test.go b/types/conversion_test.go index 40f10739351..10dfc7fc3de 100644 --- a/types/conversion_test.go +++ b/types/conversion_test.go @@ -17,10 +17,13 @@ package types import ( + "math" "reflect" "strings" "testing" "time" + + "github.com/stretchr/testify/require" ) func TestSameConversionString(t *testing.T) { @@ -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("")}, fail: true}, + {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 { From 0dc2d440ad3725008ec7c2fb7f80efb484c48c8b Mon Sep 17 00:00:00 2001 From: srfrog Date: Tue, 15 Jan 2019 20:59:57 -0700 Subject: [PATCH 03/11] change convert empty string to boolean false --- types/conversion.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/types/conversion.go b/types/conversion.go index f75af56373e..29e5234e03a 100644 --- a/types/conversion.go +++ b/types/conversion.go @@ -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 { From 40521fcb2798903f21b0154a04f39143e0563077 Mon Sep 17 00:00:00 2001 From: srfrog Date: Tue, 15 Jan 2019 21:00:32 -0700 Subject: [PATCH 04/11] update test to account for empty string to bool false --- types/conversion_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/conversion_test.go b/types/conversion_test.go index 10dfc7fc3de..6f32026caba 100644 --- a/types/conversion_test.go +++ b/types/conversion_test.go @@ -215,7 +215,7 @@ func TestConvertStringToBool(t *testing.T) { {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("")}, 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}, } From 33080a85fc6123ce4cd815413c76649a8bdcb08f Mon Sep 17 00:00:00 2001 From: srfrog Date: Wed, 16 Jan 2019 15:28:37 -0700 Subject: [PATCH 05/11] added truthy value test --- types/conversion_test.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/types/conversion_test.go b/types/conversion_test.go index 6f32026caba..1ac3996c161 100644 --- a/types/conversion_test.go +++ b/types/conversion_test.go @@ -269,6 +269,35 @@ func TestConvertBoolToInt(t *testing.T) { } } +func TestTruthy(t *testing.T) { + tests := []struct { + in Val + out Val + }{ + { + in: Val{Tid: StringID, Value: []byte("true")}, + out: Val{Tid: BoolID, Value: true}, + }, + { + in: Val{Tid: DefaultID, Value: []byte("true")}, + out: Val{Tid: BoolID, Value: true}, + }, + { + in: Val{Tid: IntID, Value: []byte{0, 0, 0, 0, 0, 0, 0, 1}}, + out: Val{Tid: BoolID, Value: true}, + }, + { + in: Val{Tid: FloatID, Value: []byte{0, 0, 0, 0, 0, 0, 0, 1}}, + out: Val{Tid: BoolID, Value: true}, + }, + } + for _, tc := range tests { + out, err := Convert(tc.in, tc.out.Tid) + require.NoError(t, err) + require.EqualValues(t, tc.out, out) + } +} + /* func TestSameConversionFloat(t *testing.T) { data := []struct { From a42954fa8bebf548c9764eef6f0551f39aca99d3 Mon Sep 17 00:00:00 2001 From: srfrog Date: Wed, 16 Jan 2019 19:50:01 -0700 Subject: [PATCH 06/11] added falsy value test --- types/conversion_test.go | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/types/conversion_test.go b/types/conversion_test.go index 1ac3996c161..6ec7802e699 100644 --- a/types/conversion_test.go +++ b/types/conversion_test.go @@ -298,6 +298,35 @@ func TestTruthy(t *testing.T) { } } +func TestFalsy(t *testing.T) { + tests := []struct { + in Val + out Val + }{ + { + in: Val{Tid: StringID, Value: []byte("false")}, + out: Val{Tid: BoolID, Value: false}, + }, + { + in: Val{Tid: DefaultID, Value: []byte("false")}, + out: Val{Tid: BoolID, Value: false}, + }, + { + in: Val{Tid: IntID, Value: []byte{0, 0, 0, 0, 0, 0, 0, 0}}, + out: Val{Tid: BoolID, Value: false}, + }, + { + in: Val{Tid: FloatID, 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, tc.out.Tid) + require.NoError(t, err) + require.EqualValues(t, tc.out, out) + } +} + /* func TestSameConversionFloat(t *testing.T) { data := []struct { From b1cfb5dd11dfdf3048d42f5d0a51e34882e5413b Mon Sep 17 00:00:00 2001 From: srfrog Date: Thu, 17 Jan 2019 10:26:44 -0700 Subject: [PATCH 07/11] simplified tests and added more cases --- types/conversion_test.go | 64 +++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 24 deletions(-) diff --git a/types/conversion_test.go b/types/conversion_test.go index 6ec7802e699..bbc9dceae59 100644 --- a/types/conversion_test.go +++ b/types/conversion_test.go @@ -271,59 +271,75 @@ func TestConvertBoolToInt(t *testing.T) { func TestTruthy(t *testing.T) { tests := []struct { - in Val - out Val + s string + in Val }{ { - in: Val{Tid: StringID, Value: []byte("true")}, - out: Val{Tid: BoolID, Value: true}, + s: "true", + in: Val{Tid: StringID, Value: []byte("true")}, + }, + { + s: "true", + in: Val{Tid: DefaultID, Value: []byte("true")}, }, { - in: Val{Tid: DefaultID, Value: []byte("true")}, - out: Val{Tid: BoolID, Value: true}, + s: "1", + in: Val{Tid: IntID, Value: []byte{0, 0, 0, 0, 0, 0, 0, 1}}, }, { - in: Val{Tid: IntID, Value: []byte{0, 0, 0, 0, 0, 0, 0, 1}}, - out: Val{Tid: BoolID, Value: true}, + s: "-1", + in: Val{Tid: IntID, Value: []byte{255, 255, 255, 255, 255, 255, 255, 255}}, }, { - in: Val{Tid: FloatID, Value: []byte{0, 0, 0, 0, 0, 0, 0, 1}}, - out: Val{Tid: BoolID, Value: true}, + s: "1.0", + in: Val{Tid: FloatID, Value: []byte{0, 0, 0, 0, 0, 0, 0, 1}}, + }, + { + s: "-1.0", + in: Val{Tid: FloatID, Value: []byte{0, 0, 0, 0, 0, 0, 240, 191}}, }, } for _, tc := range tests { - out, err := Convert(tc.in, tc.out.Tid) + out, err := Convert(tc.in, BoolID) require.NoError(t, err) - require.EqualValues(t, tc.out, out) + require.EqualValues(t, true, out.Value, "%s %s should be true", tc.in.Tid.Name(), tc.s) } } func TestFalsy(t *testing.T) { tests := []struct { - in Val - out Val + s string + in Val }{ { - in: Val{Tid: StringID, Value: []byte("false")}, - out: Val{Tid: BoolID, Value: false}, + s: "false", + in: Val{Tid: StringID, Value: []byte("false")}, + }, + { + s: "", + in: Val{Tid: StringID, Value: []byte("")}, }, { - in: Val{Tid: DefaultID, Value: []byte("false")}, - out: Val{Tid: BoolID, Value: false}, + s: "false", + in: Val{Tid: DefaultID, Value: []byte("false")}, }, { - in: Val{Tid: IntID, Value: []byte{0, 0, 0, 0, 0, 0, 0, 0}}, - out: Val{Tid: BoolID, Value: false}, + s: "", + in: Val{Tid: DefaultID, Value: []byte("")}, }, { - in: Val{Tid: FloatID, Value: []byte{0, 0, 0, 0, 0, 0, 0, 0}}, - out: Val{Tid: BoolID, Value: false}, + s: "0", + in: Val{Tid: IntID, Value: []byte{0, 0, 0, 0, 0, 0, 0, 0}}, + }, + { + s: "0.0", + in: Val{Tid: FloatID, Value: []byte{0, 0, 0, 0, 0, 0, 0, 0}}, }, } for _, tc := range tests { - out, err := Convert(tc.in, tc.out.Tid) + out, err := Convert(tc.in, BoolID) require.NoError(t, err) - require.EqualValues(t, tc.out, out) + require.EqualValues(t, false, out.Value, "%s %s should be false", tc.in.Tid.Name(), tc.s) } } From e1b505099ce47ab49ba99b5f08715662740112de Mon Sep 17 00:00:00 2001 From: srfrog Date: Thu, 17 Jan 2019 14:36:56 -0700 Subject: [PATCH 08/11] refactor tests for legibility and support --- types/conversion_test.go | 502 ++++++++++++++++++++++++++------------- 1 file changed, 336 insertions(+), 166 deletions(-) diff --git a/types/conversion_test.go b/types/conversion_test.go index bbc9dceae59..2148c29850c 100644 --- a/types/conversion_test.go +++ b/types/conversion_test.go @@ -17,329 +17,499 @@ package types import ( + "encoding/binary" "math" - "reflect" - "strings" "testing" "time" "github.com/stretchr/testify/require" ) +func bs(v interface{}) []byte { + switch x := v.(type) { + case bool: + if x { + return []byte{1} + } + return []byte{0} + case int64: + var bs [8]byte + binary.LittleEndian.PutUint64(bs[:], uint64(x)) + return bs[:] + case float64: + var bs [8]byte + binary.LittleEndian.PutUint64(bs[:], math.Float64bits(x)) + return bs[:] + case time.Time: + bs, err := x.MarshalBinary() + if err == nil { + return bs + } + } + return nil +} + func TestSameConversionString(t *testing.T) { - data := []struct { - in Val - out Val + tests := []struct { + in string }{ - {Val{StringID, []byte("a")}, Val{StringID, "a"}}, - {Val{StringID, []byte("")}, Val{StringID, ""}}, - {Val{DefaultID, []byte("abc")}, Val{StringID, "abc"}}, + {in: "a"}, + {in: ""}, } - for _, tc := range data { - if v, err := Convert(tc.in, StringID); err != nil { - t.Errorf("Unexpected error converting int to bool: %v", err) - } else if v != tc.out { - t.Errorf("Converting string to string: Expected %v, got %v", tc.out, v) - } + for _, tc := range tests { + out, err := Convert(Val{Tid: BinaryID, Value: []byte(tc.in)}, StringID) + require.NoError(t, err) + require.EqualValues(t, Val{Tid: StringID, Value: tc.in}, out) } } func TestConvertToDefault(t *testing.T) { - data := []struct { + tests := []struct { in Val - out Val + out string }{ - {Val{StringID, []byte("a")}, Val{DefaultID, "a"}}, - {Val{StringID, []byte("")}, Val{DefaultID, ""}}, - {Val{DefaultID, []byte("abc")}, Val{DefaultID, "abc"}}, - {Val{BinaryID, []byte("2016")}, Val{DefaultID, "2016"}}, + { + in: Val{StringID, []byte("a")}, + out: "a", + }, + { + in: Val{StringID, []byte("")}, + out: "", + }, + { + in: Val{DefaultID, []byte("abc")}, + out: "abc", + }, + { + in: Val{BinaryID, []byte("2016")}, + out: "2016", + }, + { + in: Val{IntID, bs(int64(3))}, + out: "3", + }, + { + in: Val{FloatID, bs(float64(-3.5))}, + out: "-3.5", + }, + { + in: Val{DateTimeID, bs(time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC))}, + out: "2006-01-02T15:04:05Z", + }, } - for _, tc := range data { - if v, err := Convert(tc.in, DefaultID); err != nil { - t.Errorf("Unexpected error converting int to bool: %v", err) - } else if !reflect.DeepEqual(v, tc.out) { - t.Errorf("Converting string to string: Expected %v, got %v", tc.out, v) - } + for _, tc := range tests { + out, err := Convert(tc.in, DefaultID) + require.NoError(t, err) + require.EqualValues(t, Val{Tid: DefaultID, Value: tc.out}, out) } } func TestConvertFromDefault(t *testing.T) { - data := []struct { - in Val + tests := []struct { + in string out Val - typ TypeID }{ - {Val{DefaultID, []byte("1")}, Val{IntID, int64(1)}, IntID}, - {Val{DefaultID, []byte("1.3")}, Val{FloatID, 1.3}, FloatID}, - {Val{DefaultID, []byte("true")}, Val{BoolID, true}, BoolID}, - {Val{DefaultID, []byte("2016")}, Val{BinaryID, []byte("2016")}, BinaryID}, + { + in: "1", + out: Val{IntID, int64(1)}, + }, + { + in: "1.3", + out: Val{FloatID, float64(1.3)}, + }, + { + in: "true", + out: Val{BoolID, true}, + }, + { + in: "2016", + out: Val{BinaryID, []byte("2016")}, + }, + { + in: "", + out: Val{BinaryID, []byte("")}, + }, + { + in: "hello", + out: Val{StringID, "hello"}, + }, + { + in: "", + out: Val{StringID, ""}, + }, + { + in: "2016", + out: Val{DateTimeID, time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)}, + }, } - for _, tc := range data { - if v, err := Convert(tc.in, tc.typ); err != nil { - t.Errorf("Unexpected error converting int to bool: %v", err) - } else if !reflect.DeepEqual(v, tc.out) { - t.Errorf("Converting string to string: Expected %+v, got %+v", tc.out, v) - } + for _, tc := range tests { + out, err := Convert(Val{DefaultID, []byte(tc.in)}, tc.out.Tid) + require.NoError(t, err) + require.EqualValues(t, tc.out, out) } } -func TestConversionToDateTime(t *testing.T) { - data := []struct { - in Val +func TestConvertStringToDateTime(t *testing.T) { + tests := []struct { + in string out time.Time }{ { - Val{StringID, []byte("2006-01-02T15:04:05")}, - time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC), + in: "2006-01-02T15:04:05", + out: time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC), }, { - Val{StringID, []byte("2006-01-02")}, - time.Date(2006, 01, 02, 0, 0, 0, 0, time.UTC), + in: "2006-01-02", + out: time.Date(2006, 01, 02, 0, 0, 0, 0, time.UTC), }, { - Val{StringID, []byte("2006-01")}, - time.Date(2006, 01, 01, 0, 0, 0, 0, time.UTC), + in: "2006-01", + out: time.Date(2006, 01, 01, 0, 0, 0, 0, time.UTC), }, { - Val{StringID, []byte("2006")}, - time.Date(2006, 01, 01, 0, 0, 0, 0, time.UTC), + in: "2006", + out: time.Date(2006, 01, 01, 0, 0, 0, 0, time.UTC), }, } - for _, tc := range data { - if val, err := Convert(tc.in, DateTimeID); err != nil { - t.Errorf("Unexpected error converting string to datetime: %v", err) - } else if !tc.out.Equal(val.Value.(time.Time)) { - t.Errorf("Converting string to datetime: Expected %+v, got %+v", tc.out, val.Value) - } + for _, tc := range tests { + out, err := Convert(Val{Tid: StringID, Value: []byte(tc.in)}, DateTimeID) + require.NoError(t, err) + require.EqualValues(t, Val{Tid: DateTimeID, Value: tc.out}, out) } } func TestConvertFromPassword(t *testing.T) { - data := []struct { - in Val - out Val - typ TypeID + tests := []struct { + in string + out Val + failure string }{ - {Val{PasswordID, []byte("")}, Val{StringID, ""}, StringID}, - {Val{PasswordID, []byte("testing")}, Val{StringID, "testing"}, StringID}, + { + in: "", + out: Val{StringID, ""}, + }, + { + in: "password", + out: Val{PasswordID, "password"}, + }, + { + in: "password", + out: Val{StringID, "password"}, + }, + { + in: "password", + out: Val{BinaryID, []byte("password")}, + }, + { + in: "password", + failure: `Cannot convert password to type default`, + }, + { + in: "password", out: Val{IntID, bs(int64(1))}, + failure: `Cannot convert password to type int`, + }, + { + in: "password", out: Val{FloatID, bs(float64(1.0))}, + failure: `Cannot convert password to type float`, + }, + { + in: "password", out: Val{BoolID, bs(true)}, + failure: `Cannot convert password to type bool`, + }, } - for _, tc := range data { - if val, err := Convert(tc.in, tc.typ); err != nil { - t.Errorf("Unexpected error converting to string: %v", err) - } else if !reflect.DeepEqual(val, tc.out) { - t.Errorf("Converting password to string: Expected %+v, got %+v", tc.out, val) + for _, tc := range tests { + out, err := Convert(Val{Tid: PasswordID, Value: []byte(tc.in)}, tc.out.Tid) + 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 TestConvertToPassword(t *testing.T) { - data := []struct { - in Val - out Val - hasError bool + tests := []struct { + in Val + out string + failure string }{ - {Val{IntID, []byte{0, 0, 0, 0, 0, 0, 0, 1}}, Val{PasswordID, ""}, true}, - {Val{FloatID, []byte{0, 0, 0, 0, 0, 0, 0, 1}}, Val{PasswordID, ""}, true}, - {Val{BoolID, []byte{1}}, Val{PasswordID, ""}, true}, - {Val{StringID, []byte("")}, Val{PasswordID, ""}, true}, - {Val{StringID, []byte("testing")}, Val{PasswordID, "$2a$10$"}, false}, - {Val{PasswordID, []byte("testing")}, Val{PasswordID, "testing"}, false}, - {Val{DefaultID, []byte("testing")}, Val{PasswordID, "$2a$10$"}, false}, - } - - for i, tc := range data { - val, err := Convert(tc.in, PasswordID) - if err != nil && !tc.hasError { - t.Errorf("test#%d Unexpected error converting to string: %v", i+1, err) - } else if err == nil && tc.hasError { - t.Errorf("test#%d Expected an error but got instead: %+v", i+1, val) - } else if !strings.HasPrefix(val.Value.(string), tc.out.Value.(string)) { - t.Errorf("test#%d Converting string to password: Expected %+v, got %+v", i+1, tc.out, val) + { + in: Val{StringID, []byte("testing")}, + out: "$2a$10$", + }, + { + in: Val{PasswordID, []byte("testing")}, + out: "testing", + }, + { + in: Val{DefaultID, []byte("testing")}, + out: "$2a$10$", + }, + { + in: Val{StringID, []byte("")}, + failure: `Password too short, i.e. should has at least 6 chars`, + }, + { + in: Val{IntID, bs(int64(1))}, + failure: `Cannot convert int to type password`, + }, + { + in: Val{FloatID, bs(float64(1.0))}, + failure: `Cannot convert float to type password`, + }, + { + in: Val{BoolID, bs(true)}, + failure: `Cannot convert bool to type password`, + }, + } + + for _, tc := range tests { + out, err := Convert(tc.in, PasswordID) + if tc.failure != "" { + require.Error(t, err) + require.EqualError(t, err, tc.failure) + continue } + require.NoError(t, err) + if tc.in.Tid == PasswordID { + require.EqualValues(t, Val{Tid: PasswordID, Value: tc.out}, out) + continue + } + require.True(t, out.Tid == PasswordID) + require.NoError(t, VerifyPassword(string(tc.in.Value.([]byte)), out.Value.(string))) } } func TestConvertIntToBool(t *testing.T) { tests := []struct { - in Val - out Val + in int64 + out bool }{ - {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}}, + { + in: int64(3), + out: true, + }, + { + in: int64(-3), + out: true, + }, + { + in: int64(0), + out: false, + }, } + for _, tc := range tests { - out, err := Convert(tc.in, BoolID) + out, err := Convert(Val{Tid: IntID, Value: bs(tc.in)}, BoolID) require.NoError(t, err) - require.EqualValues(t, tc.out, out) + require.EqualValues(t, Val{Tid: BoolID, Value: tc.out}, out) } } func TestConvertFloatToBool(t *testing.T) { tests := []struct { - n float64 - in Val - out Val + in float64 + out bool }{ - {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}}, + { + in: float64(3.0), + out: true, + }, + { + in: float64(-3.5), + out: true, + }, + { + in: float64(0), + out: false, + }, + { + in: math.NaN(), + out: true, + }, + { + in: math.Inf(0), + out: true, + }, + { + in: math.Inf(-1), + out: true, + }, } + for _, tc := range tests { - out, err := Convert(tc.in, BoolID) + out, err := Convert(Val{Tid: FloatID, Value: bs(tc.in)}, BoolID) require.NoError(t, err) - require.EqualValues(t, tc.out, out, "%f should be %t", tc.n, tc.out.Value) + require.EqualValues(t, Val{Tid: BoolID, Value: tc.out}, out) } } func TestConvertStringToBool(t *testing.T) { tests := []struct { - in Val - out Val - fail bool + in string + out bool + failure string }{ - {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}, + { + in: "1", + out: true, + }, + { + in: "true", + out: true, + }, + { + in: "True", + out: true, + }, + { + in: "T", + out: true, + }, + { + in: "F", + out: false, + }, + { + in: "0", + out: false, + }, + { + in: "false", + out: false, + }, + { + in: "False", + out: false, + }, + { + in: "", + out: false, + }, + { + in: "srfrog", + failure: `strconv.ParseBool: parsing "srfrog": invalid syntax`, + }, + { + in: "3", + failure: `strconv.ParseBool: parsing "3": invalid syntax`, + }, + { + in: "-3", + failure: `strconv.ParseBool: parsing "-3": invalid syntax`, + }, } + for _, tc := range tests { - out, err := Convert(tc.in, BoolID) - if tc.fail { + out, err := Convert(Val{Tid: StringID, Value: []byte(tc.in)}, BoolID) + if tc.failure != "" { require.Error(t, err) + require.EqualError(t, err, tc.failure) continue } require.NoError(t, err) - require.EqualValues(t, tc.out, out) + require.EqualValues(t, Val{Tid: BoolID, Value: 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) + _, err := Convert(Val{Tid: DateTimeID, Value: bs(time.Now())}, 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) + _, err := Convert(Val{Tid: BoolID, Value: bs(true)}, 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 bool + out int64 }{ - {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"}, + { + in: true, + out: int64(1), + }, + { + in: false, + out: int64(0), + }, } + for _, tc := range tests { - out, err := Convert(tc.in, IntID) - if tc.failure != "" { - require.Error(t, err) - require.EqualError(t, err, tc.failure) - continue - } + out, err := Convert(Val{Tid: BoolID, Value: bs(tc.in)}, IntID) require.NoError(t, err) - require.EqualValues(t, tc.out, out) + require.EqualValues(t, Val{Tid: IntID, Value: tc.out}, out) } } func TestTruthy(t *testing.T) { tests := []struct { - s string in Val }{ { - s: "true", in: Val{Tid: StringID, Value: []byte("true")}, }, { - s: "true", in: Val{Tid: DefaultID, Value: []byte("true")}, }, { - s: "1", - in: Val{Tid: IntID, Value: []byte{0, 0, 0, 0, 0, 0, 0, 1}}, + in: Val{Tid: IntID, Value: bs(int64(1))}, }, { - s: "-1", - in: Val{Tid: IntID, Value: []byte{255, 255, 255, 255, 255, 255, 255, 255}}, + in: Val{Tid: IntID, Value: bs(int64(-1))}, }, { - s: "1.0", - in: Val{Tid: FloatID, Value: []byte{0, 0, 0, 0, 0, 0, 0, 1}}, + in: Val{Tid: FloatID, Value: bs(float64(1.0))}, }, { - s: "-1.0", - in: Val{Tid: FloatID, Value: []byte{0, 0, 0, 0, 0, 0, 240, 191}}, + in: Val{Tid: FloatID, Value: bs(float64(-1.0))}, }, } for _, tc := range tests { out, err := Convert(tc.in, BoolID) require.NoError(t, err) - require.EqualValues(t, true, out.Value, "%s %s should be true", tc.in.Tid.Name(), tc.s) + require.EqualValues(t, true, out.Value) } } func TestFalsy(t *testing.T) { tests := []struct { - s string in Val }{ { - s: "false", in: Val{Tid: StringID, Value: []byte("false")}, }, { - s: "", in: Val{Tid: StringID, Value: []byte("")}, }, { - s: "false", in: Val{Tid: DefaultID, Value: []byte("false")}, }, { - s: "", in: Val{Tid: DefaultID, Value: []byte("")}, }, { - s: "0", - in: Val{Tid: IntID, Value: []byte{0, 0, 0, 0, 0, 0, 0, 0}}, + in: Val{Tid: IntID, Value: bs(int64(0))}, }, { - s: "0.0", - in: Val{Tid: FloatID, Value: []byte{0, 0, 0, 0, 0, 0, 0, 0}}, + in: Val{Tid: FloatID, Value: bs(float64(0.0))}, }, } for _, tc := range tests { out, err := Convert(tc.in, BoolID) require.NoError(t, err) - require.EqualValues(t, false, out.Value, "%s %s should be false", tc.in.Tid.Name(), tc.s) + require.EqualValues(t, false, out.Value) } } From 0cb91bf63b0d79c4dd68b2c670efcb9a7b8a611b Mon Sep 17 00:00:00 2001 From: srfrog Date: Mon, 21 Jan 2019 20:20:13 -0700 Subject: [PATCH 09/11] empty binary should be false --- types/conversion.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/types/conversion.go b/types/conversion.go index 29e5234e03a..b6c0a3d9712 100644 --- a/types/conversion.go +++ b/types/conversion.go @@ -63,6 +63,10 @@ func Convert(from Val, toID TypeID) (Val, error) { val := math.Float64frombits(i) *res = float64(val) case BoolID: + if len(data) == 0 { + *res = false + break + } if data[0] == 0 { *res = bool(false) return to, nil From e4c1b9b2ccf918fdc742618000a65f7ad6e888bc Mon Sep 17 00:00:00 2001 From: srfrog Date: Mon, 21 Jan 2019 20:20:30 -0700 Subject: [PATCH 10/11] compacted tests a bit except when failure cases are expected --- types/conversion_test.go | 280 +++++++++------------------------------ 1 file changed, 60 insertions(+), 220 deletions(-) diff --git a/types/conversion_test.go b/types/conversion_test.go index 2148c29850c..d9fca0d6c35 100644 --- a/types/conversion_test.go +++ b/types/conversion_test.go @@ -69,34 +69,14 @@ func TestConvertToDefault(t *testing.T) { in Val out string }{ - { - in: Val{StringID, []byte("a")}, - out: "a", - }, - { - in: Val{StringID, []byte("")}, - out: "", - }, - { - in: Val{DefaultID, []byte("abc")}, - out: "abc", - }, - { - in: Val{BinaryID, []byte("2016")}, - out: "2016", - }, - { - in: Val{IntID, bs(int64(3))}, - out: "3", - }, - { - in: Val{FloatID, bs(float64(-3.5))}, - out: "-3.5", - }, - { - in: Val{DateTimeID, bs(time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC))}, - out: "2006-01-02T15:04:05Z", - }, + {in: Val{StringID, []byte("a")}, out: "a"}, + {in: Val{StringID, []byte("")}, out: ""}, + {in: Val{DefaultID, []byte("abc")}, out: "abc"}, + {in: Val{BinaryID, []byte("2016")}, out: "2016"}, + {in: Val{IntID, bs(int64(3))}, out: "3"}, + {in: Val{FloatID, bs(float64(-3.5))}, out: "-3.5"}, + {in: Val{DateTimeID, bs(time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC))}, + out: "2006-01-02T15:04:05Z"}, } for _, tc := range tests { @@ -111,38 +91,14 @@ func TestConvertFromDefault(t *testing.T) { in string out Val }{ - { - in: "1", - out: Val{IntID, int64(1)}, - }, - { - in: "1.3", - out: Val{FloatID, float64(1.3)}, - }, - { - in: "true", - out: Val{BoolID, true}, - }, - { - in: "2016", - out: Val{BinaryID, []byte("2016")}, - }, - { - in: "", - out: Val{BinaryID, []byte("")}, - }, - { - in: "hello", - out: Val{StringID, "hello"}, - }, - { - in: "", - out: Val{StringID, ""}, - }, - { - in: "2016", - out: Val{DateTimeID, time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)}, - }, + {in: "1", out: Val{IntID, int64(1)}}, + {in: "1.3", out: Val{FloatID, float64(1.3)}}, + {in: "true", out: Val{BoolID, true}}, + {in: "2016", out: Val{BinaryID, []byte("2016")}}, + {in: "", out: Val{BinaryID, []byte("")}}, + {in: "hello", out: Val{StringID, "hello"}}, + {in: "", out: Val{StringID, ""}}, + {in: "2016", out: Val{DateTimeID, time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)}}, } for _, tc := range tests { @@ -157,22 +113,10 @@ func TestConvertStringToDateTime(t *testing.T) { in string out time.Time }{ - { - in: "2006-01-02T15:04:05", - out: time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC), - }, - { - in: "2006-01-02", - out: time.Date(2006, 01, 02, 0, 0, 0, 0, time.UTC), - }, - { - in: "2006-01", - out: time.Date(2006, 01, 01, 0, 0, 0, 0, time.UTC), - }, - { - in: "2006", - out: time.Date(2006, 01, 01, 0, 0, 0, 0, time.UTC), - }, + {in: "2006-01-02T15:04:05", out: time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC)}, + {in: "2006-01-02", out: time.Date(2006, 01, 02, 0, 0, 0, 0, time.UTC)}, + {in: "2006-01", out: time.Date(2006, 01, 01, 0, 0, 0, 0, time.UTC)}, + {in: "2006", out: time.Date(2006, 01, 01, 0, 0, 0, 0, time.UTC)}, } for _, tc := range tests { @@ -188,22 +132,10 @@ func TestConvertFromPassword(t *testing.T) { out Val failure string }{ - { - in: "", - out: Val{StringID, ""}, - }, - { - in: "password", - out: Val{PasswordID, "password"}, - }, - { - in: "password", - out: Val{StringID, "password"}, - }, - { - in: "password", - out: Val{BinaryID, []byte("password")}, - }, + {in: "", out: Val{StringID, ""}}, + {in: "password", out: Val{PasswordID, "password"}}, + {in: "password", out: Val{StringID, "password"}}, + {in: "password", out: Val{BinaryID, []byte("password")}}, { in: "password", failure: `Cannot convert password to type default`, @@ -240,18 +172,9 @@ func TestConvertToPassword(t *testing.T) { out string failure string }{ - { - in: Val{StringID, []byte("testing")}, - out: "$2a$10$", - }, - { - in: Val{PasswordID, []byte("testing")}, - out: "testing", - }, - { - in: Val{DefaultID, []byte("testing")}, - out: "$2a$10$", - }, + {in: Val{StringID, []byte("testing")}, out: "$2a$10$"}, + {in: Val{PasswordID, []byte("testing")}, out: "testing"}, + {in: Val{DefaultID, []byte("testing")}, out: "$2a$10$"}, { in: Val{StringID, []byte("")}, failure: `Password too short, i.e. should has at least 6 chars`, @@ -292,18 +215,9 @@ func TestConvertIntToBool(t *testing.T) { in int64 out bool }{ - { - in: int64(3), - out: true, - }, - { - in: int64(-3), - out: true, - }, - { - in: int64(0), - out: false, - }, + {in: int64(3), out: true}, + {in: int64(-3), out: true}, + {in: int64(0), out: false}, } for _, tc := range tests { @@ -318,30 +232,12 @@ func TestConvertFloatToBool(t *testing.T) { in float64 out bool }{ - { - in: float64(3.0), - out: true, - }, - { - in: float64(-3.5), - out: true, - }, - { - in: float64(0), - out: false, - }, - { - in: math.NaN(), - out: true, - }, - { - in: math.Inf(0), - out: true, - }, - { - in: math.Inf(-1), - out: true, - }, + {in: float64(3.0), out: true}, + {in: float64(-3.5), out: true}, + {in: float64(0), out: false}, + {in: math.NaN(), out: true}, + {in: math.Inf(0), out: true}, + {in: math.Inf(-1), out: true}, } for _, tc := range tests { @@ -357,42 +253,15 @@ func TestConvertStringToBool(t *testing.T) { out bool failure string }{ - { - in: "1", - out: true, - }, - { - in: "true", - out: true, - }, - { - in: "True", - out: true, - }, - { - in: "T", - out: true, - }, - { - in: "F", - out: false, - }, - { - in: "0", - out: false, - }, - { - in: "false", - out: false, - }, - { - in: "False", - out: false, - }, - { - in: "", - out: false, - }, + {in: "1", out: true}, + {in: "true", out: true}, + {in: "True", out: true}, + {in: "T", out: true}, + {in: "F", out: false}, + {in: "0", out: false}, + {in: "false", out: false}, + {in: "False", out: false}, + {in: "", out: false}, { in: "srfrog", failure: `strconv.ParseBool: parsing "srfrog": invalid syntax`, @@ -436,14 +305,8 @@ func TestConvertBoolToInt(t *testing.T) { in bool out int64 }{ - { - in: true, - out: int64(1), - }, - { - in: false, - out: int64(0), - }, + {in: true, out: int64(1)}, + {in: false, out: int64(0)}, } for _, tc := range tests { @@ -457,24 +320,12 @@ func TestTruthy(t *testing.T) { tests := []struct { in Val }{ - { - in: Val{Tid: StringID, Value: []byte("true")}, - }, - { - in: Val{Tid: DefaultID, Value: []byte("true")}, - }, - { - in: Val{Tid: IntID, Value: bs(int64(1))}, - }, - { - in: Val{Tid: IntID, Value: bs(int64(-1))}, - }, - { - in: Val{Tid: FloatID, Value: bs(float64(1.0))}, - }, - { - in: Val{Tid: FloatID, Value: bs(float64(-1.0))}, - }, + {in: Val{Tid: StringID, Value: []byte("true")}}, + {in: Val{Tid: DefaultID, Value: []byte("true")}}, + {in: Val{Tid: IntID, Value: bs(int64(1))}}, + {in: Val{Tid: IntID, Value: bs(int64(-1))}}, + {in: Val{Tid: FloatID, Value: bs(float64(1.0))}}, + {in: Val{Tid: FloatID, Value: bs(float64(-1.0))}}, } for _, tc := range tests { out, err := Convert(tc.in, BoolID) @@ -487,24 +338,13 @@ func TestFalsy(t *testing.T) { tests := []struct { in Val }{ - { - in: Val{Tid: StringID, Value: []byte("false")}, - }, - { - in: Val{Tid: StringID, Value: []byte("")}, - }, - { - in: Val{Tid: DefaultID, Value: []byte("false")}, - }, - { - in: Val{Tid: DefaultID, Value: []byte("")}, - }, - { - in: Val{Tid: IntID, Value: bs(int64(0))}, - }, - { - in: Val{Tid: FloatID, Value: bs(float64(0.0))}, - }, + {in: Val{Tid: StringID, Value: []byte("false")}}, + {in: Val{Tid: StringID, Value: []byte("")}}, + {in: Val{Tid: DefaultID, Value: []byte("false")}}, + {in: Val{Tid: DefaultID, Value: []byte("")}}, + {in: Val{Tid: IntID, Value: bs(int64(0))}}, + {in: Val{Tid: FloatID, Value: bs(float64(0.0))}}, + {in: Val{Tid: BinaryID, Value: []byte("")}}, } for _, tc := range tests { out, err := Convert(tc.in, BoolID) From 1b35f79a7267b0d90baa3b6e635867ef921ec9d9 Mon Sep 17 00:00:00 2001 From: srfrog Date: Mon, 21 Jan 2019 21:00:07 -0700 Subject: [PATCH 11/11] fixed typo --- types/conversion_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/conversion_test.go b/types/conversion_test.go index d9fca0d6c35..9d37d826272 100644 --- a/types/conversion_test.go +++ b/types/conversion_test.go @@ -177,7 +177,7 @@ func TestConvertToPassword(t *testing.T) { {in: Val{DefaultID, []byte("testing")}, out: "$2a$10$"}, { in: Val{StringID, []byte("")}, - failure: `Password too short, i.e. should has at least 6 chars`, + failure: `Password too short, i.e. should have at least 6 chars`, }, { in: Val{IntID, bs(int64(1))},