goyave.dev/goyave/v4@v4.4.11/route_test.go (about)

     1  package goyave
     2  
     3  import (
     4  	"net/http"
     5  	"net/http/httptest"
     6  	"regexp"
     7  	"testing"
     8  
     9  	"goyave.dev/goyave/v4/validation"
    10  )
    11  
    12  type RouteTestSuite struct {
    13  	TestSuite
    14  }
    15  
    16  func (suite *RouteTestSuite) TestNewRoute() {
    17  	route := newRoute(func(resp *Response, r *Request) {})
    18  	suite.NotNil(route)
    19  	suite.NotNil(route.handler)
    20  }
    21  
    22  func (suite *RouteTestSuite) TestMakeParameters() {
    23  	regexCache := make(map[string]*regexp.Regexp, 5)
    24  	route := newRoute(func(resp *Response, r *Request) {})
    25  	route.compileParameters("/product/{id:[0-9]+}", true, regexCache)
    26  	suite.Equal([]string{"id"}, route.parameters)
    27  	suite.NotNil(route.regex)
    28  	suite.True(route.regex.MatchString("/product/666"))
    29  	suite.False(route.regex.MatchString("/product/"))
    30  	suite.False(route.regex.MatchString("/product/qwerty"))
    31  }
    32  
    33  func (suite *RouteTestSuite) TestMatch() {
    34  	regexCache := make(map[string]*regexp.Regexp, 5)
    35  	handler := func(resp *Response, r *Request) {
    36  		resp.String(http.StatusOK, "Success")
    37  	}
    38  	route := &Route{
    39  		name:            "test-route",
    40  		uri:             "/product/{id:[0-9]+}",
    41  		methods:         []string{"GET", "POST"},
    42  		parent:          nil,
    43  		handler:         handler,
    44  		validationRules: nil,
    45  	}
    46  	route.compileParameters(route.uri, true, regexCache)
    47  
    48  	rawRequest := httptest.NewRequest("GET", "/product/33", nil)
    49  	match := routeMatch{currentPath: rawRequest.URL.Path}
    50  	suite.True(route.match(rawRequest, &match))
    51  	suite.Equal("33", match.parameters["id"])
    52  
    53  	rawRequest = httptest.NewRequest("POST", "/product/33", nil)
    54  	match = routeMatch{currentPath: rawRequest.URL.Path}
    55  	suite.True(route.match(rawRequest, &match))
    56  	suite.Equal("33", match.parameters["id"])
    57  
    58  	rawRequest = httptest.NewRequest("PUT", "/product/33", nil)
    59  	match = routeMatch{currentPath: rawRequest.URL.Path}
    60  	suite.False(route.match(rawRequest, &match))
    61  	suite.Equal(errMatchMethodNotAllowed, match.err)
    62  
    63  	// Test error has not been overridden
    64  	rawRequest = httptest.NewRequest("PUT", "/product/test", nil)
    65  	suite.False(route.match(rawRequest, &match))
    66  	suite.Equal(errMatchMethodNotAllowed, match.err)
    67  
    68  	match = routeMatch{currentPath: rawRequest.URL.Path}
    69  	suite.False(route.match(rawRequest, &match))
    70  	suite.Equal(errMatchNotFound, match.err)
    71  
    72  	route = &Route{
    73  		name:            "test-route",
    74  		uri:             "/product/{id:[0-9]+}/{name}",
    75  		methods:         []string{"GET"},
    76  		parent:          nil,
    77  		handler:         handler,
    78  		validationRules: nil,
    79  	}
    80  	route.compileParameters(route.uri, true, regexCache)
    81  	rawRequest = httptest.NewRequest("GET", "/product/666/test", nil)
    82  	match = routeMatch{currentPath: rawRequest.URL.Path}
    83  	suite.True(route.match(rawRequest, &match))
    84  	suite.Equal("666", match.parameters["id"])
    85  	suite.Equal("test", match.parameters["name"])
    86  
    87  	route = &Route{
    88  		name:            "test-route",
    89  		uri:             "/categories/{category}/{sort:(?:asc|desc|new)}",
    90  		methods:         []string{"GET"},
    91  		parent:          nil,
    92  		handler:         handler,
    93  		validationRules: nil,
    94  	}
    95  	route.compileParameters(route.uri, true, regexCache)
    96  	rawRequest = httptest.NewRequest("GET", "/categories/lawn-mower/asc", nil)
    97  	match = routeMatch{currentPath: rawRequest.URL.Path}
    98  	suite.True(route.match(rawRequest, &match))
    99  	suite.Equal("lawn-mower", match.parameters["category"])
   100  	suite.Equal("asc", match.parameters["sort"])
   101  
   102  	rawRequest = httptest.NewRequest("GET", "/categories/lawn-mower/notsort", nil)
   103  	match = routeMatch{currentPath: rawRequest.URL.Path}
   104  	suite.False(route.match(rawRequest, &match))
   105  }
   106  
   107  func (suite *RouteTestSuite) TestAccessors() {
   108  	route := &Route{
   109  		name:    "route-name",
   110  		uri:     "/product/{id:[0-9+]}",
   111  		parent:  NewRouter(),
   112  		methods: []string{"GET", "POST"},
   113  	}
   114  
   115  	suite.Equal("route-name", route.GetName())
   116  
   117  	suite.Panics(func() {
   118  		route.Name("new-name") // Cannot re-set name
   119  	})
   120  
   121  	route = &Route{
   122  		name:    "",
   123  		uri:     "/product/{id:[0-9+]}",
   124  		parent:  NewRouter(),
   125  		methods: []string{"GET", "POST"},
   126  	}
   127  	route.Name("new-name")
   128  	suite.Equal("new-name", route.GetName())
   129  
   130  	suite.Equal("/product/{id:[0-9+]}", route.GetURI())
   131  	suite.Equal([]string{"GET", "POST"}, route.GetMethods())
   132  }
   133  
   134  func (suite *RouteTestSuite) TestGetFullURIAndParameters() {
   135  	router := NewRouter().Subrouter("/product").Subrouter("/{id:[0-9+]}")
   136  	route := router.Route("GET|POST", "/{name}/accessories", func(resp *Response, r *Request) {}).Name("route-name")
   137  
   138  	uri, params := route.GetFullURIAndParameters()
   139  	suite.Equal("/product/{id:[0-9+]}/{name}/accessories", uri)
   140  	suite.Equal([]string{"id", "name"}, params)
   141  }
   142  
   143  func (suite *RouteTestSuite) TestGetFullURI() {
   144  	router := NewRouter().Subrouter("/product").Subrouter("/{id:[0-9+]}")
   145  	route := router.Route("GET|POST", "/{name}/accessories", func(resp *Response, r *Request) {}).Name("route-name")
   146  
   147  	suite.Equal("/product/{id:[0-9+]}/{name}/accessories", route.GetFullURI())
   148  }
   149  
   150  func (suite *RouteTestSuite) TestBuildURI() {
   151  	regexCache := make(map[string]*regexp.Regexp, 5)
   152  	route := &Route{
   153  		name:    "route-name",
   154  		uri:     "/product/{id:[0-9+]}",
   155  		methods: []string{"GET", "POST"},
   156  	}
   157  	route.compileParameters(route.uri, true, regexCache)
   158  	suite.Equal("/product/42", route.BuildURI("42"))
   159  
   160  	suite.Panics(func() {
   161  		route.BuildURI()
   162  	})
   163  	suite.Panics(func() {
   164  		route.BuildURI("42", "more")
   165  	})
   166  
   167  	route = &Route{
   168  		name:    "route-name",
   169  		uri:     "/product/{id:[0-9+]}/{name}/accessories",
   170  		methods: []string{"GET", "POST"},
   171  	}
   172  	route.compileParameters(route.uri, true, regexCache)
   173  	suite.Equal("/product/42/screwdriver/accessories", route.BuildURI("42", "screwdriver"))
   174  
   175  	router := NewRouter().Subrouter("/product").Subrouter("/{id:[0-9+]}")
   176  	route = router.Route("GET|POST", "/{name}/accessories", func(resp *Response, r *Request) {}).Name("route-name")
   177  
   178  	suite.Equal("/product/42/screwdriver/accessories", route.BuildURI("42", "screwdriver"))
   179  }
   180  
   181  func (suite *RouteTestSuite) TestBuildURL() {
   182  	regexCache := make(map[string]*regexp.Regexp, 5)
   183  	route := &Route{
   184  		name:    "route-name",
   185  		uri:     "/product/{id:[0-9+]}",
   186  		methods: []string{"GET", "POST"},
   187  	}
   188  	route.compileParameters(route.uri, true, regexCache)
   189  	suite.Equal("http://127.0.0.1:1235/product/42", route.BuildURL("42"))
   190  
   191  	suite.Panics(func() {
   192  		route.BuildURL()
   193  	})
   194  	suite.Panics(func() {
   195  		route.BuildURL("42", "more")
   196  	})
   197  
   198  	route = &Route{
   199  		name:    "route-name",
   200  		uri:     "/product/{id:[0-9+]}/{name}/accessories",
   201  		methods: []string{"GET", "POST"},
   202  	}
   203  	route.compileParameters(route.uri, true, regexCache)
   204  	suite.Equal("http://127.0.0.1:1235/product/42/screwdriver/accessories", route.BuildURL("42", "screwdriver"))
   205  
   206  	router := NewRouter().Subrouter("/product").Subrouter("/{id:[0-9+]}")
   207  	route = router.Route("GET|POST", "/{name}/accessories", func(resp *Response, r *Request) {}).Name("route-name")
   208  
   209  	suite.Equal("http://127.0.0.1:1235/product/42/screwdriver/accessories", route.BuildURL("42", "screwdriver"))
   210  }
   211  
   212  func (suite *RouteTestSuite) TestValidate() {
   213  	route := &Route{
   214  		name:    "route-name",
   215  		uri:     "/product/{id:[0-9+]}",
   216  		methods: []string{"GET", "POST"},
   217  	}
   218  	rules := &validation.Rules{
   219  		Fields: validation.FieldMap{
   220  			"field": &validation.Field{
   221  				Rules: []*validation.Rule{
   222  					{Name: "required"},
   223  					{Name: "string"},
   224  				},
   225  			},
   226  		},
   227  	}
   228  	route.Validate(rules)
   229  	suite.Equal(rules, route.validationRules)
   230  }
   231  
   232  func (suite *RouteTestSuite) TestMiddleware() {
   233  	route := &Route{
   234  		name:    "route-name",
   235  		uri:     "/product/{id:[0-9+]}",
   236  		methods: []string{"GET", "POST"},
   237  	}
   238  	middelware := func(next Handler) Handler {
   239  		return func(response *Response, r *Request) {}
   240  	}
   241  	middelware2 := func(next Handler) Handler {
   242  		return func(response *Response, r *Request) {}
   243  	}
   244  	route.Middleware(middelware, middelware2)
   245  	suite.Len(route.middleware, 2)
   246  }
   247  
   248  func (suite *RouteTestSuite) TestGetHandler() {
   249  	executed := false
   250  	route := &Route{
   251  		name:    "route-name",
   252  		uri:     "/product/{id:[0-9+]}",
   253  		methods: []string{"GET", "POST"},
   254  		handler: func(resp *Response, r *Request) {
   255  			executed = true
   256  		},
   257  	}
   258  	handler := route.GetHandler()
   259  	suite.NotNil(handler)
   260  	handler(nil, nil)
   261  	suite.True(executed)
   262  }
   263  
   264  func (suite *RouteTestSuite) TestGetValidationRules() {
   265  	route := &Route{
   266  		name:    "route-name",
   267  		uri:     "/product/{id:[0-9+]}",
   268  		methods: []string{"GET", "POST"},
   269  	}
   270  	rules := &validation.Rules{
   271  		Fields: validation.FieldMap{
   272  			"email": &validation.Field{
   273  				Rules: []*validation.Rule{
   274  					{Name: "required"},
   275  					{Name: "string"},
   276  					{Name: "between", Params: []string{"3", "125"}},
   277  					{Name: "email"},
   278  				},
   279  			},
   280  		},
   281  	}
   282  	route.Validate(rules)
   283  
   284  	suite.Same(rules, route.GetValidationRules())
   285  }
   286  
   287  func TestRouteTestSuite(t *testing.T) {
   288  	RunTest(t, new(RouteTestSuite))
   289  }