Skip to content

Commit

Permalink
- More unit tests
Browse files Browse the repository at this point in the history
- Improves HTML debug render
- InputHolder removed
- More debug logs
  • Loading branch information
manucorporat committed May 5, 2015
1 parent 0a192fb commit f414648
Show file tree
Hide file tree
Showing 13 changed files with 370 additions and 297 deletions.
3 changes: 1 addition & 2 deletions AUTHORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ List of all the awesome people working to make Gin the best Web Framework in Go.

##gin 0.x series authors

**Original Developer:** Manu Martinez-Almeida (@manucorporat)
**Long-term Maintainer:** Javier Provecho (@javierprovecho)
**Maintainer:** Manu Martinez-Almeida (@manucorporat), Javier Provecho (@javierprovecho)

People and companies, who have contributed, in alphabetical order.

Expand Down
13 changes: 5 additions & 8 deletions binding/binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,22 @@ type Binding interface {
var _validator = validator.NewValidator("binding", validator.BakedInValidators)

var (
JSON = jsonBinding{}
XML = xmlBinding{}
GETForm = getFormBinding{}
POSTForm = postFormBinding{}
JSON = jsonBinding{}
XML = xmlBinding{}
Form = formBinding{}
)

func Default(method, contentType string) Binding {
if method == "GET" {
return GETForm
return Form
} else {
switch contentType {
case MIMEPOSTForm:
return POSTForm
case MIMEJSON:
return JSON
case MIMEXML, MIMEXML2:
return XML
default:
return GETForm
return Form
}
}
}
Expand Down
51 changes: 34 additions & 17 deletions binding/binding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,63 +17,80 @@ type FooStruct struct {
}

func TestBindingDefault(t *testing.T) {
assert.Equal(t, Default("GET", ""), GETForm)
assert.Equal(t, Default("GET", MIMEJSON), GETForm)
assert.Equal(t, Default("GET", ""), Form)
assert.Equal(t, Default("GET", MIMEJSON), Form)

assert.Equal(t, Default("POST", MIMEJSON), JSON)
assert.Equal(t, Default("PUT", MIMEJSON), JSON)

assert.Equal(t, Default("POST", MIMEXML), XML)
assert.Equal(t, Default("PUT", MIMEXML2), XML)

assert.Equal(t, Default("POST", MIMEPOSTForm), POSTForm)
assert.Equal(t, Default("DELETE", MIMEPOSTForm), POSTForm)
assert.Equal(t, Default("POST", MIMEPOSTForm), Form)
assert.Equal(t, Default("DELETE", MIMEPOSTForm), Form)
}

func TestBindingJSON(t *testing.T) {
testBinding(t,
testBodyBinding(t,
JSON, "json",
"/", "/",
`{"foo": "bar"}`, `{"bar": "foo"}`)
}

func TestBindingPOSTForm(t *testing.T) {
testBinding(t,
POSTForm, "post_form",
func TestBindingForm(t *testing.T) {
testFormBinding(t, "POST",
"/", "/",
"foo=bar", "bar=foo")
}

func TestBindingGETForm(t *testing.T) {
testBinding(t,
GETForm, "get_form",
func TestBindingForm2(t *testing.T) {
testFormBinding(t, "GET",
"/?foo=bar", "/?bar=foo",
"", "")
}

func TestBindingXML(t *testing.T) {
testBinding(t,
testBodyBinding(t,
XML, "xml",
"/", "/",
"<map><foo>bar</foo></map>", "<map><bar>foo</bar></map>")
}

func testBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
func testFormBinding(t *testing.T, method, path, badPath, body, badBody string) {
b := Form
assert.Equal(t, b.Name(), "query")

obj := FooStruct{}
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")

obj = FooStruct{}
req = requestWithBody(method, badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
}

func testBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
assert.Equal(t, b.Name(), name)

obj := FooStruct{}
req := requestWithBody(path, body)
req := requestWithBody("POST", path, body)
err := b.Bind(req, &obj)
assert.NoError(t, err)
assert.Equal(t, obj.Foo, "bar")

obj = FooStruct{}
req = requestWithBody(badPath, badBody)
req = requestWithBody("POST", badPath, badBody)
err = JSON.Bind(req, &obj)
assert.Error(t, err)
}

func requestWithBody(path, body string) (req *http.Request) {
req, _ = http.NewRequest("POST", path, bytes.NewBufferString(body))
func requestWithBody(method, path, body string) (req *http.Request) {
req, _ = http.NewRequest(method, path, bytes.NewBufferString(body))
return
}
8 changes: 4 additions & 4 deletions binding/get_form.go → binding/form.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ package binding

import "net/http"

type getFormBinding struct{}
type formBinding struct{}

func (_ getFormBinding) Name() string {
return "get_form"
func (_ formBinding) Name() string {
return "query"
}

func (_ getFormBinding) Bind(req *http.Request, obj interface{}) error {
func (_ formBinding) Bind(req *http.Request, obj interface{}) error {
if err := req.ParseForm(); err != nil {
return err
}
Expand Down
23 changes: 0 additions & 23 deletions binding/post_form.go

This file was deleted.

106 changes: 104 additions & 2 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

"github.com/gin-gonic/gin/binding"
"github.com/gin-gonic/gin/render"
"golang.org/x/net/context"
)

const (
Expand All @@ -27,15 +28,37 @@ const (

const AbortIndex = math.MaxInt8 / 2

// Param is a single URL parameter, consisting of a key and a value.
type Param struct {
Key string
Value string
}

// Params is a Param-slice, as returned by the router.
// The slice is ordered, the first URL parameter is also the first slice value.
// It is therefore safe to read values by the index.
type Params []Param

// ByName returns the value of the first Param which key matches the given name.
// If no matching Param is found, an empty string is returned.
func (ps Params) ByName(name string) string {
for _, entry := range ps {
if entry.Key == name {
return entry.Value
}
}
return ""
}

// Context is the most important part of gin. It allows us to pass variables between middleware,
// manage the flow, validate the JSON of a request and render a JSON response for example.
type Context struct {
context.Context
writermem responseWriter
Request *http.Request
Writer ResponseWriter

Params Params
Input inputHolder
handlers []HandlerFunc
index int8

Expand Down Expand Up @@ -63,7 +86,6 @@ func (c *Context) Copy() *Context {
var cp Context = *c
cp.writermem.ResponseWriter = nil
cp.Writer = &cp.writermem
cp.Input.context = &cp
cp.index = AbortIndex
cp.handlers = nil
return &cp
Expand Down Expand Up @@ -138,6 +160,75 @@ func (c *Context) LastError() error {
return nil
}

/************************************/
/************ INPUT DATA ************/
/************************************/

/** Shortcut for c.Request.FormValue(key) */
func (c *Context) FormValue(key string) (va string) {
va, _ = c.formValue(key)
return
}

/** Shortcut for c.Request.PostFormValue(key) */
func (c *Context) PostFormValue(key string) (va string) {
va, _ = c.postFormValue(key)
return
}

/** Shortcut for c.Params.ByName(key) */
func (c *Context) ParamValue(key string) (va string) {
va, _ = c.paramValue(key)
return
}

func (c *Context) DefaultPostFormValue(key, defaultValue string) string {
if va, ok := c.postFormValue(key); ok {
return va
} else {
return defaultValue
}
}

func (c *Context) DefaultFormValue(key, defaultValue string) string {
if va, ok := c.formValue(key); ok {
return va
} else {
return defaultValue
}
}

func (c *Context) DefaultParamValue(key, defaultValue string) string {
if va, ok := c.paramValue(key); ok {
return va
} else {
return defaultValue
}
}

func (c *Context) paramValue(key string) (string, bool) {
va := c.Params.ByName(key)
return va, len(va) > 0
}

func (c *Context) formValue(key string) (string, bool) {
req := c.Request
req.ParseForm()
if values, ok := req.Form[key]; ok && len(values) > 0 {
return values[0], true
}
return "", false
}

func (c *Context) postFormValue(key string) (string, bool) {
req := c.Request
req.ParseForm()
if values, ok := req.PostForm[key]; ok && len(values) > 0 {
return values[0], true
}
return "", false
}

/************************************/
/******** METADATA MANAGEMENT********/
/************************************/
Expand Down Expand Up @@ -168,6 +259,17 @@ func (c *Context) MustGet(key string) interface{} {
}
}

func (c *Context) Value(key interface{}) interface{} {
if key == 0 {
return c.Request
}
if keyAsString, ok := key.(string); ok {
val, _ := c.Get(keyAsString)
return val
}
return c.Context.Value(key)
}

/************************************/
/********* PARSING REQUEST **********/
/************************************/
Expand Down
47 changes: 45 additions & 2 deletions context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,58 @@ func TestContextCopy(t *testing.T) {

cp := c.Copy()
assert.Nil(t, cp.handlers)
assert.Nil(t, cp.writermem.ResponseWriter)
assert.Equal(t, &cp.writermem, cp.Writer.(*responseWriter))
assert.Equal(t, cp.Request, c.Request)
assert.Equal(t, cp.index, AbortIndex)
assert.Equal(t, &cp.writermem, cp.Writer.(*responseWriter))
assert.Equal(t, cp.Input.context, cp)
assert.Equal(t, cp.Keys, c.Keys)
assert.Equal(t, cp.Engine, c.Engine)
assert.Equal(t, cp.Params, c.Params)
}

func TestContextFormParse(t *testing.T) {
c, _, _ := createTestContext()
c.Request, _ = http.NewRequest("GET", "http://example.com/?foo=bar&page=10", nil)

assert.Equal(t, c.DefaultFormValue("foo", "none"), "bar")
assert.Equal(t, c.FormValue("foo"), "bar")
assert.Empty(t, c.PostFormValue("foo"))

assert.Equal(t, c.DefaultFormValue("page", "0"), "10")
assert.Equal(t, c.FormValue("page"), "10")
assert.Empty(t, c.PostFormValue("page"))

assert.Equal(t, c.DefaultFormValue("NoKey", "nada"), "nada")
assert.Empty(t, c.FormValue("NoKey"))
assert.Empty(t, c.PostFormValue("NoKey"))

}

func TestContextPostFormParse(t *testing.T) {
c, _, _ := createTestContext()
body := bytes.NewBufferString("foo=bar&page=11&both=POST")
c.Request, _ = http.NewRequest("POST", "http://example.com/?both=GET&id=main", body)
c.Request.Header.Add("Content-Type", MIMEPOSTForm)

assert.Equal(t, c.DefaultPostFormValue("foo", "none"), "bar")
assert.Equal(t, c.PostFormValue("foo"), "bar")
assert.Equal(t, c.FormValue("foo"), "bar")

assert.Equal(t, c.DefaultPostFormValue("page", "0"), "11")
assert.Equal(t, c.PostFormValue("page"), "11")
assert.Equal(t, c.FormValue("page"), "11")

assert.Equal(t, c.PostFormValue("both"), "POST")
assert.Equal(t, c.FormValue("both"), "POST")

assert.Equal(t, c.FormValue("id"), "main")
assert.Empty(t, c.PostFormValue("id"))

assert.Equal(t, c.DefaultPostFormValue("NoKey", "nada"), "nada")
assert.Empty(t, c.PostFormValue("NoKey"))
assert.Empty(t, c.FormValue("NoKey"))
}

// Tests that the response is serialized as JSON
// and Content-Type is set to application/json
func TestContextRenderJSON(t *testing.T) {
Expand Down
Loading

0 comments on commit f414648

Please sign in to comment.