Skip to content

Commit

Permalink
Update tests for ParseQuery changes.
Browse files Browse the repository at this point in the history
  • Loading branch information
creachadair committed Jan 22, 2022
1 parent 92ed141 commit a4d3978
Showing 1 changed file with 103 additions and 18 deletions.
121 changes: 103 additions & 18 deletions jhttp/getter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ package jhttp_test

import (
"context"
"encoding/hex"
"fmt"
"io"
"net/http"
Expand All @@ -17,6 +16,7 @@ import (
"github.com/creachadair/jrpc2/handler"
"github.com/creachadair/jrpc2/jhttp"
"github.com/fortytw2/leaktest"
"github.com/google/go-cmp/cmp"
)

func TestGetter(t *testing.T) {
Expand Down Expand Up @@ -70,6 +70,98 @@ func TestGetter(t *testing.T) {
})
}

func TestParseQuery(t *testing.T) {
tests := []struct {
url string
body string
method string
want interface{}
errText string
}{
// Error: Missing method name.
{"http://localhost:2112/", "", "", nil, "empty URL path"},

// No parameters.
{"http://localhost/foo", "", "foo", nil, ""},

// Unbalanced double-quoted string.
{"https://fuzz.ball/foo?bad=%22xyz", "", "foo", nil, "missing string quote"},
{"https://fuzz.ball/bar?bad=xyz%22", "", "bar", nil, "missing string quote"},

// Unbalanced single-quoted string.
{`http://stripe/sister?bad='invalid`, "", "sister", nil, "missing bytes quote"},
{`http://stripe/sister?bad=invalid'`, "", "sister", nil, "missing bytes quote"},

// Invalid byte string.
{`http://green.as/balls?bad='NOT%20VALID'`, "", "balls", nil, "decoding bytes"},

// Invalid double-quoted string.
{`http://black.as/sin?bad=%22a%5Cx25%22`, "", "sin", nil, "invalid character"},

// Valid: Single-quoted byte string (base64).
{`http://fast.as.hell/and?twice='YXMgcHJldHR5IGFzIHlvdQ=='`,
"", "and", map[string]interface{}{
"twice": []byte("as pretty as you"),
}, ""},

// Valid: Unquoted strings and null.
{`http://head.like/a-hole?black=as&your=null&soul`,
"", "a-hole", map[string]interface{}{
"black": "as",
"your": nil,
"soul": "",
}, ""},

// Valid: Quoted strings, numbers, Booleans.
{`http://foo.com:1999/go/west/?alpha=%22xyz%22&bravo=3&charlie=true&delta=false&echo=3.2`,
"", "go/west", map[string]interface{}{
"alpha": "xyz",
"bravo": int64(3),
"charlie": true,
"delta": false,
"echo": 3.2,
}, ""},

// Valid: Form-encoded query in the request body.
{`http://buz.org:2013/bodyblow`,
"alpha=%22pdq%22&bravo=-19.4&charlie=false", "bodyblow", map[string]interface{}{
"alpha": "pdq",
"bravo": float64(-19.4),
"charlie": false,
}, ""},
}
for _, test := range tests {
t.Run("ParseQuery", func(t *testing.T) {
req, err := http.NewRequest("PUT", test.url, strings.NewReader(test.body))
if err != nil {
t.Fatalf("New request for %q failed: %v", test.url, err)
}
if test.body != "" {
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
}

method, params, err := jhttp.ParseQuery(req)
if err != nil {
if test.errText == "" {
t.Fatalf("ParseQuery failed: %v", err)
} else if !strings.Contains(err.Error(), test.errText) {
t.Fatalf("ParseQuery: got error %v, want %q", err, test.errText)
}
} else if test.errText != "" {
t.Fatalf("ParseQuery: got method %q, params %+v, wanted error %q",
method, params, test.errText)
} else {
if method != test.method {
t.Errorf("ParseQuery method: got %q, want %q", method, test.method)
}
if diff := cmp.Diff(test.want, params); diff != "" {
t.Errorf("Wrong params: (-want, +got)\n%s", diff)
}
}
})
}
}

func TestGetter_parseRequest(t *testing.T) {
defer leaktest.Check(t)()

Expand All @@ -84,22 +176,15 @@ func TestGetter_parseRequest(t *testing.T) {
if err := req.ParseForm(); err != nil {
return "", nil, err
}
params := make(map[string]interface{})
for key := range req.Form {
val := req.Form.Get(key)
v, err := strconv.Atoi(val)
if err == nil {
params[key] = v
continue
}
b, err := hex.DecodeString(val)
if err == nil {
params[key] = b
continue
}
params[key] = val
tag := req.Form.Get("tag")
val, err := strconv.ParseInt(req.Form.Get("value"), 10, 64)
if err != nil && req.Form.Get("value") != "" {
return "", nil, fmt.Errorf("invalid number: %w", err)
}
return strings.TrimPrefix(req.URL.Path, "/x/"), params, nil
return strings.TrimPrefix(req.URL.Path, "/x/"), map[string]interface{}{
"tag": tag,
"value": val,
}, nil
},
})
defer checkClose(t, g)
Expand Down Expand Up @@ -127,8 +212,8 @@ func TestGetter_parseRequest(t *testing.T) {
})
t.Run("InternalError", func(t *testing.T) {
// N.B. Parameter type does not match on the server side.
got := mustGet(t, url("x/format?tag=foo&value=bar"), http.StatusInternalServerError)
const want = `"code":-32602` // InvalidParams
got := mustGet(t, url("x/format?tag=foo&value=bar"), http.StatusBadRequest)
const want = `"code":-32700` // ParseError
if !strings.Contains(got, want) {
t.Errorf("Response body: got %#q, want %#q", got, want)
}
Expand Down

0 comments on commit a4d3978

Please sign in to comment.