...

Source file src/github.com/spf13/cast/cast_test.go

Documentation: github.com/spf13/cast

     1  // Copyright © 2014 Steve Francia <spf@spf13.com>.
     2  //
     3  // Use of this source code is governed by an MIT-style
     4  // license that can be found in the LICENSE file.
     5  
     6  package cast
     7  
     8  import (
     9  	"encoding/json"
    10  	"errors"
    11  	"fmt"
    12  	"html/template"
    13  	"path"
    14  	"reflect"
    15  	"testing"
    16  	"time"
    17  
    18  	qt "github.com/frankban/quicktest"
    19  )
    20  
    21  type testStep struct {
    22  	input  interface{}
    23  	expect interface{}
    24  	iserr  bool
    25  }
    26  
    27  func createNumberTestSteps(zero, one, eight, eightnegative, eightpoint31, eightpoint31negative interface{}) []testStep {
    28  	var jeight, jminuseight, jfloateight json.Number
    29  	_ = json.Unmarshal([]byte("8"), &jeight)
    30  	_ = json.Unmarshal([]byte("-8"), &jminuseight)
    31  	_ = json.Unmarshal([]byte("8.0"), &jfloateight)
    32  
    33  	kind := reflect.TypeOf(zero).Kind()
    34  	isUint := kind == reflect.Uint || kind == reflect.Uint8 || kind == reflect.Uint16 || kind == reflect.Uint32 || kind == reflect.Uint64
    35  
    36  	// Some precision is lost when converting from float64 to float32.
    37  	eightpoint31_32 := eightpoint31
    38  	eightpoint31negative_32 := eightpoint31negative
    39  	if kind == reflect.Float64 {
    40  		eightpoint31_32 = float64(float32(eightpoint31.(float64)))
    41  		eightpoint31negative_32 = float64(float32(eightpoint31negative.(float64)))
    42  	}
    43  
    44  	return []testStep{
    45  		{int(8), eight, false},
    46  		{int8(8), eight, false},
    47  		{int16(8), eight, false},
    48  		{int32(8), eight, false},
    49  		{int64(8), eight, false},
    50  		{time.Weekday(8), eight, false},
    51  		{time.Month(8), eight, false},
    52  		{uint(8), eight, false},
    53  		{uint8(8), eight, false},
    54  		{uint16(8), eight, false},
    55  		{uint32(8), eight, false},
    56  		{uint64(8), eight, false},
    57  		{float32(8.31), eightpoint31_32, false},
    58  		{float64(8.31), eightpoint31, false},
    59  		{true, one, false},
    60  		{false, zero, false},
    61  		{"8", eight, false},
    62  		{nil, zero, false},
    63  		{int(-8), eightnegative, isUint},
    64  		{int8(-8), eightnegative, isUint},
    65  		{int16(-8), eightnegative, isUint},
    66  		{int32(-8), eightnegative, isUint},
    67  		{int64(-8), eightnegative, isUint},
    68  		{float32(-8.31), eightpoint31negative_32, isUint},
    69  		{float64(-8.31), eightpoint31negative, isUint},
    70  		{"-8", eightnegative, isUint},
    71  		{jeight, eight, false},
    72  		{jminuseight, eightnegative, isUint},
    73  		{jfloateight, eight, false},
    74  		{"test", zero, true},
    75  		{testing.T{}, zero, true},
    76  	}
    77  }
    78  
    79  // Maybe Go 1.18 generics will make this less ugly?
    80  func runNumberTest(c *qt.C, tests []testStep, tove func(interface{}) (interface{}, error), tov func(interface{}) interface{}) {
    81  	c.Helper()
    82  
    83  	for i, test := range tests {
    84  		errmsg := qt.Commentf("i = %d", i)
    85  
    86  		v, err := tove(test.input)
    87  		if test.iserr {
    88  			c.Assert(err, qt.IsNotNil, errmsg)
    89  			continue
    90  		}
    91  		c.Assert(err, qt.IsNil, errmsg)
    92  		c.Assert(v, qt.Equals, test.expect, errmsg)
    93  
    94  		// Non-E test:
    95  		v = tov(test.input)
    96  		c.Assert(v, qt.Equals, test.expect, errmsg)
    97  	}
    98  }
    99  
   100  func TestToUintE(t *testing.T) {
   101  	tests := createNumberTestSteps(uint(0), uint(1), uint(8), uint(0), uint(8), uint(8))
   102  
   103  	runNumberTest(
   104  		qt.New(t),
   105  		tests,
   106  		func(v interface{}) (interface{}, error) { return ToUintE(v) },
   107  		func(v interface{}) interface{} { return ToUint(v) },
   108  	)
   109  }
   110  
   111  func TestToUint64E(t *testing.T) {
   112  	tests := createNumberTestSteps(uint64(0), uint64(1), uint64(8), uint64(0), uint64(8), uint64(8))
   113  
   114  	runNumberTest(
   115  		qt.New(t),
   116  		tests,
   117  		func(v interface{}) (interface{}, error) { return ToUint64E(v) },
   118  		func(v interface{}) interface{} { return ToUint64(v) },
   119  	)
   120  }
   121  
   122  func TestToUint32E(t *testing.T) {
   123  	tests := createNumberTestSteps(uint32(0), uint32(1), uint32(8), uint32(0), uint32(8), uint32(8))
   124  
   125  	runNumberTest(
   126  		qt.New(t),
   127  		tests,
   128  		func(v interface{}) (interface{}, error) { return ToUint32E(v) },
   129  		func(v interface{}) interface{} { return ToUint32(v) },
   130  	)
   131  }
   132  
   133  func TestToUint16E(t *testing.T) {
   134  	tests := createNumberTestSteps(uint16(0), uint16(1), uint16(8), uint16(0), uint16(8), uint16(8))
   135  
   136  	runNumberTest(
   137  		qt.New(t),
   138  		tests,
   139  		func(v interface{}) (interface{}, error) { return ToUint16E(v) },
   140  		func(v interface{}) interface{} { return ToUint16(v) },
   141  	)
   142  }
   143  
   144  func TestToUint8E(t *testing.T) {
   145  	tests := createNumberTestSteps(uint8(0), uint8(1), uint8(8), uint8(0), uint8(8), uint8(8))
   146  
   147  	runNumberTest(
   148  		qt.New(t),
   149  		tests,
   150  		func(v interface{}) (interface{}, error) { return ToUint8E(v) },
   151  		func(v interface{}) interface{} { return ToUint8(v) },
   152  	)
   153  }
   154  func TestToIntE(t *testing.T) {
   155  	tests := createNumberTestSteps(int(0), int(1), int(8), int(-8), int(8), int(-8))
   156  
   157  	runNumberTest(
   158  		qt.New(t),
   159  		tests,
   160  		func(v interface{}) (interface{}, error) { return ToIntE(v) },
   161  		func(v interface{}) interface{} { return ToInt(v) },
   162  	)
   163  }
   164  
   165  func TestToInt64E(t *testing.T) {
   166  	tests := createNumberTestSteps(int64(0), int64(1), int64(8), int64(-8), int64(8), int64(-8))
   167  
   168  	runNumberTest(
   169  		qt.New(t),
   170  		tests,
   171  		func(v interface{}) (interface{}, error) { return ToInt64E(v) },
   172  		func(v interface{}) interface{} { return ToInt64(v) },
   173  	)
   174  }
   175  
   176  func TestToInt32E(t *testing.T) {
   177  	tests := createNumberTestSteps(int32(0), int32(1), int32(8), int32(-8), int32(8), int32(-8))
   178  
   179  	runNumberTest(
   180  		qt.New(t),
   181  		tests,
   182  		func(v interface{}) (interface{}, error) { return ToInt32E(v) },
   183  		func(v interface{}) interface{} { return ToInt32(v) },
   184  	)
   185  }
   186  
   187  func TestToInt16E(t *testing.T) {
   188  	tests := createNumberTestSteps(int16(0), int16(1), int16(8), int16(-8), int16(8), int16(-8))
   189  
   190  	runNumberTest(
   191  		qt.New(t),
   192  		tests,
   193  		func(v interface{}) (interface{}, error) { return ToInt16E(v) },
   194  		func(v interface{}) interface{} { return ToInt16(v) },
   195  	)
   196  }
   197  
   198  func TestToInt8E(t *testing.T) {
   199  	tests := createNumberTestSteps(int8(0), int8(1), int8(8), int8(-8), int8(8), int8(-8))
   200  
   201  	runNumberTest(
   202  		qt.New(t),
   203  		tests,
   204  		func(v interface{}) (interface{}, error) { return ToInt8E(v) },
   205  		func(v interface{}) interface{} { return ToInt8(v) },
   206  	)
   207  }
   208  
   209  func TestToFloat64E(t *testing.T) {
   210  	tests := createNumberTestSteps(float64(0), float64(1), float64(8), float64(-8), float64(8.31), float64(-8.31))
   211  
   212  	runNumberTest(
   213  		qt.New(t),
   214  		tests,
   215  		func(v interface{}) (interface{}, error) { return ToFloat64E(v) },
   216  		func(v interface{}) interface{} { return ToFloat64(v) },
   217  	)
   218  }
   219  
   220  func TestToFloat32E(t *testing.T) {
   221  	tests := createNumberTestSteps(float32(0), float32(1), float32(8), float32(-8), float32(8.31), float32(-8.31))
   222  
   223  	runNumberTest(
   224  		qt.New(t),
   225  		tests,
   226  		func(v interface{}) (interface{}, error) { return ToFloat32E(v) },
   227  		func(v interface{}) interface{} { return ToFloat32(v) },
   228  	)
   229  }
   230  
   231  func TestToStringE(t *testing.T) {
   232  	c := qt.New(t)
   233  
   234  	var jn json.Number
   235  	_ = json.Unmarshal([]byte("8"), &jn)
   236  	type Key struct {
   237  		k string
   238  	}
   239  	key := &Key{"foo"}
   240  
   241  	tests := []struct {
   242  		input  interface{}
   243  		expect string
   244  		iserr  bool
   245  	}{
   246  		{int(8), "8", false},
   247  		{int8(8), "8", false},
   248  		{int16(8), "8", false},
   249  		{int32(8), "8", false},
   250  		{int64(8), "8", false},
   251  		{uint(8), "8", false},
   252  		{uint8(8), "8", false},
   253  		{uint16(8), "8", false},
   254  		{uint32(8), "8", false},
   255  		{uint64(8), "8", false},
   256  		{float32(8.31), "8.31", false},
   257  		{float64(8.31), "8.31", false},
   258  		{jn, "8", false},
   259  		{true, "true", false},
   260  		{false, "false", false},
   261  		{nil, "", false},
   262  		{[]byte("one time"), "one time", false},
   263  		{"one more time", "one more time", false},
   264  		{template.HTML("one time"), "one time", false},
   265  		{template.URL("http://somehost.foo"), "http://somehost.foo", false},
   266  		{template.JS("(1+2)"), "(1+2)", false},
   267  		{template.CSS("a"), "a", false},
   268  		{template.HTMLAttr("a"), "a", false},
   269  		// errors
   270  		{testing.T{}, "", true},
   271  		{key, "", true},
   272  	}
   273  
   274  	for i, test := range tests {
   275  		errmsg := qt.Commentf("i = %d", i) // assert helper message
   276  
   277  		v, err := ToStringE(test.input)
   278  		if test.iserr {
   279  			c.Assert(err, qt.IsNotNil, errmsg)
   280  			continue
   281  		}
   282  
   283  		c.Assert(err, qt.IsNil, errmsg)
   284  		c.Assert(v, qt.Equals, test.expect, errmsg)
   285  
   286  		// Non-E test
   287  		v = ToString(test.input)
   288  		c.Assert(v, qt.Equals, test.expect, errmsg)
   289  	}
   290  }
   291  
   292  type foo struct {
   293  	val string
   294  }
   295  
   296  func (x foo) String() string {
   297  	return x.val
   298  }
   299  
   300  func TestStringerToString(t *testing.T) {
   301  	c := qt.New(t)
   302  
   303  	var x foo
   304  	x.val = "bar"
   305  	c.Assert(ToString(x), qt.Equals, "bar")
   306  }
   307  
   308  type fu struct {
   309  	val string
   310  }
   311  
   312  func (x fu) Error() string {
   313  	return x.val
   314  }
   315  
   316  func TestErrorToString(t *testing.T) {
   317  	c := qt.New(t)
   318  
   319  	var x fu
   320  	x.val = "bar"
   321  	c.Assert(ToString(x), qt.Equals, "bar")
   322  }
   323  
   324  func TestStringMapStringSliceE(t *testing.T) {
   325  	c := qt.New(t)
   326  
   327  	// ToStringMapString inputs/outputs
   328  	var stringMapString = map[string]string{"key 1": "value 1", "key 2": "value 2", "key 3": "value 3"}
   329  	var stringMapInterface = map[string]interface{}{"key 1": "value 1", "key 2": "value 2", "key 3": "value 3"}
   330  	var interfaceMapString = map[interface{}]string{"key 1": "value 1", "key 2": "value 2", "key 3": "value 3"}
   331  	var interfaceMapInterface = map[interface{}]interface{}{"key 1": "value 1", "key 2": "value 2", "key 3": "value 3"}
   332  
   333  	// ToStringMapStringSlice inputs/outputs
   334  	var stringMapStringSlice = map[string][]string{"key 1": {"value 1", "value 2", "value 3"}, "key 2": {"value 1", "value 2", "value 3"}, "key 3": {"value 1", "value 2", "value 3"}}
   335  	var stringMapInterfaceSlice = map[string][]interface{}{"key 1": {"value 1", "value 2", "value 3"}, "key 2": {"value 1", "value 2", "value 3"}, "key 3": {"value 1", "value 2", "value 3"}}
   336  	var stringMapInterfaceInterfaceSlice = map[string]interface{}{"key 1": []interface{}{"value 1", "value 2", "value 3"}, "key 2": []interface{}{"value 1", "value 2", "value 3"}, "key 3": []interface{}{"value 1", "value 2", "value 3"}}
   337  	var stringMapStringSingleSliceFieldsResult = map[string][]string{"key 1": {"value", "1"}, "key 2": {"value", "2"}, "key 3": {"value", "3"}}
   338  	var interfaceMapStringSlice = map[interface{}][]string{"key 1": {"value 1", "value 2", "value 3"}, "key 2": {"value 1", "value 2", "value 3"}, "key 3": {"value 1", "value 2", "value 3"}}
   339  	var interfaceMapInterfaceSlice = map[interface{}][]interface{}{"key 1": {"value 1", "value 2", "value 3"}, "key 2": {"value 1", "value 2", "value 3"}, "key 3": {"value 1", "value 2", "value 3"}}
   340  
   341  	var stringMapStringSliceMultiple = map[string][]string{"key 1": {"value 1", "value 2", "value 3"}, "key 2": {"value 1", "value 2", "value 3"}, "key 3": {"value 1", "value 2", "value 3"}}
   342  	var stringMapStringSliceSingle = map[string][]string{"key 1": {"value 1"}, "key 2": {"value 2"}, "key 3": {"value 3"}}
   343  
   344  	var stringMapInterface1 = map[string]interface{}{"key 1": []string{"value 1"}, "key 2": []string{"value 2"}}
   345  	var stringMapInterfaceResult1 = map[string][]string{"key 1": {"value 1"}, "key 2": {"value 2"}}
   346  
   347  	var jsonStringMapString = `{"key 1": "value 1", "key 2": "value 2"}`
   348  	var jsonStringMapStringArray = `{"key 1": ["value 1"], "key 2": ["value 2", "value 3"]}`
   349  	var jsonStringMapStringArrayResult = map[string][]string{"key 1": {"value 1"}, "key 2": {"value 2", "value 3"}}
   350  
   351  	type Key struct {
   352  		k string
   353  	}
   354  
   355  	tests := []struct {
   356  		input  interface{}
   357  		expect map[string][]string
   358  		iserr  bool
   359  	}{
   360  		{stringMapStringSlice, stringMapStringSlice, false},
   361  		{stringMapInterfaceSlice, stringMapStringSlice, false},
   362  		{stringMapInterfaceInterfaceSlice, stringMapStringSlice, false},
   363  		{stringMapStringSliceMultiple, stringMapStringSlice, false},
   364  		{stringMapStringSliceMultiple, stringMapStringSlice, false},
   365  		{stringMapString, stringMapStringSliceSingle, false},
   366  		{stringMapInterface, stringMapStringSliceSingle, false},
   367  		{stringMapInterface1, stringMapInterfaceResult1, false},
   368  		{interfaceMapStringSlice, stringMapStringSlice, false},
   369  		{interfaceMapInterfaceSlice, stringMapStringSlice, false},
   370  		{interfaceMapString, stringMapStringSingleSliceFieldsResult, false},
   371  		{interfaceMapInterface, stringMapStringSingleSliceFieldsResult, false},
   372  		{jsonStringMapStringArray, jsonStringMapStringArrayResult, false},
   373  
   374  		// errors
   375  		{nil, nil, true},
   376  		{testing.T{}, nil, true},
   377  		{map[interface{}]interface{}{"foo": testing.T{}}, nil, true},
   378  		{map[interface{}]interface{}{Key{"foo"}: "bar"}, nil, true}, // ToStringE(Key{"foo"}) should fail
   379  		{jsonStringMapString, nil, true},
   380  		{"", nil, true},
   381  	}
   382  
   383  	for i, test := range tests {
   384  		errmsg := qt.Commentf("i = %d", i) // assert helper message
   385  
   386  		v, err := ToStringMapStringSliceE(test.input)
   387  		if test.iserr {
   388  			c.Assert(err, qt.IsNotNil, errmsg)
   389  			continue
   390  		}
   391  
   392  		c.Assert(err, qt.IsNil, errmsg)
   393  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   394  
   395  		// Non-E test
   396  		v = ToStringMapStringSlice(test.input)
   397  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   398  	}
   399  }
   400  
   401  func TestToStringMapE(t *testing.T) {
   402  	c := qt.New(t)
   403  
   404  	tests := []struct {
   405  		input  interface{}
   406  		expect map[string]interface{}
   407  		iserr  bool
   408  	}{
   409  		{map[interface{}]interface{}{"tag": "tags", "group": "groups"}, map[string]interface{}{"tag": "tags", "group": "groups"}, false},
   410  		{map[string]interface{}{"tag": "tags", "group": "groups"}, map[string]interface{}{"tag": "tags", "group": "groups"}, false},
   411  		{`{"tag": "tags", "group": "groups"}`, map[string]interface{}{"tag": "tags", "group": "groups"}, false},
   412  		{`{"tag": "tags", "group": true}`, map[string]interface{}{"tag": "tags", "group": true}, false},
   413  
   414  		// errors
   415  		{nil, nil, true},
   416  		{testing.T{}, nil, true},
   417  		{"", nil, true},
   418  	}
   419  
   420  	for i, test := range tests {
   421  		errmsg := qt.Commentf("i = %d", i) // assert helper message
   422  
   423  		v, err := ToStringMapE(test.input)
   424  		if test.iserr {
   425  			c.Assert(err, qt.IsNotNil, errmsg)
   426  			continue
   427  		}
   428  
   429  		c.Assert(err, qt.IsNil, errmsg)
   430  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   431  
   432  		// Non-E test
   433  		v = ToStringMap(test.input)
   434  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   435  	}
   436  }
   437  
   438  func TestToStringMapBoolE(t *testing.T) {
   439  	c := qt.New(t)
   440  
   441  	tests := []struct {
   442  		input  interface{}
   443  		expect map[string]bool
   444  		iserr  bool
   445  	}{
   446  		{map[interface{}]interface{}{"v1": true, "v2": false}, map[string]bool{"v1": true, "v2": false}, false},
   447  		{map[string]interface{}{"v1": true, "v2": false}, map[string]bool{"v1": true, "v2": false}, false},
   448  		{map[string]bool{"v1": true, "v2": false}, map[string]bool{"v1": true, "v2": false}, false},
   449  		{`{"v1": true, "v2": false}`, map[string]bool{"v1": true, "v2": false}, false},
   450  
   451  		// errors
   452  		{nil, nil, true},
   453  		{testing.T{}, nil, true},
   454  		{"", nil, true},
   455  	}
   456  
   457  	for i, test := range tests {
   458  		errmsg := qt.Commentf("i = %d", i) // assert helper message
   459  
   460  		v, err := ToStringMapBoolE(test.input)
   461  		if test.iserr {
   462  			c.Assert(err, qt.IsNotNil, errmsg)
   463  			continue
   464  		}
   465  
   466  		c.Assert(err, qt.IsNil, errmsg)
   467  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   468  
   469  		// Non-E test
   470  		v = ToStringMapBool(test.input)
   471  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   472  	}
   473  }
   474  
   475  func TestToStringMapIntE(t *testing.T) {
   476  	c := qt.New(t)
   477  
   478  	tests := []struct {
   479  		input  interface{}
   480  		expect map[string]int
   481  		iserr  bool
   482  	}{
   483  		{map[interface{}]interface{}{"v1": 1, "v2": 222}, map[string]int{"v1": 1, "v2": 222}, false},
   484  		{map[string]interface{}{"v1": 342, "v2": 5141}, map[string]int{"v1": 342, "v2": 5141}, false},
   485  		{map[string]int{"v1": 33, "v2": 88}, map[string]int{"v1": 33, "v2": 88}, false},
   486  		{map[string]int32{"v1": int32(33), "v2": int32(88)}, map[string]int{"v1": 33, "v2": 88}, false},
   487  		{map[string]uint16{"v1": uint16(33), "v2": uint16(88)}, map[string]int{"v1": 33, "v2": 88}, false},
   488  		{map[string]float64{"v1": float64(8.22), "v2": float64(43.32)}, map[string]int{"v1": 8, "v2": 43}, false},
   489  		{`{"v1": 67, "v2": 56}`, map[string]int{"v1": 67, "v2": 56}, false},
   490  
   491  		// errors
   492  		{nil, nil, true},
   493  		{testing.T{}, nil, true},
   494  		{"", nil, true},
   495  	}
   496  
   497  	for i, test := range tests {
   498  		errmsg := qt.Commentf("i = %d", i) // assert helper message
   499  
   500  		v, err := ToStringMapIntE(test.input)
   501  		if test.iserr {
   502  			c.Assert(err, qt.IsNotNil, errmsg)
   503  			continue
   504  		}
   505  
   506  		c.Assert(err, qt.IsNil, errmsg)
   507  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   508  
   509  		// Non-E test
   510  		v = ToStringMapInt(test.input)
   511  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   512  	}
   513  }
   514  
   515  func TestToStringMapInt64E(t *testing.T) {
   516  	c := qt.New(t)
   517  
   518  	tests := []struct {
   519  		input  interface{}
   520  		expect map[string]int64
   521  		iserr  bool
   522  	}{
   523  		{map[interface{}]interface{}{"v1": int32(8), "v2": int32(888)}, map[string]int64{"v1": int64(8), "v2": int64(888)}, false},
   524  		{map[string]interface{}{"v1": int64(45), "v2": int64(67)}, map[string]int64{"v1": 45, "v2": 67}, false},
   525  		{map[string]int64{"v1": 33, "v2": 88}, map[string]int64{"v1": 33, "v2": 88}, false},
   526  		{map[string]int{"v1": 33, "v2": 88}, map[string]int64{"v1": 33, "v2": 88}, false},
   527  		{map[string]int32{"v1": int32(33), "v2": int32(88)}, map[string]int64{"v1": 33, "v2": 88}, false},
   528  		{map[string]uint16{"v1": uint16(33), "v2": uint16(88)}, map[string]int64{"v1": 33, "v2": 88}, false},
   529  		{map[string]float64{"v1": float64(8.22), "v2": float64(43.32)}, map[string]int64{"v1": 8, "v2": 43}, false},
   530  		{`{"v1": 67, "v2": 56}`, map[string]int64{"v1": 67, "v2": 56}, false},
   531  
   532  		// errors
   533  		{nil, nil, true},
   534  		{testing.T{}, nil, true},
   535  		{"", nil, true},
   536  	}
   537  
   538  	for i, test := range tests {
   539  		errmsg := qt.Commentf("i = %d", i) // assert helper message
   540  
   541  		v, err := ToStringMapInt64E(test.input)
   542  		if test.iserr {
   543  			c.Assert(err, qt.IsNotNil)
   544  			continue
   545  		}
   546  
   547  		c.Assert(err, qt.IsNil)
   548  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   549  
   550  		// Non-E test
   551  		v = ToStringMapInt64(test.input)
   552  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   553  	}
   554  }
   555  
   556  func TestToStringMapStringE(t *testing.T) {
   557  	c := qt.New(t)
   558  
   559  	var stringMapString = map[string]string{"key 1": "value 1", "key 2": "value 2", "key 3": "value 3"}
   560  	var stringMapInterface = map[string]interface{}{"key 1": "value 1", "key 2": "value 2", "key 3": "value 3"}
   561  	var interfaceMapString = map[interface{}]string{"key 1": "value 1", "key 2": "value 2", "key 3": "value 3"}
   562  	var interfaceMapInterface = map[interface{}]interface{}{"key 1": "value 1", "key 2": "value 2", "key 3": "value 3"}
   563  	var jsonString = `{"key 1": "value 1", "key 2": "value 2", "key 3": "value 3"}`
   564  	var invalidJsonString = `{"key 1": "value 1", "key 2": "value 2", "key 3": "value 3"`
   565  	var emptyString = ""
   566  
   567  	tests := []struct {
   568  		input  interface{}
   569  		expect map[string]string
   570  		iserr  bool
   571  	}{
   572  		{stringMapString, stringMapString, false},
   573  		{stringMapInterface, stringMapString, false},
   574  		{interfaceMapString, stringMapString, false},
   575  		{interfaceMapInterface, stringMapString, false},
   576  		{jsonString, stringMapString, false},
   577  
   578  		// errors
   579  		{nil, nil, true},
   580  		{testing.T{}, nil, true},
   581  		{invalidJsonString, nil, true},
   582  		{emptyString, nil, true},
   583  	}
   584  
   585  	for i, test := range tests {
   586  		errmsg := qt.Commentf("i = %d", i) // assert helper message
   587  
   588  		v, err := ToStringMapStringE(test.input)
   589  		if test.iserr {
   590  			c.Assert(err, qt.IsNotNil)
   591  			continue
   592  		}
   593  
   594  		c.Assert(err, qt.IsNil)
   595  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   596  
   597  		// Non-E test
   598  		v = ToStringMapString(test.input)
   599  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   600  	}
   601  }
   602  
   603  func TestToBoolSliceE(t *testing.T) {
   604  	c := qt.New(t)
   605  
   606  	tests := []struct {
   607  		input  interface{}
   608  		expect []bool
   609  		iserr  bool
   610  	}{
   611  		{[]bool{true, false, true}, []bool{true, false, true}, false},
   612  		{[]interface{}{true, false, true}, []bool{true, false, true}, false},
   613  		{[]int{1, 0, 1}, []bool{true, false, true}, false},
   614  		{[]string{"true", "false", "true"}, []bool{true, false, true}, false},
   615  		// errors
   616  		{nil, nil, true},
   617  		{testing.T{}, nil, true},
   618  		{[]string{"foo", "bar"}, nil, true},
   619  	}
   620  
   621  	for i, test := range tests {
   622  		errmsg := qt.Commentf("i = %d", i) // assert helper message
   623  
   624  		v, err := ToBoolSliceE(test.input)
   625  		if test.iserr {
   626  			c.Assert(err, qt.IsNotNil)
   627  			continue
   628  		}
   629  
   630  		c.Assert(err, qt.IsNil)
   631  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   632  
   633  		// Non-E test
   634  		v = ToBoolSlice(test.input)
   635  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   636  	}
   637  }
   638  
   639  func TestToIntSliceE(t *testing.T) {
   640  	c := qt.New(t)
   641  
   642  	tests := []struct {
   643  		input  interface{}
   644  		expect []int
   645  		iserr  bool
   646  	}{
   647  		{[]int{1, 3}, []int{1, 3}, false},
   648  		{[]interface{}{1.2, 3.2}, []int{1, 3}, false},
   649  		{[]string{"2", "3"}, []int{2, 3}, false},
   650  		{[2]string{"2", "3"}, []int{2, 3}, false},
   651  		// errors
   652  		{nil, nil, true},
   653  		{testing.T{}, nil, true},
   654  		{[]string{"foo", "bar"}, nil, true},
   655  	}
   656  
   657  	for i, test := range tests {
   658  		errmsg := qt.Commentf("i = %d", i) // assert helper message
   659  
   660  		v, err := ToIntSliceE(test.input)
   661  		if test.iserr {
   662  			c.Assert(err, qt.IsNotNil)
   663  			continue
   664  		}
   665  
   666  		c.Assert(err, qt.IsNil)
   667  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   668  
   669  		// Non-E test
   670  		v = ToIntSlice(test.input)
   671  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   672  	}
   673  }
   674  
   675  func TestToSliceE(t *testing.T) {
   676  	c := qt.New(t)
   677  
   678  	tests := []struct {
   679  		input  interface{}
   680  		expect []interface{}
   681  		iserr  bool
   682  	}{
   683  		{[]interface{}{1, 3}, []interface{}{1, 3}, false},
   684  		{[]map[string]interface{}{{"k1": 1}, {"k2": 2}}, []interface{}{map[string]interface{}{"k1": 1}, map[string]interface{}{"k2": 2}}, false},
   685  		// errors
   686  		{nil, nil, true},
   687  		{testing.T{}, nil, true},
   688  	}
   689  
   690  	for i, test := range tests {
   691  		errmsg := qt.Commentf("i = %d", i) // assert helper message
   692  
   693  		v, err := ToSliceE(test.input)
   694  		if test.iserr {
   695  			c.Assert(err, qt.IsNotNil)
   696  			continue
   697  		}
   698  
   699  		c.Assert(err, qt.IsNil)
   700  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   701  
   702  		// Non-E test
   703  		v = ToSlice(test.input)
   704  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   705  	}
   706  }
   707  
   708  func TestToStringSliceE(t *testing.T) {
   709  	c := qt.New(t)
   710  
   711  	tests := []struct {
   712  		input  interface{}
   713  		expect []string
   714  		iserr  bool
   715  	}{
   716  		{[]int{1, 2}, []string{"1", "2"}, false},
   717  		{[]int8{int8(1), int8(2)}, []string{"1", "2"}, false},
   718  		{[]int32{int32(1), int32(2)}, []string{"1", "2"}, false},
   719  		{[]int64{int64(1), int64(2)}, []string{"1", "2"}, false},
   720  		{[]float32{float32(1.01), float32(2.01)}, []string{"1.01", "2.01"}, false},
   721  		{[]float64{float64(1.01), float64(2.01)}, []string{"1.01", "2.01"}, false},
   722  		{[]string{"a", "b"}, []string{"a", "b"}, false},
   723  		{[]interface{}{1, 3}, []string{"1", "3"}, false},
   724  		{interface{}(1), []string{"1"}, false},
   725  		{[]error{errors.New("a"), errors.New("b")}, []string{"a", "b"}, false},
   726  		// errors
   727  		{nil, nil, true},
   728  		{testing.T{}, nil, true},
   729  	}
   730  
   731  	for i, test := range tests {
   732  		errmsg := qt.Commentf("i = %d", i) // assert helper message
   733  
   734  		v, err := ToStringSliceE(test.input)
   735  		if test.iserr {
   736  			c.Assert(err, qt.IsNotNil)
   737  			continue
   738  		}
   739  
   740  		c.Assert(err, qt.IsNil)
   741  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   742  
   743  		// Non-E test
   744  		v = ToStringSlice(test.input)
   745  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   746  	}
   747  }
   748  
   749  func TestToDurationSliceE(t *testing.T) {
   750  	c := qt.New(t)
   751  
   752  	tests := []struct {
   753  		input  interface{}
   754  		expect []time.Duration
   755  		iserr  bool
   756  	}{
   757  		{[]string{"1s", "1m"}, []time.Duration{time.Second, time.Minute}, false},
   758  		{[]int{1, 2}, []time.Duration{1, 2}, false},
   759  		{[]interface{}{1, 3}, []time.Duration{1, 3}, false},
   760  		{[]time.Duration{1, 3}, []time.Duration{1, 3}, false},
   761  
   762  		// errors
   763  		{nil, nil, true},
   764  		{testing.T{}, nil, true},
   765  		{[]string{"invalid"}, nil, true},
   766  	}
   767  
   768  	for i, test := range tests {
   769  		errmsg := qt.Commentf("i = %d", i) // assert helper message
   770  
   771  		v, err := ToDurationSliceE(test.input)
   772  		if test.iserr {
   773  			c.Assert(err, qt.IsNotNil)
   774  			continue
   775  		}
   776  
   777  		c.Assert(err, qt.IsNil)
   778  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   779  
   780  		// Non-E test
   781  		v = ToDurationSlice(test.input)
   782  		c.Assert(v, qt.DeepEquals, test.expect, errmsg)
   783  	}
   784  }
   785  
   786  func TestToBoolE(t *testing.T) {
   787  	c := qt.New(t)
   788  
   789  	var jf, jt, je json.Number
   790  	_ = json.Unmarshal([]byte("0"), &jf)
   791  	_ = json.Unmarshal([]byte("1"), &jt)
   792  	_ = json.Unmarshal([]byte("1.0"), &je)
   793  	tests := []struct {
   794  		input  interface{}
   795  		expect bool
   796  		iserr  bool
   797  	}{
   798  		{0, false, false},
   799  		{int64(0), false, false},
   800  		{int32(0), false, false},
   801  		{int16(0), false, false},
   802  		{int8(0), false, false},
   803  		{uint(0), false, false},
   804  		{uint64(0), false, false},
   805  		{uint32(0), false, false},
   806  		{uint16(0), false, false},
   807  		{uint8(0), false, false},
   808  		{float64(0), false, false},
   809  		{float32(0), false, false},
   810  		{time.Duration(0), false, false},
   811  		{jf, false, false},
   812  		{nil, false, false},
   813  		{"false", false, false},
   814  		{"FALSE", false, false},
   815  		{"False", false, false},
   816  		{"f", false, false},
   817  		{"F", false, false},
   818  		{false, false, false},
   819  
   820  		{"true", true, false},
   821  		{"TRUE", true, false},
   822  		{"True", true, false},
   823  		{"t", true, false},
   824  		{"T", true, false},
   825  		{1, true, false},
   826  		{int64(1), true, false},
   827  		{int32(1), true, false},
   828  		{int16(1), true, false},
   829  		{int8(1), true, false},
   830  		{uint(1), true, false},
   831  		{uint64(1), true, false},
   832  		{uint32(1), true, false},
   833  		{uint16(1), true, false},
   834  		{uint8(1), true, false},
   835  		{float64(1), true, false},
   836  		{float32(1), true, false},
   837  		{time.Duration(1), true, false},
   838  		{jt, true, false},
   839  		{je, true, false},
   840  		{true, true, false},
   841  		{-1, true, false},
   842  		{int64(-1), true, false},
   843  		{int32(-1), true, false},
   844  		{int16(-1), true, false},
   845  		{int8(-1), true, false},
   846  
   847  		// errors
   848  		{"test", false, true},
   849  		{testing.T{}, false, true},
   850  	}
   851  
   852  	for i, test := range tests {
   853  		errmsg := qt.Commentf("i = %d", i) // assert helper message
   854  
   855  		v, err := ToBoolE(test.input)
   856  		if test.iserr {
   857  			c.Assert(err, qt.IsNotNil)
   858  			continue
   859  		}
   860  
   861  		c.Assert(err, qt.IsNil)
   862  		c.Assert(v, qt.Equals, test.expect, errmsg)
   863  
   864  		// Non-E test
   865  		v = ToBool(test.input)
   866  		c.Assert(v, qt.Equals, test.expect, errmsg)
   867  	}
   868  }
   869  
   870  func BenchmarkTooBool(b *testing.B) {
   871  	for i := 0; i < b.N; i++ {
   872  		if !ToBool(true) {
   873  			b.Fatal("ToBool returned false")
   874  		}
   875  	}
   876  }
   877  
   878  func BenchmarkTooInt(b *testing.B) {
   879  	convert := func(num52 interface{}) {
   880  		if v := ToInt(num52); v != 52 {
   881  			b.Fatalf("ToInt returned wrong value, got %d, want %d", v, 32)
   882  		}
   883  	}
   884  	for i := 0; i < b.N; i++ {
   885  		convert("52")
   886  		convert(52.0)
   887  		convert(uint64(52))
   888  	}
   889  }
   890  
   891  func BenchmarkTrimZeroDecimal(b *testing.B) {
   892  	for i := 0; i < b.N; i++ {
   893  		trimZeroDecimal("")
   894  		trimZeroDecimal("123")
   895  		trimZeroDecimal("120")
   896  		trimZeroDecimal("120.00")
   897  	}
   898  }
   899  
   900  func BenchmarkCommonTimeLayouts(b *testing.B) {
   901  	for i := 0; i < b.N; i++ {
   902  		for _, commonLayout := range []string{"2019-04-29", "2017-05-30T00:00:00Z"} {
   903  			_, err := StringToDateInDefaultLocation(commonLayout, time.UTC)
   904  			if err != nil {
   905  				b.Fatal(err)
   906  			}
   907  		}
   908  	}
   909  }
   910  
   911  func TestIndirectPointers(t *testing.T) {
   912  	c := qt.New(t)
   913  
   914  	x := 13
   915  	y := &x
   916  	z := &y
   917  
   918  	c.Assert(ToInt(y), qt.Equals, 13)
   919  	c.Assert(ToInt(z), qt.Equals, 13)
   920  
   921  }
   922  
   923  func TestToTime(t *testing.T) {
   924  	c := qt.New(t)
   925  
   926  	var jntime, jnetime json.Number
   927  	_ = json.Unmarshal([]byte("1234567890"), &jntime)
   928  	_ = json.Unmarshal([]byte("123.4567890"), &jnetime)
   929  	tests := []struct {
   930  		input  interface{}
   931  		expect time.Time
   932  		iserr  bool
   933  	}{
   934  		{"2009-11-10 23:00:00 +0000 UTC", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), false},   // Time.String()
   935  		{"Tue Nov 10 23:00:00 2009", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), false},        // ANSIC
   936  		{"Tue Nov 10 23:00:00 UTC 2009", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), false},    // UnixDate
   937  		{"Tue Nov 10 23:00:00 +0000 2009", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), false},  // RubyDate
   938  		{"10 Nov 09 23:00 UTC", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), false},             // RFC822
   939  		{"10 Nov 09 23:00 +0000", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), false},           // RFC822Z
   940  		{"Tuesday, 10-Nov-09 23:00:00 UTC", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), false}, // RFC850
   941  		{"Tue, 10 Nov 2009 23:00:00 UTC", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), false},   // RFC1123
   942  		{"Tue, 10 Nov 2009 23:00:00 +0000", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), false}, // RFC1123Z
   943  		{"2009-11-10T23:00:00Z", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), false},            // RFC3339
   944  		{"2018-10-21T23:21:29+0200", time.Date(2018, 10, 21, 21, 21, 29, 0, time.UTC), false},      // RFC3339 without timezone hh:mm colon
   945  		{"2009-11-10T23:00:00Z", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC), false},            // RFC3339Nano
   946  		{"11:00PM", time.Date(0, 1, 1, 23, 0, 0, 0, time.UTC), false},                              // Kitchen
   947  		{"Nov 10 23:00:00", time.Date(0, 11, 10, 23, 0, 0, 0, time.UTC), false},                    // Stamp
   948  		{"Nov 10 23:00:00.000", time.Date(0, 11, 10, 23, 0, 0, 0, time.UTC), false},                // StampMilli
   949  		{"Nov 10 23:00:00.000000", time.Date(0, 11, 10, 23, 0, 0, 0, time.UTC), false},             // StampMicro
   950  		{"Nov 10 23:00:00.000000000", time.Date(0, 11, 10, 23, 0, 0, 0, time.UTC), false},          // StampNano
   951  		{"2016-03-06 15:28:01-00:00", time.Date(2016, 3, 6, 15, 28, 1, 0, time.UTC), false},        // RFC3339 without T
   952  		{"2016-03-06 15:28:01-0000", time.Date(2016, 3, 6, 15, 28, 1, 0, time.UTC), false},         // RFC3339 without T or timezone hh:mm colon
   953  		{"2016-03-06 15:28:01", time.Date(2016, 3, 6, 15, 28, 1, 0, time.UTC), false},
   954  		{"2016-03-06 15:28:01 -0000", time.Date(2016, 3, 6, 15, 28, 1, 0, time.UTC), false},
   955  		{"2016-03-06 15:28:01 -00:00", time.Date(2016, 3, 6, 15, 28, 1, 0, time.UTC), false},
   956  		{"2016-03-06 15:28:01 +0900", time.Date(2016, 3, 6, 6, 28, 1, 0, time.UTC), false},
   957  		{"2016-03-06 15:28:01 +09:00", time.Date(2016, 3, 6, 6, 28, 1, 0, time.UTC), false},
   958  		{"2006-01-02", time.Date(2006, 1, 2, 0, 0, 0, 0, time.UTC), false},
   959  		{"02 Jan 2006", time.Date(2006, 1, 2, 0, 0, 0, 0, time.UTC), false},
   960  		{1472574600, time.Date(2016, 8, 30, 16, 30, 0, 0, time.UTC), false},
   961  		{int(1482597504), time.Date(2016, 12, 24, 16, 38, 24, 0, time.UTC), false},
   962  		{int64(1234567890), time.Date(2009, 2, 13, 23, 31, 30, 0, time.UTC), false},
   963  		{int32(1234567890), time.Date(2009, 2, 13, 23, 31, 30, 0, time.UTC), false},
   964  		{uint(1482597504), time.Date(2016, 12, 24, 16, 38, 24, 0, time.UTC), false},
   965  		{uint64(1234567890), time.Date(2009, 2, 13, 23, 31, 30, 0, time.UTC), false},
   966  		{uint32(1234567890), time.Date(2009, 2, 13, 23, 31, 30, 0, time.UTC), false},
   967  		{jntime, time.Date(2009, 2, 13, 23, 31, 30, 0, time.UTC), false},
   968  		{time.Date(2009, 2, 13, 23, 31, 30, 0, time.UTC), time.Date(2009, 2, 13, 23, 31, 30, 0, time.UTC), false},
   969  		// errors
   970  		{"2006", time.Time{}, true},
   971  		{jnetime, time.Time{}, true},
   972  		{testing.T{}, time.Time{}, true},
   973  	}
   974  
   975  	for i, test := range tests {
   976  		errmsg := qt.Commentf("i = %d", i) // assert helper message
   977  
   978  		v, err := ToTimeE(test.input)
   979  		if test.iserr {
   980  			c.Assert(err, qt.IsNotNil)
   981  			continue
   982  		}
   983  
   984  		c.Assert(err, qt.IsNil)
   985  		c.Assert(v.UTC(), qt.Equals, test.expect, errmsg)
   986  
   987  		// Non-E test
   988  		v = ToTime(test.input)
   989  		c.Assert(v.UTC(), qt.Equals, test.expect, errmsg)
   990  	}
   991  }
   992  
   993  func TestToDurationE(t *testing.T) {
   994  	c := qt.New(t)
   995  
   996  	var td time.Duration = 5
   997  	var jn json.Number
   998  	_ = json.Unmarshal([]byte("5"), &jn)
   999  
  1000  	tests := []struct {
  1001  		input  interface{}
  1002  		expect time.Duration
  1003  		iserr  bool
  1004  	}{
  1005  		{time.Duration(5), td, false},
  1006  		{int(5), td, false},
  1007  		{int64(5), td, false},
  1008  		{int32(5), td, false},
  1009  		{int16(5), td, false},
  1010  		{int8(5), td, false},
  1011  		{uint(5), td, false},
  1012  		{uint64(5), td, false},
  1013  		{uint32(5), td, false},
  1014  		{uint16(5), td, false},
  1015  		{uint8(5), td, false},
  1016  		{float64(5), td, false},
  1017  		{float32(5), td, false},
  1018  		{jn, td, false},
  1019  		{string("5"), td, false},
  1020  		{string("5ns"), td, false},
  1021  		{string("5us"), time.Microsecond * td, false},
  1022  		{string("5µs"), time.Microsecond * td, false},
  1023  		{string("5ms"), time.Millisecond * td, false},
  1024  		{string("5s"), time.Second * td, false},
  1025  		{string("5m"), time.Minute * td, false},
  1026  		{string("5h"), time.Hour * td, false},
  1027  		// errors
  1028  		{"test", 0, true},
  1029  		{testing.T{}, 0, true},
  1030  	}
  1031  
  1032  	for i, test := range tests {
  1033  		errmsg := qt.Commentf("i = %d", i) // assert helper message
  1034  
  1035  		v, err := ToDurationE(test.input)
  1036  		if test.iserr {
  1037  			c.Assert(err, qt.IsNotNil)
  1038  			continue
  1039  		}
  1040  
  1041  		c.Assert(err, qt.IsNil)
  1042  		c.Assert(v, qt.Equals, test.expect, errmsg)
  1043  
  1044  		// Non-E test
  1045  		v = ToDuration(test.input)
  1046  		c.Assert(v, qt.Equals, test.expect, errmsg)
  1047  	}
  1048  }
  1049  
  1050  func TestToTimeWithTimezones(t *testing.T) {
  1051  	c := qt.New(t)
  1052  
  1053  	est, err := time.LoadLocation("EST")
  1054  	c.Assert(err, qt.IsNil)
  1055  
  1056  	irn, err := time.LoadLocation("Iran")
  1057  	c.Assert(err, qt.IsNil)
  1058  
  1059  	swd, err := time.LoadLocation("Europe/Stockholm")
  1060  	c.Assert(err, qt.IsNil)
  1061  
  1062  	// Test same local time in different timezones
  1063  	utc2016 := time.Date(2016, time.January, 1, 0, 0, 0, 0, time.UTC)
  1064  	est2016 := time.Date(2016, time.January, 1, 0, 0, 0, 0, est)
  1065  	irn2016 := time.Date(2016, time.January, 1, 0, 0, 0, 0, irn)
  1066  	swd2016 := time.Date(2016, time.January, 1, 0, 0, 0, 0, swd)
  1067  	loc2016 := time.Date(2016, time.January, 1, 0, 0, 0, 0, time.Local)
  1068  
  1069  	for i, format := range timeFormats {
  1070  		format := format
  1071  		if format.typ == timeFormatTimeOnly {
  1072  			continue
  1073  		}
  1074  
  1075  		nameBase := fmt.Sprintf("%d;timeFormatType=%d;%s", i, format.typ, format.format)
  1076  
  1077  		t.Run(path.Join(nameBase), func(t *testing.T) {
  1078  			est2016str := est2016.Format(format.format)
  1079  			swd2016str := swd2016.Format(format.format)
  1080  
  1081  			t.Run("without default location", func(t *testing.T) {
  1082  				c := qt.New(t)
  1083  				converted, err := ToTimeE(est2016str)
  1084  				c.Assert(err, qt.IsNil)
  1085  				if format.hasTimezone() {
  1086  					// Converting inputs with a timezone should preserve it
  1087  					assertTimeEqual(t, est2016, converted)
  1088  					assertLocationEqual(t, est, converted.Location())
  1089  				} else {
  1090  					// Converting inputs without a timezone should be interpreted
  1091  					// as a local time in UTC.
  1092  					assertTimeEqual(t, utc2016, converted)
  1093  					assertLocationEqual(t, time.UTC, converted.Location())
  1094  				}
  1095  			})
  1096  
  1097  			t.Run("local timezone without a default location", func(t *testing.T) {
  1098  				c := qt.New(t)
  1099  				converted, err := ToTimeE(swd2016str)
  1100  				c.Assert(err, qt.IsNil)
  1101  				if format.hasTimezone() {
  1102  					// Converting inputs with a timezone should preserve it
  1103  					assertTimeEqual(t, swd2016, converted)
  1104  					assertLocationEqual(t, swd, converted.Location())
  1105  				} else {
  1106  					// Converting inputs without a timezone should be interpreted
  1107  					// as a local time in UTC.
  1108  					assertTimeEqual(t, utc2016, converted)
  1109  					assertLocationEqual(t, time.UTC, converted.Location())
  1110  				}
  1111  			})
  1112  
  1113  			t.Run("nil default location", func(t *testing.T) {
  1114  				c := qt.New(t)
  1115  
  1116  				converted, err := ToTimeInDefaultLocationE(est2016str, nil)
  1117  				c.Assert(err, qt.IsNil)
  1118  				if format.hasTimezone() {
  1119  					// Converting inputs with a timezone should preserve it
  1120  					assertTimeEqual(t, est2016, converted)
  1121  					assertLocationEqual(t, est, converted.Location())
  1122  				} else {
  1123  					// Converting inputs without a timezone should be interpreted
  1124  					// as a local time in the local timezone.
  1125  					assertTimeEqual(t, loc2016, converted)
  1126  					assertLocationEqual(t, time.Local, converted.Location())
  1127  				}
  1128  
  1129  			})
  1130  
  1131  			t.Run("default location not UTC", func(t *testing.T) {
  1132  				c := qt.New(t)
  1133  
  1134  				converted, err := ToTimeInDefaultLocationE(est2016str, irn)
  1135  				c.Assert(err, qt.IsNil)
  1136  				if format.hasTimezone() {
  1137  					// Converting inputs with a timezone should preserve it
  1138  					assertTimeEqual(t, est2016, converted)
  1139  					assertLocationEqual(t, est, converted.Location())
  1140  				} else {
  1141  					// Converting inputs without a timezone should be interpreted
  1142  					// as a local time in the given location.
  1143  					assertTimeEqual(t, irn2016, converted)
  1144  					assertLocationEqual(t, irn, converted.Location())
  1145  				}
  1146  
  1147  			})
  1148  
  1149  			t.Run("time in the local timezone default location not UTC", func(t *testing.T) {
  1150  				c := qt.New(t)
  1151  
  1152  				converted, err := ToTimeInDefaultLocationE(swd2016str, irn)
  1153  				c.Assert(err, qt.IsNil)
  1154  				if format.hasTimezone() {
  1155  					// Converting inputs with a timezone should preserve it
  1156  					assertTimeEqual(t, swd2016, converted)
  1157  					assertLocationEqual(t, swd, converted.Location())
  1158  				} else {
  1159  					// Converting inputs without a timezone should be interpreted
  1160  					// as a local time in the given location.
  1161  					assertTimeEqual(t, irn2016, converted)
  1162  					assertLocationEqual(t, irn, converted.Location())
  1163  				}
  1164  
  1165  			})
  1166  
  1167  		})
  1168  
  1169  	}
  1170  }
  1171  
  1172  func TestTrimZeroDecimal(t *testing.T) {
  1173  	c := qt.New(t)
  1174  
  1175  	c.Assert(trimZeroDecimal("10.0"), qt.Equals, "10")
  1176  	c.Assert(trimZeroDecimal("10.00"), qt.Equals, "10")
  1177  	c.Assert(trimZeroDecimal("10.010"), qt.Equals, "10.010")
  1178  	c.Assert(trimZeroDecimal("0.0000000000"), qt.Equals, "0")
  1179  	c.Assert(trimZeroDecimal("0.00000000001"), qt.Equals, "0.00000000001")
  1180  
  1181  }
  1182  
  1183  func assertTimeEqual(t *testing.T, expected, actual time.Time) {
  1184  	t.Helper()
  1185  	// Compare the dates using a numeric zone as there are cases where
  1186  	// time.Parse will assign a dummy location.
  1187  	qt.Assert(t, actual.Format(time.RFC1123Z), qt.Equals, expected.Format(time.RFC1123Z))
  1188  }
  1189  
  1190  func assertLocationEqual(t *testing.T, expected, actual *time.Location) {
  1191  	t.Helper()
  1192  	qt.Assert(t, locationEqual(expected, actual), qt.IsTrue)
  1193  }
  1194  
  1195  func locationEqual(a, b *time.Location) bool {
  1196  	// A note about comparring time.Locations:
  1197  	//   - can't only compare pointers
  1198  	//   - can't compare loc.String() because locations with the same
  1199  	//     name can have different offsets
  1200  	//   - can't use reflect.DeepEqual because time.Location has internal
  1201  	//     caches
  1202  
  1203  	if a == b {
  1204  		return true
  1205  	} else if a == nil || b == nil {
  1206  		return false
  1207  	}
  1208  
  1209  	// Check if they're equal by parsing times with a format that doesn't
  1210  	// include a timezone, which will interpret it as being a local time in
  1211  	// the given zone, and comparing the resulting local times.
  1212  	tA, err := time.ParseInLocation("2006-01-02", "2016-01-01", a)
  1213  	if err != nil {
  1214  		return false
  1215  	}
  1216  
  1217  	tB, err := time.ParseInLocation("2006-01-02", "2016-01-01", b)
  1218  	if err != nil {
  1219  		return false
  1220  	}
  1221  
  1222  	return tA.Equal(tB)
  1223  }
  1224  

View as plain text