Skip to content

Commit 55bd119

Browse files
committed
Upgraded ignore regex
it’s less strict now, and fixes a known issue. daveshanley/vacuum#520
1 parent 26566d8 commit 55bd119

File tree

2 files changed

+240
-2
lines changed

2 files changed

+240
-2
lines changed

helpers/ignore_regex.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ package helpers
66
import "regexp"
77

88
var (
9-
IgnorePattern = `^'?(anyOf|allOf|oneOf|validation)'? failed\b`
10-
IgnorePolyPattern = `^'?(anyOf|allOf|oneOf)'? failed\b`
9+
// Ignore generic poly errors that just say "none matched" since we get specific errors
10+
// But keep errors that say which subschemas matched (for multiple match scenarios)
11+
IgnorePattern = `^'?(anyOf|allOf|oneOf|validation)'? failed(, none matched)?$`
12+
IgnorePolyPattern = `^'?(anyOf|allOf|oneOf)'? failed(, none matched)?$`
1113
)
1214

1315
// IgnoreRegex is a regular expression that matches the IgnorePattern

schema_validation/validate_schema_test.go

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -820,3 +820,239 @@ func TestSchemaValidator_ValidateSchemaBytesWithVersion_NilSchema(t *testing.T)
820820
assert.False(t, valid, "Should fail with nil schema")
821821
assert.Empty(t, errors, "Should not return errors for nil schema")
822822
}
823+
824+
// https://github.com/daveshanley/vacuum/issues/520
825+
func TestValidateSchema_OneOf_MultipleMatches_Issue520(t *testing.T) {
826+
// This test reproduces the issue from vacuum #520
827+
// The example matches BOTH oneOf alternatives which should fail validation
828+
// but the error details are not being populated correctly
829+
830+
spec := `openapi: 3.1.0
831+
info:
832+
title: Test
833+
version: 1.0.0
834+
components:
835+
schemas:
836+
Test:
837+
type: object
838+
oneOf:
839+
- properties:
840+
pim:
841+
type: string
842+
- properties:
843+
pam:
844+
type: string
845+
`
846+
847+
doc, err := libopenapi.NewDocument([]byte(spec))
848+
assert.NoError(t, err)
849+
850+
model, errs := doc.BuildV3Model()
851+
assert.Empty(t, errs)
852+
853+
testSchema := model.Model.Components.Schemas.GetOrZero("Test").Schema()
854+
855+
testData := map[string]interface{}{
856+
"pam": "nop",
857+
}
858+
859+
validator := NewSchemaValidator()
860+
valid, validationErrors := validator.ValidateSchemaObject(testSchema, testData)
861+
862+
assert.False(t, valid, "validation should fail because example matches both oneOf alternatives")
863+
assert.NotEmpty(t, validationErrors, "validation errors should be present")
864+
865+
if len(validationErrors) > 0 {
866+
867+
assert.NotEmpty(t, validationErrors[0].SchemaValidationErrors,
868+
"SchemaValidationErrors should contain detailed error information about the oneOf violation")
869+
870+
if len(validationErrors[0].SchemaValidationErrors) > 0 {
871+
firstError := validationErrors[0].SchemaValidationErrors[0]
872+
873+
assert.Contains(t, firstError.Reason, "oneOf",
874+
"error should mention oneOf constraint violation")
875+
}
876+
}
877+
}
878+
879+
// https://github.com/daveshanley/vacuum/issues/520
880+
func TestValidateSchema_OneOf_Discriminant_Valid(t *testing.T) {
881+
882+
spec := `openapi: 3.1.0
883+
info:
884+
title: Test
885+
version: 1.0.0
886+
components:
887+
schemas:
888+
Test:
889+
type: object
890+
oneOf:
891+
- properties:
892+
type:
893+
const: pim
894+
pim:
895+
type: string
896+
required: [type, pim]
897+
- properties:
898+
type:
899+
const: pam
900+
pam:
901+
type: string
902+
required: [type, pam]`
903+
904+
doc, err := libopenapi.NewDocument([]byte(spec))
905+
assert.NoError(t, err)
906+
907+
model, errs := doc.BuildV3Model()
908+
assert.Empty(t, errs)
909+
910+
testSchema := model.Model.Components.Schemas.GetOrZero("Test").Schema()
911+
912+
testData := map[string]interface{}{
913+
"type": "pam",
914+
"pam": "nop",
915+
}
916+
917+
validator := NewSchemaValidator()
918+
valid, validationErrors := validator.ValidateSchemaObject(testSchema, testData)
919+
920+
assert.True(t, valid, "validation should pass for discriminant oneOf")
921+
assert.Empty(t, validationErrors, "no validation errors should be present")
922+
}
923+
924+
// https://github.com/daveshanley/vacuum/issues/520
925+
func TestValidateSchema_OneOf_NoMatches(t *testing.T) {
926+
927+
spec := `openapi: 3.1.0
928+
info:
929+
title: Test
930+
version: 1.0.0
931+
components:
932+
schemas:
933+
Test:
934+
type: object
935+
oneOf:
936+
- properties:
937+
foo:
938+
type: string
939+
required: [foo]
940+
- properties:
941+
bar:
942+
type: integer
943+
required: [bar]`
944+
945+
doc, err := libopenapi.NewDocument([]byte(spec))
946+
assert.NoError(t, err)
947+
948+
model, errs := doc.BuildV3Model()
949+
assert.Empty(t, errs)
950+
951+
testSchema := model.Model.Components.Schemas.GetOrZero("Test").Schema()
952+
953+
testData := map[string]interface{}{
954+
"baz": "invalid",
955+
}
956+
957+
validator := NewSchemaValidator()
958+
valid, validationErrors := validator.ValidateSchemaObject(testSchema, testData)
959+
960+
assert.False(t, valid, "validation should fail because example matches no oneOf alternatives")
961+
assert.NotEmpty(t, validationErrors, "validation errors should be present")
962+
963+
if len(validationErrors) > 0 {
964+
assert.NotEmpty(t, validationErrors[0].SchemaValidationErrors,
965+
"SchemaValidationErrors should contain detailed error information")
966+
}
967+
}
968+
969+
// https://github.com/daveshanley/vacuum/issues/520
970+
func TestValidateSchema_OneOf_SimpleTypes(t *testing.T) {
971+
972+
testCases := []struct {
973+
name string
974+
spec string
975+
value interface{}
976+
shouldPass bool
977+
errorDetail string
978+
}{
979+
{
980+
name: "valid string",
981+
spec: `openapi: 3.1.0
982+
info:
983+
title: Test
984+
version: 1.0.0
985+
components:
986+
schemas:
987+
Test:
988+
oneOf:
989+
- type: string
990+
- type: integer`,
991+
value: "hello",
992+
shouldPass: true,
993+
},
994+
{
995+
name: "valid integer",
996+
spec: `openapi: 3.1.0
997+
info:
998+
title: Test
999+
version: 1.0.0
1000+
components:
1001+
schemas:
1002+
Test:
1003+
oneOf:
1004+
- type: string
1005+
- type: integer`,
1006+
value: 42,
1007+
shouldPass: true,
1008+
},
1009+
{
1010+
name: "invalid - matches both (ambiguous pattern)",
1011+
spec: `openapi: 3.1.0
1012+
info:
1013+
title: Test
1014+
version: 1.0.0
1015+
components:
1016+
schemas:
1017+
Test:
1018+
oneOf:
1019+
- type: string
1020+
- type: string
1021+
pattern: '^[0-9]+$'`,
1022+
value: "123",
1023+
shouldPass: false,
1024+
errorDetail: "oneOf",
1025+
},
1026+
}
1027+
1028+
for _, tc := range testCases {
1029+
t.Run(tc.name, func(t *testing.T) {
1030+
doc, err := libopenapi.NewDocument([]byte(tc.spec))
1031+
assert.NoError(t, err)
1032+
1033+
model, errs := doc.BuildV3Model()
1034+
assert.Empty(t, errs)
1035+
1036+
testSchema := model.Model.Components.Schemas.GetOrZero("Test").Schema()
1037+
1038+
validator := NewSchemaValidator()
1039+
valid, validationErrors := validator.ValidateSchemaObject(testSchema, tc.value)
1040+
1041+
if tc.shouldPass {
1042+
assert.True(t, valid, "validation should pass")
1043+
assert.Empty(t, validationErrors, "no validation errors expected")
1044+
} else {
1045+
assert.False(t, valid, "validation should fail")
1046+
assert.NotEmpty(t, validationErrors, "validation errors should be present")
1047+
1048+
if len(validationErrors) > 0 && tc.errorDetail != "" {
1049+
if len(validationErrors[0].SchemaValidationErrors) > 0 {
1050+
firstError := validationErrors[0].SchemaValidationErrors[0]
1051+
assert.Contains(t, firstError.Reason, tc.errorDetail,
1052+
"error should contain expected detail")
1053+
}
1054+
}
1055+
}
1056+
})
1057+
}
1058+
}

0 commit comments

Comments
 (0)