check for undefined brace captures + make tests parallel

This commit is contained in:
Adrien Marquès 2020-03-16 10:56:26 +01:00
parent c32b038da2
commit e7f10723a6
Signed by: xdrm-brackets
GPG Key ID: D75243CA236D825E
4 changed files with 94 additions and 14 deletions

View File

@ -12,6 +12,8 @@ import (
) )
func TestLegalServiceName(t *testing.T) { func TestLegalServiceName(t *testing.T) {
t.Parallel()
tests := []struct { tests := []struct {
Raw string Raw string
Error error Error error
@ -51,7 +53,7 @@ func TestLegalServiceName(t *testing.T) {
}, },
{ {
`[ { "method": "GET", "info": "a", "path": "/invalid/{braces}" } ]`, `[ { "method": "GET", "info": "a", "path": "/invalid/{braces}" } ]`,
nil, ErrUndefinedBraceCapture,
}, },
{ {
`[ { "method": "GET", "info": "a", "path": "/invalid/s{braces}/abc" } ]`, `[ { "method": "GET", "info": "a", "path": "/invalid/s{braces}/abc" } ]`,
@ -63,7 +65,7 @@ func TestLegalServiceName(t *testing.T) {
}, },
{ {
`[ { "method": "GET", "info": "a", "path": "/invalid/{braces}/abc" } ]`, `[ { "method": "GET", "info": "a", "path": "/invalid/{braces}/abc" } ]`,
nil, ErrUndefinedBraceCapture,
}, },
{ {
`[ { "method": "GET", "info": "a", "path": "/invalid/{b{races}s/abc" } ]`, `[ { "method": "GET", "info": "a", "path": "/invalid/{b{races}s/abc" } ]`,
@ -99,6 +101,7 @@ func TestLegalServiceName(t *testing.T) {
} }
} }
func TestAvailableMethods(t *testing.T) { func TestAvailableMethods(t *testing.T) {
t.Parallel()
tests := []struct { tests := []struct {
Raw string Raw string
ValidMethod bool ValidMethod bool
@ -146,6 +149,7 @@ func TestAvailableMethods(t *testing.T) {
} }
} }
func TestParseEmpty(t *testing.T) { func TestParseEmpty(t *testing.T) {
t.Parallel()
reader := strings.NewReader(`[]`) reader := strings.NewReader(`[]`)
_, err := Parse(reader) _, err := Parse(reader)
if err != nil { if err != nil {
@ -167,6 +171,7 @@ func TestParseJsonError(t *testing.T) {
} }
func TestParseMissingMethodDescription(t *testing.T) { func TestParseMissingMethodDescription(t *testing.T) {
t.Parallel()
tests := []struct { tests := []struct {
Raw string Raw string
ValidDescription bool ValidDescription bool
@ -217,6 +222,7 @@ func TestParseMissingMethodDescription(t *testing.T) {
} }
func TestParamEmptyRenameNoRename(t *testing.T) { func TestParamEmptyRenameNoRename(t *testing.T) {
t.Parallel()
reader := strings.NewReader(`[ reader := strings.NewReader(`[
{ {
"method": "GET", "method": "GET",
@ -247,6 +253,7 @@ func TestParamEmptyRenameNoRename(t *testing.T) {
} }
func TestOptionalParam(t *testing.T) { func TestOptionalParam(t *testing.T) {
t.Parallel()
reader := strings.NewReader(`[ reader := strings.NewReader(`[
{ {
"method": "GET", "method": "GET",
@ -288,6 +295,7 @@ func TestOptionalParam(t *testing.T) {
} }
func TestParseParameters(t *testing.T) { func TestParseParameters(t *testing.T) {
t.Parallel()
tests := []struct { tests := []struct {
Raw string Raw string
Error error Error error
@ -473,6 +481,57 @@ func TestParseParameters(t *testing.T) {
]`, ]`,
nil, nil,
}, },
{ // URI parameter
`[
{
"method": "GET",
"path": "/{uri}",
"info": "info",
"in": {
"{uri}": { "info": "valid", "type": "any", "name": "freename" }
}
}
]`,
nil,
},
{ // URI parameter cannot be optional
`[
{
"method": "GET",
"path": "/{uri}",
"info": "info",
"in": {
"{uri}": { "info": "valid", "type": "?any", "name": "freename" }
}
}
]`,
ErrIllegalOptionalURIParam,
},
{ // URI parameter not specified
`[
{
"method": "GET",
"path": "/",
"info": "info",
"in": {
"{uri}": { "info": "valid", "type": "?any", "name": "freename" }
}
}
]`,
ErrUnspecifiedBraceCapture,
},
{ // URI parameter not defined
`[
{
"method": "GET",
"path": "/{uri}",
"info": "info",
"in": { }
}
]`,
ErrUndefinedBraceCapture,
},
} }
for i, test := range tests { for i, test := range tests {
@ -501,6 +560,7 @@ func TestParseParameters(t *testing.T) {
} }
func TestMatchSimple(t *testing.T) { func TestMatchSimple(t *testing.T) {
t.Parallel()
tests := []struct { tests := []struct {
Config string Config string
URL string URL string

View File

@ -29,9 +29,15 @@ const ErrInvalidPatternBraceCapture = Error("invalid uri capturing braces")
// ErrUnspecifiedBraceCapture - a parameter brace capture is not specified in the pattern // ErrUnspecifiedBraceCapture - a parameter brace capture is not specified in the pattern
const ErrUnspecifiedBraceCapture = Error("capturing brace missing in the path") const ErrUnspecifiedBraceCapture = Error("capturing brace missing in the path")
// ErrUndefinedBraceCapture - a parameter brace capture in the pattern is not defined in parameters
const ErrUndefinedBraceCapture = Error("capturing brace missing input definition")
// ErrMissingDescription - a service is missing its description // ErrMissingDescription - a service is missing its description
const ErrMissingDescription = Error("missing description") const ErrMissingDescription = Error("missing description")
// ErrIllegalOptionalURIParam - an URI parameter cannot be optional
const ErrIllegalOptionalURIParam = Error("URI parameter cannot be optional")
// ErrMissingParamDesc - a parameter is missing its description // ErrMissingParamDesc - a parameter is missing its description
const ErrMissingParamDesc = Error("missing parameter description") const ErrMissingParamDesc = Error("missing parameter description")

View File

@ -40,6 +40,17 @@ func Parse(r io.Reader, dtypes ...datatype.T) (*Server, error) {
return server, nil return server, nil
} }
// Find a service matching an incoming HTTP request
func (server Server) Find(r *http.Request) *Service {
for _, service := range server.Services {
if matches := service.Match(r); matches {
return service
}
}
return nil
}
// collide returns if there is collision between services // collide returns if there is collision between services
func (server *Server) collide() error { func (server *Server) collide() error {
length := len(server.Services) length := len(server.Services)
@ -120,17 +131,6 @@ func (server *Server) collide() error {
return nil return nil
} }
// Find a service matching an incoming HTTP request
func (server Server) Find(r *http.Request) *Service {
for _, service := range server.Services {
if matches := service.Match(r); matches {
return service
}
}
return nil
}
// checkAndFormat checks for errors and missing fields and sets default values for optional fields. // checkAndFormat checks for errors and missing fields and sets default values for optional fields.
func (server Server) checkAndFormat() error { func (server Server) checkAndFormat() error {
for _, service := range server.Services { for _, service := range server.Services {
@ -159,6 +159,13 @@ func (server Server) checkAndFormat() error {
return fmt.Errorf("%s '%s' [in]: %w", service.Method, service.Pattern, err) return fmt.Errorf("%s '%s' [in]: %w", service.Method, service.Pattern, err)
} }
// fail if a brace capture remains undefined
for _, capture := range service.Captures {
if capture.Ref == nil {
return fmt.Errorf("%s '%s' [in]: %s: %w", service.Method, service.Pattern, capture.Name, ErrUndefinedBraceCapture)
}
}
} }
return nil return nil
} }

View File

@ -100,7 +100,8 @@ func (svc *Service) checkAndFormatInput(types []datatype.T) error {
return fmt.Errorf("%s: %w", paramName, ErrIllegalParamName) return fmt.Errorf("%s: %w", paramName, ErrIllegalParamName)
} }
// fail if brace does not exists in pattern // fail if brace capture does not exists in pattern
iscapture := false
if matches := braceRegex.FindAllStringSubmatch(paramName, -1); len(matches) > 0 && len(matches[0]) > 1 { if matches := braceRegex.FindAllStringSubmatch(paramName, -1); len(matches) > 0 && len(matches[0]) > 1 {
braceName := matches[0][1] braceName := matches[0][1]
@ -115,6 +116,7 @@ func (svc *Service) checkAndFormatInput(types []datatype.T) error {
if !found { if !found {
return fmt.Errorf("%s: %w", paramName, ErrUnspecifiedBraceCapture) return fmt.Errorf("%s: %w", paramName, ErrUnspecifiedBraceCapture)
} }
iscapture = true
} }
// use param name if no rename // use param name if no rename
@ -127,6 +129,11 @@ func (svc *Service) checkAndFormatInput(types []datatype.T) error {
return fmt.Errorf("%s: %w", paramName, err) return fmt.Errorf("%s: %w", paramName, err)
} }
// capture parameter cannot be optional
if iscapture && param.Optional {
return fmt.Errorf("%s: %w", paramName, ErrIllegalOptionalURIParam)
}
if !param.assignDataType(types) { if !param.assignDataType(types) {
return fmt.Errorf("%s: %w", paramName, ErrUnknownDataType) return fmt.Errorf("%s: %w", paramName, ErrUnknownDataType)
} }