github.com/dgraph-io/dgraph@v1.2.8/types/conversion_test.go (about)

     1  /*
     2   * Copyright 2016-2018 Dgraph Labs, Inc. and Contributors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package types
    18  
    19  import (
    20  	"encoding/binary"
    21  	"math"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/stretchr/testify/require"
    26  )
    27  
    28  func bs(v interface{}) []byte {
    29  	switch x := v.(type) {
    30  	case bool:
    31  		if x {
    32  			return []byte{1}
    33  		}
    34  		return []byte{0}
    35  	case int64:
    36  		var bs [8]byte
    37  		binary.LittleEndian.PutUint64(bs[:], uint64(x))
    38  		return bs[:]
    39  	case float64:
    40  		var bs [8]byte
    41  		binary.LittleEndian.PutUint64(bs[:], math.Float64bits(x))
    42  		return bs[:]
    43  	case time.Time:
    44  		bs, err := x.MarshalBinary()
    45  		if err == nil {
    46  			return bs
    47  		}
    48  	}
    49  	return nil
    50  }
    51  
    52  func TestSameConversionString(t *testing.T) {
    53  	tests := []struct {
    54  		in string
    55  	}{
    56  		{in: "a"},
    57  		{in: ""},
    58  	}
    59  
    60  	for _, tc := range tests {
    61  		out, err := Convert(Val{Tid: BinaryID, Value: []byte(tc.in)}, StringID)
    62  		require.NoError(t, err)
    63  		require.EqualValues(t, Val{Tid: StringID, Value: tc.in}, out)
    64  	}
    65  }
    66  
    67  func TestSameConversionDateTime(t *testing.T) {
    68  	tests := []struct {
    69  		in time.Time
    70  	}{
    71  		{in: time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC)},
    72  		{in: time.Time{}},
    73  	}
    74  
    75  	for _, tc := range tests {
    76  		out, err := Convert(Val{Tid: BinaryID, Value: bs(tc.in)}, DateTimeID)
    77  		require.NoError(t, err)
    78  		require.EqualValues(t, Val{Tid: DateTimeID, Value: tc.in}, out)
    79  	}
    80  }
    81  
    82  func TestConversionEdgeCases(t *testing.T) {
    83  	tests := []struct {
    84  		in, out Val
    85  		failure string
    86  	}{
    87  		{in: Val{Tid: BinaryID},
    88  			out:     Val{Tid: BinaryID},
    89  			failure: "Invalid data to convert to binary"},
    90  
    91  		// From BinaryID to X
    92  		{in: Val{Tid: BinaryID, Value: []byte{}},
    93  			out:     Val{Tid: IntID, Value: int64(0)},
    94  			failure: "Invalid data for int64"},
    95  		{in: Val{Tid: BinaryID, Value: []byte{}},
    96  			out:     Val{Tid: FloatID, Value: int64(0)},
    97  			failure: "Invalid data for float"},
    98  		{in: Val{Tid: BinaryID, Value: []byte{}},
    99  			out: Val{Tid: BoolID, Value: false}},
   100  		{in: Val{Tid: BinaryID, Value: []byte{2}},
   101  			out:     Val{Tid: BoolID, Value: false},
   102  			failure: "Invalid value for bool"},
   103  		{in: Val{Tid: BinaryID, Value: []byte{8}},
   104  			out:     Val{Tid: DateTimeID, Value: time.Time{}},
   105  			failure: "Time.UnmarshalBinary:"},
   106  		{in: Val{Tid: BinaryID, Value: []byte{}},
   107  			out:     Val{Tid: DateTimeID, Value: time.Time{}},
   108  			failure: "Time.UnmarshalBinary:"},
   109  
   110  		// From StringID|DefaultID to X
   111  		{in: Val{Tid: StringID, Value: []byte{}},
   112  			out:     Val{Tid: IntID, Value: int64(0)},
   113  			failure: "strconv.ParseInt"},
   114  		{in: Val{Tid: StringID, Value: []byte{}},
   115  			out:     Val{Tid: FloatID, Value: float64(0)},
   116  			failure: "strconv.ParseFloat"},
   117  		{in: Val{Tid: StringID, Value: []byte{}},
   118  			out:     Val{Tid: BoolID, Value: false},
   119  			failure: "strconv.ParseBool"},
   120  		{in: Val{Tid: StringID, Value: []byte{}},
   121  			out:     Val{Tid: DateTimeID, Value: time.Time{}},
   122  			failure: `parsing time "" as "2006": cannot parse "" as "2006"`},
   123  
   124  		// From IntID to X
   125  		{in: Val{Tid: IntID, Value: []byte{}},
   126  			failure: "Invalid data for int64"},
   127  		{in: Val{Tid: IntID, Value: bs(int64(0))},
   128  			out: Val{Tid: DateTimeID, Value: time.Unix(0, 0).UTC()}},
   129  
   130  		// From FloatID to X
   131  		{in: Val{Tid: FloatID, Value: []byte{}},
   132  			failure: "Invalid data for float"},
   133  		{in: Val{Tid: FloatID, Value: bs(float64(0))},
   134  			out: Val{Tid: DateTimeID, Value: time.Unix(0, 0).UTC()}},
   135  
   136  		// From BoolID to X
   137  		{in: Val{Tid: BoolID, Value: []byte{}},
   138  			failure: "Invalid value for bool"},
   139  		{in: Val{Tid: BoolID, Value: []byte{8}},
   140  			failure: "Invalid value for bool"},
   141  
   142  		// From DateTimeID to X
   143  		{in: Val{Tid: DateTimeID, Value: []byte{}},
   144  			out:     Val{Tid: DateTimeID, Value: time.Time{}},
   145  			failure: "Time.UnmarshalBinary:"},
   146  		{in: Val{Tid: DateTimeID, Value: bs(time.Time{})},
   147  			out: Val{Tid: DateTimeID, Value: time.Time{}}},
   148  		{in: Val{Tid: DateTimeID, Value: []byte{}},
   149  			out:     Val{Tid: BinaryID, Value: []byte{}},
   150  			failure: "Time.UnmarshalBinary"},
   151  		{in: Val{Tid: DateTimeID, Value: bs(time.Time{})},
   152  			out: Val{Tid: BinaryID, Value: bs(time.Time{})}},
   153  		{in: Val{Tid: DateTimeID, Value: []byte{}},
   154  			out:     Val{Tid: StringID, Value: ""},
   155  			failure: "Time.UnmarshalBinary: no data"},
   156  		{in: Val{Tid: DateTimeID, Value: bs(time.Time{})},
   157  			out: Val{Tid: StringID, Value: "0001-01-01T00:00:00Z"}},
   158  		{in: Val{Tid: DateTimeID, Value: []byte{}},
   159  			out:     Val{Tid: DefaultID, Value: ""},
   160  			failure: "Time.UnmarshalBinary: no data"},
   161  		{in: Val{Tid: DateTimeID, Value: bs(time.Time{})},
   162  			out: Val{Tid: DefaultID, Value: "0001-01-01T00:00:00Z"}},
   163  		{in: Val{Tid: DateTimeID, Value: []byte{}},
   164  			out:     Val{Tid: IntID, Value: int64(0)},
   165  			failure: "Time.UnmarshalBinary: no data"},
   166  		{in: Val{Tid: DateTimeID, Value: bs(time.Time{})},
   167  			out: Val{Tid: IntID, Value: time.Time{}.Unix()}},
   168  		{in: Val{Tid: DateTimeID, Value: []byte{}},
   169  			out:     Val{Tid: FloatID, Value: float64(0)},
   170  			failure: "Time.UnmarshalBinary: no data"},
   171  		{in: Val{Tid: DateTimeID, Value: bs(time.Time{})},
   172  			out: Val{Tid: FloatID,
   173  				Value: float64(time.Time{}.UnixNano()) / float64(nanoSecondsInSec)}},
   174  	}
   175  	for _, tc := range tests {
   176  		t.Logf("%s to %s != %v", tc.in.Tid.Name(), tc.out.Tid.Name(), tc.out.Value)
   177  		out, err := Convert(tc.in, tc.out.Tid)
   178  		if tc.failure != "" {
   179  			require.Error(t, err)
   180  			require.Contains(t, err.Error(), tc.failure)
   181  		} else {
   182  			require.NoError(t, err)
   183  			require.EqualValues(t, tc.out, out)
   184  		}
   185  	}
   186  }
   187  
   188  func TestConvertToDefault(t *testing.T) {
   189  	tests := []struct {
   190  		in  Val
   191  		out string
   192  	}{
   193  		{in: Val{StringID, []byte("a")}, out: "a"},
   194  		{in: Val{StringID, []byte("")}, out: ""},
   195  		{in: Val{DefaultID, []byte("abc")}, out: "abc"},
   196  		{in: Val{BinaryID, []byte("2016")}, out: "2016"},
   197  		{in: Val{IntID, bs(int64(3))}, out: "3"},
   198  		{in: Val{FloatID, bs(float64(-3.5))}, out: "-3.5"},
   199  		{in: Val{DateTimeID, bs(time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC))}, out: "2006-01-02T15:04:05Z"},
   200  		{in: Val{DateTimeID, bs(time.Time{})}, out: "0001-01-01T00:00:00Z"},
   201  	}
   202  
   203  	for _, tc := range tests {
   204  		out, err := Convert(tc.in, DefaultID)
   205  		require.NoError(t, err)
   206  		require.EqualValues(t, Val{Tid: DefaultID, Value: tc.out}, out)
   207  	}
   208  }
   209  
   210  func TestConvertFromDefault(t *testing.T) {
   211  	tests := []struct {
   212  		in  string
   213  		out Val
   214  	}{
   215  		{in: "1", out: Val{IntID, int64(1)}},
   216  		{in: "1.3", out: Val{FloatID, float64(1.3)}},
   217  		{in: "true", out: Val{BoolID, true}},
   218  		{in: "2016", out: Val{BinaryID, []byte("2016")}},
   219  		{in: "", out: Val{BinaryID, []byte("")}},
   220  		{in: "hello", out: Val{StringID, "hello"}},
   221  		{in: "", out: Val{StringID, ""}},
   222  		{in: "2016", out: Val{DateTimeID, time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)}},
   223  	}
   224  
   225  	for _, tc := range tests {
   226  		out, err := Convert(Val{DefaultID, []byte(tc.in)}, tc.out.Tid)
   227  		require.NoError(t, err)
   228  		require.EqualValues(t, tc.out, out)
   229  	}
   230  }
   231  
   232  func TestConvertToBinary(t *testing.T) {
   233  	tests := []struct {
   234  		in  Val
   235  		out []byte
   236  	}{
   237  		{in: Val{StringID, []byte("a")}, out: []byte("a")},
   238  		{in: Val{StringID, []byte("")}, out: []byte("")},
   239  		{in: Val{DefaultID, []byte("abc")}, out: []byte("abc")},
   240  		{in: Val{BinaryID, []byte("2016")}, out: []byte("2016")},
   241  		{in: Val{IntID, bs(int64(3))}, out: bs(int64(3))},
   242  		{in: Val{FloatID, bs(float64(-3.5))}, out: bs(float64(-3.5))},
   243  		{in: Val{DateTimeID, bs(time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC))}, out: bs(time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC))},
   244  	}
   245  
   246  	for _, tc := range tests {
   247  		out, err := Convert(tc.in, BinaryID)
   248  		require.NoError(t, err)
   249  		require.EqualValues(t, Val{Tid: BinaryID, Value: tc.out}, out)
   250  	}
   251  }
   252  
   253  func TestConvertFromBinary(t *testing.T) {
   254  	tests := []struct {
   255  		in  []byte
   256  		out Val
   257  	}{
   258  		{in: bs(true), out: Val{BoolID, true}},
   259  		{in: bs(false), out: Val{BoolID, false}},
   260  		{in: []byte(""), out: Val{BoolID, false}},
   261  		{in: nil, out: Val{BoolID, false}},
   262  		{in: bs(int64(1)), out: Val{IntID, int64(1)}},
   263  		{in: bs(float64(1.3)), out: Val{FloatID, float64(1.3)}},
   264  		{in: []byte("2016"), out: Val{BinaryID, []byte("2016")}},
   265  		{in: []byte(""), out: Val{BinaryID, []byte("")}},
   266  		{in: []byte("hello"), out: Val{StringID, "hello"}},
   267  		{in: []byte(""), out: Val{StringID, ""}},
   268  		{in: bs(time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)), out: Val{DateTimeID, time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC)}},
   269  		{in: bs(time.Time{}), out: Val{DateTimeID, time.Time{}}},
   270  	}
   271  
   272  	for _, tc := range tests {
   273  		out, err := Convert(Val{BinaryID, tc.in}, tc.out.Tid)
   274  		require.NoError(t, err)
   275  		require.EqualValues(t, tc.out, out)
   276  	}
   277  }
   278  
   279  func TestConvertStringToDateTime(t *testing.T) {
   280  	tests := []struct {
   281  		in  string
   282  		out time.Time
   283  	}{
   284  		{in: "2006-01-02T15:04:05", out: time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC)},
   285  		{in: "2006-01-02", out: time.Date(2006, 01, 02, 0, 0, 0, 0, time.UTC)},
   286  		{in: "2006-01", out: time.Date(2006, 01, 01, 0, 0, 0, 0, time.UTC)},
   287  		{in: "2006", out: time.Date(2006, 01, 01, 0, 0, 0, 0, time.UTC)},
   288  	}
   289  
   290  	for _, tc := range tests {
   291  		out, err := Convert(Val{Tid: StringID, Value: []byte(tc.in)}, DateTimeID)
   292  		require.NoError(t, err)
   293  		require.EqualValues(t, Val{Tid: DateTimeID, Value: tc.out}, out)
   294  	}
   295  }
   296  
   297  func TestConvertDateTimeToString(t *testing.T) {
   298  	tests := []struct {
   299  		in  time.Time
   300  		out string
   301  	}{
   302  		{in: time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC), out: "2006-01-02T15:04:05Z"},
   303  		{in: time.Date(2006, 01, 02, 0, 0, 0, 0, time.UTC), out: "2006-01-02T00:00:00Z"},
   304  		{in: time.Date(2006, 01, 01, 0, 0, 0, 0, time.UTC), out: "2006-01-01T00:00:00Z"},
   305  	}
   306  
   307  	for _, tc := range tests {
   308  		out, err := Convert(Val{Tid: DateTimeID, Value: bs(tc.in)}, StringID)
   309  		require.NoError(t, err)
   310  		require.EqualValues(t, Val{Tid: StringID, Value: tc.out}, out)
   311  	}
   312  }
   313  
   314  func TestConvertFromPassword(t *testing.T) {
   315  	tests := []struct {
   316  		in      string
   317  		out     Val
   318  		failure string
   319  	}{
   320  		{in: "", out: Val{StringID, ""}},
   321  		{in: "password", out: Val{PasswordID, "password"}},
   322  		{in: "password", out: Val{StringID, "password"}},
   323  		{in: "password", out: Val{BinaryID, []byte("password")}},
   324  		{
   325  			in:      "password",
   326  			failure: `Cannot convert password to type default`,
   327  		},
   328  		{
   329  			in: "password", out: Val{IntID, bs(int64(1))},
   330  			failure: `Cannot convert password to type int`,
   331  		},
   332  		{
   333  			in: "password", out: Val{FloatID, bs(float64(1.0))},
   334  			failure: `Cannot convert password to type float`,
   335  		},
   336  		{
   337  			in: "password", out: Val{BoolID, bs(true)},
   338  			failure: `Cannot convert password to type bool`,
   339  		},
   340  	}
   341  
   342  	for _, tc := range tests {
   343  		out, err := Convert(Val{Tid: PasswordID, Value: []byte(tc.in)}, tc.out.Tid)
   344  		if tc.failure != "" {
   345  			require.Error(t, err)
   346  			require.EqualError(t, err, tc.failure)
   347  			continue
   348  		}
   349  		require.NoError(t, err)
   350  		require.EqualValues(t, tc.out, out)
   351  	}
   352  }
   353  
   354  func TestConvertToPassword(t *testing.T) {
   355  	tests := []struct {
   356  		in      Val
   357  		out     string
   358  		failure string
   359  	}{
   360  		{in: Val{StringID, []byte("testing")}, out: "$2a$10$"},
   361  		{in: Val{PasswordID, []byte("testing")}, out: "testing"},
   362  		{in: Val{DefaultID, []byte("testing")}, out: "$2a$10$"},
   363  		{
   364  			in:      Val{StringID, []byte("")},
   365  			failure: `Password too short, i.e. should have at least 6 chars`,
   366  		},
   367  		{
   368  			in:      Val{IntID, bs(int64(1))},
   369  			failure: `Cannot convert int to type password`,
   370  		},
   371  		{
   372  			in:      Val{FloatID, bs(float64(1.0))},
   373  			failure: `Cannot convert float to type password`,
   374  		},
   375  		{
   376  			in:      Val{BoolID, bs(true)},
   377  			failure: `Cannot convert bool to type password`,
   378  		},
   379  	}
   380  
   381  	for _, tc := range tests {
   382  		out, err := Convert(tc.in, PasswordID)
   383  		if tc.failure != "" {
   384  			require.Error(t, err)
   385  			require.EqualError(t, err, tc.failure)
   386  			continue
   387  		}
   388  		require.NoError(t, err)
   389  		if tc.in.Tid == PasswordID {
   390  			require.EqualValues(t, Val{Tid: PasswordID, Value: tc.out}, out)
   391  			continue
   392  		}
   393  		require.True(t, out.Tid == PasswordID)
   394  		require.NoError(t, VerifyPassword(string(tc.in.Value.([]byte)), out.Value.(string)))
   395  	}
   396  }
   397  
   398  func TestSameConversionBool(t *testing.T) {
   399  	tests := []struct {
   400  		in bool
   401  	}{
   402  		{in: true},
   403  		{in: false},
   404  	}
   405  
   406  	for _, tc := range tests {
   407  		out, err := Convert(Val{Tid: BinaryID, Value: bs(tc.in)}, BoolID)
   408  		require.NoError(t, err)
   409  		require.EqualValues(t, Val{Tid: BoolID, Value: tc.in}, out)
   410  	}
   411  }
   412  
   413  func TestConvertIntToBool(t *testing.T) {
   414  	tests := []struct {
   415  		in  int64
   416  		out bool
   417  	}{
   418  		{in: int64(3), out: true},
   419  		{in: int64(-3), out: true},
   420  		{in: int64(0), out: false},
   421  	}
   422  
   423  	for _, tc := range tests {
   424  		out, err := Convert(Val{Tid: IntID, Value: bs(tc.in)}, BoolID)
   425  		require.NoError(t, err)
   426  		require.EqualValues(t, Val{Tid: BoolID, Value: tc.out}, out)
   427  	}
   428  }
   429  
   430  func TestConvertFloatToBool(t *testing.T) {
   431  	tests := []struct {
   432  		in  float64
   433  		out bool
   434  	}{
   435  		{in: float64(3.0), out: true},
   436  		{in: float64(-3.5), out: true},
   437  		{in: float64(0), out: false},
   438  		{in: math.NaN(), out: true},
   439  		{in: math.Inf(0), out: true},
   440  		{in: math.Inf(-1), out: true},
   441  	}
   442  
   443  	for _, tc := range tests {
   444  		out, err := Convert(Val{Tid: FloatID, Value: bs(tc.in)}, BoolID)
   445  		require.NoError(t, err)
   446  		require.EqualValues(t, Val{Tid: BoolID, Value: tc.out}, out)
   447  	}
   448  }
   449  
   450  func TestConvertStringToBool(t *testing.T) {
   451  	tests := []struct {
   452  		in      string
   453  		out     bool
   454  		failure string
   455  	}{
   456  		{in: "1", out: true},
   457  		{in: "true", out: true},
   458  		{in: "True", out: true},
   459  		{in: "T", out: true},
   460  		{in: "F", out: false},
   461  		{in: "0", out: false},
   462  		{in: "false", out: false},
   463  		{in: "False", out: false},
   464  		{
   465  			in:      "",
   466  			failure: `strconv.ParseBool: parsing "": invalid syntax`,
   467  		},
   468  		{
   469  			in:      "srfrog",
   470  			failure: `strconv.ParseBool: parsing "srfrog": invalid syntax`,
   471  		},
   472  		{
   473  			in:      "3",
   474  			failure: `strconv.ParseBool: parsing "3": invalid syntax`,
   475  		},
   476  		{
   477  			in:      "-3",
   478  			failure: `strconv.ParseBool: parsing "-3": invalid syntax`,
   479  		},
   480  	}
   481  
   482  	for _, tc := range tests {
   483  		out, err := Convert(Val{Tid: StringID, Value: []byte(tc.in)}, BoolID)
   484  		if tc.failure != "" {
   485  			require.Error(t, err)
   486  			require.EqualError(t, err, tc.failure)
   487  			continue
   488  		}
   489  		require.NoError(t, err)
   490  		require.EqualValues(t, Val{Tid: BoolID, Value: tc.out}, out)
   491  	}
   492  }
   493  
   494  func TestConvertDateTimeToBool(t *testing.T) {
   495  	_, err := Convert(Val{Tid: DateTimeID, Value: bs(time.Now())}, BoolID)
   496  	require.Error(t, err)
   497  	require.EqualError(t, err, "Cannot convert datetime to type bool")
   498  }
   499  
   500  func TestConvertBoolToDateTime(t *testing.T) {
   501  	_, err := Convert(Val{Tid: BoolID, Value: bs(true)}, DateTimeID)
   502  	require.Error(t, err)
   503  	require.EqualError(t, err, "Cannot convert bool to type datetime")
   504  }
   505  
   506  func TestConvertBoolToInt(t *testing.T) {
   507  	tests := []struct {
   508  		in  bool
   509  		out int64
   510  	}{
   511  		{in: true, out: int64(1)},
   512  		{in: false, out: int64(0)},
   513  	}
   514  
   515  	for _, tc := range tests {
   516  		out, err := Convert(Val{Tid: BoolID, Value: bs(tc.in)}, IntID)
   517  		require.NoError(t, err)
   518  		require.EqualValues(t, Val{Tid: IntID, Value: tc.out}, out)
   519  	}
   520  }
   521  
   522  func TestTruthy(t *testing.T) {
   523  	tests := []struct {
   524  		in Val
   525  	}{
   526  		{in: Val{Tid: StringID, Value: []byte("true")}},
   527  		{in: Val{Tid: DefaultID, Value: []byte("true")}},
   528  		{in: Val{Tid: IntID, Value: bs(int64(1))}},
   529  		{in: Val{Tid: IntID, Value: bs(int64(-1))}},
   530  		{in: Val{Tid: FloatID, Value: bs(float64(1.0))}},
   531  		{in: Val{Tid: FloatID, Value: bs(float64(-1.0))}},
   532  	}
   533  	for _, tc := range tests {
   534  		out, err := Convert(tc.in, BoolID)
   535  		require.NoError(t, err)
   536  		require.EqualValues(t, true, out.Value)
   537  	}
   538  }
   539  
   540  func TestFalsy(t *testing.T) {
   541  	tests := []struct {
   542  		in Val
   543  	}{
   544  		{in: Val{Tid: StringID, Value: []byte("false")}},
   545  		{in: Val{Tid: DefaultID, Value: []byte("false")}},
   546  		{in: Val{Tid: IntID, Value: bs(int64(0))}},
   547  		{in: Val{Tid: FloatID, Value: bs(float64(0.0))}},
   548  		{in: Val{Tid: BinaryID, Value: []byte("")}},
   549  	}
   550  	for _, tc := range tests {
   551  		out, err := Convert(tc.in, BoolID)
   552  		require.NoError(t, err)
   553  		require.EqualValues(t, false, out.Value)
   554  	}
   555  }
   556  
   557  func TestSameConversionFloat(t *testing.T) {
   558  	tests := []struct {
   559  		in float64
   560  	}{
   561  		{in: float64(3.4434)},
   562  		{in: float64(-3.0)},
   563  		{in: float64(0.5e2)},
   564  	}
   565  
   566  	for _, tc := range tests {
   567  		out, err := Convert(Val{Tid: BinaryID, Value: bs(tc.in)}, FloatID)
   568  		require.NoError(t, err)
   569  		require.EqualValues(t, Val{Tid: FloatID, Value: tc.in}, out)
   570  	}
   571  }
   572  
   573  func TestSameConversionInt(t *testing.T) {
   574  	tests := []struct {
   575  		in int64
   576  	}{
   577  		{in: int64(3)},
   578  		{in: int64(-3)},
   579  		{in: int64(9999)},
   580  		{in: int64(0)},
   581  	}
   582  
   583  	for _, tc := range tests {
   584  		out, err := Convert(Val{Tid: BinaryID, Value: bs(tc.in)}, IntID)
   585  		require.NoError(t, err)
   586  		require.EqualValues(t, Val{Tid: IntID, Value: tc.in}, out)
   587  	}
   588  }
   589  
   590  func TestConvertBoolToFloat(t *testing.T) {
   591  	tests := []struct {
   592  		in  bool
   593  		out float64
   594  	}{
   595  		{in: true, out: float64(1.0)},
   596  		{in: false, out: float64(0.0)},
   597  	}
   598  
   599  	for _, tc := range tests {
   600  		out, err := Convert(Val{Tid: BoolID, Value: bs(tc.in)}, FloatID)
   601  		require.NoError(t, err)
   602  		require.EqualValues(t, Val{Tid: FloatID, Value: tc.out}, out)
   603  	}
   604  }
   605  
   606  func TestConvertBoolToString(t *testing.T) {
   607  	tests := []struct {
   608  		in  bool
   609  		out string
   610  	}{
   611  		{in: true, out: "true"},
   612  		{in: false, out: "false"},
   613  	}
   614  
   615  	for _, tc := range tests {
   616  		out, err := Convert(Val{Tid: BoolID, Value: bs(tc.in)}, StringID)
   617  		require.NoError(t, err)
   618  		require.EqualValues(t, Val{Tid: StringID, Value: tc.out}, out)
   619  	}
   620  }
   621  
   622  func TestConvertIntToFloat(t *testing.T) {
   623  	tests := []struct {
   624  		in  int64
   625  		out float64
   626  	}{
   627  		{in: int64(3), out: float64(3.0)},
   628  		{in: int64(-3), out: float64(-3.0)},
   629  		{in: int64(0), out: float64(0.0)},
   630  	}
   631  
   632  	for _, tc := range tests {
   633  		out, err := Convert(Val{Tid: IntID, Value: bs(tc.in)}, FloatID)
   634  		require.NoError(t, err)
   635  		require.EqualValues(t, Val{Tid: FloatID, Value: tc.out}, out)
   636  	}
   637  }
   638  
   639  func TestConvertFloatToInt(t *testing.T) {
   640  	tests := []struct {
   641  		in      float64
   642  		out     int64
   643  		failure string
   644  	}{
   645  		{in: float64(3), out: int64(3)},
   646  		{in: float64(-3.0), out: int64(-3)},
   647  		{in: float64(0), out: int64(0)},
   648  		{in: float64(522638295213.3243), out: int64(522638295213)},
   649  		{in: float64(-522638295213.3243), out: int64(-522638295213)},
   650  		{
   651  			in:      math.NaN(),
   652  			failure: "Float out of int64 range",
   653  		},
   654  		{
   655  			in:      math.Inf(0),
   656  			failure: "Float out of int64 range",
   657  		},
   658  		{
   659  			in:      math.Inf(-1),
   660  			failure: "Float out of int64 range",
   661  		},
   662  	}
   663  
   664  	for _, tc := range tests {
   665  		out, err := Convert(Val{Tid: FloatID, Value: bs(tc.in)}, IntID)
   666  		if tc.failure != "" {
   667  			require.Error(t, err)
   668  			require.EqualError(t, err, tc.failure)
   669  			continue
   670  		}
   671  		require.NoError(t, err)
   672  		require.EqualValues(t, Val{Tid: IntID, Value: tc.out}, out)
   673  	}
   674  }
   675  
   676  func TestConvertStringToInt(t *testing.T) {
   677  	tests := []struct {
   678  		in      string
   679  		out     int64
   680  		failure string
   681  	}{
   682  		{in: "1", out: int64(1)},
   683  		{in: "13816", out: int64(13816)},
   684  		{in: "-1221", out: int64(-1221)},
   685  		{in: "0", out: int64(0)},
   686  		{in: "203716381366627", out: int64(203716381366627)},
   687  		{
   688  			in:      "",
   689  			failure: `strconv.ParseInt: parsing "": invalid syntax`,
   690  		},
   691  		{
   692  			in:      "srfrog",
   693  			failure: `strconv.ParseInt: parsing "srfrog": invalid syntax`,
   694  		},
   695  		{
   696  			in:      "3.0",
   697  			failure: `strconv.ParseInt: parsing "3.0": invalid syntax`,
   698  		},
   699  		{
   700  			in:      "-3a.5",
   701  			failure: `strconv.ParseInt: parsing "-3a.5": invalid syntax`,
   702  		},
   703  	}
   704  
   705  	for _, tc := range tests {
   706  		out, err := Convert(Val{Tid: StringID, Value: []byte(tc.in)}, IntID)
   707  		if tc.failure != "" {
   708  			require.Error(t, err)
   709  			require.EqualError(t, err, tc.failure)
   710  			continue
   711  		}
   712  		require.NoError(t, err)
   713  		require.EqualValues(t, Val{Tid: IntID, Value: tc.out}, out)
   714  	}
   715  }
   716  
   717  func TestConvertStringToFloat(t *testing.T) {
   718  	tests := []struct {
   719  		in      string
   720  		out     float64
   721  		failure string
   722  	}{
   723  		{in: "1", out: float64(1)},
   724  		{in: "13816.251", out: float64(13816.251)},
   725  		{in: "-1221.12", out: float64(-1221.12)},
   726  		{in: "-0.0", out: float64(-0.0)},
   727  		{in: "1e10", out: float64(1e10)},
   728  		{in: "1e-2", out: float64(0.01)},
   729  		{
   730  			in:      "",
   731  			failure: `strconv.ParseFloat: parsing "": invalid syntax`,
   732  		},
   733  		{
   734  			in:      "srfrog",
   735  			failure: `strconv.ParseFloat: parsing "srfrog": invalid syntax`,
   736  		},
   737  		{
   738  			in:      "-3a.5",
   739  			failure: `strconv.ParseFloat: parsing "-3a.5": invalid syntax`,
   740  		},
   741  		{
   742  			in:      "1e400",
   743  			failure: `strconv.ParseFloat: parsing "1e400": value out of range`,
   744  		},
   745  	}
   746  
   747  	for _, tc := range tests {
   748  		out, err := Convert(Val{Tid: StringID, Value: []byte(tc.in)}, FloatID)
   749  		if tc.failure != "" {
   750  			require.Error(t, err)
   751  			require.EqualError(t, err, tc.failure)
   752  			continue
   753  		}
   754  		require.NoError(t, err)
   755  		require.EqualValues(t, Val{Tid: FloatID, Value: tc.out}, out)
   756  	}
   757  }
   758  
   759  func TestConvertFloatToDateTime(t *testing.T) {
   760  	tests := []struct {
   761  		in  float64
   762  		out time.Time
   763  	}{
   764  		{in: float64(1257894000), out: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)},
   765  		{in: float64(-4410000), out: time.Date(1969, time.November, 10, 23, 0, 0, 0, time.UTC)},
   766  		{in: float64(2204578800), out: time.Date(2039, time.November, 10, 23, 0, 0, 0, time.UTC)},
   767  		{in: float64(-2150326800), out: time.Date(1901, time.November, 10, 23, 0, 0, 0, time.UTC)},
   768  		{in: float64(1257894000.001), out: time.Date(2009, time.November, 10, 23, 0, 0, 999927, time.UTC)},
   769  		{in: float64(-4409999.999), out: time.Date(1969, time.November, 10, 23, 0, 0, 1000001, time.UTC)},
   770  	}
   771  
   772  	for _, tc := range tests {
   773  		out, err := Convert(Val{Tid: FloatID, Value: bs(tc.in)}, DateTimeID)
   774  		require.NoError(t, err)
   775  		require.EqualValues(t, Val{Tid: DateTimeID, Value: tc.out}, out)
   776  	}
   777  }
   778  
   779  func TestConvertDateTimeToFloat(t *testing.T) {
   780  	tests := []struct {
   781  		in  time.Time
   782  		out float64
   783  	}{
   784  		{in: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), out: float64(1257894000)},
   785  		{in: time.Date(1969, time.November, 10, 23, 0, 0, 0, time.UTC), out: float64(-4410000)},
   786  		{in: time.Date(2039, time.November, 10, 23, 0, 0, 0, time.UTC), out: float64(2204578800)},
   787  		{in: time.Date(1901, time.November, 10, 23, 0, 0, 0, time.UTC), out: float64(-2150326800)},
   788  		{in: time.Date(2009, time.November, 10, 23, 0, 0, 1000000, time.UTC), out: float64(1257894000.001)},
   789  		{in: time.Date(1969, time.November, 10, 23, 0, 0, 1000000, time.UTC), out: float64(-4409999.999)},
   790  	}
   791  
   792  	for _, tc := range tests {
   793  		out, err := Convert(Val{Tid: DateTimeID, Value: bs(tc.in)}, FloatID)
   794  		require.NoError(t, err)
   795  		require.EqualValues(t, Val{Tid: FloatID, Value: tc.out}, out)
   796  	}
   797  }
   798  
   799  func TestConvertIntToDateTime(t *testing.T) {
   800  	tests := []struct {
   801  		in  int64
   802  		out time.Time
   803  	}{
   804  		{in: int64(1257894000), out: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)},
   805  		{in: int64(-4410000), out: time.Date(1969, time.November, 10, 23, 0, 0, 0, time.UTC)},
   806  	}
   807  
   808  	for _, tc := range tests {
   809  		out, err := Convert(Val{Tid: IntID, Value: bs(tc.in)}, DateTimeID)
   810  		require.NoError(t, err)
   811  		require.EqualValues(t, Val{Tid: DateTimeID, Value: tc.out}, out)
   812  	}
   813  }
   814  
   815  func TestConvertDateTimeToInt(t *testing.T) {
   816  	tests := []struct {
   817  		in  time.Time
   818  		out int64
   819  	}{
   820  		{in: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC), out: int64(1257894000)},
   821  		{in: time.Date(1969, time.November, 10, 23, 0, 0, 0, time.UTC), out: int64(-4410000)},
   822  		{in: time.Date(2039, time.November, 10, 23, 0, 0, 0, time.UTC), out: int64(2204578800)},
   823  		{in: time.Date(1901, time.November, 10, 23, 0, 0, 0, time.UTC), out: int64(-2150326800)},
   824  	}
   825  
   826  	for _, tc := range tests {
   827  		out, err := Convert(Val{Tid: DateTimeID, Value: bs(tc.in)}, IntID)
   828  		require.NoError(t, err)
   829  		require.EqualValues(t, Val{Tid: IntID, Value: tc.out}, out)
   830  	}
   831  }
   832  
   833  func TestConvertToString(t *testing.T) {
   834  	tests := []struct {
   835  		in  Val
   836  		out string
   837  	}{
   838  		{in: Val{Tid: FloatID, Value: bs(float64(13816.251))}, out: "13816.251"},
   839  		{in: Val{Tid: IntID, Value: bs(int64(-1221))}, out: "-1221"},
   840  		{in: Val{Tid: BoolID, Value: bs(true)}, out: "true"},
   841  		{in: Val{Tid: StringID, Value: []byte("srfrog")}, out: "srfrog"},
   842  		{in: Val{Tid: PasswordID, Value: []byte("password")}, out: "password"},
   843  		{in: Val{Tid: DateTimeID, Value: bs(time.Date(2006, time.January, 2, 15, 4, 5, 0, time.UTC))}, out: "2006-01-02T15:04:05Z"},
   844  	}
   845  
   846  	for _, tc := range tests {
   847  		out, err := Convert(tc.in, StringID)
   848  		require.NoError(t, err)
   849  		require.EqualValues(t, Val{Tid: StringID, Value: tc.out}, out)
   850  	}
   851  }