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 }