From 8712ebd853ac49efb9e1eb921f763d38ebe0b593 Mon Sep 17 00:00:00 2001 From: aix3 Date: Wed, 26 Jul 2023 14:30:13 +0800 Subject: [PATCH] add `StringToURLHookFunc` decode hook --- decode_hooks.go | 21 +++++++++++++++++++++ decode_hooks_test.go | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/decode_hooks.go b/decode_hooks.go index 3a754ca..e7b1986 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..c6fc6d5 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