@@ -837,3 +837,172 @@ func Test_ParameterValidation_CacheConsistency(t *testing.T) {
837837 })
838838 }
839839}
840+
841+ // Test_GetRenderedSchema_NilSchema verifies GetRenderedSchema handles nil schema gracefully.
842+ func Test_GetRenderedSchema_NilSchema (t * testing.T ) {
843+ opts := config .NewValidationOptions ()
844+ result := GetRenderedSchema (nil , opts )
845+ assert .Empty (t , result , "GetRenderedSchema should return empty string for nil schema" )
846+ }
847+
848+ // Test_GetRenderedSchema_NilOptions verifies GetRenderedSchema works without options.
849+ func Test_GetRenderedSchema_NilOptions (t * testing.T ) {
850+ // Parse a document to get a properly initialized schema
851+ spec := []byte (`{
852+ "openapi": "3.1.0",
853+ "info": {"title": "Test", "version": "1.0.0"},
854+ "paths": {
855+ "/test": {
856+ "get": {
857+ "parameters": [{
858+ "name": "id",
859+ "in": "query",
860+ "schema": {"type": "string", "minLength": 1}
861+ }],
862+ "responses": {"200": {"description": "OK"}}
863+ }
864+ }
865+ }
866+ }` )
867+
868+ doc , err := libopenapi .NewDocument (spec )
869+ require .NoError (t , err )
870+
871+ v3Model , errs := doc .BuildV3Model ()
872+ require .Nil (t , errs )
873+
874+ // Get the parameter schema
875+ pathItem := v3Model .Model .Paths .PathItems .GetOrZero ("/test" )
876+ param := pathItem .Get .Parameters [0 ]
877+ schema := param .Schema .Schema ()
878+
879+ // Call with nil options - should still render the schema (returns some representation)
880+ result := GetRenderedSchema (schema , nil )
881+ assert .NotEmpty (t , result , "GetRenderedSchema should render schema even with nil options" )
882+ }
883+
884+ // Test_GetRenderedSchema_CacheHit verifies GetRenderedSchema uses cached data when available.
885+ func Test_GetRenderedSchema_CacheHit (t * testing.T ) {
886+ spec := []byte (`{
887+ "openapi": "3.1.0",
888+ "info": {"title": "Test", "version": "1.0.0"},
889+ "paths": {
890+ "/test": {
891+ "get": {
892+ "parameters": [{
893+ "name": "id",
894+ "in": "query",
895+ "schema": {"type": "integer", "minimum": 1}
896+ }],
897+ "responses": {"200": {"description": "OK"}}
898+ }
899+ }
900+ }
901+ }` )
902+
903+ doc , err := libopenapi .NewDocument (spec )
904+ require .NoError (t , err )
905+
906+ v3Model , errs := doc .BuildV3Model ()
907+ require .Nil (t , errs )
908+
909+ // Get the parameter schema
910+ pathItem := v3Model .Model .Paths .PathItems .GetOrZero ("/test" )
911+ param := pathItem .Get .Parameters [0 ]
912+ schema := param .Schema .Schema ()
913+
914+ // Create options with cache and pre-populate with known value
915+ opts := config .NewValidationOptions ()
916+ hash := schema .GoLow ().Hash ()
917+ testCachedJSON := []byte (`{"type":"integer","minimum":1,"cached":true}` )
918+ opts .SchemaCache .Store (hash , & cache.SchemaCacheEntry {
919+ Schema : schema ,
920+ RenderedJSON : testCachedJSON ,
921+ })
922+
923+ // GetRenderedSchema should return the cached value
924+ result := GetRenderedSchema (schema , opts )
925+ assert .Equal (t , string (testCachedJSON ), result , "GetRenderedSchema should return cached JSON" )
926+ }
927+
928+ // Test_GetRenderedSchema_NilCache verifies GetRenderedSchema works when cache is disabled.
929+ func Test_GetRenderedSchema_NilCache (t * testing.T ) {
930+ spec := []byte (`{
931+ "openapi": "3.1.0",
932+ "info": {"title": "Test", "version": "1.0.0"},
933+ "paths": {
934+ "/test": {
935+ "get": {
936+ "parameters": [{
937+ "name": "id",
938+ "in": "query",
939+ "schema": {"type": "boolean"}
940+ }],
941+ "responses": {"200": {"description": "OK"}}
942+ }
943+ }
944+ }
945+ }` )
946+
947+ doc , err := libopenapi .NewDocument (spec )
948+ require .NoError (t , err )
949+
950+ v3Model , errs := doc .BuildV3Model ()
951+ require .Nil (t , errs )
952+
953+ // Get the parameter schema
954+ pathItem := v3Model .Model .Paths .PathItems .GetOrZero ("/test" )
955+ param := pathItem .Get .Parameters [0 ]
956+ schema := param .Schema .Schema ()
957+
958+ // Create options with cache disabled
959+ opts := config .NewValidationOptions (config .WithSchemaCache (nil ))
960+ require .Nil (t , opts .SchemaCache )
961+
962+ // GetRenderedSchema should still work by rendering fresh (returns some representation)
963+ result := GetRenderedSchema (schema , opts )
964+ assert .NotEmpty (t , result , "GetRenderedSchema should render schema even with nil cache" )
965+ }
966+
967+ // arrayValidationSpec is used to test array parameter validation with the updated function signatures
968+ var arrayValidationSpec = []byte (`{
969+ "openapi": "3.1.0",
970+ "info": {"title": "Array Test", "version": "1.0.0"},
971+ "paths": {
972+ "/test": {
973+ "get": {
974+ "parameters": [{
975+ "name": "ids",
976+ "in": "query",
977+ "schema": {
978+ "type": "array",
979+ "items": {"type": "integer", "minimum": 1}
980+ }
981+ }],
982+ "responses": {"200": {"description": "OK"}}
983+ }
984+ }
985+ }
986+ }` )
987+
988+ // Test_ArrayValidation_ErrorContainsRenderedSchema verifies that array validation errors
989+ // still contain the rendered schema after the rendering optimization.
990+ func Test_ArrayValidation_ErrorContainsRenderedSchema (t * testing.T ) {
991+ doc , err := libopenapi .NewDocument (arrayValidationSpec )
992+ require .NoError (t , err )
993+
994+ v3Model , errs := doc .BuildV3Model ()
995+ require .Nil (t , errs )
996+
997+ validator := NewParameterValidator (& v3Model .Model )
998+
999+ // Request with invalid array values (strings instead of integers)
1000+ req , _ := http .NewRequest ("GET" , "/test?ids=abc,def" , nil )
1001+
1002+ success , validationErrors := validator .ValidateQueryParams (req )
1003+ assert .False (t , success , "Validation should fail for non-integer array values" )
1004+ assert .NotEmpty (t , validationErrors , "Should have validation errors" )
1005+
1006+ // Verify error message is properly formatted
1007+ assert .Contains (t , validationErrors [0 ].Message , "ids" , "Error should reference parameter name" )
1008+ }
0 commit comments