package treerack import ( "bytes" "code.squareroundforest.org/arpio/notation" "net/url" "os" "testing" "time" ) type urlCheck struct { stdQuery func(u *url.URL) string treerackQuery func(Node) string expect string } type urlTestCase struct { title string input string checks []urlCheck bench int skipSTD bool skipSTDReq bool } func queryTreerack(p ...string) func(Node) string { return func(a Node) string { return astPath(a, p...) } } func fakeSTDCheck(v string) func(*url.URL) string { return func(*url.URL) string { return v } } func fakeTRCheck(v string) func(Node) string { return func(Node) string { return v } } func printURLTree(t *testing.T, a Node) { var trimTokens func(a Node) Node trimTokens = func(a Node) Node { for i := range a.Nodes { a.Nodes[i] = trimTokens(a.Nodes[i]) } a.tokens = nil return a } a = trimTokens(a) notation.Lprintw(t, a) } func urlParser() func(string) (Node, error) { b, err := os.ReadFile("doc/example/url.treerack") if err != nil { panic(err) } p := new(Syntax) if err = p.ReadSyntax(bytes.NewBuffer(b)); err != nil { panic(err) } return func(s string) (a Node, err error) { return p.Parse(bytes.NewBufferString(s)) } } func astPath(a Node, p ...string) string { if len(p) == 0 { return a.Text() } for _, ai := range a.Nodes { if ai.Name == p[0] { return astPath(ai, p[1:]...) } } return "" } func TestURL(t *testing.T) { for _, test := range []urlTestCase{{ title: "scheme only", input: "http:", bench: 3600, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }}, }, { title: "scheme only with separator", input: "http://", bench: 3600, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url-rfc", "scheme"), expect: "http", }}, }, { title: "user and passord only", input: "//foo:bar@", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("relative-url-rfc", "userinfo"), expect: "foo:bar", }}, }, { title: "user only", input: "//foo@", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("relative-url-rfc", "userinfo"), expect: "foo", }}, }, { title: "host only", input: "//foo.bar", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("relative-url", "hostname"), expect: "foo.bar", }}, }, { title: "host only with port", input: "//foo.bar:8080", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: fakeTRCheck("foo.bar:8080"), expect: "foo.bar:8080", }, { stdQuery: fakeSTDCheck("foo.bar"), treerackQuery: queryTreerack("relative-url", "hostname"), expect: "foo.bar", }, { stdQuery: fakeSTDCheck("8080"), treerackQuery: queryTreerack("relative-url", "port"), expect: "8080", }}, }, { title: "absolute path only", input: "/foo/bar", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url", "path-absolute"), expect: "/foo/bar", }}, }, { title: "relative path only", input: "foo/bar", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url", "path-noscheme"), expect: "foo/bar", }}, }, { title: "relative path only with navigation segments", input: "../foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url", "path-noscheme"), expect: "../foo", }}, }, { title: "query only", input: "?foo=bar", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("relative-url", "query"), expect: "foo=bar", }}, }, { title: "query only empty", input: "?", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("relative-url", "query"), expect: "", }}, }, { title: "fragment only", input: "#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("relative-url", "fragment"), expect: "foo", }}, }, { title: "fragment only empty", input: "#", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("relative-url", "fragment"), expect: "", }}, }, { title: "scheme and user", input: "http://foo:bar@", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url-rfc", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("absolute-url-rfc", "userinfo"), expect: "foo:bar", }}, }, { title: "scheme and user without password", input: "http://foo@", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url-rfc", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("absolute-url-rfc", "userinfo"), expect: "foo", }}, }, { title: "scheme and host", input: "http://foo.bar", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("absolute-url", "hostname", "domain-name"), expect: "foo.bar", }}, }, { title: "scheme and host with port", input: "http://foo.bar:8080", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: fakeTRCheck("foo.bar:8080"), expect: "foo.bar:8080", }, { stdQuery: fakeSTDCheck("foo.bar"), treerackQuery: queryTreerack("absolute-url", "hostname"), expect: "foo.bar", }, { stdQuery: fakeSTDCheck("8080"), treerackQuery: queryTreerack("absolute-url", "port"), expect: "8080", }}, }, { title: "scheme and path", input: "http:/foo/bar", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("absolute-url", "path-absolute"), expect: "/foo/bar", }}, }, { title: "scheme and relative path", input: "http:foo/bar", skipSTD: true, skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("absolute-url", "path-rootless"), expect: "foo/bar", }}, }, { title: "scheme and query", input: "http:?foo=bar", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("absolute-url", "query"), expect: "foo=bar", }}, }, { title: "scheme and query empty", input: "http:?", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("absolute-url", "query"), expect: "", }}, }, { title: "scheme and fragment", input: "http:#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("absolute-url", "fragment"), expect: "foo", }}, }, { title: "scheme and fragment", input: "http:#", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("absolute-url", "fragment"), expect: "", }}, }, { title: "user and host", input: "//foo:bar@foo.bar", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("relative-url", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("relative-url", "hostname"), expect: "foo.bar", }}, }, { title: "user and path", input: "//foo:bar@/foo/bar", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("relative-url-rfc", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url-rfc", "path-absolute-or-empty"), expect: "/foo/bar", }}, }, { title: "user and query", input: "//foo:bar@?foo=bar", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("relative-url-rfc", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("relative-url-rfc", "query"), expect: "foo=bar", }}, }, { title: "user and fragment", input: "//foo:bar@#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("relative-url-rfc", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("relative-url-rfc", "fragment"), expect: "foo", }}, }, { title: "host and path", input: "//foo.bar/foo/bar", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("relative-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url", "path-absolute-or-empty"), expect: "/foo/bar", }}, }, { title: "host and query", input: "//foo.bar?foo=bar", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("relative-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("relative-url", "query"), expect: "foo=bar", }}, }, { title: "host and fragment", input: "//foo.bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("relative-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("relative-url", "fragment"), expect: "foo", }}, }, { title: "path and query", input: "/foo/bar?foo=bar", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url", "path-absolute"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("relative-url", "query"), expect: "foo=bar", }}, }, { title: "path and fragment", input: "/foo/bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url", "path-absolute"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("relative-url", "fragment"), expect: "foo", }}, }, { title: "query and fragment", input: "?foo=bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("relative-url", "query"), expect: "foo=bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("relative-url", "fragment"), expect: "foo", }}, }, { title: "scheme and user and host", input: "http://foo:bar@foo.bar", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("absolute-url", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("absolute-url", "hostname"), expect: "foo.bar", }}, }, { title: "scheme and user and path", input: "http://foo:bar@/foo/bar", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url-rfc", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("absolute-url-rfc", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("absolute-url-rfc", "path-absolute-or-empty"), expect: "/foo/bar", }}, }, { title: "scheme and user and query", input: "http://foo:bar@?foo=bar", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url-rfc", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("absolute-url-rfc", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("absolute-url-rfc", "query"), expect: "foo=bar", }}, }, { title: "scheme and user and fragment", input: "http://foo:bar@#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url-rfc", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("absolute-url-rfc", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("absolute-url-rfc", "fragment"), expect: "foo", }}, }, { title: "scheme and host and path", input: "http://foo.bar/foo/bar", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("absolute-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("absolute-url", "path-absolute-or-empty"), expect: "/foo/bar", }}, }, { title: "scheme and host and query", input: "http://foo.bar?foo=bar", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("absolute-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("absolute-url", "query"), expect: "foo=bar", }}, }, { title: "scheme and host and fragment", input: "http://foo.bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("absolute-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("absolute-url", "fragment"), expect: "foo", }}, }, { title: "scheme and path and query", input: "http:/foo/bar?foo=bar", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("absolute-url", "path-absolute"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("absolute-url", "query"), expect: "foo=bar", }}, }, { title: "scheme and path and fragment", input: "http:/foo/bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("absolute-url", "path-absolute"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("absolute-url", "fragment"), expect: "foo", }}, }, { title: "scheme and query and fragment", input: "http:?foo=bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("absolute-url", "query"), expect: "foo=bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("absolute-url", "fragment"), expect: "foo", }}, }, { title: "user and host and path", input: "//foo:bar@foo.bar/foo/bar", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("relative-url", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("relative-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url", "path-absolute-or-empty"), expect: "/foo/bar", }}, }, { title: "user and host and query", input: "//foo:bar@foo.bar?foo=bar", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("relative-url", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("relative-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("relative-url", "query"), expect: "foo=bar", }}, }, { title: "user and host and fragment", input: "//foo:bar@foo.bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("relative-url", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("relative-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("relative-url", "fragment"), expect: "foo", }}, }, { title: "user and path and query", input: "//foo:bar@/foo/bar?foo=bar", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("relative-url-rfc", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url-rfc", "path-absolute-or-empty"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("relative-url-rfc", "query"), expect: "foo=bar", }}, }, { title: "user and path and fragment", input: "//foo:bar@/foo/bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("relative-url-rfc", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url-rfc", "path-absolute-or-empty"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("relative-url-rfc", "fragment"), expect: "foo", }}, }, { title: "user and query and fragment", input: "//foo:bar@?foo=bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("relative-url-rfc", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("relative-url-rfc", "query"), expect: "foo=bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("relative-url-rfc", "fragment"), expect: "foo", }}, }, { title: "host and path and query", input: "//foo.bar/foo/bar?foo=bar", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("relative-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url", "path-absolute-or-empty"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("relative-url", "query"), expect: "foo=bar", }}, }, { title: "host and path and fragment", input: "//foo.bar/foo/bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("relative-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url", "path-absolute-or-empty"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("relative-url", "fragment"), expect: "foo", }}, }, { title: "host and query and fragment", input: "//foo.bar?foo=bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("relative-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("relative-url", "query"), expect: "foo=bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("relative-url", "fragment"), expect: "foo", }}, }, { title: "path and query and fragment", input: "/foo/bar?foo=bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url", "path-absolute"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("relative-url", "query"), expect: "foo=bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("relative-url", "fragment"), expect: "foo", }}, }, { title: "relative path and query and fragment", input: "../foo/bar?foo=bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url", "path-noscheme"), expect: "../foo/bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("relative-url", "query"), expect: "foo=bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("relative-url", "fragment"), expect: "foo", }}, }, { title: "scheme and user and host and path", input: "http://foo:bar@foo.bar/foo/bar", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("absolute-url", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("absolute-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("absolute-url", "path-absolute-or-empty"), expect: "/foo/bar", }}, }, { title: "scheme and user and host and query", input: "http://foo:bar@foo.bar?foo=bar", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("absolute-url", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("absolute-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("absolute-url", "query"), expect: "foo=bar", }}, }, { title: "scheme and user and host and fragment", input: "http://foo:bar@foo.bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("absolute-url", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("absolute-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("absolute-url", "fragment"), expect: "foo", }}, }, { title: "scheme and user and path and query", input: "http://foo:bar@/foo/bar?foo=bar", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url-rfc", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("absolute-url-rfc", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("absolute-url-rfc", "path-absolute-or-empty"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("absolute-url-rfc", "query"), expect: "foo=bar", }}, }, { title: "scheme and user and path and fragment", input: "http://foo:bar@/foo/bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url-rfc", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("absolute-url-rfc", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("absolute-url-rfc", "path-absolute-or-empty"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("absolute-url-rfc", "fragment"), expect: "foo", }}, }, { title: "scheme and user and query and fragment", input: "http://foo:bar@?foo=bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url-rfc", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("absolute-url-rfc", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("absolute-url-rfc", "query"), expect: "foo=bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("absolute-url-rfc", "fragment"), expect: "foo", }}, }, { title: "scheme and host and path and query", input: "http://foo.bar/foo/bar?foo=bar", checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("absolute-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("absolute-url", "path-absolute-or-empty"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("absolute-url", "query"), expect: "foo=bar", }}, }, { title: "scheme and host and path and fragment", input: "http://foo.bar/foo/bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("absolute-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("absolute-url", "path-absolute-or-empty"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("absolute-url", "fragment"), expect: "foo", }}, }, { title: "scheme and host and query and fragment", input: "http://foo.bar?foo=bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("absolute-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("absolute-url", "query"), expect: "foo=bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("absolute-url", "fragment"), expect: "foo", }}, }, { title: "scheme and path and query and fragment", input: "http:/foo/bar?foo=bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("absolute-url", "path-absolute"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("absolute-url", "query"), expect: "foo=bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("absolute-url", "fragment"), expect: "foo", }}, }, { title: "user and host and path and query", input: "//foo:bar@foo.bar/foo/bar?foo=bar", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("relative-url", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("relative-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url", "path-absolute-or-empty"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("relative-url", "query"), expect: "foo=bar", }}, }, { title: "user and host and path and fragment", input: "//foo:bar@foo.bar/foo/bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("relative-url", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("relative-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url", "path-absolute-or-empty"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("relative-url", "fragment"), expect: "foo", }}, }, { title: "user and path and query and fragment", input: "//foo:bar@/foo/bar?foo=bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("relative-url-rfc", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url-rfc", "path-absolute-or-empty"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("relative-url-rfc", "query"), expect: "foo=bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("relative-url-rfc", "fragment"), expect: "foo", }}, }, { title: "host and path and query and fragment", input: "//foo.bar/foo/bar?foo=bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("relative-url", "hostname"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url", "path-absolute-or-empty"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("relative-url", "query"), expect: "foo=bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("relative-url", "fragment"), expect: "foo", }}, }, { title: "scheme and user and host and path and query", input: "http://foo:bar@foo.bar/foo/bar?foo=bar", bench: 3600, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("absolute-url", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("absolute-url", "hostname", "domain-name"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("absolute-url", "path-absolute-or-empty"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("absolute-url", "query"), expect: "foo=bar", }}, }, { title: "scheme and user and host and path and fragment", input: "http://foo:bar@foo.bar/foo/bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("absolute-url", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("absolute-url", "hostname", "domain-name"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("absolute-url", "path-absolute-or-empty"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("absolute-url", "fragment"), expect: "foo", }}, }, { title: "scheme and user and host and query and fragment", input: "http://foo:bar@foo.bar?foo=bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("absolute-url", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("absolute-url", "hostname", "domain-name"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("absolute-url", "query"), expect: "foo=bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("absolute-url", "fragment"), expect: "foo", }}, }, { title: "scheme and user and path and query and fragment", input: "http://foo:bar@/foo/bar?foo=bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url-rfc", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("absolute-url-rfc", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("absolute-url-rfc", "path-absolute-or-empty"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("absolute-url-rfc", "query"), expect: "foo=bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("absolute-url-rfc", "fragment"), expect: "foo", }}, }, { title: "scheme and host and path and query and fragment", input: "http://foo.bar/foo/bar?foo=bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("absolute-url", "hostname", "domain-name"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("absolute-url", "path-absolute-or-empty"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("absolute-url", "query"), expect: "foo=bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("absolute-url", "fragment"), expect: "foo", }}, }, { title: "user and host and path and query and fragment", input: "//foo:bar@foo.bar/foo/bar?foo=bar#foo", skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("relative-url", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("relative-url", "hostname", "domain-name"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("relative-url", "path-absolute-or-empty"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("relative-url", "query"), expect: "foo=bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("relative-url", "fragment"), expect: "foo", }}, }, { title: "scheme and user and host and path and query and fragment", input: "http://foo:bar@foo.bar/foo/bar?foo=bar#foo", bench: 3600, skipSTDReq: true, checks: []urlCheck{{ stdQuery: func(u *url.URL) string { return u.Scheme }, treerackQuery: queryTreerack("absolute-url", "scheme"), expect: "http", }, { stdQuery: func(u *url.URL) string { return u.User.String() }, treerackQuery: queryTreerack("absolute-url", "userinfo"), expect: "foo:bar", }, { stdQuery: func(u *url.URL) string { return u.Host }, treerackQuery: queryTreerack("absolute-url", "hostname", "domain-name"), expect: "foo.bar", }, { stdQuery: func(u *url.URL) string { return u.Path }, treerackQuery: queryTreerack("absolute-url", "path-absolute-or-empty"), expect: "/foo/bar", }, { stdQuery: func(u *url.URL) string { return u.RawQuery }, treerackQuery: queryTreerack("absolute-url", "query"), expect: "foo=bar", }, { stdQuery: func(u *url.URL) string { return u.Fragment }, treerackQuery: queryTreerack("absolute-url", "fragment"), expect: "foo", }}, }} { t.Run(test.title, func(t *testing.T) { t.Run("std", func(t *testing.T) { if test.skipSTD { t.Skip("!!!skipping standard library parser!!!") } n := test.bench if n <= 0 { n = 1 } var d time.Duration for i := 0; i < n && !t.Failed(); i++ { start := time.Now() u, err := url.Parse(test.input) d += time.Since(start) if err != nil { t.Fatal(err) } if i > 0 { continue } for _, check := range test.checks { v := check.stdQuery(u) if v != check.expect { notation.Lprintw(t, u) t.Fatal("expecting:", check.expect, "got:", v) } } } if test.bench > 0 { t.Log("average duration:", d/time.Duration(n)) } }) t.Run("stdreq", func(t *testing.T) { if test.skipSTDReq { t.Skip("non-request URI") } n := test.bench if n <= 0 { n = 1 } var d time.Duration for i := 0; i < n && !t.Failed(); i++ { start := time.Now() u, err := url.ParseRequestURI(test.input) d += time.Since(start) if err != nil { t.Fatal(err) } if i > 0 { continue } for _, check := range test.checks { v := check.stdQuery(u) if v != check.expect { notation.Lprintw(t, u) t.Fatal("expecting:", check.expect, "got:", v) } } } if test.bench > 0 { t.Log("average duration:", d/time.Duration(n)) } }) t.Run("treerack", func(t *testing.T) { n := test.bench if n <= 0 { n = 1 } var d time.Duration p := urlParser() for i := 0; i < n && !t.Failed(); i++ { start := time.Now() a, err := p(test.input) d += time.Since(start) if err != nil { t.Fatal(err) } if i > 0 { continue } for _, check := range test.checks { v := check.treerackQuery(a) if v != check.expect { printURLTree(t, a) t.Fatal("expecting:", check.expect, "got:", v) } } } if test.bench > 0 { t.Log("average duration:", d/time.Duration(n)) } }) }) } }