@@ -1053,3 +1053,218 @@ components:
10531053 })
10541054 }
10551055}
1056+
1057+ // TestValidateSchema_Discriminator_OneOf_WithRefs_Issue788 tests that validation works correctly
1058+ // when a schema has discriminator + oneOf with $ref to component schemas.
1059+ // This was a regression in vacuum v0.21.2+ where the validator would fail with
1060+ // "JSON schema compile failed: json-pointer not found" because discriminator refs
1061+ // were being preserved instead of inlined.
1062+ // https://github.com/daveshanley/vacuum/issues/788
1063+ func TestValidateSchema_Discriminator_OneOf_WithRefs_Issue788 (t * testing.T ) {
1064+ spec := `openapi: 3.1.0
1065+ info:
1066+ title: Test Discriminator OneOf With Refs
1067+ version: 1.0.0
1068+ components:
1069+ schemas:
1070+ ProductWidget:
1071+ type: object
1072+ required:
1073+ - productName
1074+ - quantity
1075+ - color
1076+ properties:
1077+ productName:
1078+ type: string
1079+ enum:
1080+ - Widget
1081+ quantity:
1082+ type: integer
1083+ minimum: 1
1084+ color:
1085+ type: string
1086+ enum:
1087+ - Red
1088+ - Blue
1089+ - Green
1090+ ProductGadget:
1091+ type: object
1092+ required:
1093+ - productName
1094+ - quantity
1095+ - size
1096+ properties:
1097+ productName:
1098+ type: string
1099+ enum:
1100+ - Gadget
1101+ quantity:
1102+ type: integer
1103+ minimum: 1
1104+ size:
1105+ type: string
1106+ enum:
1107+ - Small
1108+ - Medium
1109+ - Large
1110+ Product:
1111+ oneOf:
1112+ - $ref: '#/components/schemas/ProductWidget'
1113+ - $ref: '#/components/schemas/ProductGadget'
1114+ discriminator:
1115+ propertyName: productName`
1116+
1117+ doc , err := libopenapi .NewDocument ([]byte (spec ))
1118+ assert .NoError (t , err )
1119+
1120+ model , errs := doc .BuildV3Model ()
1121+ assert .Empty (t , errs )
1122+
1123+ productSchema := model .Model .Components .Schemas .GetOrZero ("Product" ).Schema ()
1124+
1125+ // Valid Widget product
1126+ validWidget := map [string ]interface {}{
1127+ "productName" : "Widget" ,
1128+ "quantity" : 1 ,
1129+ "color" : "Green" ,
1130+ }
1131+
1132+ validator := NewSchemaValidator ()
1133+ valid , validationErrors := validator .ValidateSchemaObject (productSchema , validWidget )
1134+
1135+ // This should pass without "json-pointer not found" error
1136+ assert .True (t , valid , "validation should pass for valid product with discriminator oneOf refs" )
1137+ assert .Empty (t , validationErrors , "no validation errors should be present" )
1138+ }
1139+
1140+ // TestValidateSchema_Discriminator_AnyOf_WithRefs tests anyOf with discriminator and $refs
1141+ func TestValidateSchema_Discriminator_AnyOf_WithRefs (t * testing.T ) {
1142+ spec := `openapi: 3.1.0
1143+ info:
1144+ title: Test Discriminator AnyOf With Refs
1145+ version: 1.0.0
1146+ components:
1147+ schemas:
1148+ Cat:
1149+ type: object
1150+ required:
1151+ - petType
1152+ - meow
1153+ properties:
1154+ petType:
1155+ type: string
1156+ const: cat
1157+ meow:
1158+ type: boolean
1159+ Dog:
1160+ type: object
1161+ required:
1162+ - petType
1163+ - bark
1164+ properties:
1165+ petType:
1166+ type: string
1167+ const: dog
1168+ bark:
1169+ type: boolean
1170+ Pet:
1171+ anyOf:
1172+ - $ref: '#/components/schemas/Cat'
1173+ - $ref: '#/components/schemas/Dog'
1174+ discriminator:
1175+ propertyName: petType`
1176+
1177+ doc , err := libopenapi .NewDocument ([]byte (spec ))
1178+ assert .NoError (t , err )
1179+
1180+ model , errs := doc .BuildV3Model ()
1181+ assert .Empty (t , errs )
1182+
1183+ petSchema := model .Model .Components .Schemas .GetOrZero ("Pet" ).Schema ()
1184+
1185+ // Valid cat
1186+ validCat := map [string ]interface {}{
1187+ "petType" : "cat" ,
1188+ "meow" : true ,
1189+ }
1190+
1191+ validator := NewSchemaValidator ()
1192+ valid , validationErrors := validator .ValidateSchemaObject (petSchema , validCat )
1193+
1194+ assert .True (t , valid , "validation should pass for valid cat with discriminator anyOf refs" )
1195+ assert .Empty (t , validationErrors , "no validation errors should be present" )
1196+ }
1197+
1198+ // TestValidateSchema_Discriminator_OneOf_WithRefs_InvalidData tests that invalid data
1199+ // still fails validation correctly (not a false negative)
1200+ func TestValidateSchema_Discriminator_OneOf_WithRefs_InvalidData (t * testing.T ) {
1201+ spec := `openapi: 3.1.0
1202+ info:
1203+ title: Test Discriminator OneOf Invalid
1204+ version: 1.0.0
1205+ components:
1206+ schemas:
1207+ ProductWidget:
1208+ type: object
1209+ required:
1210+ - productName
1211+ - quantity
1212+ - color
1213+ properties:
1214+ productName:
1215+ type: string
1216+ enum:
1217+ - Widget
1218+ quantity:
1219+ type: integer
1220+ minimum: 1
1221+ color:
1222+ type: string
1223+ enum:
1224+ - Red
1225+ - Blue
1226+ ProductGadget:
1227+ type: object
1228+ required:
1229+ - productName
1230+ - quantity
1231+ - size
1232+ properties:
1233+ productName:
1234+ type: string
1235+ enum:
1236+ - Gadget
1237+ quantity:
1238+ type: integer
1239+ minimum: 1
1240+ size:
1241+ type: string
1242+ Product:
1243+ oneOf:
1244+ - $ref: '#/components/schemas/ProductWidget'
1245+ - $ref: '#/components/schemas/ProductGadget'
1246+ discriminator:
1247+ propertyName: productName`
1248+
1249+ doc , err := libopenapi .NewDocument ([]byte (spec ))
1250+ assert .NoError (t , err )
1251+
1252+ model , errs := doc .BuildV3Model ()
1253+ assert .Empty (t , errs )
1254+
1255+ productSchema := model .Model .Components .Schemas .GetOrZero ("Product" ).Schema ()
1256+
1257+ // Invalid product - missing required field 'color' for Widget
1258+ invalidProduct := map [string ]interface {}{
1259+ "productName" : "Widget" ,
1260+ "quantity" : 1 ,
1261+ // missing required 'color' field
1262+ }
1263+
1264+ validator := NewSchemaValidator ()
1265+ valid , validationErrors := validator .ValidateSchemaObject (productSchema , invalidProduct )
1266+
1267+ // This should fail because 'color' is required for Widget
1268+ assert .False (t , valid , "validation should fail for invalid product" )
1269+ assert .NotEmpty (t , validationErrors , "validation errors should be present" )
1270+ }
0 commit comments