@@ -5,7 +5,6 @@ package parameters
55
66import (
77 "net/http"
8- "regexp"
98 "sync"
109 "sync/atomic"
1110 "testing"
@@ -2075,7 +2074,7 @@ paths:
20752074 request , _ := http .NewRequest (http .MethodGet , "https://things.com/pizza/;burgerId=22334/locate" , nil )
20762075
20772076 // preset the path
2078- path , _ , pv := paths .FindPath (request , & m .Model , & sync.Map {})
2077+ path , _ , pv := paths .FindPath (request , & m .Model , & config. ValidationOptions { RegexCache : & sync.Map {} })
20792078
20802079 valid , errors := v .ValidatePathParamsWithPathItem (request , path , pv )
20812080
@@ -2271,51 +2270,6 @@ func (c *regexCacheWatcher) Store(key, value any) {
22712270 c .inner .Store (key , value )
22722271}
22732272
2274- func TestNewValidator_CacheCompiledRegex (t * testing.T ) {
2275- spec := `openapi: 3.1.0
2276- paths:
2277- /pizza:
2278- get:
2279- operationId: getPizza`
2280-
2281- doc , _ := libopenapi .NewDocument ([]byte (spec ))
2282-
2283- m , _ := doc .BuildV3Model ()
2284-
2285- cache := & regexCacheWatcher {inner : & sync.Map {}}
2286- v := NewParameterValidator (& m .Model , config .WithRegexCache (cache ))
2287-
2288- compiledPizza := regexp .MustCompile ("^pizza$" )
2289- cache .inner .Store ("pizza" , compiledPizza )
2290-
2291- assert .EqualValues (t , 0 , cache .storeCount )
2292- assert .EqualValues (t , 0 , cache .hitCount + cache .missCount )
2293-
2294- request , _ := http .NewRequest (http .MethodGet , "https://things.com/pizza" , nil )
2295- v .ValidatePathParams (request )
2296-
2297- assert .EqualValues (t , 0 , cache .storeCount )
2298- assert .EqualValues (t , 0 , cache .missCount )
2299- assert .EqualValues (t , 1 , cache .hitCount )
2300-
2301- mapLength := 0
2302-
2303- cache .inner .Range (func (key , value any ) bool {
2304- mapLength += 1
2305- return true
2306- })
2307-
2308- assert .Equal (t , 1 , mapLength )
2309-
2310- cache .inner .Clear ()
2311-
2312- v .ValidatePathParams (request )
2313-
2314- assert .EqualValues (t , 1 , cache .storeCount )
2315- assert .EqualValues (t , 1 , cache .missCount )
2316- assert .EqualValues (t , 1 , cache .hitCount )
2317- }
2318-
23192273func TestValidatePathParamsWithPathItem_RegexCache_WithOneCached (t * testing.T ) {
23202274 spec := `openapi: 3.1.0
23212275paths:
@@ -2350,33 +2304,46 @@ paths:
23502304 assert .EqualValues (t , 1 , cache .hitCount )
23512305}
23522306
2353- func TestValidatePathParamsWithPathItem_RegexCache_MissOnceThenHit (t * testing.T ) {
2307+ // TestRadixTree_RegexFallback verifies that:
2308+ // 1. Simple paths use the radix tree (no regex cache)
2309+ // 2. Complex paths (OData style) fall back to regex and use the cache
2310+ func TestRadixTree_RegexFallback (t * testing.T ) {
23542311 spec := `openapi: 3.1.0
23552312paths:
2356- /burgers/{burgerId}/locate:
2357- parameters:
2358- - in: path
2359- name: burgerId
2360- schema:
2361- type: integer
2313+ /simple/{id}:
23622314 get:
2363- operationId: locateBurgers`
2315+ operationId: getSimple
2316+ /entities('{Entity}'):
2317+ get:
2318+ operationId: getOData`
2319+
23642320 doc , _ := libopenapi .NewDocument ([]byte (spec ))
23652321 m , _ := doc .BuildV3Model ()
23662322
23672323 cache := & regexCacheWatcher {inner : & sync.Map {}}
2368-
2369- v := NewParameterValidator (& m .Model , config .WithRegexCache (cache ))
2370-
2371- request , _ := http .NewRequest (http .MethodGet , "https://things.com/burgers/123/locate" , nil )
2372- pathItem , _ , foundPath := paths .FindPath (request , & m .Model , cache )
2373-
2374- v .ValidatePathParamsWithPathItem (request , pathItem , foundPath )
2375-
2376- assert .EqualValues (t , 3 , cache .storeCount )
2377- assert .EqualValues (t , 3 , cache .missCount )
2378- assert .EqualValues (t , 3 , cache .hitCount )
2379-
2380- _ , found := cache .inner .Load ("{burgerId}" )
2381- assert .True (t , found )
2324+ opts := & config.ValidationOptions {RegexCache : cache }
2325+
2326+ // Simple path - should NOT use regex cache (handled by radix tree)
2327+ simpleRequest , _ := http .NewRequest (http .MethodGet , "https://things.com/simple/123" , nil )
2328+ pathItem , _ , foundPath := paths .FindPath (simpleRequest , & m .Model , opts )
2329+
2330+ assert .NotNil (t , pathItem )
2331+ assert .Equal (t , "/simple/{id}" , foundPath )
2332+ assert .EqualValues (t , 0 , cache .storeCount , "Simple paths should not use regex cache" )
2333+ assert .EqualValues (t , 0 , cache .hitCount + cache .missCount , "Simple paths should not touch regex cache" )
2334+
2335+ // OData path - SHOULD use regex cache (radix tree can't handle embedded params)
2336+ odataRequest , _ := http .NewRequest (http .MethodGet , "https://things.com/entities('abc')" , nil )
2337+ pathItem , _ , foundPath = paths .FindPath (odataRequest , & m .Model , opts )
2338+
2339+ assert .NotNil (t , pathItem )
2340+ assert .Equal (t , "/entities('{Entity}')" , foundPath )
2341+ assert .EqualValues (t , 1 , cache .storeCount , "OData paths should use regex cache" )
2342+ assert .EqualValues (t , 1 , cache .missCount , "First OData lookup should miss cache" )
2343+
2344+ // Second OData call should hit cache
2345+ pathItem , _ , _ = paths .FindPath (odataRequest , & m .Model , opts )
2346+ assert .NotNil (t , pathItem )
2347+ assert .EqualValues (t , 1 , cache .storeCount , "No new stores on cache hit" )
2348+ assert .EqualValues (t , 1 , cache .hitCount , "Second OData lookup should hit cache" )
23822349}
0 commit comments