github.com/gofiber/fiber/v2@v2.47.0/path_test.go (about)

     1  // ⚡️ Fiber is an Express inspired web framework written in Go with ☕️
     2  // 📝 Github Repository: https://github.com/gofiber/fiber
     3  // 📌 API Documentation: https://docs.gofiber.io
     4  
     5  package fiber
     6  
     7  import (
     8  	"fmt"
     9  	"testing"
    10  
    11  	"github.com/gofiber/fiber/v2/utils"
    12  )
    13  
    14  // go test -race -run Test_Path_parseRoute
    15  func Test_Path_parseRoute(t *testing.T) {
    16  	t.Parallel()
    17  	var rp routeParser
    18  
    19  	rp = parseRoute("/shop/product/::filter/color::color/size::size")
    20  	utils.AssertEqual(t, routeParser{
    21  		segs: []*routeSegment{
    22  			{Const: "/shop/product/:", Length: 15},
    23  			{IsParam: true, ParamName: "filter", ComparePart: "/color:", PartCount: 1},
    24  			{Const: "/color:", Length: 7},
    25  			{IsParam: true, ParamName: "color", ComparePart: "/size:", PartCount: 1},
    26  			{Const: "/size:", Length: 6},
    27  			{IsParam: true, ParamName: "size", IsLast: true},
    28  		},
    29  		params: []string{"filter", "color", "size"},
    30  	}, rp)
    31  
    32  	rp = parseRoute("/api/v1/:param/abc/*")
    33  	utils.AssertEqual(t, routeParser{
    34  		segs: []*routeSegment{
    35  			{Const: "/api/v1/", Length: 8},
    36  			{IsParam: true, ParamName: "param", ComparePart: "/abc", PartCount: 1},
    37  			{Const: "/abc/", Length: 5, HasOptionalSlash: true},
    38  			{IsParam: true, ParamName: "*1", IsGreedy: true, IsOptional: true, IsLast: true},
    39  		},
    40  		params:        []string{"param", "*1"},
    41  		wildCardCount: 1,
    42  	}, rp)
    43  
    44  	rp = parseRoute("/v1/some/resource/name\\:customVerb")
    45  	utils.AssertEqual(t, routeParser{
    46  		segs: []*routeSegment{
    47  			{Const: "/v1/some/resource/name:customVerb", Length: 33, IsLast: true},
    48  		},
    49  		params: nil,
    50  	}, rp)
    51  
    52  	rp = parseRoute("/v1/some/resource/:name\\:customVerb")
    53  	utils.AssertEqual(t, routeParser{
    54  		segs: []*routeSegment{
    55  			{Const: "/v1/some/resource/", Length: 18},
    56  			{IsParam: true, ParamName: "name", ComparePart: ":customVerb", PartCount: 1},
    57  			{Const: ":customVerb", Length: 11, IsLast: true},
    58  		},
    59  		params: []string{"name"},
    60  	}, rp)
    61  
    62  	// heavy test with escaped charaters
    63  	rp = parseRoute("/v1/some/resource/name\\\\:customVerb?\\?/:param/*")
    64  	utils.AssertEqual(t, routeParser{
    65  		segs: []*routeSegment{
    66  			{Const: "/v1/some/resource/name:customVerb??/", Length: 36},
    67  			{IsParam: true, ParamName: "param", ComparePart: "/", PartCount: 1},
    68  			{Const: "/", Length: 1, HasOptionalSlash: true},
    69  			{IsParam: true, ParamName: "*1", IsGreedy: true, IsOptional: true, IsLast: true},
    70  		},
    71  		params:        []string{"param", "*1"},
    72  		wildCardCount: 1,
    73  	}, rp)
    74  
    75  	rp = parseRoute("/api/*/:param/:param2")
    76  	utils.AssertEqual(t, routeParser{
    77  		segs: []*routeSegment{
    78  			{Const: "/api/", Length: 5, HasOptionalSlash: true},
    79  			{IsParam: true, ParamName: "*1", IsGreedy: true, IsOptional: true, ComparePart: "/", PartCount: 2},
    80  			{Const: "/", Length: 1},
    81  			{IsParam: true, ParamName: "param", ComparePart: "/", PartCount: 1},
    82  			{Const: "/", Length: 1},
    83  			{IsParam: true, ParamName: "param2", IsLast: true},
    84  		},
    85  		params:        []string{"*1", "param", "param2"},
    86  		wildCardCount: 1,
    87  	}, rp)
    88  
    89  	rp = parseRoute("/test:optional?:optional2?")
    90  	utils.AssertEqual(t, routeParser{
    91  		segs: []*routeSegment{
    92  			{Const: "/test", Length: 5},
    93  			{IsParam: true, ParamName: "optional", IsOptional: true, Length: 1},
    94  			{IsParam: true, ParamName: "optional2", IsOptional: true, IsLast: true},
    95  		},
    96  		params: []string{"optional", "optional2"},
    97  	}, rp)
    98  
    99  	rp = parseRoute("/config/+.json")
   100  	utils.AssertEqual(t, routeParser{
   101  		segs: []*routeSegment{
   102  			{Const: "/config/", Length: 8},
   103  			{IsParam: true, ParamName: "+1", IsGreedy: true, IsOptional: false, ComparePart: ".json", PartCount: 1},
   104  			{Const: ".json", Length: 5, IsLast: true},
   105  		},
   106  		params:    []string{"+1"},
   107  		plusCount: 1,
   108  	}, rp)
   109  
   110  	rp = parseRoute("/api/:day.:month?.:year?")
   111  	utils.AssertEqual(t, routeParser{
   112  		segs: []*routeSegment{
   113  			{Const: "/api/", Length: 5},
   114  			{IsParam: true, ParamName: "day", IsOptional: false, ComparePart: ".", PartCount: 2},
   115  			{Const: ".", Length: 1},
   116  			{IsParam: true, ParamName: "month", IsOptional: true, ComparePart: ".", PartCount: 1},
   117  			{Const: ".", Length: 1},
   118  			{IsParam: true, ParamName: "year", IsOptional: true, IsLast: true},
   119  		},
   120  		params: []string{"day", "month", "year"},
   121  	}, rp)
   122  
   123  	rp = parseRoute("/*v1*/proxy")
   124  	utils.AssertEqual(t, routeParser{
   125  		segs: []*routeSegment{
   126  			{Const: "/", Length: 1, HasOptionalSlash: true},
   127  			{IsParam: true, ParamName: "*1", IsGreedy: true, IsOptional: true, ComparePart: "v1", PartCount: 1},
   128  			{Const: "v1", Length: 2},
   129  			{IsParam: true, ParamName: "*2", IsGreedy: true, IsOptional: true, ComparePart: "/proxy", PartCount: 1},
   130  			{Const: "/proxy", Length: 6, IsLast: true},
   131  		},
   132  		params:        []string{"*1", "*2"},
   133  		wildCardCount: 2,
   134  	}, rp)
   135  }
   136  
   137  // go test -race -run Test_Path_matchParams
   138  func Test_Path_matchParams(t *testing.T) {
   139  	t.Parallel()
   140  	var ctxParams [maxParams]string
   141  	testCaseFn := func(testCollection routeCaseCollection) {
   142  		parser := parseRoute(testCollection.pattern)
   143  		for _, c := range testCollection.testCases {
   144  			match := parser.getMatch(c.url, c.url, &ctxParams, c.partialCheck)
   145  			utils.AssertEqual(t, c.match, match, fmt.Sprintf("route: '%s', url: '%s'", testCollection.pattern, c.url))
   146  			if match && len(c.params) > 0 {
   147  				utils.AssertEqual(t, c.params[0:len(c.params)], ctxParams[0:len(c.params)], fmt.Sprintf("route: '%s', url: '%s'", testCollection.pattern, c.url))
   148  			}
   149  		}
   150  	}
   151  	for _, testCaseCollection := range routeTestCases {
   152  		testCaseFn(testCaseCollection)
   153  	}
   154  }
   155  
   156  // go test -race -run Test_RoutePatternMatch
   157  func Test_RoutePatternMatch(t *testing.T) {
   158  	t.Parallel()
   159  	testCaseFn := func(pattern string, cases []routeTestCase) {
   160  		for _, c := range cases {
   161  			// skip all cases for partial checks
   162  			if c.partialCheck {
   163  				continue
   164  			}
   165  			match := RoutePatternMatch(c.url, pattern)
   166  			utils.AssertEqual(t, c.match, match, fmt.Sprintf("route: '%s', url: '%s'", pattern, c.url))
   167  		}
   168  	}
   169  	for _, testCase := range routeTestCases {
   170  		testCaseFn(testCase.pattern, testCase.testCases)
   171  	}
   172  }
   173  
   174  func Test_Utils_GetTrimmedParam(t *testing.T) {
   175  	t.Parallel()
   176  	res := GetTrimmedParam("")
   177  	utils.AssertEqual(t, "", res)
   178  	res = GetTrimmedParam("*")
   179  	utils.AssertEqual(t, "*", res)
   180  	res = GetTrimmedParam(":param")
   181  	utils.AssertEqual(t, "param", res)
   182  	res = GetTrimmedParam(":param1?")
   183  	utils.AssertEqual(t, "param1", res)
   184  	res = GetTrimmedParam("noParam")
   185  	utils.AssertEqual(t, "noParam", res)
   186  }
   187  
   188  func Test_Utils_RemoveEscapeChar(t *testing.T) {
   189  	t.Parallel()
   190  	res := RemoveEscapeChar(":test\\:bla")
   191  	utils.AssertEqual(t, ":test:bla", res)
   192  	res = RemoveEscapeChar("\\abc")
   193  	utils.AssertEqual(t, "abc", res)
   194  	res = RemoveEscapeChar("noEscapeChar")
   195  	utils.AssertEqual(t, "noEscapeChar", res)
   196  }
   197  
   198  // go test -race -run Test_Path_matchParams
   199  func Benchmark_Path_matchParams(t *testing.B) {
   200  	var ctxParams [maxParams]string
   201  	benchCaseFn := func(testCollection routeCaseCollection) {
   202  		parser := parseRoute(testCollection.pattern)
   203  		for _, c := range testCollection.testCases {
   204  			var matchRes bool
   205  			state := "match"
   206  			if !c.match {
   207  				state = "not match"
   208  			}
   209  			t.Run(testCollection.pattern+" | "+state+" | "+c.url, func(b *testing.B) {
   210  				for i := 0; i <= b.N; i++ {
   211  					if match := parser.getMatch(c.url, c.url, &ctxParams, c.partialCheck); match {
   212  						// Get testCases from the original path
   213  						matchRes = true
   214  					}
   215  				}
   216  				utils.AssertEqual(t, c.match, matchRes, fmt.Sprintf("route: '%s', url: '%s'", testCollection.pattern, c.url))
   217  				if matchRes && len(c.params) > 0 {
   218  					utils.AssertEqual(t, c.params[0:len(c.params)-1], ctxParams[0:len(c.params)-1], fmt.Sprintf("route: '%s', url: '%s'", testCollection.pattern, c.url))
   219  				}
   220  			})
   221  		}
   222  	}
   223  
   224  	for _, testCollection := range benchmarkCases {
   225  		benchCaseFn(testCollection)
   226  	}
   227  }
   228  
   229  // go test -race -run Test_RoutePatternMatch
   230  func Benchmark_RoutePatternMatch(t *testing.B) {
   231  	benchCaseFn := func(testCollection routeCaseCollection) {
   232  		for _, c := range testCollection.testCases {
   233  			// skip all cases for partial checks
   234  			if c.partialCheck {
   235  				continue
   236  			}
   237  			var matchRes bool
   238  			state := "match"
   239  			if !c.match {
   240  				state = "not match"
   241  			}
   242  			t.Run(testCollection.pattern+" | "+state+" | "+c.url, func(b *testing.B) {
   243  				for i := 0; i <= b.N; i++ {
   244  					if match := RoutePatternMatch(c.url, testCollection.pattern); match {
   245  						// Get testCases from the original path
   246  						matchRes = true
   247  					}
   248  				}
   249  				utils.AssertEqual(t, c.match, matchRes, fmt.Sprintf("route: '%s', url: '%s'", testCollection.pattern, c.url))
   250  			})
   251  		}
   252  	}
   253  
   254  	for _, testCollection := range benchmarkCases {
   255  		benchCaseFn(testCollection)
   256  	}
   257  }