package echo import ( "bytes" "io" "mime/multipart" "net/http" "net/http/httptest" "reflect" "strings" "testing" "github.com/stretchr/testify/assert" ) type ( binderTestStruct struct { I int I8 int8 I16 int16 I32 int32 I64 int64 UI uint UI8 uint8 UI16 uint16 UI32 uint32 UI64 uint64 B bool F32 float32 F64 float64 S string cantSet string DoesntExist string } ) func (t binderTestStruct) GetCantSet() string { return t.cantSet } var values = map[string][]string{ "I": {"0"}, "I8": {"8"}, "I16": {"16"}, "I32": {"32"}, "I64": {"64"}, "UI": {"0"}, "UI8": {"8"}, "UI16": {"16"}, "UI32": {"32"}, "UI64": {"64"}, "B": {"true"}, "F32": {"32.5"}, "F64": {"64.5"}, "S": {"test"}, "cantSet": {"test"}, } func TestBinderJSON(t *testing.T) { testBinderOkay(t, strings.NewReader(userJSON), MIMEApplicationJSON) testBinderError(t, strings.NewReader(invalidContent), MIMEApplicationJSON) } func TestBinderXML(t *testing.T) { testBinderOkay(t, strings.NewReader(userXML), MIMEApplicationXML) testBinderError(t, strings.NewReader(invalidContent), MIMEApplicationXML) } func TestBinderForm(t *testing.T) { testBinderOkay(t, strings.NewReader(userForm), MIMEApplicationForm) testBinderError(t, nil, MIMEApplicationForm) e := New() req, _ := http.NewRequest(POST, "/", strings.NewReader(userForm)) rec := httptest.NewRecorder() c := e.NewContext(req, rec) req.Header.Set(HeaderContentType, MIMEApplicationForm) obj := []struct{ Field string }{} err := c.Bind(&obj) assert.Error(t, err) } func TestBinderQueryParams(t *testing.T) { e := New() req, _ := http.NewRequest(GET, "/?id=1&name=Jon Snow", nil) rec := httptest.NewRecorder() c := e.NewContext(req, rec) u := new(user) err := c.Bind(u) if assert.NoError(t, err) { assert.Equal(t, 1, u.ID) assert.Equal(t, "Jon Snow", u.Name) } } func TestBinderMultipartForm(t *testing.T) { body := new(bytes.Buffer) mw := multipart.NewWriter(body) mw.WriteField("id", "1") mw.WriteField("name", "Jon Snow") mw.Close() testBinderOkay(t, body, mw.FormDataContentType()) } func TestBinderUnsupportedMediaType(t *testing.T) { testBinderError(t, strings.NewReader(invalidContent), MIMEApplicationJSON) } func TestBinderbindForm(t *testing.T) { ts := new(binderTestStruct) b := new(binder) b.bindData(ts, values) assertBinderTestStruct(t, ts) } func TestBinderSetWithProperType(t *testing.T) { ts := new(binderTestStruct) typ := reflect.TypeOf(ts).Elem() val := reflect.ValueOf(ts).Elem() for i := 0; i < typ.NumField(); i++ { typeField := typ.Field(i) structField := val.Field(i) if !structField.CanSet() { continue } if len(values[typeField.Name]) == 0 { continue } val := values[typeField.Name][0] err := setWithProperType(typeField.Type.Kind(), val, structField) assert.NoError(t, err) } assertBinderTestStruct(t, ts) type foo struct { Bar bytes.Buffer } v := &foo{} typ = reflect.TypeOf(v).Elem() val = reflect.ValueOf(v).Elem() assert.Error(t, setWithProperType(typ.Field(0).Type.Kind(), "5", val.Field(0))) } func TestBinderSetFields(t *testing.T) { ts := new(binderTestStruct) val := reflect.ValueOf(ts).Elem() // Int if assert.NoError(t, setIntField("5", 0, val.FieldByName("I"))) { assert.Equal(t, 5, ts.I) } if assert.NoError(t, setIntField("", 0, val.FieldByName("I"))) { assert.Equal(t, 0, ts.I) } // Uint if assert.NoError(t, setUintField("10", 0, val.FieldByName("UI"))) { assert.Equal(t, uint(10), ts.UI) } if assert.NoError(t, setUintField("", 0, val.FieldByName("UI"))) { assert.Equal(t, uint(0), ts.UI) } // Float if assert.NoError(t, setFloatField("15.5", 0, val.FieldByName("F32"))) { assert.Equal(t, float32(15.5), ts.F32) } if assert.NoError(t, setFloatField("", 0, val.FieldByName("F32"))) { assert.Equal(t, float32(0.0), ts.F32) } // Bool if assert.NoError(t, setBoolField("true", val.FieldByName("B"))) { assert.Equal(t, true, ts.B) } if assert.NoError(t, setBoolField("", val.FieldByName("B"))) { assert.Equal(t, false, ts.B) } } func assertBinderTestStruct(t *testing.T, ts *binderTestStruct) { assert.Equal(t, 0, ts.I) assert.Equal(t, int8(8), ts.I8) assert.Equal(t, int16(16), ts.I16) assert.Equal(t, int32(32), ts.I32) assert.Equal(t, int64(64), ts.I64) assert.Equal(t, uint(0), ts.UI) assert.Equal(t, uint8(8), ts.UI8) assert.Equal(t, uint16(16), ts.UI16) assert.Equal(t, uint32(32), ts.UI32) assert.Equal(t, uint64(64), ts.UI64) assert.Equal(t, true, ts.B) assert.Equal(t, float32(32.5), ts.F32) assert.Equal(t, float64(64.5), ts.F64) assert.Equal(t, "test", ts.S) assert.Equal(t, "", ts.GetCantSet()) } func testBinderOkay(t *testing.T, r io.Reader, ctype string) { e := New() req, _ := http.NewRequest(POST, "/", r) rec := httptest.NewRecorder() c := e.NewContext(req, rec) req.Header.Set(HeaderContentType, ctype) u := new(user) err := c.Bind(u) if assert.NoError(t, err) { assert.Equal(t, 1, u.ID) assert.Equal(t, "Jon Snow", u.Name) } } func testBinderError(t *testing.T, r io.Reader, ctype string) { e := New() req, _ := http.NewRequest(POST, "/", r) rec := httptest.NewRecorder() c := e.NewContext(req, rec) req.Header.Set(HeaderContentType, ctype) u := new(user) err := c.Bind(u) switch { case strings.HasPrefix(ctype, MIMEApplicationJSON), strings.HasPrefix(ctype, MIMEApplicationXML), strings.HasPrefix(ctype, MIMEApplicationForm), strings.HasPrefix(ctype, MIMEMultipartForm): if assert.IsType(t, new(HTTPError), err) { assert.Equal(t, http.StatusBadRequest, err.(*HTTPError).Code) } default: if assert.IsType(t, new(HTTPError), err) { assert.Equal(t, ErrUnsupportedMediaType, err) } } }