@@ -846,7 +846,6 @@ func Test_GetRenderedSchema_NilSchema(t *testing.T) {
846846
847847// Test_GetRenderedSchema_NilOptions verifies GetRenderedSchema works without options.
848848func Test_GetRenderedSchema_NilOptions (t * testing.T ) {
849- // Parse a document to get a properly initialized schema
850849 spec := []byte (`{
851850 "openapi": "3.1.0",
852851 "info": {"title": "Test", "version": "1.0.0"},
@@ -870,14 +869,16 @@ func Test_GetRenderedSchema_NilOptions(t *testing.T) {
870869 v3Model , errs := doc .BuildV3Model ()
871870 require .Nil (t , errs )
872871
873- // Get the parameter schema
874872 pathItem := v3Model .Model .Paths .PathItems .GetOrZero ("/test" )
875- param := pathItem .Get .Parameters [0 ]
876- schema := param .Schema .Schema ()
873+ schema := pathItem .Get .Parameters [0 ].Schema .Schema ()
874+
875+ // Ground truth
876+ rendered , _ := schema .RenderInline ()
877+ expected := string (rendered )
877878
878- // Call with nil options - should still render the schema (returns some representation)
879+ // With nil options should match ground truth
879880 result := GetRenderedSchema (schema , nil )
880- assert .NotEmpty (t , result , "GetRenderedSchema should render schema even with nil options" )
881+ assert .Equal (t , expected , result )
881882}
882883
883884// Test_GetRenderedSchema_CacheHit verifies GetRenderedSchema uses cached data when available.
@@ -905,23 +906,24 @@ func Test_GetRenderedSchema_CacheHit(t *testing.T) {
905906 v3Model , errs := doc .BuildV3Model ()
906907 require .Nil (t , errs )
907908
908- // Get the parameter schema
909909 pathItem := v3Model .Model .Paths .PathItems .GetOrZero ("/test" )
910- param := pathItem .Get .Parameters [0 ]
911- schema := param .Schema .Schema ()
910+ schema := pathItem .Get .Parameters [0 ].Schema .Schema ()
912911
913- // Create options with cache and pre-populate with known value
912+ // Ground truth
913+ rendered , _ := schema .RenderInline ()
914+ expected := string (rendered )
915+
916+ // Pre-populate cache with RenderedInline
914917 opts := config .NewValidationOptions ()
915918 hash := schema .GoLow ().Hash ()
916- testCachedJSON := []byte (`{"type":"integer","minimum":1,"cached":true}` )
917919 opts .SchemaCache .Store (hash , & cache.SchemaCacheEntry {
918- Schema : schema ,
919- RenderedJSON : testCachedJSON ,
920+ Schema : schema ,
921+ RenderedInline : rendered ,
920922 })
921923
922- // GetRenderedSchema should return the cached value
924+ // Cache hit should match ground truth
923925 result := GetRenderedSchema (schema , opts )
924- assert .Equal (t , string ( testCachedJSON ) , result , "GetRenderedSchema should return cached JSON" )
926+ assert .Equal (t , expected , result )
925927}
926928
927929// Test_GetRenderedSchema_NilCache verifies GetRenderedSchema works when cache is disabled.
@@ -949,22 +951,21 @@ func Test_GetRenderedSchema_NilCache(t *testing.T) {
949951 v3Model , errs := doc .BuildV3Model ()
950952 require .Nil (t , errs )
951953
952- // Get the parameter schema
953954 pathItem := v3Model .Model .Paths .PathItems .GetOrZero ("/test" )
954- param := pathItem .Get .Parameters [0 ]
955- schema := param .Schema .Schema ()
955+ schema := pathItem .Get .Parameters [0 ].Schema .Schema ()
956956
957- // Create options with cache disabled
958- opts := config . NewValidationOptions ( config . WithSchemaCache ( nil ) )
959- require . Nil ( t , opts . SchemaCache )
957+ // Ground truth
958+ rendered , _ := schema . RenderInline ( )
959+ expected := string ( rendered )
960960
961- // GetRenderedSchema should still work by rendering fresh (returns some representation)
961+ // With nil cache should match ground truth
962+ opts := config .NewValidationOptions (config .WithSchemaCache (nil ))
962963 result := GetRenderedSchema (schema , opts )
963- assert .NotEmpty (t , result , "GetRenderedSchema should render schema even with nil cache" )
964+ assert .Equal (t , expected , result )
964965}
965966
966- // Test_GetRenderedSchema_CacheMiss verifies GetRenderedSchema renders fresh when cache entry has empty RenderedJSON .
967- // This tests the code path where cache lookup succeeds but RenderedJSON is empty.
967+ // Test_GetRenderedSchema_CacheMiss verifies GetRenderedSchema renders fresh when cache entry has empty RenderedInline .
968+ // This tests the code path where cache lookup succeeds but RenderedInline is empty.
968969func Test_GetRenderedSchema_CacheMiss (t * testing.T ) {
969970 spec := []byte (`{
970971 "openapi": "3.1.0",
@@ -989,25 +990,72 @@ func Test_GetRenderedSchema_CacheMiss(t *testing.T) {
989990 v3Model , errs := doc .BuildV3Model ()
990991 require .Nil (t , errs )
991992
992- // Get the parameter schema
993993 pathItem := v3Model .Model .Paths .PathItems .GetOrZero ("/test" )
994- param := pathItem .Get .Parameters [0 ]
995- schema := param .Schema .Schema ()
994+ schema := pathItem .Get .Parameters [0 ].Schema .Schema ()
996995
997- // Create options with cache enabled
998- opts := config . NewValidationOptions ()
999- require . NotNil ( t , opts . SchemaCache )
996+ // Ground truth
997+ rendered , _ := schema . RenderInline ()
998+ expected := string ( rendered )
1000999
1001- // Store an entry with empty RenderedJSON to simulate cache miss scenario
1000+ // Store entry with empty RenderedInline to force cache miss
1001+ opts := config .NewValidationOptions ()
10021002 hash := schema .GoLow ().Hash ()
10031003 opts .SchemaCache .Store (hash , & cache.SchemaCacheEntry {
1004- Schema : schema ,
1005- RenderedJSON : nil , // Empty - should trigger fresh rendering
1004+ Schema : schema ,
1005+ RenderedInline : nil , // Empty - should trigger fresh rendering
10061006 })
10071007
1008- // GetRenderedSchema should render fresh since RenderedJSON is empty
1008+ // Cache miss should still match ground truth
10091009 result := GetRenderedSchema (schema , opts )
1010- assert .NotEmpty (t , result , "GetRenderedSchema should render fresh when cached RenderedJSON is empty" )
1010+ assert .Equal (t , expected , result )
1011+ }
1012+
1013+ // Test_GetRenderedSchema_Deterministic verifies that GetRenderedSchema returns the same
1014+ // output regardless of cache state (cache hit vs cache miss).
1015+ func Test_GetRenderedSchema_Deterministic (t * testing.T ) {
1016+ spec := []byte (`{
1017+ "openapi": "3.1.0",
1018+ "info": {"title": "Test", "version": "1.0.0"},
1019+ "paths": {
1020+ "/test": {
1021+ "get": {
1022+ "parameters": [{
1023+ "name": "status",
1024+ "in": "query",
1025+ "schema": {"type": "string", "enum": ["active", "inactive"]}
1026+ }],
1027+ "responses": {"200": {"description": "OK"}}
1028+ }
1029+ }
1030+ }
1031+ }` )
1032+
1033+ doc , err := libopenapi .NewDocument (spec )
1034+ require .NoError (t , err )
1035+
1036+ v3Model , errs := doc .BuildV3Model ()
1037+ require .Nil (t , errs )
1038+
1039+ pathItem := v3Model .Model .Paths .PathItems .GetOrZero ("/test" )
1040+ schema := pathItem .Get .Parameters [0 ].Schema .Schema ()
1041+
1042+ // Ground truth
1043+ rendered , _ := schema .RenderInline ()
1044+ expected := string (rendered )
1045+
1046+ // Cache miss path (no cache)
1047+ optsNoCache := config .NewValidationOptions (config .WithSchemaCache (nil ))
1048+ resultMiss := GetRenderedSchema (schema , optsNoCache )
1049+ assert .Equal (t , expected , resultMiss )
1050+
1051+ // Cache hit path (pre-populated cache)
1052+ optsWithCache := config .NewValidationOptions ()
1053+ hash := schema .GoLow ().Hash ()
1054+ optsWithCache .SchemaCache .Store (hash , & cache.SchemaCacheEntry {
1055+ RenderedInline : rendered ,
1056+ })
1057+ resultHit := GetRenderedSchema (schema , optsWithCache )
1058+ assert .Equal (t , expected , resultHit )
10111059}
10121060
10131061// Test_ValidateSingleParameterSchema_CacheMissCompiledSchema tests the path where cache entry
@@ -1165,3 +1213,51 @@ func Test_ParameterValidation_CompleteCacheEntry(t *testing.T) {
11651213 assert .NotNil (t , cached .CompiledSchema , "CompiledSchema should be populated" )
11661214 assert .NotNil (t , cached .RenderedNode , "RenderedNode should be populated" )
11671215}
1216+
1217+ // Test_ReferenceSchema_ConsistentFormat verifies that ReferenceSchema has the same
1218+ // format whether the error comes from GetRenderedSchema or formatJsonSchemaValidationError.
1219+ func Test_ReferenceSchema_ConsistentFormat (t * testing.T ) {
1220+ spec := []byte (`{
1221+ "openapi": "3.1.0",
1222+ "info": {"title": "Test", "version": "1.0.0"},
1223+ "paths": {
1224+ "/test": {
1225+ "get": {
1226+ "parameters": [{
1227+ "name": "count",
1228+ "in": "query",
1229+ "required": true,
1230+ "schema": {"type": "integer", "minimum": 1, "maximum": 100}
1231+ }],
1232+ "responses": {"200": {"description": "OK"}}
1233+ }
1234+ }
1235+ }
1236+ }` )
1237+
1238+ doc , err := libopenapi .NewDocument (spec )
1239+ require .NoError (t , err )
1240+
1241+ v3Model , errs := doc .BuildV3Model ()
1242+ require .Nil (t , errs )
1243+
1244+ validator := NewParameterValidator (& v3Model .Model )
1245+
1246+ // Error path 1: Missing required parameter (uses GetRenderedSchema)
1247+ req1 , _ := http .NewRequest (http .MethodGet , "/test" , nil )
1248+ _ , errors1 := validator .ValidateQueryParams (req1 )
1249+ require .NotEmpty (t , errors1 )
1250+ require .NotEmpty (t , errors1 [0 ].SchemaValidationErrors )
1251+ refSchema1 := errors1 [0 ].SchemaValidationErrors [0 ].ReferenceSchema
1252+
1253+ // Error path 2: Value outside range (uses formatJsonSchemaValidationError)
1254+ req2 , _ := http .NewRequest (http .MethodGet , "/test?count=999" , nil )
1255+ _ , errors2 := validator .ValidateQueryParams (req2 )
1256+ require .NotEmpty (t , errors2 )
1257+ require .NotEmpty (t , errors2 [0 ].SchemaValidationErrors )
1258+ refSchema2 := errors2 [0 ].SchemaValidationErrors [0 ].ReferenceSchema
1259+
1260+ // Both should be plain YAML with the same content
1261+ assert .Equal (t , refSchema1 , refSchema2 ,
1262+ "ReferenceSchema should be consistent regardless of error path" )
1263+ }
0 commit comments