check for undefined brace captures + make tests parallel
This commit is contained in:
parent
c32b038da2
commit
e7f10723a6
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue