From 6fca78d12a79a687df208e7bf78e981075564205 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Tue, 21 Feb 2017 13:26:30 +0200 Subject: [PATCH] Add tests for context binders, render policy and readform Former-commit-id: 66d7c86e8c0ec1cb9fcc2d77b40aae5335ff5961 --- context.go | 3 +- context_test.go | 173 +++++++++++++++++++++++++++++++++++++++++- policy_render_test.go | 87 +++++++++++++++++++++ 3 files changed, 260 insertions(+), 3 deletions(-) create mode 100644 policy_render_test.go diff --git a/context.go b/context.go index 07b1ca43..ffad1caf 100644 --- a/context.go +++ b/context.go @@ -899,7 +899,6 @@ func (ctx *Context) fastRenderWithStatus(status int, cType string, data []byte) // RenderWithStatus builds up the response from the specified template or a serialize engine. // Note: the options: "gzip" and "charset" are built'n support by Iris, so you can pass these on any template engine or serialize engines func (ctx *Context) RenderWithStatus(status int, name string, binding interface{}, options ...map[string]interface{}) (err error) { - if _, shouldFirstStatusCode := ctx.ResponseWriter.(*responseWriter); shouldFirstStatusCode { ctx.SetStatusCode(status) } @@ -1005,7 +1004,7 @@ func (ctx *Context) Data(status int, data []byte) error { // To change their default behavior users should use // the context.RenderWithStatus(statusCode, contentType, content, options...) instead. func (ctx *Context) Text(status int, text string) error { - return ctx.fastRenderWithStatus(status, contentBinary, []byte(text)) + return ctx.fastRenderWithStatus(status, contentText, []byte(text)) } // HTML writes html string with a http status diff --git a/context_test.go b/context_test.go index 2264ee83..3ad4b1fe 100644 --- a/context_test.go +++ b/context_test.go @@ -1,13 +1,18 @@ package iris_test import ( + "encoding/json" + "encoding/xml" + "fmt" "io/ioutil" "net/http" + "net/url" "strconv" "strings" "testing" "time" + "github.com/iris-contrib/httpexpect" "gopkg.in/kataras/iris.v6" "gopkg.in/kataras/iris.v6/adaptors/httprouter" "gopkg.in/kataras/iris.v6/httptest" @@ -240,6 +245,173 @@ func TestLimitRequestBodySizeMiddleware(t *testing.T) { } +type testBinderData struct { + Username string + Mail string + Data []string `form:"mydata" json:"mydata"` +} + +type testBinderXMLData struct { + XMLName xml.Name `xml:"info"` + FirstAttr string `xml:"first,attr"` + SecondAttr string `xml:"second,attr"` + Name string `xml:"name" json:"name"` + Birth string `xml:"birth" json:"birth"` + Stars int `xml:"stars" json:"stars"` +} + +type testBinder struct { + //pointer of testBinderDataJSON or testBinderXMLData + vp interface{} + m iris.Unmarshaler + shouldError bool +} + +func (tj *testBinder) Decode(data []byte) error { + if tj.shouldError { + return fmt.Errorf("Should error") + } + return tj.m.Unmarshal(data, tj.vp) +} + +func testUnmarshaler(app *iris.Framework, t *testing.T, tb *testBinder, + write func(ctx *iris.Context)) *httpexpect.Request { + + // a very dirty and awful way but here we must test in deep + // the custom object's decoder error with the custom + // unmarshaler result whenever the testUnmarshaler called. + if tb.shouldError == false { + tb.shouldError = true + testUnmarshaler(app, t, tb, write) + tb.shouldError = false + } + + h := func(ctx *iris.Context) { + err := ctx.UnmarshalBody(tb.vp, tb.m) + if tb.shouldError && err == nil { + t.Fatalf("Should prompted for error 'Should error' but not error returned from the custom decoder!") + } else if err != nil { + t.Fatalf("Error when parsing the body: %s", err.Error()) + } + if write != nil { + write(ctx) + } + + if app.Config.DisableBodyConsumptionOnUnmarshal { + rawData, _ := ioutil.ReadAll(ctx.Request.Body) + if len(rawData) == 0 { + t.Fatalf("Expected data to NOT BE consumed by the previous UnmarshalBody call but we got empty body.") + } + } + } + + app.Post("/bind_req_body", h) + + e := httptest.New(app, t) + return e.POST("/bind_req_body") +} + +// same as DecodeBody +// JSON, XML by DecodeBody passing the default unmarshalers +func TestContextBinders(t *testing.T) { + + passed := map[string]interface{}{"Username": "myusername", + "Mail": "mymail@iris-go.com", + "mydata": []string{"mydata1", "mydata2"}} + expectedObject := testBinderData{Username: "myusername", + Mail: "mymail@iris-go.com", + Data: []string{"mydata1", "mydata2"}} + + // JSON + vJSON := &testBinder{&testBinderData{}, + iris.UnmarshalerFunc(json.Unmarshal), false} + + // XML + expectedObj := testBinderXMLData{ + XMLName: xml.Name{Local: "info", Space: "info"}, + FirstAttr: "this is the first attr", + SecondAttr: "this is the second attr", + Name: "Iris web framework", + Birth: "13 March 2016", + Stars: 5758, + } + expectedAndPassedObjText := `<` + expectedObj.XMLName.Local + ` first="` + + expectedObj.FirstAttr + `" second="` + + expectedObj.SecondAttr + `">` + + expectedObj.Name + `` + + expectedObj.Birth + `` + + strconv.Itoa(expectedObj.Stars) + `` + + vXML := &testBinder{&testBinderXMLData{}, + iris.UnmarshalerFunc(xml.Unmarshal), false} + + app := iris.New() + app.Adapt(httprouter.New()) + + testUnmarshaler(app, + t, + vXML, + func(ctx *iris.Context) { + ctx.XML(iris.StatusOK, vXML.vp) + }). + WithText(expectedAndPassedObjText). + Expect(). + Status(iris.StatusOK). + Body().Equal(expectedAndPassedObjText) + + app2 := iris.New() + app2.Adapt(httprouter.New()) + testUnmarshaler(app2, + t, + vJSON, + func(ctx *iris.Context) { + ctx.JSON(iris.StatusOK, vJSON.vp) + }). + WithJSON(passed). + Expect(). + Status(iris.StatusOK). + JSON().Object().Equal(expectedObject) + + // JSON with DisableBodyConsumptionOnUnmarshal + app3 := iris.New() + app3.Adapt(httprouter.New()) + + app3.Config.DisableBodyConsumptionOnUnmarshal = true + testUnmarshaler(app3, + t, + vJSON, + func(ctx *iris.Context) { + ctx.JSON(iris.StatusOK, vJSON.vp) + }). + WithJSON(passed). + Expect(). + Status(iris.StatusOK). + JSON().Object().Equal(expectedObject) +} + +func TestContextReadForm(t *testing.T) { + app := iris.New() + app.Adapt(httprouter.New()) + + app.Post("/form", func(ctx *iris.Context) { + obj := testBinderData{} + err := ctx.ReadForm(&obj) + if err != nil { + t.Fatalf("Error when parsing the FORM: %s", err.Error()) + } + ctx.JSON(iris.StatusOK, obj) + }) + + e := httptest.New(app, t) + + passed := map[string]interface{}{"Username": "myusername", "Mail": "mymail@iris-go.com", "mydata": url.Values{"[0]": []string{"mydata1"}, + "[1]": []string{"mydata2"}}} + + expectedObject := testBinderData{Username: "myusername", Mail: "mymail@iris-go.com", Data: []string{"mydata1", "mydata2"}} + + e.POST("/form").WithForm(passed).Expect().Status(iris.StatusOK).JSON().Object().Equal(expectedObject) +} + func TestRedirectHTTP(t *testing.T) { host := "localhost:" + strconv.Itoa(getRandomNumber(1717, 9281)) @@ -341,7 +513,6 @@ func TestContextUserValues(t *testing.T) { e := httptest.New(app, t) e.GET("/test").Expect().Status(iris.StatusOK) - } func TestContextCookieSetGetRemove(t *testing.T) { diff --git a/policy_render_test.go b/policy_render_test.go new file mode 100644 index 00000000..61546973 --- /dev/null +++ b/policy_render_test.go @@ -0,0 +1,87 @@ +package iris_test + +import ( + "encoding/xml" + "strconv" + "testing" + + "gopkg.in/kataras/iris.v6" + "gopkg.in/kataras/iris.v6/httptest" +) + +type renderTestInformationType struct { + XMLName xml.Name `xml:"info"` + FirstAttr string `xml:"first,attr"` + SecondAttr string `xml:"second,attr"` + Name string `xml:"name" json:"name"` + Birth string `xml:"birth" json:"birth"` + Stars int `xml:"stars" json:"stars"` +} + +func TestContextRenderRest(t *testing.T) { + app := iris.New() + app.Adapt(newTestNativeRouter()) + + dataContents := []byte("Some binary data here.") + textContents := "Plain text here" + JSONPContents := map[string]string{"hello": "jsonp"} + JSONPCallback := "callbackName" + JSONXMLContents := renderTestInformationType{ + XMLName: xml.Name{Local: "info", Space: "info"}, // only need to verify that later + FirstAttr: "this is the first attr", + SecondAttr: "this is the second attr", + Name: "Iris web framework", + Birth: "13 March 2016", + Stars: 4064, + } + markdownContents := "# Hello dynamic markdown from Iris" + + // data is not part of the render policy but let's test it here. + app.Get("/data", func(ctx *iris.Context) { + ctx.Data(iris.StatusOK, dataContents) + }) + // text is not part of the render policy but let's test it here. + app.Get("/text", func(ctx *iris.Context) { + ctx.Text(iris.StatusOK, textContents) + }) + + app.Get("/jsonp", func(ctx *iris.Context) { + ctx.JSONP(iris.StatusOK, JSONPCallback, JSONPContents) + }) + + app.Get("/json", func(ctx *iris.Context) { + ctx.JSON(iris.StatusOK, JSONXMLContents) + }) + app.Get("/xml", func(ctx *iris.Context) { + ctx.XML(iris.StatusOK, JSONXMLContents) + }) + + app.Get("/markdown", func(ctx *iris.Context) { + ctx.Markdown(iris.StatusOK, markdownContents) + }) + + e := httptest.New(app, t) + dataT := e.GET("/data").Expect().Status(iris.StatusOK) + dataT.Header("Content-Type").Equal("application/octet-stream") + dataT.Body().Equal(string(dataContents)) + + textT := e.GET("/text").Expect().Status(iris.StatusOK) + textT.Header("Content-Type").Equal("text/plain; charset=UTF-8") + textT.Body().Equal(textContents) + + JSONPT := e.GET("/jsonp").Expect().Status(iris.StatusOK) + JSONPT.Header("Content-Type").Equal("application/javascript; charset=UTF-8") + JSONPT.Body().Equal(JSONPCallback + `({"hello":"jsonp"});`) + + JSONT := e.GET("/json").Expect().Status(iris.StatusOK) + JSONT.Header("Content-Type").Equal("application/json; charset=UTF-8") + JSONT.JSON().Object().Equal(JSONXMLContents) + + XMLT := e.GET("/xml").Expect().Status(iris.StatusOK) + XMLT.Header("Content-Type").Equal("text/xml; charset=UTF-8") + XMLT.Body().Equal(`<` + JSONXMLContents.XMLName.Local + ` first="` + JSONXMLContents.FirstAttr + `" second="` + JSONXMLContents.SecondAttr + `">` + JSONXMLContents.Name + `` + JSONXMLContents.Birth + `` + strconv.Itoa(JSONXMLContents.Stars) + ``) + + markdownT := e.GET("/markdown").Expect().Status(iris.StatusOK) + markdownT.Header("Content-Type").Equal("text/html; charset=UTF-8") + markdownT.Body().Equal("

" + markdownContents[2:] + "

\n") +}