From ebbf60de70519a93a6de3761a3014bc4d98e4453 Mon Sep 17 00:00:00 2001 From: tomato0111 <119634480+tomato0111@users.noreply.github.com> Date: Tue, 6 Dec 2022 05:14:22 -0800 Subject: [PATCH] fix: setting defaults for oneOf and anyOf (#690) --- openapi3/schema.go | 17 +-- openapi3filter/validate_set_default_test.go | 116 ++++++++++++++++++++ 2 files changed, 125 insertions(+), 8 deletions(-) diff --git a/openapi3/schema.go b/openapi3/schema.go index 9f874d90e..67cc7dce0 100644 --- a/openapi3/schema.go +++ b/openapi3/schema.go @@ -934,10 +934,6 @@ func (schema *Schema) visitSetOperations(settings *schemaValidationSettings, val matchedOneOfIdx = 0 tempValue = value ) - // make a deep copy to protect origin value from being injected default value that defined in mismatched oneOf schema - if settings.asreq || settings.asrep { - tempValue = deepcopy.Copy(value) - } for idx, item := range v { v := item.Value if v == nil { @@ -948,6 +944,11 @@ func (schema *Schema) visitSetOperations(settings *schemaValidationSettings, val continue } + // make a deep copy to protect origin value from being injected default value that defined in mismatched oneOf schema + if settings.asreq || settings.asrep { + tempValue = deepcopy.Copy(value) + } + if err := v.visitJSON(settings, tempValue); err != nil { validationErrors = append(validationErrors, err) continue @@ -990,15 +991,15 @@ func (schema *Schema) visitSetOperations(settings *schemaValidationSettings, val matchedAnyOfIdx = 0 tempValue = value ) - // make a deep copy to protect origin value from being injected default value that defined in mismatched anyOf schema - if settings.asreq || settings.asrep { - tempValue = deepcopy.Copy(value) - } for idx, item := range v { v := item.Value if v == nil { return foundUnresolvedRef(item.Ref) } + // make a deep copy to protect origin value from being injected default value that defined in mismatched anyOf schema + if settings.asreq || settings.asrep { + tempValue = deepcopy.Copy(value) + } if err := v.visitJSON(settings, tempValue); err == nil { ok = true matchedAnyOfIdx = idx diff --git a/openapi3filter/validate_set_default_test.go b/openapi3filter/validate_set_default_test.go index 4550b51b2..731cbbdca 100644 --- a/openapi3filter/validate_set_default_test.go +++ b/openapi3filter/validate_set_default_test.go @@ -317,6 +317,70 @@ func TestValidateRequestBodyAndSetDefault(t *testing.T) { } } ] + }, + "contact": { + "oneOf": [ + { + "type": "object", + "required": ["email"], + "properties": { + "email": { + "type": "string" + }, + "allow_image": { + "type": "boolean", + "default": true + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": ["phone"], + "properties": { + "phone": { + "type": "string" + }, + "allow_text": { + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + } + ] + }, + "contact2": { + "anyOf": [ + { + "type": "object", + "required": ["email"], + "properties": { + "email": { + "type": "string" + }, + "allow_image": { + "type": "boolean", + "default": true + } + }, + "additionalProperties": false + }, + { + "type": "object", + "required": ["phone"], + "properties": { + "phone": { + "type": "string" + }, + "allow_text": { + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + } + ] } } } @@ -358,6 +422,10 @@ func TestValidateRequestBodyAndSetDefault(t *testing.T) { FBLink string `json:"fb_link,omitempty"` TWLink string `json:"tw_link,omitempty"` } + type contact struct { + Email string `json:"email,omitempty"` + Phone string `json:"phone,omitempty"` + } type body struct { ID string `json:"id,omitempty"` Name string `json:"name,omitempty"` @@ -367,6 +435,8 @@ func TestValidateRequestBodyAndSetDefault(t *testing.T) { Filters []filter `json:"filters,omitempty"` SocialNetwork *socialNetwork `json:"social_network,omitempty"` SocialNetwork2 *socialNetwork `json:"social_network_2,omitempty"` + Contact *contact `json:"contact,omitempty"` + Contact2 *contact `json:"contact2,omitempty"` } testCases := []struct { @@ -656,6 +726,52 @@ func TestValidateRequestBodyAndSetDefault(t *testing.T) { "platform": "facebook", "fb_link": "www.facebook.com" } +} + `, body) + }, + }, + { + name: "contact(oneOf)", + body: body{ + ID: "bt6kdc3d0cvp6u8u3ft0", + Contact: &contact{ + Phone: "123456", + }, + }, + bodyAssertion: func(t *testing.T, body string) { + require.JSONEq(t, ` +{ + "id": "bt6kdc3d0cvp6u8u3ft0", + "name": "default", + "code": 123, + "all": false, + "contact": { + "phone": "123456", + "allow_text": false + } +} + `, body) + }, + }, + { + name: "contact(anyOf)", + body: body{ + ID: "bt6kdc3d0cvp6u8u3ft0", + Contact2: &contact{ + Phone: "123456", + }, + }, + bodyAssertion: func(t *testing.T, body string) { + require.JSONEq(t, ` +{ + "id": "bt6kdc3d0cvp6u8u3ft0", + "name": "default", + "code": 123, + "all": false, + "contact2": { + "phone": "123456", + "allow_text": false + } } `, body) },