Repository: getkin/kin-openapi (go)

Issue:
oneof schema error improvment  
**Context:** 
currently, the library when validating an input against a schema and when an error occurred it returns schema error contains scheme filed where the error happens or input is invalid, under some circumstance, this is still not a piece of useful information to exactly know what happened behind the scene. 

**Pain:** 
Inappropriate error message returned when input matches more than "oneof" scheme.   

**Goal:** 
return a different error to distinguish input match more than oneof schemas (conflict) from input does not match oneof schemas. 

**Got:** 
`Error at "/address": Doesn't match schema "oneOf"`

**Expected:**
`Error at "/address": Conflict input match all oneof schemas"`

**Reproduce:** 
```go
package main

import (
	"fmt"

	"github.com/getkin/kin-openapi/openapi3"
)

func main() {
	data := map[string]interface{}{
		"name":      "kin-openapi",
		"address": "127.0.0.1",
	}
	s, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData([]byte(api))
	if err != nil {
		panic(err)
	}
	err = s.Components.Schemas["Server"].Value.VisitJSON(data)
	fmt.Println(err)

	//
}

var api = 
`components: 
  schemas: 
    Server: 
      properties: 
        address: 
          oneOf: 
            - $ref: "#/components/schemas/ip-address"
            - $ref: "#/components/schemas/domain-name"
        name: 
          type: string
      type: object
    domain-name: 
      maxLength: 10
      minLength: 5
      pattern: "((([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.)*([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.?)|\\."
      type: string
    ip-address: 
      pattern: "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$"
      type: string
openapi: "3.0.1"
`
```

**Note:** 
* Releated to https://github.com/getkin/kin-openapi/blob/master/openapi3/schema.go#L850. 
* Oneof in the above example added for only to reproduce otherwise should be anyof.

**Suggested Solution:**

```go 
var ErrOneOfConflict = errors.new("input match all oneof schemas")  

//  https://github.com/getkin/kin-openapi/blob/master/openapi3/schema.go#L850.
		if ok != 1 {
			if settings.failfast {
				return errSchema
			}
			 err := &SchemaError{
				Value:       value,
				Schema:      schema,
				SchemaField: "oneOf",
			}
                        if ok > 1 {
                           err.Origin = ErrOneOfConflict
                         }
                        return err 
		}
``` 


Pull request description:
Return a more specific error when more than oneOf schemas match
Fixes #289

cc @shaj13

Patch:
diff --git a/openapi3/schema.go b/openapi3/schema.go
index 4fcc864..4968fec 100644
--- a/openapi3/schema.go
+++ b/openapi3/schema.go
@@ -25,6 +25,9 @@ var (
 
 	errSchema = errors.New("Input does not match the schema")
 
+	// ErrOneOfConflict is the SchemaError Origin when data matches more than one oneOf schema
+	ErrOneOfConflict = errors.New("input matches more than one oneOf schemas")
+
 	// ErrSchemaInputNaN may be returned when validating a number
 	ErrSchemaInputNaN = errors.New("NaN is not allowed")
 	// ErrSchemaInputInf may be returned when validating a number
@@ -851,11 +854,15 @@ func (schema *Schema) visitSetOperations(settings *schemaValidationSettings, val
 			if settings.failfast {
 				return errSchema
 			}
-			return &SchemaError{
+			e := &SchemaError{
 				Value:       value,
 				Schema:      schema,
 				SchemaField: "oneOf",
 			}
+			if ok > 1 {
+				e.Origin = ErrOneOfConflict
+			}
+			return e
 		}
 	}
 


Test patch:
diff --git a/openapi3/schema_issue289_test.go b/openapi3/schema_issue289_test.go
new file mode 100644
index 0000000..e4e4aad
--- /dev/null
+++ b/openapi3/schema_issue289_test.go
@@ -0,0 +1,39 @@
+package openapi3
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/require"
+)
+
+func TestIssue289(t *testing.T) {
+	spec := []byte(`components:
+  schemas:
+    Server:
+      properties:
+        address:
+          oneOf:
+          - $ref: "#/components/schemas/ip-address"
+          - $ref: "#/components/schemas/domain-name"
+        name:
+          type: string
+      type: object
+    domain-name:
+      maxLength: 10
+      minLength: 5
+      pattern: "((([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.)*([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.?)|\\."
+      type: string
+    ip-address:
+      pattern: "^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$"
+      type: string
+openapi: "3.0.1"
+`)
+
+	s, err := NewSwaggerLoader().LoadSwaggerFromData(spec)
+	require.NoError(t, err)
+	err = s.Components.Schemas["Server"].Value.VisitJSON(map[string]interface{}{
+		"name":    "kin-openapi",
+		"address": "127.0.0.1",
+	})
+	require.EqualError(t, err, ErrOneOfConflict.Error())
+}