1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-09 13:05:56 +00:00

New ':int64' and ':uint64' route path parameters - and - support the new uint64 for MVC (int64 was already supported there) - and - add ctx.Params().GetUint64 (GetInt64 was already there) - and - make the ':int or :number' to accept negative numbers with no digit limit (at low level) and rename the 'app.Macros().Int.RegisterFunc' to 'Number.RegisterFunc' because number can be any type of number not only standard go type limited - and - add alias for ':boolean' -> ':bool'. Finally, Update the examples but not the version yet, I have to provide a good README table to explain the end-developers how they can benefit by those changes and why the breaking change (which is to accept negative numbers via ':int') is for their own good and how they can make their own macro functions so they do not depend on the Iris builtn macro funcs only. More to come tomorrow, stay tuned

Former-commit-id: 3601abfc89478185afec3594375080778214283e
This commit is contained in:
Gerasimos (Makis) Maropoulos
2018-08-23 06:30:12 +03:00
parent 01b5f6089d
commit b019a281eb
28 changed files with 478 additions and 242 deletions

View File

@@ -270,10 +270,10 @@ func (api *APIBuilder) Handle(method string, relativePath string, handlers ...co
// otherwise use `Party` which can handle many paths with different handlers and middlewares.
//
// Usage:
// app.HandleMany("GET", "/user /user/{id:int} /user/me", genericUserHandler)
// app.HandleMany("GET", "/user /user/{id:uint64} /user/me", genericUserHandler)
// At the other side, with `Handle` we've had to write:
// app.Handle("GET", "/user", userHandler)
// app.Handle("GET", "/user/{id:int}", userByIDHandler)
// app.Handle("GET", "/user/{id:uint64}", userByIDHandler)
// app.Handle("GET", "/user/me", userMeHandler)
//
// This method is used behind the scenes at the `Controller` function

View File

@@ -56,7 +56,7 @@ func genPaths(routesLength, minCharLength, maxCharLength int) []string {
b.WriteString(randStringBytesMaskImprSrc(pathSegmentCharsLength))
b.WriteString("/{name:string}/") // sugar.
b.WriteString(randStringBytesMaskImprSrc(pathSegmentCharsLength))
b.WriteString("/{age:int}/end")
b.WriteString("/{age:number}/end")
paths[i] = b.String()
b.Reset()

View File

@@ -35,8 +35,9 @@ func registerBuiltinsMacroFuncs(out *macro.Map) {
//
// these can be overridden by the user, later on.
registerStringMacroFuncs(out.String)
registerIntMacroFuncs(out.Int)
registerIntMacroFuncs(out.Long)
registerNumberMacroFuncs(out.Number)
registerInt64MacroFuncs(out.Int64)
registerUint64MacroFuncs(out.Uint64)
registerAlphabeticalMacroFuncs(out.Alphabetical)
registerFileMacroFuncs(out.File)
registerPathMacroFuncs(out.Path)
@@ -87,9 +88,9 @@ func registerStringMacroFuncs(out *macro.Macro) {
})
}
// Int
// only numbers (0-9)
func registerIntMacroFuncs(out *macro.Macro) {
// Number
// positive and negative numbers, number of digits depends on the arch.
func registerNumberMacroFuncs(out *macro.Macro) {
// checks if the param value's int representation is
// bigger or equal than 'min'
out.RegisterFunc("min", func(min int) macro.EvaluatorFunc {
@@ -131,6 +132,94 @@ func registerIntMacroFuncs(out *macro.Macro) {
})
}
// Int64
// -9223372036854775808 to 9223372036854775807.
func registerInt64MacroFuncs(out *macro.Macro) {
// checks if the param value's int64 representation is
// bigger or equal than 'min'
out.RegisterFunc("min", func(min int64) macro.EvaluatorFunc {
return func(paramValue string) bool {
n, err := strconv.ParseInt(paramValue, 10, 64)
if err != nil {
return false
}
return n >= min
}
})
// checks if the param value's int64 representation is
// smaller or equal than 'max'
out.RegisterFunc("max", func(max int64) macro.EvaluatorFunc {
return func(paramValue string) bool {
n, err := strconv.ParseInt(paramValue, 10, 64)
if err != nil {
return false
}
return n <= max
}
})
// checks if the param value's int64 representation is
// between min and max, including 'min' and 'max'
out.RegisterFunc("range", func(min, max int64) macro.EvaluatorFunc {
return func(paramValue string) bool {
n, err := strconv.ParseInt(paramValue, 10, 64)
if err != nil {
return false
}
if n < min || n > max {
return false
}
return true
}
})
}
// Uint64
// 0 to 18446744073709551615.
func registerUint64MacroFuncs(out *macro.Macro) {
// checks if the param value's uint64 representation is
// bigger or equal than 'min'
out.RegisterFunc("min", func(min uint64) macro.EvaluatorFunc {
return func(paramValue string) bool {
n, err := strconv.ParseUint(paramValue, 10, 64)
if err != nil {
return false
}
return n >= min
}
})
// checks if the param value's uint64 representation is
// smaller or equal than 'max'
out.RegisterFunc("max", func(max uint64) macro.EvaluatorFunc {
return func(paramValue string) bool {
n, err := strconv.ParseUint(paramValue, 10, 64)
if err != nil {
return false
}
return n <= max
}
})
// checks if the param value's uint64 representation is
// between min and max, including 'min' and 'max'
out.RegisterFunc("range", func(min, max uint64) macro.EvaluatorFunc {
return func(paramValue string) bool {
n, err := strconv.ParseUint(paramValue, 10, 64)
if err != nil {
return false
}
if n < min || n > max {
return false
}
return true
}
})
}
// Alphabetical
// letters only (upper or lowercase)
func registerAlphabeticalMacroFuncs(out *macro.Macro) {

View File

@@ -16,20 +16,27 @@ const (
// ParamTypeString is the string type.
// If parameter type is missing then it defaults to String type.
// Allows anything
// Declaration: /mypath/{myparam:string} or /mypath{myparam}
// Declaration: /mypath/{myparam:string} or {myparam}
ParamTypeString
// ParamTypeInt is the integer, a number type.
// Allows only positive numbers (0-9)
// Declaration: /mypath/{myparam:int}
ParamTypeInt
// ParamTypeLong is the integer, a number type.
// Allows only positive numbers (0-9)
// Declaration: /mypath/{myparam:long}
ParamTypeLong
// ParamTypeNumber is the integer, a number type.
// Allows both positive and negative numbers, any number of digits.
// Declaration: /mypath/{myparam:number} or {myparam:int} for backwards-compatibility
ParamTypeNumber
// ParamTypeInt64 is a number type.
// Allows only -9223372036854775808 to 9223372036854775807.
// Declaration: /mypath/{myparam:int64} or {myparam:long}
ParamTypeInt64
// ParamTypeUint64 a number type.
// Allows only 0 to 18446744073709551615.
// Declaration: /mypath/{myparam:uint64}
ParamTypeUint64
// ParamTypeBoolean is the bool type.
// Allows only "1" or "t" or "T" or "TRUE" or "true" or "True"
// or "0" or "f" or "F" or "FALSE" or "false" or "False".
// Declaration: /mypath/{myparam:boolean}
// Declaration: /mypath/{myparam:bool} or {myparam:boolean}
ParamTypeBoolean
// ParamTypeAlphabetical is the alphabetical/letter type type.
// Allows letters only (upper or lowercase)
@@ -79,10 +86,12 @@ func (pt ParamType) Kind() reflect.Kind {
fallthrough
case ParamTypeString:
return reflect.String
case ParamTypeInt:
case ParamTypeNumber:
return reflect.Int
case ParamTypeLong:
case ParamTypeInt64:
return reflect.Int64
case ParamTypeUint64:
return reflect.Uint64
case ParamTypeBoolean:
return reflect.Bool
}
@@ -99,6 +108,8 @@ func ValidKind(k reflect.Kind) bool {
fallthrough
case reflect.Int64:
fallthrough
case reflect.Uint64:
fallthrough
case reflect.Bool:
return true
default:
@@ -113,10 +124,17 @@ func (pt ParamType) Assignable(k reflect.Kind) bool {
}
var paramTypes = map[string]ParamType{
"string": ParamTypeString,
"int": ParamTypeInt,
"long": ParamTypeLong,
"boolean": ParamTypeBoolean,
"string": ParamTypeString,
"number": ParamTypeNumber,
"int": ParamTypeNumber, // same as number.
"long": ParamTypeInt64,
"int64": ParamTypeInt64, // same as long.
"uint64": ParamTypeUint64,
"boolean": ParamTypeBoolean,
"bool": ParamTypeBoolean, // same as boolean.
"alphabetical": ParamTypeAlphabetical,
"file": ParamTypeFile,
"path": ParamTypePath,
@@ -131,8 +149,10 @@ var paramTypes = map[string]ParamType{
// representation of a parameter type.
// Available:
// "string"
// "int"
// "long"
// "number" or "int"
// "long" or "int64"
// "uint64"
// "boolean" or "bool"
// "alphabetical"
// "file"
// "path"
@@ -149,17 +169,20 @@ func LookupParamType(ident string) ParamType {
// make sure that caller resolves these types before this call.
//
// string matches to string
// int matches to int
// int64 matches to long
// bool matches to boolean
// int matches to int/number
// int64 matches to int64/long
// uint64 matches to uint64
// bool matches to bool/boolean
func LookupParamTypeFromStd(goType string) ParamType {
switch goType {
case "string":
return ParamTypeString
case "int":
return ParamTypeInt
return ParamTypeNumber
case "int64":
return ParamTypeLong
return ParamTypeInt64
case "uint64":
return ParamTypeUint64
case "bool":
return ParamTypeBoolean
default:

View File

@@ -179,7 +179,7 @@ func (l *Lexer) skipWhitespace() {
func (l *Lexer) readIdentifier() string {
pos := l.pos
for isLetter(l.ch) {
for isLetter(l.ch) || isDigit(l.ch) {
l.readChar()
}
return l.input[pos:l.pos]

View File

@@ -7,27 +7,27 @@ import (
)
func TestNextToken(t *testing.T) {
input := `{id:int min(1) max(5) else 404}`
input := `{id:number min(1) max(5) else 404}`
tests := []struct {
expectedType token.Type
expectedLiteral string
}{
{token.LBRACE, "{"}, // 0
{token.IDENT, "id"}, // 1
{token.COLON, ":"}, // 2
{token.IDENT, "int"}, // 3
{token.IDENT, "min"}, // 4
{token.LPAREN, "("}, // 5
{token.INT, "1"}, // 6
{token.RPAREN, ")"}, // 7
{token.IDENT, "max"}, // 8
{token.LPAREN, "("}, // 9
{token.INT, "5"}, // 10
{token.RPAREN, ")"}, // 11
{token.ELSE, "else"}, // 12
{token.INT, "404"}, // 13
{token.RBRACE, "}"}, // 14
{token.LBRACE, "{"}, // 0
{token.IDENT, "id"}, // 1
{token.COLON, ":"}, // 2
{token.IDENT, "number"}, // 3
{token.IDENT, "min"}, // 4
{token.LPAREN, "("}, // 5
{token.INT, "1"}, // 6
{token.RPAREN, ")"}, // 7
{token.IDENT, "max"}, // 8
{token.LPAREN, "("}, // 9
{token.INT, "5"}, // 10
{token.RPAREN, ")"}, // 11
{token.ELSE, "else"}, // 12
{token.INT, "404"}, // 13
{token.RBRACE, "}"}, // 14
}
l := New(input)

View File

@@ -120,11 +120,11 @@ func (p *ParamParser) Parse() (*ast.ParamStatement, error) {
switch t.Type {
case token.LBRACE:
// name, alphabetical and _, param names are not allowed to contain any number.
// can accept only letter or number only.
nextTok := l.NextToken()
stmt.Name = nextTok.Literal
case token.COLON:
// type
// type can accept both letters and numbers but not symbols ofc.
nextTok := l.NextToken()
paramType := ast.LookupParamType(nextTok.Literal)
if paramType == ast.ParamTypeUnExpected {

View File

@@ -30,7 +30,7 @@ func TestParseParamError(t *testing.T) {
//
// success
input2 := "{id:int range(1,5) else 404}"
input2 := "{id:uint64 range(1,5) else 404}"
p.Reset(input2)
_, err = p.Parse()
@@ -47,9 +47,9 @@ func TestParseParam(t *testing.T) {
}{
{true,
ast.ParamStatement{
Src: "{id:int min(1) max(5) else 404}",
Src: "{id:number min(1) max(5) else 404}",
Name: "id",
Type: ast.ParamTypeInt,
Type: ast.ParamTypeNumber,
Funcs: []ast.ParamFunc{
{
Name: "min",
@@ -63,9 +63,9 @@ func TestParseParam(t *testing.T) {
{true,
ast.ParamStatement{
Src: "{id:int range(1,5)}",
Src: "{id:number range(1,5)}",
Name: "id",
Type: ast.ParamTypeInt,
Type: ast.ParamTypeNumber,
Funcs: []ast.ParamFunc{
{
Name: "range",
@@ -106,18 +106,18 @@ func TestParseParam(t *testing.T) {
Type: ast.ParamTypeUnExpected,
ErrorCode: 404,
}}, // 5
{false, // false because it will give an error of unexpeced token type with value 2
{true,
ast.ParamStatement{
Src: "{myparam2}",
Name: "myparam", // expected "myparam" because we don't allow integers to the parameter names.
Name: "myparam2", // we now allow integers to the parameter names.
Type: ast.ParamTypeString,
ErrorCode: 404,
}}, // 6
{true,
ast.ParamStatement{
Src: "{id:int even()}", // test param funcs without any arguments (LPAREN peek for RPAREN)
Src: "{id:number even()}", // test param funcs without any arguments (LPAREN peek for RPAREN)
Name: "id",
Type: ast.ParamTypeInt,
Type: ast.ParamTypeNumber,
Funcs: []ast.ParamFunc{
{
Name: "even"},
@@ -126,18 +126,32 @@ func TestParseParam(t *testing.T) {
}}, // 7
{true,
ast.ParamStatement{
Src: "{id:long else 404}",
Src: "{id:int64 else 404}",
Name: "id",
Type: ast.ParamTypeLong,
Type: ast.ParamTypeInt64,
ErrorCode: 404,
}}, // 8
{true,
ast.ParamStatement{
Src: "{has:boolean else 404}",
Src: "{id:long else 404}", // backwards-compatible test.
Name: "id",
Type: ast.ParamTypeInt64,
ErrorCode: 404,
}}, // 9
{true,
ast.ParamStatement{
Src: "{has:bool else 404}",
Name: "has",
Type: ast.ParamTypeBoolean,
ErrorCode: 404,
}}, // 9
}}, // 10
{true,
ast.ParamStatement{
Src: "{has:boolean else 404}", // backwards-compatible test.
Name: "has",
Type: ast.ParamTypeBoolean,
ErrorCode: 404,
}}, // 11
}
@@ -167,11 +181,11 @@ func TestParse(t *testing.T) {
valid bool
expectedStatements []ast.ParamStatement
}{
{"/api/users/{id:int min(1) max(5) else 404}", true,
{"/api/users/{id:number min(1) max(5) else 404}", true,
[]ast.ParamStatement{{
Src: "{id:int min(1) max(5) else 404}",
Src: "{id:number min(1) max(5) else 404}",
Name: "id",
Type: ast.ParamTypeInt,
Type: ast.ParamTypeNumber,
Funcs: []ast.ParamFunc{
{
Name: "min",
@@ -183,11 +197,11 @@ func TestParse(t *testing.T) {
ErrorCode: 404,
},
}}, // 0
{"/admin/{id:int range(1,5)}", true,
{"/admin/{id:uint64 range(1,5)}", true,
[]ast.ParamStatement{{
Src: "{id:int range(1,5)}",
Src: "{id:uint64 range(1,5)}", // test alternative (backwards-compatibility) "int"
Name: "id",
Type: ast.ParamTypeInt,
Type: ast.ParamTypeUint64,
Funcs: []ast.ParamFunc{
{
Name: "range",
@@ -233,10 +247,10 @@ func TestParse(t *testing.T) {
ErrorCode: 404,
},
}}, // 5
{"/p2/{myparam2}", false, // false because it will give an error of unexpeced token type with value 2
{"/p2/{myparam2}", true,
[]ast.ParamStatement{{
Src: "{myparam2}",
Name: "myparam", // expected "myparam" because we don't allow integers to the parameter names.
Name: "myparam2", // we now allow integers to the parameter names.
Type: ast.ParamTypeString,
ErrorCode: 404,
},

View File

@@ -13,8 +13,8 @@ type Token struct {
// /about/{fullname:alphabetical}
// /profile/{anySpecialName:string}
// {id:int range(1,5) else 404}
// /admin/{id:int eq(1) else 402}
// {id:uint64 range(1,5) else 404}
// /admin/{id:number eq(1) else 402}
// /file/{filepath:file else 405}
const (
EOF = iota // 0

View File

@@ -214,14 +214,17 @@ type Map struct {
// string type
// anything
String *Macro
// uint type
// only positive numbers (+0-9)
// it could be uint/uint32 but we keep int for simplicity
Int *Macro
// long an int64 type
// only positive numbers (+0-9)
// it could be uint64 but we keep int64 for simplicity
Long *Macro
// int type
// both positive and negative numbers, any number of digits.
Number *Macro
// int64 as int64 type
// -9223372036854775808 to 9223372036854775807.
Int64 *Macro
// uint64 as uint64 type
// 0 to 18446744073709551615.
Uint64 *Macro
// boolean as bool type
// a string which is "1" or "t" or "T" or "TRUE" or "true" or "True"
// or "0" or "f" or "F" or "FALSE" or "false" or "False".
@@ -247,11 +250,26 @@ type Map struct {
//
// Learn more at: https://github.com/kataras/iris/tree/master/_examples/routing/dynamic-path
func NewMap() *Map {
simpleNumberEvalutator := MustNewEvaluatorFromRegexp("^-?[0-9]+$")
return &Map{
// it allows everything, so no need for a regexp here.
String: newMacro(func(string) bool { return true }),
Int: newMacro(MustNewEvaluatorFromRegexp("^[0-9]+$")),
Long: newMacro(MustNewEvaluatorFromRegexp("^[0-9]+$")),
Number: newMacro(simpleNumberEvalutator), //"^(-?0\\.[0-9]*[1-9]+[0-9]*$)|(^-?[1-9]+[0-9]*((\\.[0-9]*[1-9]+[0-9]*$)|(\\.[0-9]+)))|(^-?[1-9]+[0-9]*$)|(^0$){1}")), //("^-?[0-9]+$")),
Int64: newMacro(func(paramValue string) bool {
if !simpleNumberEvalutator(paramValue) {
return false
}
_, err := strconv.ParseInt(paramValue, 10, 64)
// if err == strconv.ErrRange...
return err == nil
}), //("^-[1-9]|-?[1-9][0-9]{1,14}|-?1000000000000000|-?10000000000000000|-?100000000000000000|-?[1-9]000000000000000000|-?9[0-2]00000000000000000|-?92[0-2]0000000000000000|-?922[0-3]000000000000000|-?9223[0-3]00000000000000|-?92233[0-7]0000000000000|-?922337[0-2]000000000000|-?92233720[0-3]0000000000|-?922337203[0-6]000000000|-?9223372036[0-8]00000000|-?92233720368[0-5]0000000|-?922337203685[0-4]000000|-?9223372036854[0-7]00000|-?92233720368547[0-7]0000|-?922337203685477[0-5]000|-?922337203685477[56]000|[0-9]$")),
Uint64: newMacro(func(paramValue string) bool {
if !simpleNumberEvalutator(paramValue) {
return false
}
_, err := strconv.ParseUint(paramValue, 10, 64)
return err == nil
}), //("^[0-9]|[1-9][0-9]{1,14}|1000000000000000|10000000000000000|100000000000000000|1000000000000000000|1[0-8]000000000000000000|18[0-4]00000000000000000|184[0-4]0000000000000000|1844[0-6]000000000000000|18446[0-7]00000000000000|184467[0-4]0000000000000|1844674[0-4]000000000000|184467440[0-7]0000000000|1844674407[0-3]000000000|18446744073[0-7]00000000|1844674407370000000[0-9]|18446744073709[0-5]00000|184467440737095[0-5]0000|1844674407370955[0-2]000$")),
Boolean: newMacro(func(paramValue string) bool {
// a simple if statement is faster than regex ^(true|false|True|False|t|0|f|FALSE|TRUE)$
// in this case.
@@ -270,14 +288,16 @@ func NewMap() *Map {
// Lookup returns the specific Macro from the map
// based on the parameter type.
// i.e if ast.ParamTypeInt then it will return the m.Int.
// i.e if ast.ParamTypeNumber then it will return the m.Number.
// Returns the m.String if not matched.
func (m *Map) Lookup(typ ast.ParamType) *Macro {
switch typ {
case ast.ParamTypeInt:
return m.Int
case ast.ParamTypeLong:
return m.Long
case ast.ParamTypeNumber:
return m.Number
case ast.ParamTypeInt64:
return m.Int64
case ast.ParamTypeUint64:
return m.Uint64
case ast.ParamTypeBoolean:
return m.Boolean
case ast.ParamTypeAlphabetical:

View File

@@ -64,9 +64,9 @@ func TestGoodParamFuncName(t *testing.T) {
}
}
func testEvaluatorRaw(macroEvaluator *Macro, input string, pass bool, i int, t *testing.T) {
func testEvaluatorRaw(t *testing.T, macroEvaluator *Macro, input string, pass bool, i int) {
if got := macroEvaluator.Evaluator(input); pass != got {
t.Fatalf("tests[%d] - expecting %v but got %v", i, pass, got)
t.Fatalf("%s - tests[%d] - expecting %v but got %v", t.Name(), i, pass, got)
}
}
@@ -86,26 +86,86 @@ func TestStringEvaluatorRaw(t *testing.T) {
} // 0
for i, tt := range tests {
testEvaluatorRaw(f.String, tt.input, tt.pass, i, t)
testEvaluatorRaw(t, f.String, tt.input, tt.pass, i)
}
}
func TestIntEvaluatorRaw(t *testing.T) {
func TestNumberEvaluatorRaw(t *testing.T) {
f := NewMap()
tests := []struct {
pass bool
input string
}{
{false, "astring"}, // 0
{false, "astringwith_numb3rS_and_symbol$"}, // 1
{true, "32321"}, // 2
{false, "main.css"}, // 3
{false, "/assets/main.css"}, // 4
{false, "astring"}, // 0
{false, "astringwith_numb3rS_and_symbol$"}, // 1
{true, "32321"}, // 2
{true, "18446744073709551615"}, // 3
{true, "-18446744073709551615"}, // 4
{true, "-18446744073709553213213213213213121615"}, // 5
{false, "42 18446744073709551615"}, // 6
{false, "--42"}, // 7
{false, "+42"}, // 9
{false, "main.css"}, // 9
{false, "/assets/main.css"}, // 10
}
for i, tt := range tests {
testEvaluatorRaw(f.Int, tt.input, tt.pass, i, t)
testEvaluatorRaw(t, f.Number, tt.input, tt.pass, i)
}
}
func TestInt64EvaluatorRaw(t *testing.T) {
f := NewMap()
tests := []struct {
pass bool
input string
}{
{false, "astring"}, // 0
{false, "astringwith_numb3rS_and_symbol$"}, // 1
{false, "18446744073709551615"}, // 2
{false, "92233720368547758079223372036854775807"}, // 3
{false, "9223372036854775808 9223372036854775808"}, // 4
{false, "main.css"}, // 5
{false, "/assets/main.css"}, // 6
{true, "9223372036854775807"}, // 7
{true, "-9223372036854775808"}, // 8
{true, "-0"}, // 9
{true, "1"}, // 10
{true, "-042"}, // 11
{true, "142"}, // 12
}
for i, tt := range tests {
testEvaluatorRaw(t, f.Int64, tt.input, tt.pass, i)
}
}
func TestUint64EvaluatorRaw(t *testing.T) {
f := NewMap()
tests := []struct {
pass bool
input string
}{
{false, "astring"}, // 0
{false, "astringwith_numb3rS_and_symbol$"}, // 1
{false, "-9223372036854775808"}, // 2
{false, "main.css"}, // 3
{false, "/assets/main.css"}, // 4
{false, "92233720368547758079223372036854775807"}, // 5
{false, "9223372036854775808 9223372036854775808"}, // 6
{false, "-1"}, // 7
{false, "-0"}, // 8
{false, "+1"}, // 9
{true, "18446744073709551615"}, // 10
{true, "9223372036854775807"}, // 11
{true, "0"}, // 12
}
for i, tt := range tests {
testEvaluatorRaw(t, f.Uint64, tt.input, tt.pass, i)
}
}
@@ -124,7 +184,7 @@ func TestAlphabeticalEvaluatorRaw(t *testing.T) {
}
for i, tt := range tests {
testEvaluatorRaw(f.Alphabetical, tt.input, tt.pass, i, t)
testEvaluatorRaw(t, f.Alphabetical, tt.input, tt.pass, i)
}
}
@@ -143,7 +203,7 @@ func TestFileEvaluatorRaw(t *testing.T) {
}
for i, tt := range tests {
testEvaluatorRaw(f.File, tt.input, tt.pass, i, t)
testEvaluatorRaw(t, f.File, tt.input, tt.pass, i)
}
}
@@ -163,7 +223,7 @@ func TestPathEvaluatorRaw(t *testing.T) {
}
for i, tt := range pathTests {
testEvaluatorRaw(f.Path, tt.input, tt.pass, i, t)
testEvaluatorRaw(t, f.Path, tt.input, tt.pass, i)
}
}
@@ -182,5 +242,5 @@ func TestPathEvaluatorRaw(t *testing.T) {
// // p.Params = append(p.)
// testEvaluatorRaw(m.String, p.Src, false, 0, t)
// testEvaluatorRaw(t, m.String, p.Src, false, 0)
// }

View File

@@ -110,10 +110,10 @@ type Party interface {
// otherwise use `Party` which can handle many paths with different handlers and middlewares.
//
// Usage:
// app.HandleMany(iris.MethodGet, "/user /user/{id:int} /user/me", userHandler)
// app.HandleMany(iris.MethodGet, "/user /user/{id:uint64} /user/me", userHandler)
// At the other side, with `Handle` we've had to write:
// app.Handle(iris.MethodGet, "/user", userHandler)
// app.Handle(iris.MethodGet, "/user/{id:int}", userHandler)
// app.Handle(iris.MethodGet, "/user/{id:uint64}", userHandler)
// app.Handle(iris.MethodGet, "/user/me", userHandler)
//
// This method is used behind the scenes at the `Controller` function

View File

@@ -27,8 +27,8 @@ func TestCleanPath(t *testing.T) {
"/total/{year:string regexp(\\d{4})}/more/{s:string regexp(\\d{7})}"},
{"/single_no_params",
"/single_no_params"},
{"/single/{id:int}",
"/single/{id:int}"},
{"/single/{id:uint64}",
"/single/{id:uint64}"},
}
for i, tt := range tests {
@@ -45,14 +45,16 @@ func TestSplitPath(t *testing.T) {
}{
{"/v2/stores/{id:string format(uuid)} /v3",
[]string{"/v2/stores/{id:string format(uuid)}", "/v3"}},
{"/user/{id:int} /admin/{id:int}",
[]string{"/user/{id:int}", "/admin/{id:int}"}},
{"/user/{id:uint64} /admin/{id:uint64}",
[]string{"/user/{id:uint64}", "/admin/{id:uint64}"}},
{"/users/{id:int} /admins/{id:int64}",
[]string{"/users/{id:int}", "/admins/{id:int64}"}},
{"/user /admin",
[]string{"/user", "/admin"}},
{"/single_no_params",
[]string{"/single_no_params"}},
{"/single/{id:int}",
[]string{"/single/{id:int}"}},
{"/single/{id:number}",
[]string{"/single/{id:number}"}},
}
equalSlice := func(s1 []string, s2 []string) bool {

View File

@@ -16,7 +16,7 @@ type Route struct {
Method string `json:"method"` // "GET"
methodBckp string // if Method changed to something else (which is possible at runtime as well, via RefreshRouter) then this field will be filled with the old one.
Subdomain string `json:"subdomain"` // "admin."
tmpl *macro.Template // Tmpl().Src: "/api/user/{id:int}"
tmpl *macro.Template // Tmpl().Src: "/api/user/{id:uint64}"
// temp storage, they're appended to the Handlers on build.
// Execution happens before Handlers, can be empty.
beginHandlers context.Handlers
@@ -198,7 +198,7 @@ func formatPath(path string) string {
// StaticPath returns the static part of the original, registered route path.
// if /user/{id} it will return /user
// if /user/{id}/friend/{friendid:int} it will return /user too
// if /user/{id}/friend/{friendid:uint64} it will return /user too
// if /assets/{filepath:path} it will return /assets.
func (r Route) StaticPath() string {
src := r.tmpl.Src