1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-25 12:55:57 +00:00

add the stale release

This commit is contained in:
Gerasimos (Makis) Maropoulos
2020-08-12 23:41:20 +03:00
parent 535fb6dc0d
commit 2a4ce876b6
793 changed files with 188 additions and 52415 deletions

View File

@@ -5,7 +5,7 @@ import (
"reflect"
"sort"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/context"
)
// binding contains the Dependency and the Input, it's the result of a function or struct + dependencies.

View File

@@ -1,548 +0,0 @@
package hero
import (
stdContext "context"
"fmt"
"net/http"
"reflect"
"testing"
"time"
"github.com/kataras/golog"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/v12/sessions"
)
var (
stdContextTyp = reflect.TypeOf((*stdContext.Context)(nil)).Elem()
sessionTyp = reflect.TypeOf((*sessions.Session)(nil))
timeTyp = reflect.TypeOf((*time.Time)(nil)).Elem()
mapStringsTyp = reflect.TypeOf(map[string][]string{})
)
func contextBinding(index int) *binding {
return &binding{
Dependency: BuiltinDependencies[0],
Input: &Input{Type: BuiltinDependencies[0].DestType, Index: index},
}
}
func TestGetBindingsForFunc(t *testing.T) {
type (
testResponse struct {
Name string `json:"name"`
}
testRequest struct {
Email string `json:"email"`
}
testRequest2 struct {
// normally a body can't have two requests but let's test it.
Age int `json:"age"`
}
)
var testRequestTyp = reflect.TypeOf(testRequest{})
var deps = []*Dependency{
NewDependency(func(ctx *context.Context) testRequest { return testRequest{Email: "should be ignored"} }),
NewDependency(42),
NewDependency(func(ctx *context.Context) (v testRequest, err error) {
err = ctx.ReadJSON(&v)
return
}),
NewDependency("if two strings requested this should be the last one"),
NewDependency("should not be ignored when requested"),
// Dependencies like these should always be registered last.
NewDependency(func(ctx *context.Context, input *Input) (newValue reflect.Value, err error) {
wasPtr := input.Type.Kind() == reflect.Ptr
newValue = reflect.New(indirectType(input.Type))
ptr := newValue.Interface()
err = ctx.ReadJSON(ptr)
if !wasPtr {
newValue = newValue.Elem()
}
return newValue, err
}),
}
var tests = []struct {
Func interface{}
Expected []*binding
}{
{ // 0
Func: func(ctx *context.Context) {
ctx.WriteString("t1")
},
Expected: []*binding{contextBinding(0)},
},
{ // 1
Func: func(ctx *context.Context) error {
return fmt.Errorf("err1")
},
Expected: []*binding{contextBinding(0)},
},
{ // 2
Func: func(ctx *context.Context) testResponse {
return testResponse{Name: "name"}
},
Expected: []*binding{contextBinding(0)},
},
{ // 3
Func: func(in testRequest) (testResponse, error) {
return testResponse{Name: "email of " + in.Email}, nil
},
Expected: []*binding{{Dependency: deps[2], Input: &Input{Index: 0, Type: testRequestTyp}}},
},
{ // 4
Func: func(in testRequest) (testResponse, error) {
return testResponse{Name: "not valid "}, fmt.Errorf("invalid")
},
Expected: []*binding{{Dependency: deps[2], Input: &Input{Index: 0, Type: testRequestTyp}}},
},
{ // 5
Func: func(ctx *context.Context, in testRequest) testResponse {
return testResponse{Name: "(with ctx) email of " + in.Email}
},
Expected: []*binding{contextBinding(0), {Dependency: deps[2], Input: &Input{Index: 1, Type: testRequestTyp}}},
},
{ // 6
Func: func(in testRequest, ctx *context.Context) testResponse { // reversed.
return testResponse{Name: "(with ctx) email of " + in.Email}
},
Expected: []*binding{{Dependency: deps[2], Input: &Input{Index: 0, Type: testRequestTyp}}, contextBinding(1)},
},
{ // 7
Func: func(in testRequest, ctx *context.Context, in2 string) testResponse { // reversed.
return testResponse{Name: "(with ctx) email of " + in.Email + "and in2: " + in2}
},
Expected: []*binding{
{
Dependency: deps[2],
Input: &Input{Index: 0, Type: testRequestTyp},
},
contextBinding(1),
{
Dependency: deps[4],
Input: &Input{Index: 2, Type: reflect.TypeOf("")},
},
},
},
{ // 8
Func: func(in testRequest, ctx *context.Context, in2, in3 string) testResponse { // reversed.
return testResponse{Name: "(with ctx) email of " + in.Email + " | in2: " + in2 + " in3: " + in3}
},
Expected: []*binding{
{
Dependency: deps[2],
Input: &Input{Index: 0, Type: testRequestTyp},
},
contextBinding(1),
{
Dependency: deps[len(deps)-3],
Input: &Input{Index: 2, Type: reflect.TypeOf("")},
},
{
Dependency: deps[len(deps)-2],
Input: &Input{Index: 3, Type: reflect.TypeOf("")},
},
},
},
{ // 9
Func: func(ctx *context.Context, in testRequest, in2 testRequest2) testResponse {
return testResponse{Name: fmt.Sprintf("(with ctx) email of %s and in2.Age %d", in.Email, in2.Age)}
},
Expected: []*binding{
contextBinding(0),
{
Dependency: deps[2],
Input: &Input{Index: 1, Type: testRequestTyp},
},
{
Dependency: deps[len(deps)-1],
Input: &Input{Index: 2, Type: reflect.TypeOf(testRequest2{})},
},
},
},
{ // 10
Func: func() testResponse {
return testResponse{Name: "empty in, one out"}
},
Expected: nil,
},
{ // 1
Func: func(userID string, age int) testResponse {
return testResponse{Name: "in from path parameters"}
},
Expected: []*binding{
paramBinding(0, 0, reflect.TypeOf("")),
paramBinding(1, 1, reflect.TypeOf(0)),
},
},
// test std context, session, time, request, response writer and headers bindings.
{ // 12
Func: func(stdContext.Context, *sessions.Session, *golog.Logger, time.Time, *http.Request, http.ResponseWriter, http.Header) testResponse {
return testResponse{"builtin deps"}
},
Expected: []*binding{
{
Dependency: NewDependency(BuiltinDependencies[1]),
Input: &Input{Index: 0, Type: stdContextTyp},
},
{
Dependency: NewDependency(BuiltinDependencies[2]),
Input: &Input{Index: 1, Type: sessionTyp},
},
{
Dependency: NewDependency(BuiltinDependencies[3]),
Input: &Input{Index: 2, Type: BuiltinDependencies[3].DestType},
},
{
Dependency: NewDependency(BuiltinDependencies[4]),
Input: &Input{Index: 3, Type: timeTyp},
},
{
Dependency: NewDependency(BuiltinDependencies[5]),
Input: &Input{Index: 4, Type: BuiltinDependencies[5].DestType},
},
{
Dependency: NewDependency(BuiltinDependencies[6]),
Input: &Input{Index: 5, Type: BuiltinDependencies[6].DestType},
},
{
Dependency: NewDependency(BuiltinDependencies[7]),
Input: &Input{Index: 6, Type: BuiltinDependencies[7].DestType},
},
},
},
// test explicitly of http.Header and its underline type map[string][]string which
// but shouldn't be binded to request headers because of the (.Explicitly()), instead
// the map should be binded to our last of "deps" which is is a dynamic functions reads from request body's JSON
// (it's a builtin dependency as well but we declared it to test user dynamic dependencies too).
{ // 13
Func: func(http.Header) testResponse {
return testResponse{"builtin http.Header dep"}
},
Expected: []*binding{
{
Dependency: NewDependency(BuiltinDependencies[7]),
Input: &Input{Index: 0, Type: BuiltinDependencies[7].DestType},
},
},
},
{ // 14
Func: func(map[string][]string) testResponse {
return testResponse{"not dep registered except the dynamic one"}
},
Expected: []*binding{
{
Dependency: deps[len(deps)-1],
Input: &Input{Index: 0, Type: mapStringsTyp},
},
},
},
{ // 15
Func: func(http.Header, map[string][]string) testResponse {
return testResponse{}
},
Expected: []*binding{ // only http.Header should be binded, we don't have map[string][]string registered.
{
Dependency: NewDependency(BuiltinDependencies[7]),
Input: &Input{Index: 0, Type: BuiltinDependencies[7].DestType},
},
{
Dependency: deps[len(deps)-1],
Input: &Input{Index: 1, Type: mapStringsTyp},
},
},
},
}
c := New()
for _, dependency := range deps {
c.Register(dependency)
}
for i, tt := range tests {
bindings := getBindingsForFunc(reflect.ValueOf(tt.Func), c.Dependencies, 0)
if expected, got := len(tt.Expected), len(bindings); expected != got {
t.Fatalf("[%d] expected bindings length to be: %d but got: %d of: %s", i, expected, got, bindings)
}
for j, b := range bindings {
if b == nil {
t.Fatalf("[%d:%d] binding is nil!", i, j)
}
if tt.Expected[j] == nil {
t.Fatalf("[%d:%d] expected dependency was not found!", i, j)
}
// if expected := tt.Expected[j]; !expected.Equal(b) {
// t.Fatalf("[%d:%d] got unexpected binding:\n%s", i, j, spew.Sdump(expected, b))
// }
if expected := tt.Expected[j]; !expected.Equal(b) {
t.Fatalf("[%d:%d] expected binding:\n%s\nbut got:\n%s", i, j, expected, b)
}
}
}
}
type (
service interface {
String() string
}
serviceImpl struct{}
)
var serviceTyp = reflect.TypeOf((*service)(nil)).Elem()
func (s *serviceImpl) String() string {
return "service"
}
func TestBindingsForStruct(t *testing.T) {
type (
controller struct {
Name string
Service service
}
embedded1 struct {
Age int
}
embedded2 struct {
Now time.Time
}
Embedded3 struct {
Age int
}
Embedded4 struct {
Now time.Time
}
controllerEmbeddingExported struct {
Embedded3
Embedded4
}
controllerEmbeddingUnexported struct {
embedded1
embedded2
}
controller2 struct {
Emb1 embedded1
Emb2 embedded2
}
controller3 struct {
Emb1 embedded1
emb2 embedded2 // unused
}
)
var deps = []*Dependency{
NewDependency("name"),
NewDependency(new(serviceImpl)),
}
var depsForAnonymousEmbedded = []*Dependency{
NewDependency(42),
NewDependency(time.Now()),
}
var depsForFieldsOfStruct = []*Dependency{
NewDependency(embedded1{Age: 42}),
NewDependency(embedded2{time.Now()}),
}
var depsInterfaces = []*Dependency{
NewDependency(func(ctx *context.Context) interface{} {
return "name"
}),
}
var autoBindings = []*binding{
payloadBinding(0, reflect.TypeOf(embedded1{})),
payloadBinding(1, reflect.TypeOf(embedded2{})),
}
for _, b := range autoBindings {
b.Input.StructFieldIndex = []int{b.Input.Index}
}
var tests = []struct {
Value interface{}
Registered []*Dependency
Expected []*binding
}{
{ // 0.
Value: &controller{},
Registered: deps,
Expected: []*binding{
{
Dependency: deps[0],
Input: &Input{Index: 0, StructFieldIndex: []int{0}, Type: reflect.TypeOf("")},
},
{
Dependency: deps[1],
Input: &Input{Index: 1, StructFieldIndex: []int{1}, Type: serviceTyp},
},
},
},
// 1. test controller with pre-defined variables.
{
Value: &controller{Name: "name_struct", Service: new(serviceImpl)},
Expected: []*binding{
{
Dependency: NewDependency("name_struct"),
Input: &Input{Index: 0, StructFieldIndex: []int{0}, Type: reflect.TypeOf("")},
},
{
Dependency: NewDependency(new(serviceImpl)),
Input: &Input{Index: 1, StructFieldIndex: []int{1}, Type: serviceTyp},
},
},
},
// 2. test controller with pre-defined variables and other deps with the exact order and value
// (deps from non zero values should be registerded only, if not the Dependency:name_struct will fail for sure).
{
Value: &controller{Name: "name_struct", Service: new(serviceImpl)},
Registered: deps,
Expected: []*binding{
{
Dependency: NewDependency("name_struct"),
Input: &Input{Index: 0, StructFieldIndex: []int{0}, Type: reflect.TypeOf("")},
},
{
Dependency: NewDependency(new(serviceImpl)),
Input: &Input{Index: 1, StructFieldIndex: []int{1}, Type: serviceTyp},
},
},
},
// 3. test embedded structs with anonymous and exported.
{
Value: &controllerEmbeddingExported{},
Registered: depsForAnonymousEmbedded,
Expected: []*binding{
{
Dependency: depsForAnonymousEmbedded[0],
Input: &Input{Index: 0, StructFieldIndex: []int{0, 0}, Type: reflect.TypeOf(0)},
},
{
Dependency: depsForAnonymousEmbedded[1],
Input: &Input{Index: 1, StructFieldIndex: []int{1, 0}, Type: reflect.TypeOf(time.Time{})},
},
},
},
// 4. test for anonymous but not exported (should still be 2, unexported structs are binded).
{
Value: &controllerEmbeddingUnexported{},
Registered: depsForAnonymousEmbedded,
Expected: []*binding{
{
Dependency: depsForAnonymousEmbedded[0],
Input: &Input{Index: 0, StructFieldIndex: []int{0, 0}, Type: reflect.TypeOf(0)},
},
{
Dependency: depsForAnonymousEmbedded[1],
Input: &Input{Index: 1, StructFieldIndex: []int{1, 0}, Type: reflect.TypeOf(time.Time{})},
},
},
},
// 5. test for auto-bindings with zero registered.
{
Value: &controller2{},
Registered: nil,
Expected: autoBindings,
},
// 6. test for embedded with named fields which should NOT contain any registered deps
// except the two auto-bindings for structs,
{
Value: &controller2{},
Registered: depsForAnonymousEmbedded,
Expected: autoBindings,
}, // 7. and only embedded struct's fields are readen, otherwise we expect the struct to be a dependency.
{
Value: &controller2{},
Registered: depsForFieldsOfStruct,
Expected: []*binding{
{
Dependency: depsForFieldsOfStruct[0],
Input: &Input{Index: 0, StructFieldIndex: []int{0}, Type: reflect.TypeOf(embedded1{})},
},
{
Dependency: depsForFieldsOfStruct[1],
Input: &Input{Index: 1, StructFieldIndex: []int{1}, Type: reflect.TypeOf(embedded2{})},
},
},
},
// 8. test one exported and other not exported.
{
Value: &controller3{},
Registered: []*Dependency{depsForFieldsOfStruct[0]},
Expected: []*binding{
{
Dependency: depsForFieldsOfStruct[0],
Input: &Input{Index: 0, StructFieldIndex: []int{0}, Type: reflect.TypeOf(embedded1{})},
},
},
},
// 9. test same as the above but by registering all dependencies.
{
Value: &controller3{},
Registered: depsForFieldsOfStruct,
Expected: []*binding{
{
Dependency: depsForFieldsOfStruct[0],
Input: &Input{Index: 0, StructFieldIndex: []int{0}, Type: reflect.TypeOf(embedded1{})},
},
},
},
// 10. test bind an interface{}.
{
Value: &controller{},
Registered: depsInterfaces,
Expected: []*binding{
{
Dependency: depsInterfaces[0],
Input: &Input{Index: 0, StructFieldIndex: []int{0}, Type: reflect.TypeOf("")},
},
},
},
}
for i, tt := range tests {
bindings := getBindingsForStruct(reflect.ValueOf(tt.Value), tt.Registered, 0, nil)
if expected, got := len(tt.Expected), len(bindings); expected != got {
t.Logf("[%d] expected bindings length to be: %d but got: %d:\n", i, expected, got)
for _, b := range bindings {
t.Logf("\t%s\n", b)
}
t.FailNow()
}
for j, b := range bindings {
if tt.Expected[j] == nil {
t.Fatalf("[%d:%d] expected dependency was not found!", i, j)
}
if expected := tt.Expected[j]; !expected.Equal(b) {
t.Fatalf("[%d:%d] expected binding:\n%s\nbut got:\n%s", i, j, expected, b)
}
}
}
}

View File

@@ -8,8 +8,8 @@ import (
"reflect"
"time"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/v12/sessions"
"github.com/kataras/iris/context"
"github.com/kataras/iris/sessions"
"github.com/kataras/golog"
)

View File

@@ -1,131 +0,0 @@
package hero_test
import (
"fmt"
"reflect"
"testing"
"github.com/kataras/iris/v12"
. "github.com/kataras/iris/v12/hero"
"github.com/kataras/iris/v12/httptest"
)
var errTyp = reflect.TypeOf((*error)(nil)).Elem()
// isError returns true if "typ" is type of `error`.
func isError(typ reflect.Type) bool {
return typ.Implements(errTyp)
}
type (
testInput struct {
Name string `json:"name"`
}
testOutput struct {
ID int `json:"id"`
Name string `json:"name"`
}
)
var (
fn = func(id int, in testInput) testOutput {
return testOutput{
ID: id,
Name: in.Name,
}
}
expectedOutput = testOutput{
ID: 42,
Name: "makis",
}
input = testInput{
Name: "makis",
}
)
func TestContainerHandler(t *testing.T) {
app := iris.New()
c := New()
postHandler := c.Handler(fn)
app.Post("/{id:int}", postHandler)
e := httptest.New(t, app)
path := fmt.Sprintf("/%d", expectedOutput.ID)
e.POST(path).WithJSON(input).Expect().Status(httptest.StatusOK).JSON().Equal(expectedOutput)
}
func TestContainerInject(t *testing.T) {
c := New()
expected := testInput{Name: "test"}
c.Register(expected)
c.Register(&expected)
// struct value.
var got1 testInput
if err := c.Inject(&got1); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(expected, got1) {
t.Fatalf("[struct value] expected: %#+v but got: %#+v", expected, got1)
}
// ptr.
var got2 *testInput
if err := c.Inject(&got2); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(&expected, got2) {
t.Fatalf("[ptr] expected: %#+v but got: %#+v", &expected, got2)
}
// register implementation, expect interface.
expected3 := &testServiceImpl{prefix: "prefix: "}
c.Register(expected3)
var got3 testService
if err := c.Inject(&got3); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(expected3, got3) {
t.Fatalf("[service] expected: %#+v but got: %#+v", expected3, got3)
}
}
func TestContainerUseResultHandler(t *testing.T) {
c := New()
resultLogger := func(next ResultHandler) ResultHandler {
return func(ctx iris.Context, v interface{}) error {
t.Logf("%#+v", v)
return next(ctx, v)
}
}
c.UseResultHandler(resultLogger)
expectedResponse := map[string]interface{}{"injected": true}
c.UseResultHandler(func(next ResultHandler) ResultHandler {
return func(ctx iris.Context, v interface{}) error {
return next(ctx, expectedResponse)
}
})
c.UseResultHandler(resultLogger)
handler := c.Handler(func(id int) testOutput {
return testOutput{
ID: id,
Name: "kataras",
}
})
app := iris.New()
app.Get("/{id:int}", handler)
e := httptest.New(t, app)
e.GET("/42").Expect().Status(httptest.StatusOK).JSON().Equal(expectedResponse)
}

View File

@@ -5,7 +5,7 @@ import (
"reflect"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/context"
)
type (

View File

@@ -1,206 +0,0 @@
package hero_test
import (
"fmt"
"reflect"
"testing"
"github.com/kataras/iris/v12/context"
. "github.com/kataras/iris/v12/hero"
)
type testDependencyTest struct {
Dependency interface{}
Expected interface{}
}
func TestDependency(t *testing.T) {
var tests = []testDependencyTest{
{
Dependency: "myValue",
Expected: "myValue",
},
{
Dependency: struct{ Name string }{"name"},
Expected: struct{ Name string }{"name"},
},
{
Dependency: func(*context.Context, *Input) (reflect.Value, error) {
return reflect.ValueOf(42), nil
},
Expected: 42,
},
{
Dependency: DependencyHandler(func(*context.Context, *Input) (reflect.Value, error) {
return reflect.ValueOf(255), nil
}),
Expected: 255,
},
{
Dependency: func(*context.Context) (reflect.Value, error) {
return reflect.ValueOf("OK without Input"), nil
},
Expected: "OK without Input",
},
{
Dependency: func(*context.Context, ...string) (reflect.Value, error) {
return reflect.ValueOf("OK variadic ignored"), nil
},
Expected: "OK variadic ignored",
},
{
Dependency: func(*context.Context) reflect.Value {
return reflect.ValueOf("OK without Input and error")
},
Expected: "OK without Input and error",
},
{
Dependency: func(*context.Context, ...int) reflect.Value {
return reflect.ValueOf("OK without error and variadic ignored")
},
Expected: "OK without error and variadic ignored",
},
{
Dependency: func(*context.Context) interface{} {
return "1"
},
Expected: "1",
},
{
Dependency: func(*context.Context) interface{} {
return false
},
Expected: false,
},
}
testDependencies(t, tests)
}
// Test dependencies that depend on previous one(s).
func TestDependentDependency(t *testing.T) {
msgBody := "prefix: it is a deep dependency"
newMsgBody := msgBody + " new"
var tests = []testDependencyTest{
// test three level depth and error.
{ // 0
Dependency: &testServiceImpl{prefix: "prefix:"},
Expected: &testServiceImpl{prefix: "prefix:"},
},
{ // 1
Dependency: func(service testService) testMessage {
return testMessage{Body: service.Say("it is a deep") + " dependency"}
},
Expected: testMessage{Body: msgBody},
},
{ // 2
Dependency: func(msg testMessage) string {
return msg.Body
},
Expected: msgBody,
},
{ // 3
Dependency: func(msg testMessage) error {
return fmt.Errorf(msg.Body)
},
Expected: fmt.Errorf(msgBody),
},
// Test depend on more than one previous registered dependencies and require a before-previous one.
{ // 4
Dependency: func(body string, msg testMessage) string {
if body != msg.Body {
t.Fatalf("body[%s] != msg.Body[%s]", body, msg.Body)
}
return body + " new"
},
Expected: newMsgBody,
},
// Test dependency order by expecting the first <string> returning value and not the later-on registered dependency(#4).
// 5
{
Dependency: func(body string) string {
return body
},
Expected: newMsgBody,
},
}
testDependencies(t, tests)
}
func testDependencies(t *testing.T, tests []testDependencyTest) {
t.Helper()
c := New()
for i, tt := range tests {
d := c.Register(tt.Dependency)
if d == nil {
t.Fatalf("[%d] expected %#+v to be converted to a valid dependency", i, tt)
}
val, err := d.Handle(context.NewContext(nil), &Input{})
if expectError := isError(reflect.TypeOf(tt.Expected)); expectError {
val = reflect.ValueOf(err)
err = nil
}
if err != nil {
t.Fatalf("[%d] expected a nil error but got: %v", i, err)
}
if !val.CanInterface() {
t.Fatalf("[%d] expected output value to be accessible: %T", i, val)
}
if expected, got := fmt.Sprintf("%#+v", tt.Expected), fmt.Sprintf("%#+v", val.Interface()); expected != got {
t.Fatalf("[%d] expected return value to be:\n%s\nbut got:\n%s", i, expected, got)
}
// t.Logf("[%d] %s", i, d)
// t.Logf("[%d] output: %#+v", i, val.Interface())
}
}
func TestDependentDependencyInheritanceStatic(t *testing.T) {
// Tests the following case #1564:
// Logger
// func(Logger) S1
// ^ Should be static because Logger
// is a structure, a static dependency.
//
// func(Logger) S2
// func(S1, S2) S3
// ^ Should be marked as static dependency
// because everything that depends on are static too.
type S1 struct {
msg string
}
type S2 struct {
msg2 string
}
serviceDep := NewDependency(&testServiceImpl{prefix: "1"})
d1 := NewDependency(func(t testService) S1 {
return S1{t.Say("2")}
}, serviceDep)
if !d1.Static {
t.Fatalf("d1 dependency should be static: %#+v", d1)
}
d2 := NewDependency(func(t testService, s S1) S2 {
return S2{"3"}
}, serviceDep, d1)
if !d2.Static {
t.Fatalf("d2 dependency should be static: %#+v", d2)
}
}

View File

@@ -4,7 +4,7 @@ import (
"reflect"
"strings"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/context"
"github.com/fatih/structs"
"google.golang.org/protobuf/proto"

View File

@@ -1,281 +0,0 @@
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")
}
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")
}

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"reflect"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/context"
)
type (

View File

@@ -1,287 +0,0 @@
package hero_test
import (
"fmt"
"testing"
"github.com/kataras/iris/v12"
. "github.com/kataras/iris/v12/hero"
"github.com/kataras/iris/v12/httptest"
)
// dynamic func
type testUserStruct struct {
ID int64 `json:"id" form:"id" url:"id"`
Username string `json:"username" form:"username" url:"username"`
}
func testBinderFunc(ctx iris.Context) testUserStruct {
id, _ := ctx.Params().GetInt64("id")
username := ctx.Params().Get("username")
return testUserStruct{
ID: id,
Username: username,
}
}
// service
type (
// these testService and testServiceImpl could be in lowercase, unexported
// but the `Say` method should be exported however we have those exported
// because of the controller handler test.
testService interface {
Say(string) string
}
testServiceImpl struct {
prefix string
}
)
func (s *testServiceImpl) Say(message string) string {
return s.prefix + " " + message
}
var (
// binders, as user-defined
testBinderFuncUserStruct = testBinderFunc
testBinderService = &testServiceImpl{prefix: "say"}
testBinderFuncParam = func(ctx iris.Context) string {
return ctx.Params().Get("param")
}
// consumers
// a context as first input arg, which is not needed to be binded manually,
// and a user struct which is binded to the input arg by the #1 func(ctx) any binder.
testConsumeUserHandler = func(ctx iris.Context, user testUserStruct) {
ctx.JSON(user)
}
// just one input arg, the service which is binded by the #2 service binder.
testConsumeServiceHandler = func(service testService) string {
return service.Say("something")
}
// just one input arg, a standar string which is binded by the #3 func(ctx) any binder.
testConsumeParamHandler = func(myParam string) string {
return "param is: " + myParam
}
)
func TestHandler(t *testing.T) {
Register(testBinderFuncUserStruct)
Register(testBinderService)
Register(testBinderFuncParam)
var (
h1 = Handler(testConsumeUserHandler)
h2 = Handler(testConsumeServiceHandler)
h3 = Handler(testConsumeParamHandler)
)
testAppWithHeroHandlers(t, h1, h2, h3)
}
func testAppWithHeroHandlers(t *testing.T, h1, h2, h3 iris.Handler) {
app := iris.New()
app.Get("/{id:int64}/{username:string}", h1)
app.Get("/service", h2)
app.Get("/param/{param:string}", h3)
expectedUser := testUserStruct{
ID: 42,
Username: "kataras",
}
e := httptest.New(t, app)
// 1
e.GET(fmt.Sprintf("/%d/%s", expectedUser.ID, expectedUser.Username)).Expect().Status(httptest.StatusOK).
JSON().Equal(expectedUser)
// 2
e.GET("/service").Expect().Status(httptest.StatusOK).
Body().Equal("say something")
// 3
e.GET("/param/the_param_value").Expect().Status(httptest.StatusOK).
Body().Equal("param is: the_param_value")
}
// TestBindFunctionAsFunctionInputArgument tests to bind
// a whole dynamic function based on the current context
// as an input argument in the hero handler's function.
func TestBindFunctionAsFunctionInputArgument(t *testing.T) {
app := iris.New()
postsBinder := func(ctx iris.Context) func(string) string {
return ctx.PostValue // or FormValue, the same here.
}
h := New(postsBinder).Handler(func(get func(string) string) string {
// send the `ctx.PostValue/FormValue("username")` value
// to the client.
return get("username")
})
app.Post("/", h)
e := httptest.New(t, app)
expectedUsername := "kataras"
e.POST("/").WithFormField("username", expectedUsername).
Expect().Status(iris.StatusOK).Body().Equal(expectedUsername)
}
func TestPayloadBinding(t *testing.T) {
h := New()
ptrHandler := h.Handler(func(input *testUserStruct /* ptr */) string {
return input.Username
})
valHandler := h.Handler(func(input testUserStruct) string {
return input.Username
})
app := iris.New()
app.Get("/", ptrHandler)
app.Post("/", ptrHandler)
app.Post("/2", valHandler)
e := httptest.New(t, app)
// JSON
e.POST("/").WithJSON(iris.Map{"username": "makis"}).Expect().Status(httptest.StatusOK).Body().Equal("makis")
e.POST("/2").WithJSON(iris.Map{"username": "kataras"}).Expect().Status(httptest.StatusOK).Body().Equal("kataras")
// FORM (url-encoded)
e.POST("/").WithFormField("username", "makis").Expect().Status(httptest.StatusOK).Body().Equal("makis")
// FORM (multipart)
e.POST("/").WithMultipart().WithFormField("username", "makis").Expect().Status(httptest.StatusOK).Body().Equal("makis")
// POST URL query.
e.POST("/").WithQuery("username", "makis").Expect().Status(httptest.StatusOK).Body().Equal("makis")
// GET URL query.
e.GET("/").WithQuery("username", "makis").Expect().Status(httptest.StatusOK).Body().Equal("makis")
}
/* Author's notes:
If aksed or required by my company, make the following test to pass but think downsides of code complexity and performance-cost
before begin the implementation of it.
- Dependencies without depending on other values can be named "root-level dependencies"
- Dependencies could be linked (a new .DependsOn?) to a "root-level dependency"(or by theirs same-level deps too?) with much
more control if "root-level dependencies" are named, e.g.:
b.Register("db", &myDBImpl{})
b.Register("user_dep", func(db myDB) User{...}).DependsOn("db")
b.Handler(func(user User) error{...})
b.Handler(func(ctx iris.Context, reuseDB myDB) {...})
Why linked over automatically? Because more than one dependency can implement the same input and
end-user does not care about ordering the registered ones.
Link with `DependsOn` SHOULD be optional, if exists then limit the available dependencies,
`DependsOn` SHOULD accept comma-separated values, e.g. "db, otherdep" and SHOULD also work
by calling it multiple times i.e `Depends("db").DependsOn("otherdep")`.
Handlers should also be able to explicitly limit the list of
their available dependencies per-handler, a `.DependsOn` feature SHOULD exist there too.
Also, note that with the new implementation a `*hero.Input` value can be accepted on dynamic dependencies,
that value contains an `Options.Dependencies` field which lists all the registered dependencies,
so, in theory, end-developers could achieve same results by hand-code(inside the dependency's function body).
26 Feb 2020. Gerasimos Maropoulos
______________________________________________
29 Feb 2020. It's done.
*/
type testMessage struct {
Body string
}
func TestDependentDependencies(t *testing.T) {
b := New()
b.Register(&testServiceImpl{prefix: "prefix:"})
b.Register(func(service testService) testMessage {
return testMessage{Body: service.Say("it is a deep") + " dependency"}
})
var (
h1 = b.Handler(func(msg testMessage) string {
return msg.Body
})
h2 = b.Handler(func(reuse testService) string {
return reuse.Say("message")
})
)
app := iris.New()
app.Get("/h1", h1)
app.Get("/h2", h2)
e := httptest.New(t, app)
e.GET("/h1").Expect().Status(httptest.StatusOK).Body().Equal("prefix: it is a deep dependency")
e.GET("/h2").Expect().Status(httptest.StatusOK).Body().Equal("prefix: message")
}
func TestHandlerPathParams(t *testing.T) {
// See white box `TestPathParams` test too.
// All cases should pass.
app := iris.New()
handler := func(id uint64) string {
return fmt.Sprintf("%d", id)
}
app.Party("/users").ConfigureContainer(func(api *iris.APIContainer) {
api.Get("/{id:uint64}", handler)
})
app.Party("/editors/{id:uint64}").ConfigureContainer(func(api *iris.APIContainer) {
api.Get("/", handler)
})
// should receive the last one, as we expected only one useful for MVC (there is a similar test there too).
app.ConfigureContainer().Get("/{ownerID:uint64}/book/{booKID:uint64}", handler)
e := httptest.New(t, app)
for _, testReq := range []*httptest.Request{
e.GET("/users/42"),
e.GET("/editors/42"),
e.GET("/1/book/42"),
} {
testReq.Expect().Status(httptest.StatusOK).Body().Equal("42")
}
}
func TestRegisterDependenciesFromContext(t *testing.T) {
// Tests serve-time struct dependencies through a common Iris middleware.
app := iris.New()
app.Use(func(ctx iris.Context) {
ctx.RegisterDependency(testUserStruct{Username: "kataras"})
ctx.Next()
})
app.Use(func(ctx iris.Context) {
ctx.RegisterDependency(&testServiceImpl{prefix: "say"})
ctx.Next()
})
app.ConfigureContainer(func(api *iris.APIContainer) {
api.Get("/", func(u testUserStruct) string {
return u.Username
})
api.Get("/service", func(s *testServiceImpl) string {
return s.Say("hello")
})
// Note: we are not allowed to pass the service as an interface here
// because the container will, correctly, panic because it will expect
// a dependency to be registered before server ran.
api.Get("/both", func(s *testServiceImpl, u testUserStruct) string {
return s.Say(u.Username)
})
api.Get("/non", func() string {
return "nothing"
})
})
e := httptest.New(t, app)
e.GET("/").Expect().Status(httptest.StatusOK).Body().Equal("kataras")
e.GET("/service").Expect().Status(httptest.StatusOK).Body().Equal("say hello")
e.GET("/both").Expect().Status(httptest.StatusOK).Body().Equal("say kataras")
e.GET("/non").Expect().Status(httptest.StatusOK).Body().Equal("nothing")
}

View File

@@ -1,47 +0,0 @@
package hero
import (
"testing"
"github.com/kataras/iris/v12/context"
)
func TestPathParams(t *testing.T) {
got := ""
h := New()
handler := h.Handler(func(firstname string, lastname string) {
got = firstname + lastname
})
h.Register(func(ctx *context.Context) func() string { return func() string { return "" } })
handlerWithOther := h.Handler(func(f func() string, firstname string, lastname string) {
got = f() + firstname + lastname
})
handlerWithOtherBetweenThem := h.Handler(func(firstname string, f func() string, lastname string) {
got = firstname + lastname
})
ctx := context.NewContext(nil)
ctx.Params().Set("firstname", "Gerasimos")
ctx.Params().Set("lastname", "Maropoulos")
handler(ctx)
expected := "GerasimosMaropoulos"
if got != expected {
t.Fatalf("[0] expected the params 'firstname' + 'lastname' to be '%s' but got '%s'", expected, got)
}
got = ""
handlerWithOther(ctx)
expected = "GerasimosMaropoulos"
if got != expected {
t.Fatalf("[1] expected the params 'firstname' + 'lastname' to be '%s' but got '%s'", expected, got)
}
got = ""
handlerWithOtherBetweenThem(ctx)
expected = "GerasimosMaropoulos"
if got != expected {
t.Fatalf("[2] expected the params 'firstname' + 'lastname' to be '%s' but got '%s'", expected, got)
}
}

View File

@@ -4,7 +4,7 @@ import (
"net"
"reflect"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/context"
)
func valueOf(v interface{}) reflect.Value {

View File

@@ -1,39 +0,0 @@
package hero
import (
"reflect"
"testing"
)
type testInterface interface {
Get() string
}
var testInterfaceTyp = reflect.TypeOf((*testInterface)(nil)).Elem()
type testImplPtr struct{}
func (*testImplPtr) Get() string { return "get_ptr" }
type testImpl struct{}
func (testImpl) Get() string { return "get" }
func TestEqualTypes(t *testing.T) {
of := reflect.TypeOf
var tests = map[reflect.Type]reflect.Type{
of("string"): of("input"),
of(42): of(10),
testInterfaceTyp: testInterfaceTyp,
of(new(testImplPtr)): testInterfaceTyp,
of(new(testImpl)): testInterfaceTyp,
of(testImpl{}): testInterfaceTyp,
}
for binding, input := range tests {
if !equalTypes(binding, input) {
t.Fatalf("expected type of: %s to be equal to the binded one of: %s", input, binding)
}
}
}

View File

@@ -4,7 +4,7 @@ import (
"fmt"
"reflect"
"github.com/kataras/iris/v12/context"
"github.com/kataras/iris/context"
)
// Sorter is the type for sort customization of a struct's fields

View File

@@ -1,121 +0,0 @@
package hero_test
import (
"errors"
"fmt"
"testing"
"github.com/kataras/iris/v12"
. "github.com/kataras/iris/v12/hero"
"github.com/kataras/iris/v12/httptest"
)
type testStruct struct {
Ctx iris.Context
}
func (c *testStruct) MyHandler(name string) testOutput {
return fn(42, testInput{Name: name})
}
func (c *testStruct) MyHandler2(id int, in testInput) testOutput {
return fn(id, in)
}
func (c *testStruct) MyHandler3(in testInput) testOutput {
return fn(42, in)
}
func (c *testStruct) MyHandler4() {
c.Ctx.WriteString("MyHandler4")
}
func TestStruct(t *testing.T) {
app := iris.New()
b := New()
s := b.Struct(&testStruct{}, 0)
postHandler := s.MethodHandler("MyHandler", 0) // fallbacks such as {path} and {string} should registered first when same path.
app.Post("/{name:string}", postHandler)
postHandler2 := s.MethodHandler("MyHandler2", 0)
app.Post("/{id:int}", postHandler2)
postHandler3 := s.MethodHandler("MyHandler3", 0)
app.Post("/myHandler3", postHandler3)
getHandler := s.MethodHandler("MyHandler4", 0)
app.Get("/myHandler4", getHandler)
e := httptest.New(t, app)
e.POST("/" + input.Name).Expect().Status(httptest.StatusOK).JSON().Equal(expectedOutput)
path := fmt.Sprintf("/%d", expectedOutput.ID)
e.POST(path).WithJSON(input).Expect().Status(httptest.StatusOK).JSON().Equal(expectedOutput)
e.POST("/myHandler3").WithJSON(input).Expect().Status(httptest.StatusOK).JSON().Equal(expectedOutput)
e.GET("/myHandler4").Expect().Status(httptest.StatusOK).Body().Equal("MyHandler4")
}
type testStructErrorHandler struct{}
func (s *testStructErrorHandler) HandleError(ctx iris.Context, err error) {
ctx.StopWithError(httptest.StatusConflict, err)
}
func (s *testStructErrorHandler) Handle(errText string) error {
return errors.New(errText)
}
func TestStructErrorHandler(t *testing.T) {
b := New()
s := b.Struct(&testStructErrorHandler{}, 0)
app := iris.New()
app.Get("/{errText:string}", s.MethodHandler("Handle", 0))
expectedErrText := "an error"
e := httptest.New(t, app)
e.GET("/" + expectedErrText).Expect().Status(httptest.StatusConflict).Body().Equal(expectedErrText)
}
type (
testServiceInterface1 interface {
Parse() string
}
testServiceImpl1 struct {
inner string
}
testServiceInterface2 interface {
}
testServiceImpl2 struct {
tf int
}
testControllerDependenciesSorter struct {
Service2 testServiceInterface2
Service1 testServiceInterface1
}
)
func (s *testServiceImpl1) Parse() string {
return s.inner
}
func (c *testControllerDependenciesSorter) Index() string {
return fmt.Sprintf("%#+v | %#+v", c.Service1, c.Service2)
}
func TestStructFieldsSorter(t *testing.T) { // see https://github.com/kataras/iris/issues/1343
b := New()
b.Register(&testServiceImpl1{"parser"})
b.Register(&testServiceImpl2{24})
s := b.Struct(&testControllerDependenciesSorter{}, 0)
app := iris.New()
app.Get("/", s.MethodHandler("Index", 0))
e := httptest.New(t, app)
expectedBody := `&hero_test.testServiceImpl1{inner:"parser"} | &hero_test.testServiceImpl2{tf:24}`
e.GET("/").Expect().Status(httptest.StatusOK).Body().Equal(expectedBody)
}