diff --git a/decode_hooks.go b/decode_hooks.go index 3a754ca..0e3632f 100644 --- a/decode_hooks.go +++ b/decode_hooks.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "net" + "net/url" "reflect" "strconv" "strings" @@ -201,6 +202,26 @@ func StringToTimeHookFunc(layout string) DecodeHookFunc { } } +// StringToURLHookFunc returns a DecodeHookFunc that converts +// strings to url.URL. +func StringToURLHookFunc() DecodeHookFunc { + return func( + f reflect.Type, + t reflect.Type, + data interface{}) (interface{}, error) { + if f.Kind() != reflect.String { + return data, nil + } + if t != reflect.TypeOf(url.URL{}) { + return data, nil + } + + // Convert it by parsing + u, err := url.Parse(data.(string)) + return *u, err + } +} + // WeaklyTypedHook is a DecodeHookFunc which adds support for weak typing to // the decoder. // diff --git a/decode_hooks_test.go b/decode_hooks_test.go index bf02952..b58ad5b 100644 --- a/decode_hooks_test.go +++ b/decode_hooks_test.go @@ -4,6 +4,7 @@ import ( "errors" "math/big" "net" + "net/url" "reflect" "testing" "time" @@ -361,6 +362,45 @@ func TestStringToIPNetHookFunc(t *testing.T) { } } +func TestStringToURLHookFunc(t *testing.T) { + f := StringToURLHookFunc() + + urlValue := reflect.ValueOf(url.URL{}) + strValue := reflect.ValueOf("") + + cases := []struct { + f, t reflect.Value + result interface{} + err bool + }{ + {reflect.ValueOf("https://u:p@example.com?p=1"), urlValue, + url.URL{ + Scheme: "https", + Host: "example.com", + User: url.UserPassword("u", "p"), + RawQuery: "p=1", + }, false}, + {reflect.ValueOf("https://example.com"), strValue, "https://example.com", false}, + {strValue, urlValue, url.URL{}, false}, + {reflect.ValueOf("example"), urlValue, + url.URL{ + Path: "example", + }, false}, + } + + for i, tc := range cases { + actual, err := DecodeHookExec(f, tc.f, tc.t) + if tc.err != (err != nil) { + t.Fatalf("case %d: expected err %#v", i, tc.err) + } + if !reflect.DeepEqual(actual, tc.result) { + t.Fatalf( + "case %d: expected %#v, got %#v", + i, tc.result, actual) + } + } +} + func TestWeaklyTypedHook(t *testing.T) { var f DecodeHookFunc = WeaklyTypedHook