Skip to content

Commit

Permalink
fix bugs and improve test infra
Browse files Browse the repository at this point in the history
  • Loading branch information
ori-shalom committed May 21, 2023
1 parent 325861a commit e9724a4
Show file tree
Hide file tree
Showing 14 changed files with 298 additions and 217 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/piiano/cellotape

go 1.18
go 1.20

retract v1.0.0 // Published accidentally.

Expand Down
4 changes: 0 additions & 4 deletions router/binders.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,10 +270,6 @@ func requestValidationInput(ctx *Context) *openapi3filter.RequestValidationInput
ParamDecoder: nil,
}

input.Options.WithCustomSchemaErrorFunc(func(err *openapi3.SchemaError) string {
return err.Reason
})

if ctx.Request != nil {
input.Request = ctx.Request
if ctx.Request.URL != nil {
Expand Down
210 changes: 48 additions & 162 deletions router/binders_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
package router

import (
"bytes"
"errors"
"io"
"net/http"
"net/http/httptest"
"net/url"
"reflect"
"testing"

Expand Down Expand Up @@ -37,16 +35,7 @@ type StructType struct {
func TestQueryBinderFactory(t *testing.T) {
queryBinder := queryBinderFactory[StructType](reflect.TypeOf(StructType{}))
var params StructType
requestURL, err := url.Parse("http:0.0.0.0:90/abc?Foo=42")
require.NoError(t, err)
err = queryBinder(&Context{
Request: &http.Request{
URL: requestURL,
},
Operation: SpecOperation{
Operation: openapi3.NewOperation(),
},
}, &params)
err := queryBinder(testContext(withURL(t, "http:0.0.0.0:90/abc?Foo=42")), &params)
require.NoError(t, err)
assert.Equal(t, StructType{Foo: 42}, params)
}
Expand All @@ -58,130 +47,74 @@ type StructWithArrayType struct {
func TestQueryBinderFactoryWithArrayType(t *testing.T) {
queryBinder := queryBinderFactory[StructWithArrayType](reflect.TypeOf(StructWithArrayType{}))
var params StructWithArrayType
requestURL, err := url.Parse("http:0.0.0.0:90/abc?Foo=42&Foo=6&Foo=7")
require.NoError(t, err)
err = queryBinder(&Context{
Request: &http.Request{
URL: requestURL,
},
Operation: SpecOperation{
Operation: openapi3.NewOperation(),
},
}, &params)
err := queryBinder(testContext(withURL(t, "http:0.0.0.0:90/abc?Foo=42&Foo=6&Foo=7")), &params)
require.NoError(t, err)
assert.Equal(t, StructWithArrayType{Foo: []int{42, 6, 7}}, params)
}

func TestQueryBinderFactoryMultipleParamToNonArrayError(t *testing.T) {
queryBinder := queryBinderFactory[StructType](reflect.TypeOf(StructType{}))
var params StructType
requestURL, err := url.Parse("http:0.0.0.0:90/abc?Foo=42&Foo=6&Foo=7")
require.NoError(t, err)
err = queryBinder(&Context{
Request: &http.Request{
URL: requestURL,
},
Operation: SpecOperation{
Operation: openapi3.NewOperation(),
},
}, &params)
err := queryBinder(testContext(withURL(t, "http:0.0.0.0:90/abc?Foo=42&Foo=6&Foo=7")), &params)
require.Error(t, err)
}

func TestQueryBinderFactoryError(t *testing.T) {
queryBinder := queryBinderFactory[StructType](reflect.TypeOf(StructType{}))
var params StructType
requestURL, err := url.Parse("http:0.0.0.0:90/abc?Foo=abc")
require.NoError(t, err)
err = queryBinder(&Context{
Request: &http.Request{
URL: requestURL,
},
Operation: SpecOperation{
Operation: openapi3.NewOperation(),
},
}, &params)

err := queryBinder(testContext(withURL(t, "http:0.0.0.0:90/abc?Foo=abc")), &params)
require.Error(t, err)
}

func TestPathBinderFactory(t *testing.T) {
pathBinder := pathBinderFactory[StructType](reflect.TypeOf(StructType{}))
var params StructType
err := pathBinder(&Context{
Params: &httprouter.Params{{
Key: "Foo",
Value: "42",
}},
Operation: SpecOperation{
Operation: openapi3.NewOperation(),
},
}, &params)
err := pathBinder(testContext(withParams(&httprouter.Params{{
Key: "Foo",
Value: "42",
}})), &params)
require.NoError(t, err)
assert.Equal(t, StructType{Foo: 42}, params)
}

func TestPathBinderFactoryError(t *testing.T) {
pathBinder := pathBinderFactory[StructType](reflect.TypeOf(StructType{}))
var params StructType
err := pathBinder(&Context{
Params: &httprouter.Params{{
Key: "Foo",
Value: "bar",
}},
Operation: SpecOperation{
Operation: openapi3.NewOperation(),
},
}, &params)
err := pathBinder(testContext(withParams(&httprouter.Params{{
Key: "Foo",
Value: "bar",
}})), &params)
require.Error(t, err)
}

func TestRequestBodyBinderFactory(t *testing.T) {
requestBodyBinder := requestBodyBinderFactory[int](reflect.TypeOf(0), DefaultContentTypes())
var param int
err := requestBodyBinder(&Context{
Request: &http.Request{
Body: io.NopCloser(bytes.NewBuffer([]byte("42"))),
},
Operation: SpecOperation{
Operation: openapi3.NewOperation(),
},
}, &param)
err := requestBodyBinder(testContext(withBody("42")), &param)
require.NoError(t, err)
assert.Equal(t, 42, param)
}

func TestRequestBodyBinderFactoryWithSchema(t *testing.T) {
operation := openapi3.NewOperation()
operation.RequestBody = &openapi3.RequestBodyRef{
testOp := openapi3.NewOperation()
testOp.RequestBody = &openapi3.RequestBodyRef{
Value: openapi3.NewRequestBody().WithJSONSchema(openapi3.NewIntegerSchema()),
}
requestBodyBinder := requestBodyBinderFactory[int](reflect.TypeOf(0), DefaultContentTypes())
var param int
err := requestBodyBinder(&Context{
Request: &http.Request{
Header: map[string][]string{"Content-Type": {"application/json"}},
Body: io.NopCloser(bytes.NewBuffer([]byte("42"))),
},
Operation: SpecOperation{
Operation: operation,
},
}, &param)
err := requestBodyBinder(testContext(
withBody("42"),
withHeader("Content-Type", "application/json"),
withOperation(testOp)), &param)
require.NoError(t, err)
assert.Equal(t, 42, param)
}

func TestRequestBodyBinderFactoryError(t *testing.T) {
requestBodyBinder := requestBodyBinderFactory[int](reflect.TypeOf(0), DefaultContentTypes())
var param int
err := requestBodyBinder(&Context{
Request: &http.Request{
Body: io.NopCloser(bytes.NewBuffer([]byte(`"foo"`))),
},
Operation: SpecOperation{
Operation: openapi3.NewOperation(),
},
}, &param)

err := requestBodyBinder(testContext(withBody(`"foo"`)), &param)
require.Error(t, err)
}

Expand All @@ -196,75 +129,46 @@ func (r readerWithError) Read(_ []byte) (int, error) {
func TestRequestBodyBinderFactoryReaderError(t *testing.T) {
requestBodyBinder := requestBodyBinderFactory[int](reflect.TypeOf(0), DefaultContentTypes())
var param int
err := requestBodyBinder(&Context{
Request: &http.Request{
Body: io.NopCloser(readerWithError(`42`)),
},
Operation: SpecOperation{
Operation: openapi3.NewOperation(),
},
}, &param)
err := requestBodyBinder(testContext(
withBodyReader(io.NopCloser(readerWithError(`42`)))), &param)
require.Error(t, err)
}

func TestRequestBodyBinderFactoryContentTypeError(t *testing.T) {
requestBodyBinder := requestBodyBinderFactory[int](reflect.TypeOf(0), DefaultContentTypes())
var param int
err := requestBodyBinder(&Context{
Request: &http.Request{
Header: http.Header{"Content-Type": {"no-such-content-type"}},
Body: io.NopCloser(bytes.NewBuffer([]byte(`42`))),
},
Operation: SpecOperation{
Operation: openapi3.NewOperation(),
},
}, &param)

err := requestBodyBinder(testContext(
withBody("42"),
withHeader("Content-Type", "no-such-content-type")), &param)
require.Error(t, err)
}

func TestRequestBodyBinderFactoryContentTypeWithCharset(t *testing.T) {
requestBodyBinder := requestBodyBinderFactory[int](reflect.TypeOf(0), DefaultContentTypes())
var param int
err := requestBodyBinder(&Context{
Request: &http.Request{
Header: http.Header{"Content-Type": {"application/json; charset=utf-8"}},
Body: io.NopCloser(bytes.NewBuffer([]byte("42"))),
},
Operation: SpecOperation{
Operation: openapi3.NewOperation(),
},
}, &param)
err := requestBodyBinder(testContext(
withBody("42"),
withHeader("Content-Type", "application/json; charset=utf-8")), &param)
require.NoError(t, err)
assert.Equal(t, 42, param)
}

func TestRequestBodyBinderFactoryInvalidContentType(t *testing.T) {
requestBodyBinder := requestBodyBinderFactory[int](reflect.TypeOf(0), DefaultContentTypes())
var param int
err := requestBodyBinder(&Context{
Request: &http.Request{
Header: http.Header{"Content-Type": {"invalid content type"}},
Body: io.NopCloser(bytes.NewBuffer([]byte("42"))),
},
Operation: SpecOperation{
Operation: openapi3.NewOperation(),
},
}, &param)
err := requestBodyBinder(testContext(
withBody("42"),
withHeader("Content-Type", "invalid content type")), &param)
require.Error(t, err)
}

func TestRequestBodyBinderFactoryContentTypeAnyWithCharset(t *testing.T) {
requestBodyBinder := requestBodyBinderFactory[int](reflect.TypeOf(0), DefaultContentTypes())
var param int
err := requestBodyBinder(&Context{
Request: &http.Request{
Header: http.Header{"Content-Type": {"*/*; charset=utf-8"}},
Body: io.NopCloser(bytes.NewBuffer([]byte("42"))),
},
Operation: SpecOperation{
Operation: openapi3.NewOperation(),
},
}, &param)
err := requestBodyBinder(testContext(
withBody("42"),
withHeader("Content-Type", "*/*; charset=utf-8")), &param)
require.NoError(t, err)
assert.Equal(t, 42, param)
}
Expand All @@ -282,17 +186,11 @@ type CollidingFieldsParams struct {

func TestBindingEmbeddedQueryParamsCollidingFields(t *testing.T) {
requestBodyBinder := queryBinderFactory[CollidingFieldsParams](reflect.TypeOf(CollidingFieldsParams{}))
requestURL, err := url.Parse("http://http:0.0.0.0:8080/path?param1=foo&param2=bar")
require.NoError(t, err)
var param CollidingFieldsParams
err = requestBodyBinder(&Context{
Request: &http.Request{
URL: requestURL,
},
Operation: SpecOperation{
Operation: openapi3.NewOperation(),
},
}, &param)

ctx := testContext(withURL(t, "http://http:0.0.0.0:8080/path?param1=foo&param2=bar"))

err := requestBodyBinder(ctx, &param)
require.NoError(t, err)
require.Equal(t, "foo", param.CollidingFieldsParam1.Value)
require.Equal(t, "bar", param.CollidingFieldsParam2.Value)
Expand All @@ -311,17 +209,10 @@ type CollidingParams struct {

func TestBindingEmbeddedQueryParamsCollidingParams(t *testing.T) {
requestBodyBinder := queryBinderFactory[CollidingParams](reflect.TypeOf(CollidingParams{}))
requestURL, err := url.Parse("http://http:0.0.0.0:8080/path?param1=42")
require.NoError(t, err)

var param CollidingParams
err = requestBodyBinder(&Context{
Request: &http.Request{
URL: requestURL,
},
Operation: SpecOperation{
Operation: openapi3.NewOperation(),
},
}, &param)
err := requestBodyBinder(testContext(
withURL(t, "http://http:0.0.0.0:8080/path?param1=42")), &param)
require.NoError(t, err)
require.Equal(t, "42", param.CollidingParamString.Value)
require.Equal(t, 42, param.CollidingParamInt.Value)
Expand Down Expand Up @@ -362,16 +253,11 @@ func TestErrOnWriterError(t *testing.T) {

for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
_, err := binder(&Context{
Operation: SpecOperation{
Operation: testOp,
},
Request: &http.Request{
URL: &url.URL{},
},
Writer: test.writer,
RawResponse: &RawResponse{},
}, response)
ctx := testContext(
withOperation(testOp),
withResponseWriter(test.writer),
)
_, err := binder(ctx, response)
test.assertion(t, err)
})
}
Expand Down
Loading

0 comments on commit e9724a4

Please sign in to comment.