|
| 1 | +package echo |
| 2 | + |
| 3 | +import ( |
| 4 | + "bytes" |
| 5 | + "io" |
| 6 | + "mime/multipart" |
| 7 | + "net/http" |
| 8 | + "reflect" |
| 9 | + "strings" |
| 10 | + "testing" |
| 11 | + |
| 12 | + "github.com/labstack/echo/test" |
| 13 | + "github.com/stretchr/testify/assert" |
| 14 | +) |
| 15 | + |
| 16 | +type ( |
| 17 | + binderTestStruct struct { |
| 18 | + I int |
| 19 | + I8 int8 |
| 20 | + I16 int16 |
| 21 | + I32 int32 |
| 22 | + I64 int64 |
| 23 | + UI uint |
| 24 | + UI8 uint8 |
| 25 | + UI16 uint16 |
| 26 | + UI32 uint32 |
| 27 | + UI64 uint64 |
| 28 | + B bool |
| 29 | + F32 float32 |
| 30 | + F64 float64 |
| 31 | + S string |
| 32 | + cantSet string |
| 33 | + DoesntExist string |
| 34 | + } |
| 35 | +) |
| 36 | + |
| 37 | +func (t binderTestStruct) GetCantSet() string { |
| 38 | + return t.cantSet |
| 39 | +} |
| 40 | + |
| 41 | +var values = map[string][]string{ |
| 42 | + "I": {"0"}, |
| 43 | + "I8": {"8"}, |
| 44 | + "I16": {"16"}, |
| 45 | + "I32": {"32"}, |
| 46 | + "I64": {"64"}, |
| 47 | + "UI": {"0"}, |
| 48 | + "UI8": {"8"}, |
| 49 | + "UI16": {"16"}, |
| 50 | + "UI32": {"32"}, |
| 51 | + "UI64": {"64"}, |
| 52 | + "B": {"true"}, |
| 53 | + "F32": {"32.5"}, |
| 54 | + "F64": {"64.5"}, |
| 55 | + "S": {"test"}, |
| 56 | + "cantSet": {"test"}, |
| 57 | +} |
| 58 | + |
| 59 | +func TestBinderJSON(t *testing.T) { |
| 60 | + testBinderOkay(t, strings.NewReader(userJSON), MIMEApplicationJSON) |
| 61 | + testBinderError(t, strings.NewReader(invalidContent), MIMEApplicationJSON) |
| 62 | +} |
| 63 | + |
| 64 | +func TestBinderXML(t *testing.T) { |
| 65 | + testBinderOkay(t, strings.NewReader(userXML), MIMEApplicationXML) |
| 66 | + testBinderError(t, strings.NewReader(invalidContent), MIMEApplicationXML) |
| 67 | +} |
| 68 | + |
| 69 | +func TestBinderForm(t *testing.T) { |
| 70 | + testBinderOkay(t, strings.NewReader(userForm), MIMEApplicationForm) |
| 71 | +} |
| 72 | + |
| 73 | +func TestBinderMultipartForm(t *testing.T) { |
| 74 | + body := new(bytes.Buffer) |
| 75 | + mw := multipart.NewWriter(body) |
| 76 | + mw.WriteField("id", "1") |
| 77 | + mw.WriteField("name", "Jon Snow") |
| 78 | + mw.Close() |
| 79 | + testBinderOkay(t, body, mw.FormDataContentType()) |
| 80 | +} |
| 81 | + |
| 82 | +func TestBinderUnsupportedMediaType(t *testing.T) { |
| 83 | + testBinderError(t, strings.NewReader(invalidContent), MIMEApplicationJSON) |
| 84 | +} |
| 85 | + |
| 86 | +// func assertCustomer(t *testing.T, c *user) { |
| 87 | +// assert.Equal(t, 1, c.ID) |
| 88 | +// assert.Equal(t, "Joe", c.Name) |
| 89 | +// } |
| 90 | + |
| 91 | +func TestBinderbindForm(t *testing.T) { |
| 92 | + ts := new(binderTestStruct) |
| 93 | + b := new(binder) |
| 94 | + b.bindForm(ts, values) |
| 95 | + assertBinderTestStruct(t, ts) |
| 96 | +} |
| 97 | + |
| 98 | +func TestBinderSetWithProperType(t *testing.T) { |
| 99 | + ts := new(binderTestStruct) |
| 100 | + typ := reflect.TypeOf(ts).Elem() |
| 101 | + val := reflect.ValueOf(ts).Elem() |
| 102 | + for i := 0; i < typ.NumField(); i++ { |
| 103 | + typeField := typ.Field(i) |
| 104 | + structField := val.Field(i) |
| 105 | + if !structField.CanSet() { |
| 106 | + continue |
| 107 | + } |
| 108 | + if len(values[typeField.Name]) == 0 { |
| 109 | + continue |
| 110 | + } |
| 111 | + val := values[typeField.Name][0] |
| 112 | + err := setWithProperType(typeField.Type.Kind(), val, structField) |
| 113 | + assert.NoError(t, err) |
| 114 | + } |
| 115 | + assertBinderTestStruct(t, ts) |
| 116 | + |
| 117 | + type foo struct { |
| 118 | + Bar bytes.Buffer |
| 119 | + } |
| 120 | + v := &foo{} |
| 121 | + typ = reflect.TypeOf(v).Elem() |
| 122 | + val = reflect.ValueOf(v).Elem() |
| 123 | + assert.Error(t, setWithProperType(typ.Field(0).Type.Kind(), "5", val.Field(0))) |
| 124 | +} |
| 125 | + |
| 126 | +func TestBinderSetFields(t *testing.T) { |
| 127 | + ts := new(binderTestStruct) |
| 128 | + val := reflect.ValueOf(ts).Elem() |
| 129 | + // Int |
| 130 | + if assert.NoError(t, setIntField("5", 0, val.FieldByName("I"))) { |
| 131 | + assert.Equal(t, 5, ts.I) |
| 132 | + } |
| 133 | + if assert.NoError(t, setIntField("", 0, val.FieldByName("I"))) { |
| 134 | + assert.Equal(t, 0, ts.I) |
| 135 | + } |
| 136 | + |
| 137 | + // Uint |
| 138 | + if assert.NoError(t, setUintField("10", 0, val.FieldByName("UI"))) { |
| 139 | + assert.Equal(t, uint(10), ts.UI) |
| 140 | + } |
| 141 | + if assert.NoError(t, setUintField("", 0, val.FieldByName("UI"))) { |
| 142 | + assert.Equal(t, uint(0), ts.UI) |
| 143 | + } |
| 144 | + |
| 145 | + // Float |
| 146 | + if assert.NoError(t, setFloatField("15.5", 0, val.FieldByName("F32"))) { |
| 147 | + assert.Equal(t, float32(15.5), ts.F32) |
| 148 | + } |
| 149 | + if assert.NoError(t, setFloatField("", 0, val.FieldByName("F32"))) { |
| 150 | + assert.Equal(t, float32(0.0), ts.F32) |
| 151 | + } |
| 152 | + |
| 153 | + // Bool |
| 154 | + if assert.NoError(t, setBoolField("true", val.FieldByName("B"))) { |
| 155 | + assert.Equal(t, true, ts.B) |
| 156 | + } |
| 157 | + if assert.NoError(t, setBoolField("", val.FieldByName("B"))) { |
| 158 | + assert.Equal(t, false, ts.B) |
| 159 | + } |
| 160 | +} |
| 161 | + |
| 162 | +func assertBinderTestStruct(t *testing.T, ts *binderTestStruct) { |
| 163 | + assert.Equal(t, 0, ts.I) |
| 164 | + assert.Equal(t, int8(8), ts.I8) |
| 165 | + assert.Equal(t, int16(16), ts.I16) |
| 166 | + assert.Equal(t, int32(32), ts.I32) |
| 167 | + assert.Equal(t, int64(64), ts.I64) |
| 168 | + assert.Equal(t, uint(0), ts.UI) |
| 169 | + assert.Equal(t, uint8(8), ts.UI8) |
| 170 | + assert.Equal(t, uint16(16), ts.UI16) |
| 171 | + assert.Equal(t, uint32(32), ts.UI32) |
| 172 | + assert.Equal(t, uint64(64), ts.UI64) |
| 173 | + assert.Equal(t, true, ts.B) |
| 174 | + assert.Equal(t, float32(32.5), ts.F32) |
| 175 | + assert.Equal(t, float64(64.5), ts.F64) |
| 176 | + assert.Equal(t, "test", ts.S) |
| 177 | + assert.Equal(t, "", ts.GetCantSet()) |
| 178 | +} |
| 179 | + |
| 180 | +func testBinderOkay(t *testing.T, r io.Reader, ctype string) { |
| 181 | + e := New() |
| 182 | + req := test.NewRequest(POST, "/", r) |
| 183 | + rec := test.NewResponseRecorder() |
| 184 | + c := e.NewContext(req, rec) |
| 185 | + req.Header().Set(HeaderContentType, ctype) |
| 186 | + u := new(user) |
| 187 | + err := c.Bind(u) |
| 188 | + if assert.NoError(t, err) { |
| 189 | + assert.Equal(t, 1, u.ID) |
| 190 | + assert.Equal(t, "Jon Snow", u.Name) |
| 191 | + } |
| 192 | +} |
| 193 | + |
| 194 | +func testBinderError(t *testing.T, r io.Reader, ctype string) { |
| 195 | + e := New() |
| 196 | + req := test.NewRequest(POST, "/", r) |
| 197 | + rec := test.NewResponseRecorder() |
| 198 | + c := e.NewContext(req, rec) |
| 199 | + req.Header().Set(HeaderContentType, ctype) |
| 200 | + u := new(user) |
| 201 | + err := c.Bind(u) |
| 202 | + |
| 203 | + switch { |
| 204 | + case strings.HasPrefix(ctype, MIMEApplicationJSON), strings.HasPrefix(ctype, MIMEApplicationXML), |
| 205 | + strings.HasPrefix(ctype, MIMEApplicationForm), strings.HasPrefix(ctype, MIMEMultipartForm): |
| 206 | + if assert.IsType(t, new(HTTPError), err) { |
| 207 | + assert.Equal(t, http.StatusBadRequest, err.(*HTTPError).Code) |
| 208 | + } |
| 209 | + default: |
| 210 | + if assert.IsType(t, new(HTTPError), err) { |
| 211 | + assert.Equal(t, ErrUnsupportedMediaType, err) |
| 212 | + } |
| 213 | + } |
| 214 | +} |
0 commit comments