mirror of
https://github.com/kataras/iris.git
synced 2025-12-19 10:57:05 +00:00
Version 11 released. Read https://github.com/kataras/iris/blob/master/HISTORY.md#su-21-october-2018--v1100
Former-commit-id: fe6305deed00e170bf4d39a12c0644fe686e0a24
This commit is contained in:
340
macro/interpreter/parser/parser_test.go
Normal file
340
macro/interpreter/parser/parser_test.go
Normal file
@@ -0,0 +1,340 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/kataras/iris/macro/interpreter/ast"
|
||||
)
|
||||
|
||||
type simpleParamType string
|
||||
|
||||
func (pt simpleParamType) Indent() string { return string(pt) }
|
||||
|
||||
type masterParamType simpleParamType
|
||||
|
||||
func (pt masterParamType) Indent() string { return string(pt) }
|
||||
func (pt masterParamType) Master() bool { return true }
|
||||
|
||||
type wildcardParamType string
|
||||
|
||||
func (pt wildcardParamType) Indent() string { return string(pt) }
|
||||
func (pt wildcardParamType) Trailing() bool { return true }
|
||||
|
||||
type aliasedParamType []string
|
||||
|
||||
func (pt aliasedParamType) Indent() string { return string(pt[0]) }
|
||||
func (pt aliasedParamType) Alias() string { return pt[1] }
|
||||
|
||||
var (
|
||||
paramTypeString = masterParamType("string")
|
||||
paramTypeNumber = aliasedParamType{"number", "int"}
|
||||
paramTypeInt64 = aliasedParamType{"int64", "long"}
|
||||
paramTypeUint8 = simpleParamType("uint8")
|
||||
paramTypeUint64 = simpleParamType("uint64")
|
||||
paramTypeBool = aliasedParamType{"bool", "boolean"}
|
||||
paramTypeAlphabetical = simpleParamType("alphabetical")
|
||||
paramTypeFile = simpleParamType("file")
|
||||
paramTypePath = wildcardParamType("path")
|
||||
)
|
||||
|
||||
var testParamTypes = []ast.ParamType{
|
||||
paramTypeString,
|
||||
paramTypeNumber, paramTypeInt64, paramTypeUint8, paramTypeUint64,
|
||||
paramTypeBool,
|
||||
paramTypeAlphabetical, paramTypeFile, paramTypePath,
|
||||
}
|
||||
|
||||
func TestParseParamError(t *testing.T) {
|
||||
// fail
|
||||
illegalChar := '$'
|
||||
|
||||
input := "{id" + string(illegalChar) + "int range(1,5) else 404}"
|
||||
p := NewParamParser(input)
|
||||
|
||||
_, err := p.Parse(testParamTypes)
|
||||
|
||||
if err == nil {
|
||||
t.Fatalf("expecting not empty error on input '%s'", input)
|
||||
}
|
||||
|
||||
illIdx := strings.IndexRune(input, illegalChar)
|
||||
expectedErr := fmt.Sprintf("[%d:%d] illegal token: %s", illIdx, illIdx, "$")
|
||||
if got := err.Error(); got != expectedErr {
|
||||
t.Fatalf("expecting error to be '%s' but got: %s", expectedErr, got)
|
||||
}
|
||||
//
|
||||
|
||||
// success
|
||||
input2 := "{id:uint64 range(1,5) else 404}"
|
||||
p.Reset(input2)
|
||||
_, err = p.Parse(testParamTypes)
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("expecting empty error on input '%s', but got: %s", input2, err.Error())
|
||||
}
|
||||
//
|
||||
}
|
||||
|
||||
// mustLookupParamType same as `ast.LookupParamType` but it panics if "indent" does not match with a valid Param Type.
|
||||
func mustLookupParamType(indent string) ast.ParamType {
|
||||
pt, found := ast.LookupParamType(indent, testParamTypes...)
|
||||
if !found {
|
||||
panic("param type '" + indent + "' is not part of the provided param types")
|
||||
}
|
||||
|
||||
return pt
|
||||
}
|
||||
|
||||
func TestParseParam(t *testing.T) {
|
||||
tests := []struct {
|
||||
valid bool
|
||||
expectedStatement ast.ParamStatement
|
||||
}{
|
||||
{true,
|
||||
ast.ParamStatement{
|
||||
Src: "{id:int min(1) max(5) else 404}",
|
||||
Name: "id",
|
||||
Type: mustLookupParamType("number"),
|
||||
Funcs: []ast.ParamFunc{
|
||||
{
|
||||
Name: "min",
|
||||
Args: []string{"1"}},
|
||||
{
|
||||
Name: "max",
|
||||
Args: []string{"5"}},
|
||||
},
|
||||
ErrorCode: 404,
|
||||
}}, // 0
|
||||
|
||||
{true,
|
||||
ast.ParamStatement{
|
||||
// test alias of int.
|
||||
Src: "{id:number range(1,5)}",
|
||||
Name: "id",
|
||||
Type: mustLookupParamType("number"),
|
||||
Funcs: []ast.ParamFunc{
|
||||
{
|
||||
Name: "range",
|
||||
Args: []string{"1", "5"}},
|
||||
},
|
||||
ErrorCode: 404,
|
||||
}}, // 1
|
||||
{true,
|
||||
ast.ParamStatement{
|
||||
Src: "{file:path contains(.)}",
|
||||
Name: "file",
|
||||
Type: mustLookupParamType("path"),
|
||||
Funcs: []ast.ParamFunc{
|
||||
{
|
||||
Name: "contains",
|
||||
Args: []string{"."}},
|
||||
},
|
||||
ErrorCode: 404,
|
||||
}}, // 2
|
||||
{true,
|
||||
ast.ParamStatement{
|
||||
Src: "{username:alphabetical}",
|
||||
Name: "username",
|
||||
Type: mustLookupParamType("alphabetical"),
|
||||
ErrorCode: 404,
|
||||
}}, // 3
|
||||
{true,
|
||||
ast.ParamStatement{
|
||||
Src: "{myparam}",
|
||||
Name: "myparam",
|
||||
Type: mustLookupParamType("string"),
|
||||
ErrorCode: 404,
|
||||
}}, // 4
|
||||
{false,
|
||||
ast.ParamStatement{
|
||||
Src: "{myparam_:thisianunexpected}",
|
||||
Name: "myparam_",
|
||||
Type: nil,
|
||||
ErrorCode: 404,
|
||||
}}, // 5
|
||||
{true,
|
||||
ast.ParamStatement{
|
||||
Src: "{myparam2}",
|
||||
Name: "myparam2", // we now allow integers to the parameter names.
|
||||
Type: ast.GetMasterParamType(testParamTypes...),
|
||||
ErrorCode: 404,
|
||||
}}, // 6
|
||||
{true,
|
||||
ast.ParamStatement{
|
||||
Src: "{id:int even()}", // test param funcs without any arguments (LPAREN peek for RPAREN)
|
||||
Name: "id",
|
||||
Type: mustLookupParamType("number"),
|
||||
Funcs: []ast.ParamFunc{
|
||||
{
|
||||
Name: "even"},
|
||||
},
|
||||
ErrorCode: 404,
|
||||
}}, // 7
|
||||
{true,
|
||||
ast.ParamStatement{
|
||||
Src: "{id:int64 else 404}",
|
||||
Name: "id",
|
||||
Type: mustLookupParamType("int64"),
|
||||
ErrorCode: 404,
|
||||
}}, // 8
|
||||
{true,
|
||||
ast.ParamStatement{
|
||||
Src: "{id:long else 404}", // backwards-compatible test.
|
||||
Name: "id",
|
||||
Type: mustLookupParamType("int64"),
|
||||
ErrorCode: 404,
|
||||
}}, // 9
|
||||
{true,
|
||||
ast.ParamStatement{
|
||||
Src: "{id:long else 404}",
|
||||
Name: "id",
|
||||
Type: mustLookupParamType("int64"), // backwards-compatible test of LookupParamType.
|
||||
ErrorCode: 404,
|
||||
}}, // 10
|
||||
{true,
|
||||
ast.ParamStatement{
|
||||
Src: "{has:bool else 404}",
|
||||
Name: "has",
|
||||
Type: mustLookupParamType("bool"),
|
||||
ErrorCode: 404,
|
||||
}}, // 11
|
||||
{true,
|
||||
ast.ParamStatement{
|
||||
Src: "{has:boolean else 404}", // backwards-compatible test.
|
||||
Name: "has",
|
||||
Type: mustLookupParamType("bool"),
|
||||
ErrorCode: 404,
|
||||
}}, // 12
|
||||
|
||||
}
|
||||
|
||||
p := new(ParamParser)
|
||||
for i, tt := range tests {
|
||||
p.Reset(tt.expectedStatement.Src)
|
||||
resultStmt, err := p.Parse(testParamTypes)
|
||||
|
||||
if tt.valid && err != nil {
|
||||
t.Fatalf("tests[%d] - error %s", i, err.Error())
|
||||
} else if !tt.valid && err == nil {
|
||||
t.Fatalf("tests[%d] - expected to be a failure", i)
|
||||
}
|
||||
|
||||
if resultStmt != nil { // is valid here
|
||||
if !reflect.DeepEqual(tt.expectedStatement, *resultStmt) {
|
||||
t.Fatalf("tests[%d] - wrong statement, expected and result differs. Details:\n%#v\n%#v", i, tt.expectedStatement, *resultStmt)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
tests := []struct {
|
||||
path string
|
||||
valid bool
|
||||
expectedStatements []ast.ParamStatement
|
||||
}{
|
||||
{"/api/users/{id:int min(1) max(5) else 404}", true,
|
||||
[]ast.ParamStatement{{
|
||||
Src: "{id:int min(1) max(5) else 404}",
|
||||
Name: "id",
|
||||
Type: paramTypeNumber,
|
||||
Funcs: []ast.ParamFunc{
|
||||
{
|
||||
Name: "min",
|
||||
Args: []string{"1"}},
|
||||
{
|
||||
Name: "max",
|
||||
Args: []string{"5"}},
|
||||
},
|
||||
ErrorCode: 404,
|
||||
},
|
||||
}}, // 0
|
||||
{"/admin/{id:uint64 range(1,5)}", true,
|
||||
[]ast.ParamStatement{{
|
||||
Src: "{id:uint64 range(1,5)}",
|
||||
Name: "id",
|
||||
Type: paramTypeUint64,
|
||||
Funcs: []ast.ParamFunc{
|
||||
{
|
||||
Name: "range",
|
||||
Args: []string{"1", "5"}},
|
||||
},
|
||||
ErrorCode: 404,
|
||||
},
|
||||
}}, // 1
|
||||
{"/files/{file:path contains(.)}", true,
|
||||
[]ast.ParamStatement{{
|
||||
Src: "{file:path contains(.)}",
|
||||
Name: "file",
|
||||
Type: paramTypePath,
|
||||
Funcs: []ast.ParamFunc{
|
||||
{
|
||||
Name: "contains",
|
||||
Args: []string{"."}},
|
||||
},
|
||||
ErrorCode: 404,
|
||||
},
|
||||
}}, // 2
|
||||
{"/profile/{username:alphabetical}", true,
|
||||
[]ast.ParamStatement{{
|
||||
Src: "{username:alphabetical}",
|
||||
Name: "username",
|
||||
Type: paramTypeAlphabetical,
|
||||
ErrorCode: 404,
|
||||
},
|
||||
}}, // 3
|
||||
{"/something/here/{myparam}", true,
|
||||
[]ast.ParamStatement{{
|
||||
Src: "{myparam}",
|
||||
Name: "myparam",
|
||||
Type: paramTypeString,
|
||||
ErrorCode: 404,
|
||||
},
|
||||
}}, // 4
|
||||
{"/unexpected/{myparam_:thisianunexpected}", false,
|
||||
[]ast.ParamStatement{{
|
||||
Src: "{myparam_:thisianunexpected}",
|
||||
Name: "myparam_",
|
||||
Type: nil,
|
||||
ErrorCode: 404,
|
||||
},
|
||||
}}, // 5
|
||||
{"/p2/{myparam2}", true,
|
||||
[]ast.ParamStatement{{
|
||||
Src: "{myparam2}",
|
||||
Name: "myparam2", // we now allow integers to the parameter names.
|
||||
Type: paramTypeString,
|
||||
ErrorCode: 404,
|
||||
},
|
||||
}}, // 6
|
||||
{"/assets/{file:path}/invalid", false, // path should be in the end segment
|
||||
[]ast.ParamStatement{{
|
||||
Src: "{file:path}",
|
||||
Name: "file",
|
||||
Type: paramTypePath,
|
||||
ErrorCode: 404,
|
||||
},
|
||||
}}, // 7
|
||||
}
|
||||
for i, tt := range tests {
|
||||
statements, err := Parse(tt.path, testParamTypes)
|
||||
|
||||
if tt.valid && err != nil {
|
||||
t.Fatalf("tests[%d] - error %s", i, err.Error())
|
||||
} else if !tt.valid && err == nil {
|
||||
t.Fatalf("tests[%d] - expected to be a failure", i)
|
||||
}
|
||||
for j := range statements {
|
||||
for l := range tt.expectedStatements {
|
||||
if !reflect.DeepEqual(tt.expectedStatements[l], *statements[j]) {
|
||||
t.Fatalf("tests[%d] - wrong statements, expected and result differs. Details:\n%#v\n%#v", i, tt.expectedStatements[l], *statements[j])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user