test and fix internal/reqdata #8
|
@ -4,8 +4,19 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"git.xdrm.io/go/aicra/internal/cerr"
|
||||
)
|
||||
|
||||
// ErrUnknownType is returned when encountering an unknown type
|
||||
const ErrUnknownType = cerr.Error("unknown type")
|
||||
|
||||
// ErrInvalidJSON is returned when json parse failed
|
||||
const ErrInvalidJSON = cerr.Error("invalid json")
|
||||
|
||||
// ErrInvalidRootType is returned when json is a map
|
||||
const ErrInvalidRootType = cerr.Error("invalid json root type")
|
||||
|
||||
// Parameter represents an http request parameter
|
||||
// that can be of type URL, GET, or FORM (multipart, json, urlencoded)
|
||||
type Parameter struct {
|
||||
|
@ -22,16 +33,23 @@ type Parameter struct {
|
|||
}
|
||||
|
||||
// Parse parameter (json-like) if not already done
|
||||
func (i *Parameter) Parse() {
|
||||
func (i *Parameter) Parse() error {
|
||||
|
||||
/* (1) Stop if already parsed or nil*/
|
||||
if i.Parsed || i.Value == nil {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
/* (2) Try to parse value */
|
||||
i.Value = parseParameter(i.Value)
|
||||
parsed, err := parseParameter(i.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i.Parsed = true
|
||||
i.Value = parsed
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseParameter parses http GET/POST data
|
||||
|
@ -39,7 +57,7 @@ func (i *Parameter) Parse() {
|
|||
// - size = 1 : return json of first element
|
||||
// - size > 1 : return array of json elements
|
||||
// - string : return json if valid, else return raw string
|
||||
func parseParameter(data interface{}) interface{} {
|
||||
func parseParameter(data interface{}) (interface{}, error) {
|
||||
dtype := reflect.TypeOf(data)
|
||||
dvalue := reflect.ValueOf(data)
|
||||
|
||||
|
@ -48,23 +66,12 @@ func parseParameter(data interface{}) interface{} {
|
|||
/* (1) []string -> recursive */
|
||||
case reflect.Slice:
|
||||
|
||||
// 1. Return nothing if empty
|
||||
// 1. ignore empty
|
||||
if dvalue.Len() == 0 {
|
||||
return nil
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// 2. only return first element if alone
|
||||
if dvalue.Len() == 1 {
|
||||
|
||||
element := dvalue.Index(0)
|
||||
if element.Kind() != reflect.String {
|
||||
return nil
|
||||
}
|
||||
return parseParameter(element.String())
|
||||
|
||||
}
|
||||
|
||||
// 3. Return all elements if more than 1
|
||||
// 2. parse each element recursively
|
||||
result := make([]interface{}, dvalue.Len())
|
||||
|
||||
for i, l := 0, dvalue.Len(); i < l; i++ {
|
||||
|
@ -72,12 +79,17 @@ func parseParameter(data interface{}) interface{} {
|
|||
|
||||
// ignore non-string
|
||||
if element.Kind() != reflect.String {
|
||||
result[i] = element.Interface()
|
||||
continue
|
||||
}
|
||||
|
||||
result[i] = parseParameter(element.String())
|
||||
parsed, err := parseParameter(element.String())
|
||||
if err != nil {
|
||||
return data, err
|
||||
}
|
||||
return result
|
||||
result[i] = parsed
|
||||
}
|
||||
return result, nil
|
||||
|
||||
/* (2) string -> parse */
|
||||
case reflect.String:
|
||||
|
@ -94,23 +106,23 @@ func parseParameter(data interface{}) interface{} {
|
|||
|
||||
mapval, ok := result.(map[string]interface{})
|
||||
if !ok {
|
||||
return dvalue.String()
|
||||
return dvalue.String(), ErrInvalidRootType
|
||||
}
|
||||
|
||||
wrapped, ok := mapval["wrapped"]
|
||||
if !ok {
|
||||
return dvalue.String()
|
||||
return dvalue.String(), ErrInvalidJSON
|
||||
}
|
||||
|
||||
return wrapped
|
||||
return wrapped, nil
|
||||
}
|
||||
|
||||
// else return as string
|
||||
return dvalue.String()
|
||||
return dvalue.String(), nil
|
||||
|
||||
}
|
||||
|
||||
/* (3) NIL if unknown type */
|
||||
return dvalue
|
||||
return dvalue.Interface(), nil
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,358 @@
|
|||
package reqdata
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSimpleString(t *testing.T) {
|
||||
p := Parameter{Parsed: false, File: false, Value: "some-string"}
|
||||
|
||||
err := p.Parse()
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: <%s>", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !p.Parsed {
|
||||
t.Errorf("expected parameter to be parsed")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
cast, canCast := p.Value.(string)
|
||||
if !canCast {
|
||||
t.Errorf("expected parameter to be a string")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if cast != "some-string" {
|
||||
t.Errorf("expected parameter to equal 'some-string', got '%s'", cast)
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimpleFloat(t *testing.T) {
|
||||
tcases := []float64{12.3456789, -12.3456789, 0.0000001, -0.0000001}
|
||||
|
||||
for i, tcase := range tcases {
|
||||
t.Run("case "+string(i), func(t *testing.T) {
|
||||
p := Parameter{Parsed: false, File: false, Value: tcase}
|
||||
|
||||
if err := p.Parse(); err != nil {
|
||||
t.Errorf("unexpected error: <%s>", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !p.Parsed {
|
||||
t.Errorf("expected parameter to be parsed")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
cast, canCast := p.Value.(float64)
|
||||
if !canCast {
|
||||
t.Errorf("expected parameter to be a float64")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if math.Abs(cast-tcase) > 0.00000001 {
|
||||
t.Errorf("expected parameter to equal '%f', got '%f'", tcase, cast)
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSimpleBool(t *testing.T) {
|
||||
tcases := []bool{true, false}
|
||||
|
||||
for i, tcase := range tcases {
|
||||
t.Run("case "+string(i), func(t *testing.T) {
|
||||
p := Parameter{Parsed: false, File: false, Value: tcase}
|
||||
|
||||
if err := p.Parse(); err != nil {
|
||||
t.Errorf("unexpected error: <%s>", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !p.Parsed {
|
||||
t.Errorf("expected parameter to be parsed")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
cast, canCast := p.Value.(bool)
|
||||
if !canCast {
|
||||
t.Errorf("expected parameter to be a bool")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if cast != tcase {
|
||||
t.Errorf("expected parameter to equal '%t', got '%t'", tcase, cast)
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJsonStringSlice(t *testing.T) {
|
||||
p := Parameter{Parsed: false, File: false, Value: `["str1", "str2"]`}
|
||||
|
||||
err := p.Parse()
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: <%s>", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !p.Parsed {
|
||||
t.Errorf("expected parameter to be parsed")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
slice, canCast := p.Value.([]interface{})
|
||||
if !canCast {
|
||||
t.Errorf("expected parameter to be a []interface{}")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if len(slice) != 2 {
|
||||
t.Errorf("expected 2 values, got %d", len(slice))
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
results := []string{"str1", "str2"}
|
||||
|
||||
for i, res := range results {
|
||||
|
||||
cast, canCast := slice[i].(string)
|
||||
if !canCast {
|
||||
t.Errorf("expected parameter %d to be a []string", i)
|
||||
continue
|
||||
}
|
||||
if cast != res {
|
||||
t.Errorf("expected first value to be '%s', got '%s'", res, cast)
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestStringSlice(t *testing.T) {
|
||||
p := Parameter{Parsed: false, File: false, Value: []string{"str1", "str2"}}
|
||||
|
||||
err := p.Parse()
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: <%s>", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !p.Parsed {
|
||||
t.Errorf("expected parameter to be parsed")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
slice, canCast := p.Value.([]interface{})
|
||||
if !canCast {
|
||||
t.Errorf("expected parameter to be a []interface{}")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if len(slice) != 2 {
|
||||
t.Errorf("expected 2 values, got %d", len(slice))
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
results := []string{"str1", "str2"}
|
||||
|
||||
for i, res := range results {
|
||||
|
||||
cast, canCast := slice[i].(string)
|
||||
if !canCast {
|
||||
t.Errorf("expected parameter %d to be a []string", i)
|
||||
continue
|
||||
}
|
||||
if cast != res {
|
||||
t.Errorf("expected first value to be '%s', got '%s'", res, cast)
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestJsonPrimitiveBool(t *testing.T) {
|
||||
tcases := []struct {
|
||||
Raw string
|
||||
BoolValue bool
|
||||
}{
|
||||
{"true", true},
|
||||
{"false", false},
|
||||
}
|
||||
|
||||
for i, tcase := range tcases {
|
||||
t.Run("case "+string(i), func(t *testing.T) {
|
||||
p := Parameter{Parsed: false, File: false, Value: tcase.Raw}
|
||||
|
||||
err := p.Parse()
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: <%s>", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !p.Parsed {
|
||||
t.Errorf("expected parameter to be parsed")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
cast, canCast := p.Value.(bool)
|
||||
if !canCast {
|
||||
t.Errorf("expected parameter to be a bool")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if cast != tcase.BoolValue {
|
||||
t.Errorf("expected a value of %t, got %t", tcase.BoolValue, cast)
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestJsonPrimitiveFloat(t *testing.T) {
|
||||
tcases := []struct {
|
||||
Raw string
|
||||
FloatValue float64
|
||||
}{
|
||||
{"1", 1},
|
||||
{"-1", -1},
|
||||
|
||||
{"0.001", 0.001},
|
||||
{"-0.001", -0.001},
|
||||
|
||||
{"1.9992", 1.9992},
|
||||
{"-1.9992", -1.9992},
|
||||
|
||||
{"19992", 19992},
|
||||
{"-19992", -19992},
|
||||
}
|
||||
|
||||
for i, tcase := range tcases {
|
||||
t.Run("case "+string(i), func(t *testing.T) {
|
||||
p := Parameter{Parsed: false, File: false, Value: tcase.Raw}
|
||||
|
||||
err := p.Parse()
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: <%s>", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !p.Parsed {
|
||||
t.Errorf("expected parameter to be parsed")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
cast, canCast := p.Value.(float64)
|
||||
if !canCast {
|
||||
t.Errorf("expected parameter to be a float64")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if math.Abs(cast-tcase.FloatValue) > 0.00001 {
|
||||
t.Errorf("expected a value of %f, got %f", tcase.FloatValue, cast)
|
||||
t.FailNow()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestJsonBoolSlice(t *testing.T) {
|
||||
p := Parameter{Parsed: false, File: false, Value: []string{"true", "false"}}
|
||||
|
||||
err := p.Parse()
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: <%s>", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !p.Parsed {
|
||||
t.Errorf("expected parameter to be parsed")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
slice, canCast := p.Value.([]interface{})
|
||||
if !canCast {
|
||||
t.Errorf("expected parameter to be a []interface{}")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if len(slice) != 2 {
|
||||
t.Errorf("expected 2 values, got %d", len(slice))
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
results := []bool{true, false}
|
||||
|
||||
for i, res := range results {
|
||||
|
||||
cast, canCast := slice[i].(bool)
|
||||
if !canCast {
|
||||
t.Errorf("expected parameter %d to be a []bool", i)
|
||||
continue
|
||||
}
|
||||
if cast != res {
|
||||
t.Errorf("expected first value to be '%t', got '%t'", res, cast)
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestBoolSlice(t *testing.T) {
|
||||
p := Parameter{Parsed: false, File: false, Value: []bool{true, false}}
|
||||
|
||||
err := p.Parse()
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: <%s>", err)
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if !p.Parsed {
|
||||
t.Errorf("expected parameter to be parsed")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
slice, canCast := p.Value.([]interface{})
|
||||
if !canCast {
|
||||
t.Errorf("expected parameter to be a []interface{}")
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
if len(slice) != 2 {
|
||||
t.Errorf("expected 2 values, got %d", len(slice))
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
results := []bool{true, false}
|
||||
|
||||
for i, res := range results {
|
||||
|
||||
cast, canCast := slice[i].(bool)
|
||||
if !canCast {
|
||||
t.Errorf("expected parameter %d to be a bool, got %v", i, slice[i])
|
||||
continue
|
||||
}
|
||||
if cast != res {
|
||||
t.Errorf("expected first value to be '%t', got '%t'", res, cast)
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,11 +1,12 @@
|
|||
package reqdata
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
@ -222,7 +223,28 @@ func TestStoreWithGet(t *testing.T) {
|
|||
}
|
||||
|
||||
}
|
||||
func TestStoreWithUrlEncodedFormParseError(t *testing.T) {
|
||||
// http.Request.ParseForm() fails when:
|
||||
// - http.Request.Method is one of [POST,PUT,PATCH]
|
||||
// - http.Request.Form is not nil (created manually)
|
||||
// - http.Request.PostForm is nil (deleted manually)
|
||||
// - http.Request.Body is nil (deleted manually)
|
||||
|
||||
req := httptest.NewRequest(http.MethodPost, "http://host.com/", nil)
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
// break everything
|
||||
req.Body = nil
|
||||
req.Form = make(url.Values)
|
||||
req.PostForm = nil
|
||||
|
||||
// defer req.Body.Close()
|
||||
store := New(nil, req)
|
||||
if len(store.Form) > 0 {
|
||||
t.Errorf("expected malformed urlencoded to have failed being parsed (got %d elements)", len(store.Form))
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
func TestStoreWithUrlEncodedForm(t *testing.T) {
|
||||
tests := []struct {
|
||||
URLEncoded string
|
||||
|
@ -301,7 +323,7 @@ func TestStoreWithUrlEncodedForm(t *testing.T) {
|
|||
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("request.%d", i), func(t *testing.T) {
|
||||
body := bytes.NewBufferString(test.URLEncoded)
|
||||
body := strings.NewReader(test.URLEncoded)
|
||||
req := httptest.NewRequest(http.MethodPost, "http://host.com", body)
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
defer req.Body.Close()
|
||||
|
@ -474,7 +496,7 @@ func TestJsonParameters(t *testing.T) {
|
|||
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("request.%d", i), func(t *testing.T) {
|
||||
body := bytes.NewBufferString(test.RawJson)
|
||||
body := strings.NewReader(test.RawJson)
|
||||
req := httptest.NewRequest(http.MethodPost, "http://host.com", body)
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
defer req.Body.Close()
|
||||
|
@ -545,3 +567,238 @@ func TestJsonParameters(t *testing.T) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
func TestMultipartParameters(t *testing.T) {
|
||||
tests := []struct {
|
||||
RawMultipart string
|
||||
|
||||
InvalidNames []string
|
||||
ParamNames []string
|
||||
ParamValues []interface{}
|
||||
}{
|
||||
// no need to fully check json because it is parsed with the standard library
|
||||
{
|
||||
RawMultipart: ``,
|
||||
InvalidNames: []string{},
|
||||
ParamNames: []string{},
|
||||
ParamValues: []interface{}{},
|
||||
},
|
||||
{
|
||||
RawMultipart: `--xxx
|
||||
`,
|
||||
InvalidNames: []string{},
|
||||
ParamNames: []string{},
|
||||
ParamValues: []interface{}{},
|
||||
},
|
||||
{
|
||||
RawMultipart: `--xxx
|
||||
--xxx--`,
|
||||
InvalidNames: []string{},
|
||||
ParamNames: []string{},
|
||||
ParamValues: []interface{}{},
|
||||
},
|
||||
{
|
||||
RawMultipart: `--xxx
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
b
|
||||
--xxx--`,
|
||||
InvalidNames: []string{},
|
||||
ParamNames: []string{"a"},
|
||||
ParamValues: []interface{}{"b"},
|
||||
},
|
||||
{
|
||||
RawMultipart: `--xxx
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
b
|
||||
--xxx
|
||||
Content-Disposition: form-data; name="c"
|
||||
|
||||
d
|
||||
--xxx--`,
|
||||
InvalidNames: []string{},
|
||||
ParamNames: []string{"a", "c"},
|
||||
ParamValues: []interface{}{"b", "d"},
|
||||
},
|
||||
{
|
||||
RawMultipart: `--xxx
|
||||
Content-Disposition: form-data; name="_invalid"
|
||||
|
||||
x
|
||||
--xxx--`,
|
||||
InvalidNames: []string{"_invalid"},
|
||||
ParamNames: []string{"_invalid"},
|
||||
ParamValues: []interface{}{nil},
|
||||
},
|
||||
{
|
||||
RawMultipart: `--xxx
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
b
|
||||
--xxx
|
||||
Content-Disposition: form-data; name="_invalid"
|
||||
|
||||
x
|
||||
--xxx--`,
|
||||
InvalidNames: []string{"_invalid"},
|
||||
ParamNames: []string{"a", "_invalid"},
|
||||
ParamValues: []interface{}{"b", nil},
|
||||
},
|
||||
|
||||
{
|
||||
RawMultipart: `--xxx
|
||||
Content-Disposition: form-data; name="invalid_"
|
||||
|
||||
x
|
||||
--xxx--`,
|
||||
InvalidNames: []string{"invalid_"},
|
||||
ParamNames: []string{"invalid_"},
|
||||
ParamValues: []interface{}{nil},
|
||||
},
|
||||
{
|
||||
RawMultipart: `--xxx
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
b
|
||||
--xxx
|
||||
Content-Disposition: form-data; name="invalid_"
|
||||
|
||||
x
|
||||
--xxx--`,
|
||||
InvalidNames: []string{"invalid_"},
|
||||
ParamNames: []string{"a", "invalid_"},
|
||||
ParamValues: []interface{}{"b", nil},
|
||||
},
|
||||
|
||||
{
|
||||
RawMultipart: `--xxx
|
||||
Content-Disposition: form-data; name="GET@injection"
|
||||
|
||||
x
|
||||
--xxx--`,
|
||||
InvalidNames: []string{"GET@injection"},
|
||||
ParamNames: []string{"GET@injection"},
|
||||
ParamValues: []interface{}{nil},
|
||||
},
|
||||
{
|
||||
RawMultipart: `--xxx
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
b
|
||||
--xxx
|
||||
Content-Disposition: form-data; name="GET@injection"
|
||||
|
||||
x
|
||||
--xxx--`,
|
||||
InvalidNames: []string{"GET@injection"},
|
||||
ParamNames: []string{"a", "GET@injection"},
|
||||
ParamValues: []interface{}{"b", nil},
|
||||
},
|
||||
|
||||
{
|
||||
RawMultipart: `--xxx
|
||||
Content-Disposition: form-data; name="URL#injection"
|
||||
|
||||
x
|
||||
--xxx--`,
|
||||
InvalidNames: []string{"URL#injection"},
|
||||
ParamNames: []string{"URL#injection"},
|
||||
ParamValues: []interface{}{nil},
|
||||
},
|
||||
{
|
||||
RawMultipart: `--xxx
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
b
|
||||
--xxx
|
||||
Content-Disposition: form-data; name="URL#injection"
|
||||
|
||||
x
|
||||
--xxx--`,
|
||||
InvalidNames: []string{"URL#injection"},
|
||||
ParamNames: []string{"a", "URL#injection"},
|
||||
ParamValues: []interface{}{"b", nil},
|
||||
},
|
||||
// json parse error
|
||||
{
|
||||
RawMultipart: "{ \"a\": \"b\", }",
|
||||
InvalidNames: []string{},
|
||||
ParamNames: []string{},
|
||||
ParamValues: []interface{}{},
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprintf("request.%d", i), func(t *testing.T) {
|
||||
body := strings.NewReader(test.RawMultipart)
|
||||
req := httptest.NewRequest(http.MethodPost, "http://host.com", body)
|
||||
req.Header.Add("Content-Type", "multipart/form-data; boundary=xxx")
|
||||
defer req.Body.Close()
|
||||
store := New(nil, req)
|
||||
|
||||
if test.ParamNames == nil || test.ParamValues == nil {
|
||||
if len(store.Set) != 0 {
|
||||
t.Errorf("expected no JSON parameters and got %d", len(store.Get))
|
||||
t.Failed()
|
||||
}
|
||||
|
||||
// no param to check
|
||||
return
|
||||
}
|
||||
|
||||
if len(test.ParamNames) != len(test.ParamValues) {
|
||||
t.Errorf("invalid test: names and values differ in size (%d vs %d)", len(test.ParamNames), len(test.ParamValues))
|
||||
t.Failed()
|
||||
}
|
||||
|
||||
for pi, pName := range test.ParamNames {
|
||||
key := pName
|
||||
value := test.ParamValues[pi]
|
||||
|
||||
isNameValid := true
|
||||
for _, invalid := range test.InvalidNames {
|
||||
if pName == invalid {
|
||||
isNameValid = false
|
||||
}
|
||||
}
|
||||
|
||||
t.Run(key, func(t *testing.T) {
|
||||
|
||||
param, isset := store.Set[key]
|
||||
if !isset {
|
||||
if isNameValid {
|
||||
t.Errorf("store should contain element with key '%s'", key)
|
||||
t.Failed()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// if should be invalid
|
||||
if isset && !isNameValid {
|
||||
t.Errorf("store should NOT contain element with key '%s' (invalid name)", key)
|
||||
t.Failed()
|
||||
}
|
||||
|
||||
valueType := reflect.TypeOf(value)
|
||||
|
||||
paramValue := param.Value
|
||||
paramValueType := reflect.TypeOf(param.Value)
|
||||
|
||||
if valueType != paramValueType {
|
||||
t.Errorf("should be of type %v (got '%v')", valueType, paramValueType)
|
||||
t.Failed()
|
||||
}
|
||||
|
||||
if paramValue != value {
|
||||
t.Errorf("should return %v (got '%v')", value, paramValue)
|
||||
t.Failed()
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -41,6 +41,18 @@ func TestString_AvailableTypes(t *testing.T) {
|
|||
{"string(1 )", false},
|
||||
{"string( 1 )", false},
|
||||
|
||||
{"string()", false},
|
||||
{"string(a)", false},
|
||||
{"string(-1)", false},
|
||||
|
||||
{"string(,)", false},
|
||||
{"string(1,b)", false},
|
||||
{"string(a,b)", false},
|
||||
{"string(a,1)", false},
|
||||
{"string(-1,1)", false},
|
||||
{"string(1,-1)", false},
|
||||
{"string(-1,-1)", false},
|
||||
|
||||
{"string(1,2)", true},
|
||||
{"string(1, 2)", true},
|
||||
{"string(1, 2)", false},
|
||||
|
|
|
@ -96,6 +96,11 @@ func TestUint_Values(t *testing.T) {
|
|||
// strane offset because of how precision works
|
||||
{fmt.Sprintf("%f", float64(math.MaxUint64+1024*3)), false},
|
||||
|
||||
{[]byte(fmt.Sprintf("%d", math.MaxInt64)), true},
|
||||
{[]byte(fmt.Sprintf("%d", uint(math.MaxUint64))), true},
|
||||
// strane offset because of how precision works
|
||||
{[]byte(fmt.Sprintf("%f", float64(math.MaxUint64+1024*3))), false},
|
||||
|
||||
{"string", false},
|
||||
{[]byte("bytes"), false},
|
||||
{-0.1, false},
|
||||
|
|
Loading…
Reference in New Issue