iris/hero/func_result_test.go

285 lines
9.1 KiB
Go
Raw Normal View History

package hero_test
import (
"errors"
"fmt"
"net/http"
"testing"
"github.com/kataras/iris/v12"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/v12/httptest"
. "github.com/kataras/iris/v12/hero"
)
func GetText() string {
return "text"
}
func GetStatus() int {
return iris.StatusBadGateway
}
func GetTextWithStatusOk() (string, int) {
return "OK", iris.StatusOK
}
// tests should have output arguments mixed
func GetStatusWithTextNotOkBy(first string, second string) (int, string) {
return iris.StatusForbidden, "NOT_OK_" + first + second
}
func GetTextAndContentType() (string, string) {
return "<b>text</b>", "text/html"
}
type testCustomResult struct {
HTML string
}
// The only one required function to make that a custom Response dispatcher.
func (r testCustomResult) Dispatch(ctx iris.Context) {
_, _ = ctx.HTML(r.HTML)
}
func GetCustomResponse() testCustomResult {
return testCustomResult{"<b>text</b>"}
}
func GetCustomResponseWithStatusOk() (testCustomResult, int) {
return testCustomResult{"<b>OK</b>"}, iris.StatusOK
}
func GetCustomResponseWithStatusNotOk() (testCustomResult, int) {
return testCustomResult{"<b>internal server error</b>"}, iris.StatusInternalServerError
}
type testCustomStruct struct {
Name string `json:"name" xml:"name"`
Age int `json:"age" xml:"age"`
}
func GetCustomStruct() testCustomStruct {
return testCustomStruct{"Iris", 2}
}
func GetCustomStructWithStatusNotOk() (testCustomStruct, int) {
return testCustomStruct{"Iris", 2}, iris.StatusInternalServerError
}
func GetCustomStructWithContentType() (testCustomStruct, string) {
return testCustomStruct{"Iris", 2}, "text/xml"
}
func GetCustomStructWithError(ctx iris.Context) (s testCustomStruct, err error) {
s = testCustomStruct{"Iris", 2}
if ctx.URLParamExists("err") {
err = errors.New("omit return of testCustomStruct and fire error")
}
// it should send the testCustomStruct as JSON if error is nil
// otherwise it should fire the default error(BadRequest) with the error's text.
return
}
type err struct {
Status int `json:"status_code"`
Message string `json:"message"`
}
func (e err) Dispatch(ctx iris.Context) {
// write the status code based on the err's StatusCode.
ctx.StatusCode(e.Status)
// send to the client the whole object as json
_ = ctx.JSON(e)
}
func GetCustomErrorAsDispatcher() err {
return err{iris.StatusBadRequest, "this is my error as json"}
}
func GetCustomTypedNilEmptyResponse() iris.Map {
return nil
}
func GetCustomTypedPtrNilEmptyResponse() *iris.Map {
return nil
}
func GetCustomMapNilEmptyResponse() map[string]interface{} {
return nil
}
func GetCustomPtrStructNilEmptyResponse() *testCustomStruct {
return nil
}
func TestFuncResult(t *testing.T) {
app := iris.New()
h := New()
// for any 'By', by is not required but we use this suffix here, like controllers
// to make it easier for the future to resolve if any bug.
// add the binding for path parameters.
app.Get("/text", h.Handler(GetText))
app.Get("/status", h.Handler(GetStatus))
app.Get("/text/with/status/ok", h.Handler(GetTextWithStatusOk))
app.Get("/status/with/text/not/ok/{first}/{second}", h.Handler(GetStatusWithTextNotOkBy))
app.Get("/text/and/content/type", h.Handler(GetTextAndContentType))
//
app.Get("/custom/response", h.Handler(GetCustomResponse))
app.Get("/custom/response/with/status/ok", h.Handler(GetCustomResponseWithStatusOk))
app.Get("/custom/response/with/status/not/ok", h.Handler(GetCustomResponseWithStatusNotOk))
//
app.Get("/custom/struct", h.Handler(GetCustomStruct))
app.Get("/custom/struct/with/status/not/ok", h.Handler(GetCustomStructWithStatusNotOk))
app.Get("/custom/struct/with/content/type", h.Handler(GetCustomStructWithContentType))
app.Get("/custom/struct/with/error", h.Handler(GetCustomStructWithError))
app.Get("/custom/error/as/dispatcher", h.Handler(GetCustomErrorAsDispatcher))
app.Get("/custom/nil/typed", h.Handler(GetCustomTypedNilEmptyResponse))
app.Get("/custom/nil/typed/ptr", h.Handler(GetCustomTypedPtrNilEmptyResponse))
app.Get("/custom/nil/map", h.Handler(GetCustomMapNilEmptyResponse))
app.Get("/custom/nil/struct", h.Handler(GetCustomPtrStructNilEmptyResponse))
e := httptest.New(t, app)
e.GET("/text").Expect().Status(iris.StatusOK).
Body().Equal("text")
e.GET("/status").Expect().Status(iris.StatusBadGateway)
e.GET("/text/with/status/ok").Expect().Status(iris.StatusOK).
Body().Equal("OK")
e.GET("/status/with/text/not/ok/first/second").Expect().Status(iris.StatusForbidden).
Body().Equal("NOT_OK_firstsecond")
// Author's note: <-- if that fails means that the last binder called for both input args,
// see path_param_binder.go
e.GET("/text/and/content/type").Expect().Status(iris.StatusOK).
ContentType("text/html", "utf-8").
Body().Equal("<b>text</b>")
e.GET("/custom/response").Expect().Status(iris.StatusOK).
ContentType("text/html", "utf-8").
Body().Equal("<b>text</b>")
e.GET("/custom/response/with/status/ok").Expect().Status(iris.StatusOK).
ContentType("text/html", "utf-8").
Body().Equal("<b>OK</b>")
e.GET("/custom/response/with/status/not/ok").Expect().Status(iris.StatusInternalServerError).
ContentType("text/html", "utf-8").
Body().Equal("<b>internal server error</b>")
expectedResultFromCustomStruct := map[string]interface{}{
"name": "Iris",
"age": 2,
}
e.GET("/custom/struct").Expect().Status(iris.StatusOK).
JSON().Equal(expectedResultFromCustomStruct)
e.GET("/custom/struct/with/status/not/ok").Expect().Status(iris.StatusInternalServerError).
JSON().Equal(expectedResultFromCustomStruct)
e.GET("/custom/struct/with/content/type").Expect().Status(iris.StatusOK).
ContentType("text/xml", "utf-8")
e.GET("/custom/struct/with/error").Expect().Status(iris.StatusOK).
JSON().Equal(expectedResultFromCustomStruct)
e.GET("/custom/struct/with/error").WithQuery("err", true).Expect().
Status(iris.StatusBadRequest). // the default status code if error is not nil
// the content should be not JSON it should be the status code's text
// it will fire the error's text
Body().Equal("omit return of testCustomStruct and fire error")
e.GET("/custom/error/as/dispatcher").Expect().
Status(iris.StatusBadRequest). // the default status code if error is not nil
// the content should be not JSON it should be the status code's text
// it will fire the error's text
JSON().Equal(err{iris.StatusBadRequest, "this is my error as json"})
// its result is nil should give an empty response but content-type is set correctly.
e.GET("/custom/nil/typed").Expect().
Status(iris.StatusOK).ContentType(context.ContentJSONHeaderValue).Body().Empty()
e.GET("/custom/nil/typed/ptr").Expect().
Status(iris.StatusOK).ContentType(context.ContentJSONHeaderValue).Body().Empty()
e.GET("/custom/nil/map").Expect().
Status(iris.StatusOK).ContentType(context.ContentJSONHeaderValue).Body().Empty()
e.GET("/custom/nil/struct").Expect().
Status(iris.StatusOK).ContentType(context.ContentJSONHeaderValue).Body().Empty()
}
type (
testPreflightRequest struct {
FailCode int `json:"fail_code"` // for the sake of the test.
}
testPreflightResponse struct {
Code int
Message string
}
)
func (r testPreflightResponse) Preflight(ctx iris.Context) error {
if r.Code == httptest.StatusInternalServerError {
return fmt.Errorf("custom error")
}
2020-08-18 22:14:11 +02:00
if r.Code > 0 {
ctx.StatusCode(r.Code)
}
return nil
}
func TestPreflightResult(t *testing.T) {
app := iris.New()
c := New()
handler := c.Handler(func(in testPreflightRequest) testPreflightResponse {
return testPreflightResponse{Code: in.FailCode, Message: http.StatusText(in.FailCode)}
})
app.Post("/", handler)
handler2 := c.Handler(func(in testInput) (int, testOutput) {
return httptest.StatusAccepted, testOutput{Name: in.Name}
})
app.Post("/alternative", handler2)
e := httptest.New(t, app)
expected1 := testPreflightResponse{Code: httptest.StatusOK, Message: "OK"}
e.POST("/").WithJSON(testPreflightRequest{FailCode: expected1.Code}).
Expect().Status(httptest.StatusOK).JSON().Equal(expected1)
expected2 := testPreflightResponse{Code: httptest.StatusBadRequest, Message: "Bad Request"}
e.POST("/").WithJSON(testPreflightRequest{FailCode: expected2.Code}).
Expect().Status(httptest.StatusBadRequest).JSON().Equal(expected2)
// Test error returned from Preflight.
e.POST("/").WithJSON(testPreflightRequest{FailCode: httptest.StatusInternalServerError}).
Expect().Status(httptest.StatusBadRequest).Body().Equal("custom error")
// Can be done without Preflight as the second output argument can be a status code.
expected4 := testOutput{Name: "my_name"}
e.POST("/alternative").WithJSON(testInput{expected4.Name}).
Expect().Status(httptest.StatusAccepted).JSON().Equal(expected4)
}
func TestResponseErr(t *testing.T) {
app := iris.New()
var expectedErr = errors.New("response error")
app.OnAnyErrorCode(func(ctx iris.Context) {
err := ctx.GetErr()
if err != expectedErr {
t.Fatalf("expected error value does not match")
}
ctx.WriteString(err.Error())
})
app.ConfigureContainer().Get("/", func() Response {
return Response{Code: iris.StatusBadGateway, Err: expectedErr}
})
e := httptest.New(t, app)
e.GET("/").Expect().Status(iris.StatusBadGateway).Body().Equal("response error")
}