From 7567bdd32aa6d079b2702306f087e83b6a94897b Mon Sep 17 00:00:00 2001 From: Cameron Moore Date: Fri, 3 Mar 2017 23:06:46 -0600 Subject: [PATCH] Add ToSliceStringMapStringE function Fixes #36 --- cast.go | 6 ++++++ cast_test.go | 58 +++++++++++++++++++++++++++++++++++++++++++++++++--- caste.go | 29 ++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 3 deletions(-) diff --git a/cast.go b/cast.go index dc504b4..ca5c9de 100644 --- a/cast.go +++ b/cast.go @@ -151,3 +151,9 @@ func ToIntSlice(i interface{}) []int { v, _ := ToIntSliceE(i) return v } + +// ToSliceStringMapString casts an interface to a []map[string]string type. +func ToSliceStringMapString(i interface{}) []map[string]string { + v, _ := ToSliceStringMapStringE(i) + return v +} diff --git a/cast_test.go b/cast_test.go index 2bb8c5f..adc2b8c 100644 --- a/cast_test.go +++ b/cast_test.go @@ -14,6 +14,10 @@ import ( "github.com/stretchr/testify/assert" ) +type Key struct { + k string +} + func TestToUintE(t *testing.T) { tests := []struct { input interface{} @@ -593,9 +597,6 @@ func TestToFloat32E(t *testing.T) { } func TestToStringE(t *testing.T) { - type Key struct { - k string - } key := &Key{"foo"} tests := []struct { @@ -975,6 +976,57 @@ func TestToStringSliceE(t *testing.T) { } } +func TestToSliceStringMapString(t *testing.T) { + var sliceStringMapString = []map[string]string{ + {"key 1": "value 1", "key 2": "value 2"}, + {"key 3": "value 3", "key 4": "value 4"}, + } + var sliceInterfaceMapString = []map[interface{}]string{ + {"key 1": "value 1", "key 2": "value 2"}, + {"key 3": "value 3", "key 4": "value 4"}, + } + var sliceInterfaceMapInterface = []map[interface{}]string{ + {"key 1": "value 1", "key 2": "value 2"}, + {"key 3": "value 3", "key 4": "value 4"}, + } + var sliceStringMapInterface = []map[interface{}]string{ + {"key 1": "value 1", "key 2": "value 2"}, + {"key 3": "value 3", "key 4": "value 4"}, + } + + tests := []struct { + input interface{} + expect []map[string]string + iserr bool + }{ + {sliceStringMapString, sliceStringMapString, false}, + {sliceStringMapInterface, sliceStringMapString, false}, + {sliceInterfaceMapString, sliceStringMapString, false}, + {sliceInterfaceMapInterface, sliceStringMapString, false}, + // errors + {nil, nil, true}, + {testing.T{}, nil, true}, + {[]Key{{"foo"}, {"bar"}}, nil, true}, + } + + for i, test := range tests { + errmsg := fmt.Sprintf("i = %d", i) // assert helper message + + v, err := ToSliceStringMapStringE(test.input) + if test.iserr { + assert.Error(t, err, errmsg) + continue + } + + assert.NoError(t, err, errmsg) + assert.Equal(t, test.expect, v, errmsg) + + // Non-E test + v = ToSliceStringMapString(test.input) + assert.Equal(t, test.expect, v, errmsg) + } +} + func TestToBoolE(t *testing.T) { tests := []struct { input interface{} diff --git a/caste.go b/caste.go index 569d852..b2bedd6 100644 --- a/caste.go +++ b/caste.go @@ -1077,6 +1077,35 @@ func ToIntSliceE(i interface{}) ([]int, error) { } } +// ToSliceStringMapString casts an interface to a []map[string]string type. +func ToSliceStringMapStringE(i interface{}) ([]map[string]string, error) { + if i == nil { + return []map[string]string{}, fmt.Errorf("unable to cast %#v of type %T to []map[string]string", i, i) + } + + switch v := i.(type) { + case []map[string]string: + return v, nil + } + + kind := reflect.TypeOf(i).Kind() + switch kind { + case reflect.Slice, reflect.Array: + s := reflect.ValueOf(i) + a := make([]map[string]string, s.Len()) + for j := 0; j < s.Len(); j++ { + val, err := ToStringMapStringE(s.Index(j).Interface()) + if err != nil { + return []map[string]string{}, fmt.Errorf("unable to cast %#v of type %T to []map[string]string", i, i) + } + a[j] = val + } + return a, nil + default: + return []map[string]string{}, fmt.Errorf("unable to cast %#v of type %T to []map[string]string", i, i) + } +} + // StringToDate attempts to parse a string into a time.Time type using a // predefined list of formats. If no suitable format is found, an error is // returned.