1package mapstructure 2 3import ( 4 "errors" 5 "reflect" 6 "testing" 7 "time" 8) 9 10func TestComposeDecodeHookFunc(t *testing.T) { 11 f1 := func( 12 f reflect.Kind, 13 t reflect.Kind, 14 data interface{}) (interface{}, error) { 15 return data.(string) + "foo", nil 16 } 17 18 f2 := func( 19 f reflect.Kind, 20 t reflect.Kind, 21 data interface{}) (interface{}, error) { 22 return data.(string) + "bar", nil 23 } 24 25 f := ComposeDecodeHookFunc(f1, f2) 26 27 result, err := DecodeHookExec( 28 f, reflect.TypeOf(""), reflect.TypeOf([]byte("")), "") 29 if err != nil { 30 t.Fatalf("bad: %s", err) 31 } 32 if result.(string) != "foobar" { 33 t.Fatalf("bad: %#v", result) 34 } 35} 36 37func TestComposeDecodeHookFunc_err(t *testing.T) { 38 f1 := func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) { 39 return nil, errors.New("foo") 40 } 41 42 f2 := func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) { 43 panic("NOPE") 44 } 45 46 f := ComposeDecodeHookFunc(f1, f2) 47 48 _, err := DecodeHookExec( 49 f, reflect.TypeOf(""), reflect.TypeOf([]byte("")), 42) 50 if err.Error() != "foo" { 51 t.Fatalf("bad: %s", err) 52 } 53} 54 55func TestComposeDecodeHookFunc_kinds(t *testing.T) { 56 var f2From reflect.Kind 57 58 f1 := func( 59 f reflect.Kind, 60 t reflect.Kind, 61 data interface{}) (interface{}, error) { 62 return int(42), nil 63 } 64 65 f2 := func( 66 f reflect.Kind, 67 t reflect.Kind, 68 data interface{}) (interface{}, error) { 69 f2From = f 70 return data, nil 71 } 72 73 f := ComposeDecodeHookFunc(f1, f2) 74 75 _, err := DecodeHookExec( 76 f, reflect.TypeOf(""), reflect.TypeOf([]byte("")), "") 77 if err != nil { 78 t.Fatalf("bad: %s", err) 79 } 80 if f2From != reflect.Int { 81 t.Fatalf("bad: %#v", f2From) 82 } 83} 84 85func TestStringToSliceHookFunc(t *testing.T) { 86 f := StringToSliceHookFunc(",") 87 88 strType := reflect.TypeOf("") 89 sliceType := reflect.TypeOf([]byte("")) 90 cases := []struct { 91 f, t reflect.Type 92 data interface{} 93 result interface{} 94 err bool 95 }{ 96 {sliceType, sliceType, 42, 42, false}, 97 {strType, strType, 42, 42, false}, 98 { 99 strType, 100 sliceType, 101 "foo,bar,baz", 102 []string{"foo", "bar", "baz"}, 103 false, 104 }, 105 { 106 strType, 107 sliceType, 108 "", 109 []string{}, 110 false, 111 }, 112 } 113 114 for i, tc := range cases { 115 actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data) 116 if tc.err != (err != nil) { 117 t.Fatalf("case %d: expected err %#v", i, tc.err) 118 } 119 if !reflect.DeepEqual(actual, tc.result) { 120 t.Fatalf( 121 "case %d: expected %#v, got %#v", 122 i, tc.result, actual) 123 } 124 } 125} 126 127func TestStringToTimeDurationHookFunc(t *testing.T) { 128 f := StringToTimeDurationHookFunc() 129 130 strType := reflect.TypeOf("") 131 timeType := reflect.TypeOf(time.Duration(5)) 132 cases := []struct { 133 f, t reflect.Type 134 data interface{} 135 result interface{} 136 err bool 137 }{ 138 {strType, timeType, "5s", 5 * time.Second, false}, 139 {strType, timeType, "5", time.Duration(0), true}, 140 {strType, strType, "5", "5", false}, 141 } 142 143 for i, tc := range cases { 144 actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data) 145 if tc.err != (err != nil) { 146 t.Fatalf("case %d: expected err %#v", i, tc.err) 147 } 148 if !reflect.DeepEqual(actual, tc.result) { 149 t.Fatalf( 150 "case %d: expected %#v, got %#v", 151 i, tc.result, actual) 152 } 153 } 154} 155 156func TestWeaklyTypedHook(t *testing.T) { 157 var f DecodeHookFunc = WeaklyTypedHook 158 159 boolType := reflect.TypeOf(true) 160 strType := reflect.TypeOf("") 161 sliceType := reflect.TypeOf([]byte("")) 162 cases := []struct { 163 f, t reflect.Type 164 data interface{} 165 result interface{} 166 err bool 167 }{ 168 // TO STRING 169 { 170 boolType, 171 strType, 172 false, 173 "0", 174 false, 175 }, 176 177 { 178 boolType, 179 strType, 180 true, 181 "1", 182 false, 183 }, 184 185 { 186 reflect.TypeOf(float32(1)), 187 strType, 188 float32(7), 189 "7", 190 false, 191 }, 192 193 { 194 reflect.TypeOf(int(1)), 195 strType, 196 int(7), 197 "7", 198 false, 199 }, 200 201 { 202 sliceType, 203 strType, 204 []uint8("foo"), 205 "foo", 206 false, 207 }, 208 209 { 210 reflect.TypeOf(uint(1)), 211 strType, 212 uint(7), 213 "7", 214 false, 215 }, 216 } 217 218 for i, tc := range cases { 219 actual, err := DecodeHookExec(f, tc.f, tc.t, tc.data) 220 if tc.err != (err != nil) { 221 t.Fatalf("case %d: expected err %#v", i, tc.err) 222 } 223 if !reflect.DeepEqual(actual, tc.result) { 224 t.Fatalf( 225 "case %d: expected %#v, got %#v", 226 i, tc.result, actual) 227 } 228 } 229} 230