diff --git a/doc/example/url.treerack b/doc/example/url.treerack index 0dedede..13ceb7d 100644 --- a/doc/example/url.treerack +++ b/doc/example/url.treerack @@ -1,17 +1,16 @@ -// basd on RFC3986 and RFC6874 +// based on RFC3986 and RFC6874 // char types: digit:alias:failpass = [0-9]; hex:alias:failpass = [0-9a-fA-F]; alpha:alias:failpass = [a-zA-Z]; -// delimiter: -// delimiter:alias:failpass = ":" | "/" | "?" | "#" | "[" | "]" | "@"; -subdelimiter:alias:failpass = "!" | "$" | "&" | "'" | "(" | ")" | "*" | "+" | "," | ";" | "="; -unreserved:alias:failpass = alpha | digit | "-" | "." | "_" | "~"; - -// reserved: -// reserved:alias:failpass = delimiter | subdelimiter; +// delimiters and reserved: +// listing allowed chars, so delimiters and reserved are not referenced, only listing as documentation: +// delimiter = ":" | "/" | "?" | "#" | "[" | "]" | "@"; +// reserved = delimiter | subdelimiter; +subdelimiter:alias:failpass = "!" | "$" | "&" | "'" | "(" | ")" | "*" | "+" | "," | ";" | "="; +unreserved:alias:failpass = alpha | digit | "-" | "." | "_" | "~"; percent-encoded:alias:failpass = "%" hex{2}; path-char:alias:failpass = unreserved | percent-encoded | subdelimiter | ":" | "@"; diff --git a/go.mod b/go.mod index 3b1acc9..39f2b19 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module code.squareroundforest.org/arpio/treerack -go 1.25.3 +go 1.26.0 require ( code.squareroundforest.org/arpio/docreflect v0.0.0-20260113222846-40bd1879753e @@ -11,7 +11,7 @@ require ( require ( code.squareroundforest.org/arpio/bind v0.0.0-20251125135123-0de6ad6e67f2 // indirect code.squareroundforest.org/arpio/html v0.0.0-20251103020946-e262eca50ac9 // indirect - code.squareroundforest.org/arpio/notation v0.0.0-20251101123932-5f5c05ee0239 // indirect + code.squareroundforest.org/arpio/notation v0.0.0-20260605114014-7051f4f7fc0e // indirect code.squareroundforest.org/arpio/textedit v0.0.0-20251209222254-5a3e22b886be // indirect code.squareroundforest.org/arpio/textfmt v0.0.0-20251207234108-fed32c8bbe18 // indirect golang.org/x/mod v0.27.0 // indirect diff --git a/go.sum b/go.sum index 8ccb522..d9c8106 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ code.squareroundforest.org/arpio/html v0.0.0-20251103020946-e262eca50ac9 h1:b7vo code.squareroundforest.org/arpio/html v0.0.0-20251103020946-e262eca50ac9/go.mod h1:hq+2CENEd4bVSZnOdq38FUFOJJnF3OTQRv78qMGkNlE= code.squareroundforest.org/arpio/notation v0.0.0-20251101123932-5f5c05ee0239 h1:JvLVMuvF2laxXkIZbHC1/0xtKyKndAwIHbIIWkHqTzc= code.squareroundforest.org/arpio/notation v0.0.0-20251101123932-5f5c05ee0239/go.mod h1:ait4Fvg9o0+bq5hlxi9dAcPL5a+/sr33qsZPNpToMLY= +code.squareroundforest.org/arpio/notation v0.0.0-20260605114014-7051f4f7fc0e h1:JqMl2mkKKOnn9f8Lj/p9zxqpzKZCbax24YtDF+oS3mg= +code.squareroundforest.org/arpio/notation v0.0.0-20260605114014-7051f4f7fc0e/go.mod h1:GT75JG+e1m38DYfvTCm0pNxvoI4u3hSP1h1l+qe7Png= code.squareroundforest.org/arpio/textedit v0.0.0-20251209222254-5a3e22b886be h1:hy7tbsf8Fzl0UzBUNXRottKtCg3GvVI7Hmaf28Qoias= code.squareroundforest.org/arpio/textedit v0.0.0-20251209222254-5a3e22b886be/go.mod h1:nXdFdxdI69JrkIT97f+AEE4OgplmxbgNFZC5j7gsdqs= code.squareroundforest.org/arpio/textfmt v0.0.0-20251207234108-fed32c8bbe18 h1:2aa62CYm9ld5SNoFxWzE2wUN0xjVWQ+xieoeFantdg4= diff --git a/mmlexp_test.go b/mmlexp_test.go index ca12a4f..de1cc38 100644 --- a/mmlexp_test.go +++ b/mmlexp_test.go @@ -2985,7 +2985,6 @@ func TestMMLFile(t *testing.T) { } const n = 180 - s, err := openSyntaxFile("doc/example/mml-exp.treerack") if err != nil { t.Error(err) @@ -2993,7 +2992,6 @@ func TestMMLFile(t *testing.T) { } s.Init() - b, err := os.ReadFile("doc/example/test.mml") if err != nil { t.Fatal(err) diff --git a/url_test.go b/url_test.go new file mode 100644 index 0000000..8aea823 --- /dev/null +++ b/url_test.go @@ -0,0 +1,1482 @@ +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)) + } + }) + }) + } +}