@@ -3,6 +3,8 @@ package restful
33import  (
44	"io" 
55	"net/http" 
6+ 	"regexp" 
7+ 	"sync" 
68	"testing" 
79)
810
@@ -262,3 +264,138 @@ func TestCurly_ISSUE_137_2(t *testing.T) {
262264}
263265
264266func  curlyDummy (req  * Request , resp  * Response ) { io .WriteString (resp .ResponseWriter , "curlyDummy" ) }
267+ 
268+ func  TestRegexCaching (t  * testing.T ) {
269+ 	// Store original state and enable caching for this test 
270+ 	originalEnabled  :=  pathTokenCacheEnabled 
271+ 	defer  func () {
272+ 		SetPathTokenCacheEnabled (originalEnabled )
273+ 	}()
274+ 	SetPathTokenCacheEnabled (true )
275+ 	
276+ 	// Clear cache before test 
277+ 	regexCache  =  sync.Map {}
278+ 	
279+ 	router  :=  CurlyRouter {}
280+ 	
281+ 	// Test with regex pattern 
282+ 	routeToken  :=  "{id:[0-9]+}" 
283+ 	requestToken  :=  "123" 
284+ 	
285+ 	// First call should cache the regex 
286+ 	matches1 , _  :=  router .regularMatchesPathToken (routeToken , 3 , requestToken )
287+ 	if  ! matches1  {
288+ 		t .Error ("Expected first call to match" )
289+ 	}
290+ 	
291+ 	// Verify cache contains the pattern 
292+ 	pattern  :=  "[0-9]+" 
293+ 	_ , found  :=  regexCache .Load (pattern )
294+ 	if  ! found  {
295+ 		t .Error ("Expected pattern to be cached" )
296+ 	}
297+ 	
298+ 	// Second call should use cached regex 
299+ 	matches2 , _  :=  router .regularMatchesPathToken (routeToken , 3 , requestToken )
300+ 	if  ! matches2  {
301+ 		t .Error ("Expected second call to match using cache" )
302+ 	}
303+ 	
304+ 	// Test with different pattern to ensure separate caching 
305+ 	routeToken2  :=  "{name:[a-z]+}" 
306+ 	requestToken2  :=  "john" 
307+ 	
308+ 	matches3 , _  :=  router .regularMatchesPathToken (routeToken2 , 5 , requestToken2 )
309+ 	if  ! matches3  {
310+ 		t .Error ("Expected name pattern to match" )
311+ 	}
312+ 	
313+ 	// Verify both patterns are cached 
314+ 	pattern2  :=  "[a-z]+" 
315+ 	_ , found2  :=  regexCache .Load (pattern2 )
316+ 	if  ! found2  {
317+ 		t .Error ("Expected name pattern to be cached" )
318+ 	}
319+ }
320+ 
321+ func  TestRegexCacheDisabled (t  * testing.T ) {
322+ 	// Store original state 
323+ 	originalEnabled  :=  pathTokenCacheEnabled 
324+ 	defer  func () {
325+ 		SetPathTokenCacheEnabled (originalEnabled )
326+ 	}()
327+ 	
328+ 	// Clear cache before test 
329+ 	regexCache  =  sync.Map {}
330+ 	
331+ 	// Disable caching 
332+ 	SetPathTokenCacheEnabled (false )
333+ 	
334+ 	router  :=  CurlyRouter {}
335+ 	routeToken  :=  "{id:[0-9]+}" 
336+ 	requestToken  :=  "123" 
337+ 	
338+ 	// Call should work but not cache 
339+ 	matches , _  :=  router .regularMatchesPathToken (routeToken , 3 , requestToken )
340+ 	if  ! matches  {
341+ 		t .Error ("Expected call to match" )
342+ 	}
343+ 	
344+ 	// Verify pattern is not cached 
345+ 	pattern  :=  "[0-9]+" 
346+ 	_ , found  :=  regexCache .Load (pattern )
347+ 	if  found  {
348+ 		t .Error ("Expected pattern to not be cached when caching is disabled" )
349+ 	}
350+ 	
351+ 	// Re-enable caching 
352+ 	SetPathTokenCacheEnabled (true )
353+ 	
354+ 	// Now it should cache 
355+ 	matches2 , _  :=  router .regularMatchesPathToken (routeToken , 3 , requestToken )
356+ 	if  ! matches2  {
357+ 		t .Error ("Expected call to match" )
358+ 	}
359+ 	
360+ 	// Verify pattern is now cached 
361+ 	_ , found2  :=  regexCache .Load (pattern )
362+ 	if  ! found2  {
363+ 		t .Error ("Expected pattern to be cached when caching is re-enabled" )
364+ 	}
365+ }
366+ 
367+ func  TestRegexCachePanicSafety (t  * testing.T ) {
368+ 	// Store original state 
369+ 	originalEnabled  :=  pathTokenCacheEnabled 
370+ 	defer  func () {
371+ 		SetPathTokenCacheEnabled (originalEnabled )
372+ 		regexCache  =  sync.Map {} // Clean up 
373+ 	}()
374+ 	
375+ 	SetPathTokenCacheEnabled (true )
376+ 	
377+ 	// Poison cache with wrong type 
378+ 	pattern  :=  "[0-9]+" 
379+ 	regexCache .Store (pattern , "not a regex" )
380+ 	
381+ 	router  :=  CurlyRouter {}
382+ 	routeToken  :=  "{id:[0-9]+}" 
383+ 	requestToken  :=  "123" 
384+ 	
385+ 	// Should not panic, should handle invalid cache entry gracefully 
386+ 	matches , _  :=  router .regularMatchesPathToken (routeToken , 3 , requestToken )
387+ 	if  ! matches  {
388+ 		t .Error ("Expected call to match even with corrupted cache" )
389+ 	}
390+ 	
391+ 	// After the call, the invalid entry should be overwritten with valid regex 
392+ 	if  cached , found  :=  regexCache .Load (pattern ); found  {
393+ 		if  _ , ok  :=  cached .(* regexp.Regexp ); ok  {
394+ 			// Success: cache entry is now a valid regex 
395+ 		} else  {
396+ 			t .Error ("Expected invalid cache entry to be overwritten with valid regex" )
397+ 		}
398+ 	} else  {
399+ 		t .Error ("Expected valid regex to be cached" )
400+ 	}
401+ }
0 commit comments