diff --git a/_future/macros_test.go b/_future/macros_test.go index 1b01f035..7d1e61ea 100644 --- a/_future/macros_test.go +++ b/_future/macros_test.go @@ -4,11 +4,12 @@ // The whole "router" package is a temp place to test my ideas and implementations for future iris' features. // Young developers can understand and see how ideas can be transform to real implementations on a software like Iris, // watching the history of a "dirty" code can be useful for some of you. - +// package router import ( "regexp" + "strconv" "testing" "gopkg.in/kataras/iris.v6" @@ -16,9 +17,6 @@ import ( "gopkg.in/kataras/iris.v6/httptest" ) -// macros should be registered before .Listen -type _macros map[string]func(string) bool - // a helper to return a macro from a simple regexp // it compiles the regexp and after returns the macro, for obviously performance reasons. func fromRegexp(expr string) func(paramValue string) bool { @@ -35,7 +33,6 @@ func fromRegexp(expr string) func(paramValue string) bool { if err != nil { panic(err) } - return r.MatchString } @@ -58,16 +55,17 @@ func link(path string, mac _macros) iris.HandlerFunc { if prevH != nil { prevH(ctx) } - paramValue := ctx.Param(paramName) if paramValue != "" { valid := validator(paramValue) if !valid { + print("not valid for validator on paramValue= '" + paramValue + "' ctx.Pos = ") + println(ctx.Pos) // it should be always 0. ctx.EmitError(failStatus) return } } - // println(ctx.Pos) + println(ctx.Pos) // remember: router already matches the path, so here if a path param is missing then it was allowed by the router. ctx.Next() } @@ -75,9 +73,36 @@ func link(path string, mac _macros) iris.HandlerFunc { for i := range tmpl.Params { p := tmpl.Params[i] - if m := mac[p.Param.Macro.Name]; m != nil { + if m, found := mac[p.Param.Macro.Name]; found && m.eval != nil { prevH := h - h = createH(p.Param.Name, m, p.Param.FailStatusCode, prevH) + eval := m.eval + for _, fi := range m.funcs { + println("details for: " + fi.name) + println("m.funcs len = ") + print(len(m.funcs)) + println("vs tmpl macro's funcs len = ") + print(len(p.Param.Macro.Funcs)) + println() + for _, mi := range p.Param.Macro.Funcs { + + if fi.name == mi.Name { + println(fi.name + " matches with pathtmpl macro func: " + mi.Name) + prevEval := eval + macroFuncEval := fi.eval(mi.Params) + eval = func(pvalue string) bool { + if prevEval(pvalue) { + return macroFuncEval(pvalue) + } + return false + } + continue + } + + println("fi.name = " + fi.name + " | mi.Name = " + mi.Name) + } + } + + h = createH(p.Param.Name, eval, p.Param.FailStatusCode, prevH) } } @@ -108,15 +133,75 @@ func testMacros(source string) error { return nil } -func TestMacros(t *testing.T) { - var m = _macros{ - "int": fromRegexp("[1-9]+$"), +type _macrofunc struct { + name string + eval func([]string) func(string) bool +} +type _macro struct { + funcs []_macrofunc + eval func(string) bool +} + +// macros should be registered before .Listen +type _macros map[string]*_macro + +var all_macros = _macros{} + +func addMacro(name string, v func(string) bool) { + all_macros[name] = &_macro{eval: v} +} + +func addMacroFunc(macroName string, funcName string, v func([]string) func(string) bool) { + if m, found := all_macros[macroName]; found { + m.funcs = append(m.funcs, _macrofunc{name: funcName, eval: v}) } - path := "/api/users/{id:int}/posts" +} + +func TestMacros(t *testing.T) { + addMacro("int", fromRegexp("[1-9]+$")) + // {id:int range(42,49)} + addMacroFunc("int", "range", func(params []string) func(string) bool { + // start: .Boot time, before .Listen + allowedParamsLen := 2 + // params: 42,49 (including first and second) + if len(params) != allowedParamsLen { + panic("range accepts two parameters") + } + + min, err := strconv.Atoi(params[0]) + if err != nil { + panic("invalid first parameter: " + err.Error()) + } + max, err := strconv.Atoi(params[1]) + if err != nil { + panic("invalid second parameter: " + err.Error()) + } + // end + + return func(paramValue string) bool { + paramValueInt, err := strconv.Atoi(paramValue) + if err != nil { + return false + } + print("min: ") + println(min) + print("max: ") + println(max) + print("value: ") + println(paramValueInt) + if paramValueInt >= min && paramValueInt <= max { + return true + } + return false + } + + }) + + path := "/api/users/{id:int range(42,49)}/posts" app := iris.New() app.Adapt(httprouter.New()) - hv := link(path, m) + hv := link(path, all_macros) app.Get("/api/users/:id/posts", hv, func(ctx *iris.Context) { ctx.ResponseWriter.WriteString(ctx.Path()) @@ -125,8 +210,12 @@ func TestMacros(t *testing.T) { e := httptest.New(app, t) e.GET("/api/users/42/posts").Expect().Status(iris.StatusOK).Body().Equal("/api/users/42/posts") + e.GET("/api/users/50/posts").Expect().Status(iris.StatusNotFound) // remember, it accepts 1-9 not matched if zero. e.GET("/api/users/0/posts").Expect().Status(iris.StatusNotFound) e.GET("/api/users/_/posts").Expect().Status(iris.StatusNotFound) e.GET("/api/users/s/posts").Expect().Status(iris.StatusNotFound) e.GET("/api/users/posts").Expect().Status(iris.StatusNotFound) + // macro func invalidate test with a non-zero value between 1-9 but bigger than the max(49) + e.GET("/api/users/51/posts").Expect().Status(iris.StatusNotFound) + }