123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- package binding
- import (
- "bytes"
- "mime/multipart"
- "net/http"
- "testing"
- "github.com/stretchr/testify/assert"
- )
- type FooStruct struct {
- Foo string `msgpack:"foo" json:"foo" form:"foo" xml:"foo" validate:"required"`
- }
- type FooBarStruct struct {
- FooStruct
- Bar string `msgpack:"bar" json:"bar" form:"bar" xml:"bar" validate:"required"`
- Slice []string `form:"slice" validate:"max=10"`
- }
- type ComplexDefaultStruct struct {
- Int int `form:"int" default:"999"`
- String string `form:"string" default:"default-string"`
- Bool bool `form:"bool" default:"false"`
- Int64Slice []int64 `form:"int64_slice,split" default:"1,2,3,4"`
- Int8Slice []int8 `form:"int8_slice,split" default:"1,2,3,4"`
- }
- type Int8SliceStruct struct {
- State []int8 `form:"state,split"`
- }
- type Int64SliceStruct struct {
- State []int64 `form:"state,split"`
- }
- type StringSliceStruct struct {
- State []string `form:"state,split"`
- }
- func TestBindingDefault(t *testing.T) {
- assert.Equal(t, Default("GET", ""), Form)
- assert.Equal(t, Default("GET", MIMEJSON), Form)
- assert.Equal(t, Default("GET", MIMEJSON+"; charset=utf-8"), Form)
- assert.Equal(t, Default("POST", MIMEJSON), JSON)
- assert.Equal(t, Default("PUT", MIMEJSON), JSON)
- assert.Equal(t, Default("POST", MIMEJSON+"; charset=utf-8"), JSON)
- assert.Equal(t, Default("PUT", MIMEJSON+"; charset=utf-8"), JSON)
- assert.Equal(t, Default("POST", MIMEXML), XML)
- assert.Equal(t, Default("PUT", MIMEXML2), XML)
- assert.Equal(t, Default("POST", MIMEPOSTForm), Form)
- assert.Equal(t, Default("PUT", MIMEPOSTForm), Form)
- assert.Equal(t, Default("POST", MIMEPOSTForm+"; charset=utf-8"), Form)
- assert.Equal(t, Default("PUT", MIMEPOSTForm+"; charset=utf-8"), Form)
- assert.Equal(t, Default("POST", MIMEMultipartPOSTForm), Form)
- assert.Equal(t, Default("PUT", MIMEMultipartPOSTForm), Form)
- }
- func TestStripContentType(t *testing.T) {
- c1 := "application/vnd.mozilla.xul+xml"
- c2 := "application/vnd.mozilla.xul+xml; charset=utf-8"
- assert.Equal(t, stripContentTypeParam(c1), c1)
- assert.Equal(t, stripContentTypeParam(c2), "application/vnd.mozilla.xul+xml")
- }
- func TestBindInt8Form(t *testing.T) {
- params := "state=1,2,3"
- req, _ := http.NewRequest("GET", "http://api.bilibili.com/test?"+params, nil)
- q := new(Int8SliceStruct)
- Form.Bind(req, q)
- assert.EqualValues(t, []int8{1, 2, 3}, q.State)
- params = "state=1,2,3,256"
- req, _ = http.NewRequest("GET", "http://api.bilibili.com/test?"+params, nil)
- q = new(Int8SliceStruct)
- assert.Error(t, Form.Bind(req, q))
- params = "state="
- req, _ = http.NewRequest("GET", "http://api.bilibili.com/test?"+params, nil)
- q = new(Int8SliceStruct)
- assert.NoError(t, Form.Bind(req, q))
- assert.Len(t, q.State, 0)
- params = "state=1,,2"
- req, _ = http.NewRequest("GET", "http://api.bilibili.com/test?"+params, nil)
- q = new(Int8SliceStruct)
- assert.NoError(t, Form.Bind(req, q))
- assert.EqualValues(t, []int8{1, 2}, q.State)
- }
- func TestBindInt64Form(t *testing.T) {
- params := "state=1,2,3"
- req, _ := http.NewRequest("GET", "http://api.bilibili.com/test?"+params, nil)
- q := new(Int64SliceStruct)
- Form.Bind(req, q)
- assert.EqualValues(t, []int64{1, 2, 3}, q.State)
- params = "state="
- req, _ = http.NewRequest("GET", "http://api.bilibili.com/test?"+params, nil)
- q = new(Int64SliceStruct)
- assert.NoError(t, Form.Bind(req, q))
- assert.Len(t, q.State, 0)
- }
- func TestBindStringForm(t *testing.T) {
- params := "state=1,2,3"
- req, _ := http.NewRequest("GET", "http://api.bilibili.com/test?"+params, nil)
- q := new(StringSliceStruct)
- Form.Bind(req, q)
- assert.EqualValues(t, []string{"1", "2", "3"}, q.State)
- params = "state="
- req, _ = http.NewRequest("GET", "http://api.bilibili.com/test?"+params, nil)
- q = new(StringSliceStruct)
- assert.NoError(t, Form.Bind(req, q))
- assert.Len(t, q.State, 0)
- params = "state=p,,p"
- req, _ = http.NewRequest("GET", "http://api.bilibili.com/test?"+params, nil)
- q = new(StringSliceStruct)
- Form.Bind(req, q)
- assert.EqualValues(t, []string{"p", "p"}, q.State)
- }
- func TestBindingJSON(t *testing.T) {
- testBodyBinding(t,
- JSON, "json",
- "/", "/",
- `{"foo": "bar"}`, `{"bar": "foo"}`)
- }
- func TestBindingForm(t *testing.T) {
- testFormBinding(t, "POST",
- "/", "/",
- "foo=bar&bar=foo&slice=a&slice=b", "bar2=foo")
- }
- func TestBindingForm2(t *testing.T) {
- testFormBinding(t, "GET",
- "/?foo=bar&bar=foo", "/?bar2=foo",
- "", "")
- }
- func TestBindingQuery(t *testing.T) {
- testQueryBinding(t, "POST",
- "/?foo=bar&bar=foo", "/",
- "foo=unused", "bar2=foo")
- }
- func TestBindingQuery2(t *testing.T) {
- testQueryBinding(t, "GET",
- "/?foo=bar&bar=foo", "/?bar2=foo",
- "foo=unused", "")
- }
- func TestBindingXML(t *testing.T) {
- testBodyBinding(t,
- XML, "xml",
- "/", "/",
- "<map><foo>bar</foo></map>", "<map><bar>foo</bar></map>")
- }
- func createFormPostRequest() *http.Request {
- req, _ := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", bytes.NewBufferString("foo=bar&bar=foo"))
- req.Header.Set("Content-Type", MIMEPOSTForm)
- return req
- }
- func createFormMultipartRequest() *http.Request {
- boundary := "--testboundary"
- body := new(bytes.Buffer)
- mw := multipart.NewWriter(body)
- defer mw.Close()
- mw.SetBoundary(boundary)
- mw.WriteField("foo", "bar")
- mw.WriteField("bar", "foo")
- req, _ := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
- req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
- return req
- }
- func TestBindingFormPost(t *testing.T) {
- req := createFormPostRequest()
- var obj FooBarStruct
- FormPost.Bind(req, &obj)
- assert.Equal(t, obj.Foo, "bar")
- assert.Equal(t, obj.Bar, "foo")
- }
- func TestBindingFormMultipart(t *testing.T) {
- req := createFormMultipartRequest()
- var obj FooBarStruct
- FormMultipart.Bind(req, &obj)
- assert.Equal(t, obj.Foo, "bar")
- assert.Equal(t, obj.Bar, "foo")
- }
- func TestValidationFails(t *testing.T) {
- var obj FooStruct
- req := requestWithBody("POST", "/", `{"bar": "foo"}`)
- err := JSON.Bind(req, &obj)
- assert.Error(t, err)
- }
- func TestValidationDisabled(t *testing.T) {
- backup := Validator
- Validator = nil
- defer func() { Validator = backup }()
- var obj FooStruct
- req := requestWithBody("POST", "/", `{"bar": "foo"}`)
- err := JSON.Bind(req, &obj)
- assert.NoError(t, err)
- }
- func TestExistsSucceeds(t *testing.T) {
- type HogeStruct struct {
- Hoge *int `json:"hoge" binding:"exists"`
- }
- var obj HogeStruct
- req := requestWithBody("POST", "/", `{"hoge": 0}`)
- err := JSON.Bind(req, &obj)
- assert.NoError(t, err)
- }
- func TestFormDefaultValue(t *testing.T) {
- params := "int=333&string=hello&bool=true&int64_slice=5,6,7,8&int8_slice=5,6,7,8"
- req, _ := http.NewRequest("GET", "http://api.bilibili.com/test?"+params, nil)
- q := new(ComplexDefaultStruct)
- assert.NoError(t, Form.Bind(req, q))
- assert.Equal(t, 333, q.Int)
- assert.Equal(t, "hello", q.String)
- assert.Equal(t, true, q.Bool)
- assert.EqualValues(t, []int64{5, 6, 7, 8}, q.Int64Slice)
- assert.EqualValues(t, []int8{5, 6, 7, 8}, q.Int8Slice)
- params = "string=hello&bool=false"
- req, _ = http.NewRequest("GET", "http://api.bilibili.com/test?"+params, nil)
- q = new(ComplexDefaultStruct)
- assert.NoError(t, Form.Bind(req, q))
- assert.Equal(t, 999, q.Int)
- assert.Equal(t, "hello", q.String)
- assert.Equal(t, false, q.Bool)
- assert.EqualValues(t, []int64{1, 2, 3, 4}, q.Int64Slice)
- assert.EqualValues(t, []int8{1, 2, 3, 4}, q.Int8Slice)
- params = "strings=hello"
- req, _ = http.NewRequest("GET", "http://api.bilibili.com/test?"+params, nil)
- q = new(ComplexDefaultStruct)
- assert.NoError(t, Form.Bind(req, q))
- assert.Equal(t, 999, q.Int)
- assert.Equal(t, "default-string", q.String)
- assert.Equal(t, false, q.Bool)
- assert.EqualValues(t, []int64{1, 2, 3, 4}, q.Int64Slice)
- assert.EqualValues(t, []int8{1, 2, 3, 4}, q.Int8Slice)
- params = "int=&string=&bool=true&int64_slice=&int8_slice="
- req, _ = http.NewRequest("GET", "http://api.bilibili.com/test?"+params, nil)
- q = new(ComplexDefaultStruct)
- assert.NoError(t, Form.Bind(req, q))
- assert.Equal(t, 999, q.Int)
- assert.Equal(t, "default-string", q.String)
- assert.Equal(t, true, q.Bool)
- assert.EqualValues(t, []int64{1, 2, 3, 4}, q.Int64Slice)
- assert.EqualValues(t, []int8{1, 2, 3, 4}, q.Int8Slice)
- }
- func testFormBinding(t *testing.T, method, path, badPath, body, badBody string) {
- b := Form
- assert.Equal(t, b.Name(), "form")
- obj := FooBarStruct{}
- req := requestWithBody(method, path, body)
- if method == "POST" {
- req.Header.Add("Content-Type", MIMEPOSTForm)
- }
- err := b.Bind(req, &obj)
- assert.NoError(t, err)
- assert.Equal(t, obj.Foo, "bar")
- assert.Equal(t, obj.Bar, "foo")
- obj = FooBarStruct{}
- req = requestWithBody(method, badPath, badBody)
- err = JSON.Bind(req, &obj)
- assert.Error(t, err)
- }
- func testQueryBinding(t *testing.T, method, path, badPath, body, badBody string) {
- b := Query
- assert.Equal(t, b.Name(), "query")
- obj := FooBarStruct{}
- req := requestWithBody(method, path, body)
- if method == "POST" {
- req.Header.Add("Content-Type", MIMEPOSTForm)
- }
- err := b.Bind(req, &obj)
- assert.NoError(t, err)
- assert.Equal(t, obj.Foo, "bar")
- assert.Equal(t, obj.Bar, "foo")
- }
- func testBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
- assert.Equal(t, b.Name(), name)
- obj := FooStruct{}
- req := requestWithBody("POST", path, body)
- err := b.Bind(req, &obj)
- assert.NoError(t, err)
- assert.Equal(t, obj.Foo, "bar")
- obj = FooStruct{}
- req = requestWithBody("POST", badPath, badBody)
- err = JSON.Bind(req, &obj)
- assert.Error(t, err)
- }
- func requestWithBody(method, path, body string) (req *http.Request) {
- req, _ = http.NewRequest(method, path, bytes.NewBufferString(body))
- return
- }
- func BenchmarkBindingForm(b *testing.B) {
- req := requestWithBody("POST", "/", "foo=bar&bar=foo&slice=a&slice=b&slice=c&slice=w")
- req.Header.Add("Content-Type", MIMEPOSTForm)
- f := Form
- for i := 0; i < b.N; i++ {
- obj := FooBarStruct{}
- f.Bind(req, &obj)
- }
- }
|