@@ -252,32 +252,23 @@ func TestPreactIsoUrlPatternMatch(t *testing.T) {
252252 expected : nil ,
253253 },
254254 {
255- name : "Multiple optional params" ,
256- url : "/foo" ,
257- route : "/:a?/:b?/:c?" ,
258- matches : nil ,
259- expected : & Matches {
260- Params : map [string ]string {"a" : "foo" , "b" : "" , "c" : "" },
261- },
262- },
263- {
264- name : "Mixed required and optional params" ,
265- url : "/foo/bar" ,
266- route : "/:required/:optional?" ,
267- matches : nil ,
268- expected : & Matches {
269- Params : map [string ]string {"required" : "foo" , "optional" : "bar" },
270- },
271- },
272- {
273- name : "Mixed required and optional params - missing optional" ,
274- url : "/foo" ,
275- route : "/:required/:optional?" ,
276- matches : nil ,
277- expected : & Matches {
278- Params : map [string ]string {"required" : "foo" , "optional" : "" },
279- },
280- },
255+ name : "Mixed required and optional params" ,
256+ url : "/foo/bar" ,
257+ route : "/:required/:optional?" ,
258+ matches : nil ,
259+ expected : & Matches {
260+ Params : map [string ]string {"required" : "foo" , "optional" : "bar" },
261+ },
262+ },
263+ {
264+ name : "Mixed required and optional params - missing optional" ,
265+ url : "/foo" ,
266+ route : "/:required/:optional?" ,
267+ matches : nil ,
268+ expected : & Matches {
269+ Params : map [string ]string {"required" : "foo" , "optional" : "" },
270+ },
271+ },
281272
282273 // Test with pre-existing matches
283274 {
@@ -294,18 +285,6 @@ func TestPreactIsoUrlPatternMatch(t *testing.T) {
294285 },
295286 },
296287
297- // Wildcard anonymous rest
298- {
299- name : "Anonymous wildcard rest" ,
300- url : "/static/css/main.css" ,
301- route : "/static/*" ,
302- matches : nil ,
303- expected : & Matches {
304- Params : map [string ]string {},
305- Rest : "/css/main.css" ,
306- },
307- },
308-
309288 // Complex nested paths
310289 {
311290 name : "Complex nested path with multiple params" ,
@@ -338,17 +317,6 @@ func TestPreactIsoUrlPatternMatch(t *testing.T) {
338317 Params : map [string ]string {"version" : "" },
339318 },
340319 },
341-
342- // JavaScript-specific behavior tests
343- {
344- name : "Empty string should be handled as undefined for optional rest" ,
345- url : "/user" ,
346- route : "/user/:id*" ,
347- matches : nil ,
348- expected : & Matches {
349- Params : map [string ]string {"id" : "" },
350- },
351- },
352320 {
353321 name : "Multiple slashes in URL should be normalized" ,
354322 url : "//user//123//" ,
@@ -367,33 +335,6 @@ func TestPreactIsoUrlPatternMatch(t *testing.T) {
367335 Params : map [string ]string {"id" : "123" },
368336 },
369337 },
370- {
371- name : "Special characters in param names" ,
372- url : "/user/123" ,
373- route : "/user/:user_id" ,
374- matches : nil ,
375- expected : & Matches {
376- Params : map [string ]string {"user_id" : "123" },
377- },
378- },
379- {
380- name : "Param with numbers" ,
381- url : "/api/v1" ,
382- route : "/api/:version1" ,
383- matches : nil ,
384- expected : & Matches {
385- Params : map [string ]string {"version1" : "v1" },
386- },
387- },
388- {
389- name : "Rest param with single character" ,
390- url : "/a/b" ,
391- route : "/:x+" ,
392- matches : nil ,
393- expected : & Matches {
394- Params : map [string ]string {"x" : "a/b" },
395- },
396- },
397338 {
398339 name : "Complex URL encoding in rest params" ,
399340 url : "/files/folder%2Fsubfolder/file%20name.txt" ,
@@ -404,48 +345,12 @@ func TestPreactIsoUrlPatternMatch(t *testing.T) {
404345 },
405346 },
406347 {
407- name : "Question mark in URL (not query param) " ,
408- url : "/search/what %3F" ,
348+ name : "Special characters encoded in URL" ,
349+ url : "/search/query %3F%2B%23%26test " ,
409350 route : "/search/:query" ,
410351 matches : nil ,
411352 expected : & Matches {
412- Params : map [string ]string {"query" : "what?" },
413- },
414- },
415- {
416- name : "Plus sign in URL" ,
417- url : "/math/1%2B1" ,
418- route : "/math/:expression" ,
419- matches : nil ,
420- expected : & Matches {
421- Params : map [string ]string {"expression" : "1+1" },
422- },
423- },
424- {
425- name : "Hash in URL (encoded)" ,
426- url : "/tag/%23javascript" ,
427- route : "/tag/:name" ,
428- matches : nil ,
429- expected : & Matches {
430- Params : map [string ]string {"name" : "#javascript" },
431- },
432- },
433- {
434- name : "Ampersand in URL" ,
435- url : "/search/cats%26dogs" ,
436- route : "/search/:query" ,
437- matches : nil ,
438- expected : & Matches {
439- Params : map [string ]string {"query" : "cats&dogs" },
440- },
441- },
442- {
443- name : "Unicode characters" ,
444- url : "/user/José" ,
445- route : "/user/:name" ,
446- matches : nil ,
447- expected : & Matches {
448- Params : map [string ]string {"name" : "José" },
353+ Params : map [string ]string {"query" : "query?+#&test" },
449354 },
450355 },
451356 {
@@ -457,15 +362,6 @@ func TestPreactIsoUrlPatternMatch(t *testing.T) {
457362 Params : map [string ]string {"name" : "José" },
458363 },
459364 },
460- {
461- name : "Very long param" ,
462- url : "/data/" + strings .Repeat ("a" , 1000 ),
463- route : "/data/:content" ,
464- matches : nil ,
465- expected : & Matches {
466- Params : map [string ]string {"content" : strings .Repeat ("a" , 1000 )},
467- },
468- },
469365 {
470366 name : "Empty segments in middle of URL" ,
471367 url : "/api//v1//users" ,
@@ -485,28 +381,32 @@ func TestPreactIsoUrlPatternMatch(t *testing.T) {
485381 Rest : "/anything/goes/here" ,
486382 },
487383 },
384+ }
385+
386+ // URL decoding error handling tests
387+ urlDecodingTests := []struct {
388+ name string
389+ url string
390+ route string
391+ matches * Matches
392+ }{
488393 {
489- name : "Multiple consecutive optional params " ,
490- url : "/a/b " ,
491- route : "/:first?/:second?/:third?/:fourth? " ,
394+ name : "Malformed percent encoding in simple param - should not crash " ,
395+ url : "/user/test% " ,
396+ route : "/user/:id " ,
492397 matches : nil ,
493- expected : & Matches {
494- Params : map [string ]string {
495- "first" : "a" ,
496- "second" : "b" ,
497- "third" : "" ,
498- "fourth" : "" ,
499- },
500- },
501398 },
502399 {
503- name : "Zero-width param names (edge case)" ,
504- url : "/test" ,
505- route : "/:?" ,
400+ name : "Malformed percent encoding in rest param - should not crash" ,
401+ url : "/files/test%/file" ,
402+ route : "/files/:path+" ,
403+ matches : nil ,
404+ },
405+ {
406+ name : "Invalid unicode sequence - should not crash" ,
407+ url : "/user/test%C3" ,
408+ route : "/user/:id" ,
506409 matches : nil ,
507- expected : & Matches {
508- Params : map [string ]string {"" : "test" },
509- },
510410 },
511411 }
512412
@@ -546,33 +446,22 @@ func TestPreactIsoUrlPatternMatch(t *testing.T) {
546446 }
547447 })
548448 }
549- }
550-
551- // Test to document expected JavaScript behavior for debugging
552- func TestJavaScriptBehaviorReference (t * testing.T ) {
553- // These tests document what the JavaScript version should return
554- // for direct comparison with Go implementation
555449
556- t .Run ("JavaScript rest param behavior" , func (t * testing.T ) {
557- // In JavaScript: url.slice(i).map(decodeURIComponent).join('/') || undefined
558- // This means for "/user/foo/bar" with route "/user/:id*":
559- // - url = ["user", "foo", "bar"]
560- // - route = ["user", ":id*"]
561- // - At i=1: url.slice(1) = ["foo", "bar"]
562- // - joined: "foo/bar"
563- // - Result: {params: {id: "foo/bar"}}
564-
565- t .Logf ("Expected: rest params should join ALL remaining segments with '/'" )
566- t .Logf ("Go issue: likely only taking first segment instead of all remaining" )
567- })
568-
569- t .Run ("JavaScript URL encoding behavior" , func (t * testing.T ) {
570- // JavaScript uses decodeURIComponent on each segment
571- // For rest params, it decodes EACH segment then joins with '/'
572-
573- t .Logf ("Expected: each URL segment should be decoded separately" )
574- t .Logf ("For rest params: decode each segment, then join with '/'" )
575- })
450+ // Test URL decoding error handling - these should not crash
451+ for _ , tt := range urlDecodingTests {
452+ t .Run (tt .name , func (t * testing.T ) {
453+ // The main requirement is that this doesn't crash
454+ // We don't care about the exact return value as long as it doesn't panic
455+ result := preactIsoUrlPatternMatch (tt .url , tt .route , tt .matches )
456+ // Should either work or return nil, but not crash
457+ if result != nil {
458+ // If it returns a result, just verify it has params
459+ if result .Params == nil {
460+ t .Errorf ("Result should have non-nil Params map" )
461+ }
462+ }
463+ })
464+ }
576465}
577466
578467// Debug helper to trace execution
@@ -642,26 +531,3 @@ func TestFilterEmpty(t *testing.T) {
642531 })
643532 }
644533}
645-
646- func TestMax (t * testing.T ) {
647- tests := []struct {
648- name string
649- a , b int
650- expected int
651- }{
652- {"a greater" , 5 , 3 , 5 },
653- {"b greater" , 3 , 5 , 5 },
654- {"equal" , 4 , 4 , 4 },
655- {"negative" , - 1 , - 5 , - 1 },
656- {"zero" , 0 , 0 , 0 },
657- }
658-
659- for _ , tt := range tests {
660- t .Run (tt .name , func (t * testing.T ) {
661- result := max (tt .a , tt .b )
662- if result != tt .expected {
663- t .Errorf ("max(%d, %d) = %d, expected %d" , tt .a , tt .b , result , tt .expected )
664- }
665- })
666- }
667- }
0 commit comments