diff --git a/README.md b/README.md index fbd0f0873..d6fe16a4d 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ import ( func main() { router := openapi3filter.NewRouter().WithSwaggerFromFile("swagger.json") - ctx := context.TODO() + ctx := context.Background() httpReq, _ := http.NewRequest(http.MethodGet, "/items", nil) // Find route @@ -105,9 +105,7 @@ func main() { RequestValidationInput: requestValidationInput, Status: respStatus, Header: http.Header{ - "Content-Type": []string{ - respContentType, - }, + "Content-Type": []string{respContentType}, }, } if respBody != nil { diff --git a/jsoninfo/unmarshal_test.go b/jsoninfo/unmarshal_test.go index ce448a5fb..77ab42bb3 100644 --- a/jsoninfo/unmarshal_test.go +++ b/jsoninfo/unmarshal_test.go @@ -1,10 +1,9 @@ -package jsoninfo_test +package jsoninfo import ( "errors" "testing" - "github.com/getkin/kin-openapi/jsoninfo" "github.com/stretchr/testify/assert" ) @@ -16,7 +15,7 @@ func TestNewObjectDecoder(t *testing.T) { } `) t.Run("test new object decoder", func(t *testing.T) { - decoder, err := jsoninfo.NewObjectDecoder(data) + decoder, err := NewObjectDecoder(data) assert.Nil(t, err) assert.NotNil(t, decoder) assert.Equal(t, data, decoder.Data) @@ -25,15 +24,15 @@ func TestNewObjectDecoder(t *testing.T) { } type mockStrictStruct struct { - EncodeWithFn func(encoder *jsoninfo.ObjectEncoder, value interface{}) error - DecodeWithFn func(decoder *jsoninfo.ObjectDecoder, value interface{}) error + EncodeWithFn func(encoder *ObjectEncoder, value interface{}) error + DecodeWithFn func(decoder *ObjectDecoder, value interface{}) error } -func (m *mockStrictStruct) EncodeWith(encoder *jsoninfo.ObjectEncoder, value interface{}) error { +func (m *mockStrictStruct) EncodeWith(encoder *ObjectEncoder, value interface{}) error { return m.EncodeWithFn(encoder, value) } -func (m *mockStrictStruct) DecodeWith(decoder *jsoninfo.ObjectDecoder, value interface{}) error { +func (m *mockStrictStruct) DecodeWith(decoder *ObjectDecoder, value interface{}) error { return m.DecodeWithFn(decoder, value) } @@ -48,15 +47,15 @@ func TestUnmarshalStrictStruct(t *testing.T) { t.Run("test unmarshal with StrictStruct without err", func(t *testing.T) { decodeWithFnCalled := 0 mockStruct := &mockStrictStruct{ - EncodeWithFn: func(encoder *jsoninfo.ObjectEncoder, value interface{}) error { + EncodeWithFn: func(encoder *ObjectEncoder, value interface{}) error { return nil }, - DecodeWithFn: func(decoder *jsoninfo.ObjectDecoder, value interface{}) error { + DecodeWithFn: func(decoder *ObjectDecoder, value interface{}) error { decodeWithFnCalled++ return nil }, } - err := jsoninfo.UnmarshalStrictStruct(data, mockStruct) + err := UnmarshalStrictStruct(data, mockStruct) assert.Nil(t, err) assert.Equal(t, 1, decodeWithFnCalled) }) @@ -64,15 +63,15 @@ func TestUnmarshalStrictStruct(t *testing.T) { t.Run("test unmarshal with StrictStruct with err", func(t *testing.T) { decodeWithFnCalled := 0 mockStruct := &mockStrictStruct{ - EncodeWithFn: func(encoder *jsoninfo.ObjectEncoder, value interface{}) error { + EncodeWithFn: func(encoder *ObjectEncoder, value interface{}) error { return nil }, - DecodeWithFn: func(decoder *jsoninfo.ObjectDecoder, value interface{}) error { + DecodeWithFn: func(decoder *ObjectDecoder, value interface{}) error { decodeWithFnCalled++ return errors.New("unable to decode the value") }, } - err := jsoninfo.UnmarshalStrictStruct(data, mockStruct) + err := UnmarshalStrictStruct(data, mockStruct) assert.NotNil(t, err) assert.Equal(t, 1, decodeWithFnCalled) }) @@ -85,7 +84,7 @@ func TestDecodeStructFieldsAndExtensions(t *testing.T) { "field2": "field2" } `) - decoder, err := jsoninfo.NewObjectDecoder(data) + decoder, err := NewObjectDecoder(data) assert.Nil(t, err) assert.NotNil(t, decoder) @@ -111,7 +110,7 @@ func TestDecodeStructFieldsAndExtensions(t *testing.T) { }) t.Run("successfully decoded with all fields", func(t *testing.T) { - d, err := jsoninfo.NewObjectDecoder(data) + d, err := NewObjectDecoder(data) assert.Nil(t, err) assert.NotNil(t, d) @@ -127,7 +126,7 @@ func TestDecodeStructFieldsAndExtensions(t *testing.T) { }) t.Run("successfully decoded with renaming field", func(t *testing.T) { - d, err := jsoninfo.NewObjectDecoder(data) + d, err := NewObjectDecoder(data) assert.Nil(t, err) assert.NotNil(t, d) @@ -141,7 +140,7 @@ func TestDecodeStructFieldsAndExtensions(t *testing.T) { }) t.Run("un-successfully decoded due to data mismatch", func(t *testing.T) { - d, err := jsoninfo.NewObjectDecoder(data) + d, err := NewObjectDecoder(data) assert.Nil(t, err) assert.NotNil(t, d) diff --git a/openapi3/discriminator_test.go b/openapi3/discriminator_test.go index c12227141..602b4fd68 100644 --- a/openapi3/discriminator_test.go +++ b/openapi3/discriminator_test.go @@ -1,9 +1,8 @@ -package openapi3_test +package openapi3 import ( "testing" - "github.com/getkin/kin-openapi/openapi3" "github.com/stretchr/testify/require" ) @@ -37,7 +36,7 @@ var jsonSpecWithDiscriminator = []byte(` `) func TestParsingDiscriminator(t *testing.T) { - loader, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData(jsonSpecWithDiscriminator) + loader, err := NewSwaggerLoader().LoadSwaggerFromData(jsonSpecWithDiscriminator) require.NoError(t, err) require.Equal(t, 2, len(loader.Components.Schemas["MyResponseType"].Value.OneOf)) } diff --git a/openapi3/encoding_test.go b/openapi3/encoding_test.go index 67e7b6b65..5c354540d 100644 --- a/openapi3/encoding_test.go +++ b/openapi3/encoding_test.go @@ -1,4 +1,4 @@ -package openapi3_test +package openapi3 import ( "context" @@ -6,7 +6,6 @@ import ( "reflect" "testing" - "github.com/getkin/kin-openapi/openapi3" "github.com/stretchr/testify/require" ) @@ -17,13 +16,13 @@ func TestEncodingJSON(t *testing.T) { require.NotEmpty(t, data) t.Log("Unmarshal *openapi3.Encoding from JSON") - docA := &openapi3.Encoding{} + docA := &Encoding{} err = json.Unmarshal(encodingJSON, &docA) require.NoError(t, err) require.NotEmpty(t, data) t.Log("Validate *openapi3.Encoding") - err = docA.Validate(context.TODO()) + err = docA.Validate(context.Background()) require.NoError(t, err) t.Log("Ensure representations match") @@ -45,13 +44,13 @@ var encodingJSON = []byte(` } `) -func encoding() *openapi3.Encoding { +func encoding() *Encoding { explode := true - return &openapi3.Encoding{ + return &Encoding{ ContentType: "application/json", - Headers: map[string]*openapi3.HeaderRef{ + Headers: map[string]*HeaderRef{ "someHeader": { - Value: &openapi3.Header{}, + Value: &Header{}, }, }, Style: "form", @@ -64,32 +63,32 @@ func TestEncodingSerializationMethod(t *testing.T) { boolPtr := func(b bool) *bool { return &b } testCases := []struct { name string - enc *openapi3.Encoding - want *openapi3.SerializationMethod + enc *Encoding + want *SerializationMethod }{ { name: "default", - want: &openapi3.SerializationMethod{Style: openapi3.SerializationForm, Explode: true}, + want: &SerializationMethod{Style: SerializationForm, Explode: true}, }, { name: "encoding with style", - enc: &openapi3.Encoding{Style: openapi3.SerializationSpaceDelimited}, - want: &openapi3.SerializationMethod{Style: openapi3.SerializationSpaceDelimited, Explode: true}, + enc: &Encoding{Style: SerializationSpaceDelimited}, + want: &SerializationMethod{Style: SerializationSpaceDelimited, Explode: true}, }, { name: "encoding with explode", - enc: &openapi3.Encoding{Explode: boolPtr(true)}, - want: &openapi3.SerializationMethod{Style: openapi3.SerializationForm, Explode: true}, + enc: &Encoding{Explode: boolPtr(true)}, + want: &SerializationMethod{Style: SerializationForm, Explode: true}, }, { name: "encoding with no explode", - enc: &openapi3.Encoding{Explode: boolPtr(false)}, - want: &openapi3.SerializationMethod{Style: openapi3.SerializationForm, Explode: false}, + enc: &Encoding{Explode: boolPtr(false)}, + want: &SerializationMethod{Style: SerializationForm, Explode: false}, }, { name: "encoding with style and explode ", - enc: &openapi3.Encoding{Style: openapi3.SerializationSpaceDelimited, Explode: boolPtr(false)}, - want: &openapi3.SerializationMethod{Style: openapi3.SerializationSpaceDelimited, Explode: false}, + enc: &Encoding{Style: SerializationSpaceDelimited, Explode: boolPtr(false)}, + want: &SerializationMethod{Style: SerializationSpaceDelimited, Explode: false}, }, } for _, tc := range testCases { diff --git a/openapi3/example_test.go b/openapi3/example_test.go index a5dfb3008..4e9296ac0 100644 --- a/openapi3/example_test.go +++ b/openapi3/example_test.go @@ -1,10 +1,9 @@ -package openapi3_test +package openapi3 import ( "encoding/json" "testing" - "github.com/getkin/kin-openapi/openapi3" "github.com/stretchr/testify/require" ) @@ -15,7 +14,7 @@ func TestExampleJSON(t *testing.T) { require.NotEmpty(t, data) t.Log("Unmarshal *openapi3.Example from JSON") - docA := &openapi3.Example{} + docA := &Example{} err = json.Unmarshal(exampleJSON, &docA) require.NoError(t, err) require.NotEmpty(t, data) @@ -40,7 +39,7 @@ var exampleJSON = []byte(` } `) -func example() *openapi3.Example { +func example() *Example { value := map[string]string{ "name": "Fluffy", "petType": "Cat", @@ -48,7 +47,7 @@ func example() *openapi3.Example { "gender": "male", "breed": "Persian", } - return &openapi3.Example{ + return &Example{ Summary: "An example of a cat", Value: value, } diff --git a/openapi3/extension_test.go b/openapi3/extension_test.go index 775d8b6bc..3d0b233da 100644 --- a/openapi3/extension_test.go +++ b/openapi3/extension_test.go @@ -1,16 +1,16 @@ -package openapi3_test +package openapi3 import ( + "testing" + "github.com/getkin/kin-openapi/jsoninfo" - "github.com/getkin/kin-openapi/openapi3" "github.com/stretchr/testify/assert" - "testing" ) func TestExtensionProps_EncodeWith(t *testing.T) { t.Run("successfully encoded", func(t *testing.T) { encoder := jsoninfo.NewObjectEncoder() - var extensionProps = openapi3.ExtensionProps{ + var extensionProps = ExtensionProps{ Extensions: map[string]interface{}{ "field1": "value1", }, @@ -36,7 +36,7 @@ func TestExtensionProps_DecodeWith(t *testing.T) { t.Run("successfully decode all the fields", func(t *testing.T) { decoder, err := jsoninfo.NewObjectDecoder(data) assert.Nil(t, err) - var extensionProps = &openapi3.ExtensionProps{ + var extensionProps = &ExtensionProps{ Extensions: map[string]interface{}{ "field1": "value1", "field2": "value1", @@ -58,7 +58,7 @@ func TestExtensionProps_DecodeWith(t *testing.T) { t.Run("successfully decode some of the fields", func(t *testing.T) { decoder, err := jsoninfo.NewObjectDecoder(data) assert.Nil(t, err) - var extensionProps = &openapi3.ExtensionProps{ + var extensionProps = &ExtensionProps{ Extensions: map[string]interface{}{ "field1": "value1", "field2": "value2", @@ -79,7 +79,7 @@ func TestExtensionProps_DecodeWith(t *testing.T) { decoder, err := jsoninfo.NewObjectDecoder(data) assert.Nil(t, err) - var extensionProps = &openapi3.ExtensionProps{ + var extensionProps = &ExtensionProps{ Extensions: map[string]interface{}{ "field1": "value1", "field2": "value2", diff --git a/openapi3/media_type_test.go b/openapi3/media_type_test.go index 9d5092802..099c4b667 100644 --- a/openapi3/media_type_test.go +++ b/openapi3/media_type_test.go @@ -1,11 +1,10 @@ -package openapi3_test +package openapi3 import ( "context" "encoding/json" "testing" - "github.com/getkin/kin-openapi/openapi3" "github.com/stretchr/testify/require" ) @@ -16,13 +15,13 @@ func TestMediaTypeJSON(t *testing.T) { require.NotEmpty(t, data) t.Log("Unmarshal *openapi3.MediaType from JSON") - docA := &openapi3.MediaType{} + docA := &MediaType{} err = json.Unmarshal(mediaTypeJSON, &docA) require.NoError(t, err) require.NotEmpty(t, data) t.Log("Validate *openapi3.MediaType") - err = docA.Validate(context.TODO()) + err = docA.Validate(context.Background()) require.NoError(t, err) t.Log("Ensure representations match") @@ -52,22 +51,22 @@ var mediaTypeJSON = []byte(` } `) -func mediaType() *openapi3.MediaType { +func mediaType() *MediaType { example := map[string]string{"name": "Some example"} - return &openapi3.MediaType{ - Schema: &openapi3.SchemaRef{ - Value: &openapi3.Schema{ + return &MediaType{ + Schema: &SchemaRef{ + Value: &Schema{ Description: "Some schema", }, }, - Encoding: map[string]*openapi3.Encoding{ + Encoding: map[string]*Encoding{ "someEncoding": { ContentType: "application/xml; charset=utf-8", }, }, - Examples: map[string]*openapi3.ExampleRef{ + Examples: map[string]*ExampleRef{ "someExample": { - Value: openapi3.NewExample(example), + Value: NewExample(example), }, }, } diff --git a/openapi3/schema.go b/openapi3/schema.go index edb35c40c..8a34282ff 100644 --- a/openapi3/schema.go +++ b/openapi3/schema.go @@ -995,6 +995,9 @@ func (schema *Schema) visitJSONArray(value []interface{}, fast bool) (err error) } // "uniqueItems" + if sliceUniqueItemsChecker == nil { + sliceUniqueItemsChecker = isSliceOfUniqueItems + } if v := schema.UniqueItems; v && !sliceUniqueItemsChecker(value) { if fast { return errSchema diff --git a/openapi3/schema_test.go b/openapi3/schema_test.go index e82aba26b..10e1d0589 100644 --- a/openapi3/schema_test.go +++ b/openapi3/schema_test.go @@ -1,4 +1,4 @@ -package openapi3_test +package openapi3 import ( "context" @@ -8,20 +8,19 @@ import ( "strings" "testing" - "github.com/getkin/kin-openapi/openapi3" "github.com/stretchr/testify/require" ) type schemaExample struct { Title string - Schema *openapi3.Schema + Schema *Schema Serialization interface{} AllValid []interface{} AllInvalid []interface{} } func TestSchemas(t *testing.T) { - openapi3.DefineStringFormat("uuid", openapi3.FormatOfStringForUUIDOfRFC4122) + DefineStringFormat("uuid", FormatOfStringForUUIDOfRFC4122) for _, example := range schemaExamples { t.Run(example.Title, testSchema(t, example)) } @@ -36,10 +35,10 @@ func testSchema(t *testing.T, example schemaExample) func(*testing.T) { jsonSchema, err := json.Marshal(schema) require.NoError(t, err) require.JSONEq(t, string(jsonSerialized), string(jsonSchema)) - var dataUnserialized openapi3.Schema + var dataUnserialized Schema err = json.Unmarshal(jsonSerialized, &dataUnserialized) require.NoError(t, err) - var dataSchema openapi3.Schema + var dataSchema Schema err = json.Unmarshal(jsonSchema, &dataSchema) require.NoError(t, err) require.Equal(t, dataUnserialized, dataSchema) @@ -60,7 +59,7 @@ func testSchema(t *testing.T, example schemaExample) func(*testing.T) { } } -func validateSchema(t *testing.T, schema *openapi3.Schema, value interface{}) error { +func validateSchema(t *testing.T, schema *Schema, value interface{}) error { data, err := json.Marshal(value) require.NoError(t, err) var val interface{} @@ -72,7 +71,7 @@ func validateSchema(t *testing.T, schema *openapi3.Schema, value interface{}) er var schemaExamples = []schemaExample{ { Title: "EMPTY SCHEMA", - Schema: &openapi3.Schema{}, + Schema: &Schema{}, Serialization: map[string]interface{}{ // This OA3 schema is exactly this draft-04 schema: // {"not": {"type": "null"}} @@ -92,7 +91,7 @@ var schemaExamples = []schemaExample{ { Title: "JUST NULLABLE", - Schema: openapi3.NewSchema().WithNullable(), + Schema: NewSchema().WithNullable(), Serialization: map[string]interface{}{ // This OA3 schema is exactly both this draft-04 schema: {} and: // {anyOf: [type:string, type:number, type:integer, type:boolean @@ -114,7 +113,7 @@ var schemaExamples = []schemaExample{ { Title: "NULLABLE BOOLEAN", - Schema: openapi3.NewBoolSchema().WithNullable(), + Schema: NewBoolSchema().WithNullable(), Serialization: map[string]interface{}{ "nullable": true, "type": "boolean", @@ -136,9 +135,9 @@ var schemaExamples = []schemaExample{ { Title: "NULLABLE ANYOF", - Schema: openapi3.NewAnyOfSchema( - openapi3.NewIntegerSchema(), - openapi3.NewFloat64Schema(), + Schema: NewAnyOfSchema( + NewIntegerSchema(), + NewFloat64Schema(), ).WithNullable(), Serialization: map[string]interface{}{ "nullable": true, @@ -162,7 +161,7 @@ var schemaExamples = []schemaExample{ { Title: "BOOLEAN", - Schema: openapi3.NewBoolSchema(), + Schema: NewBoolSchema(), Serialization: map[string]interface{}{ "type": "boolean", }, @@ -181,7 +180,7 @@ var schemaExamples = []schemaExample{ { Title: "NUMBER", - Schema: openapi3.NewFloat64Schema(). + Schema: NewFloat64Schema(). WithMin(2.5). WithMax(3.5), Serialization: map[string]interface{}{ @@ -208,7 +207,7 @@ var schemaExamples = []schemaExample{ { Title: "INTEGER", - Schema: openapi3.NewInt64Schema(). + Schema: NewInt64Schema(). WithMin(2). WithMax(5), Serialization: map[string]interface{}{ @@ -236,7 +235,7 @@ var schemaExamples = []schemaExample{ { Title: "STRING", - Schema: openapi3.NewStringSchema(). + Schema: NewStringSchema(). WithMinLength(2). WithMaxLength(3). WithPattern("^[abc]+$"), @@ -265,7 +264,7 @@ var schemaExamples = []schemaExample{ { Title: "STRING: optional format 'uuid'", - Schema: openapi3.NewUUIDSchema(), + Schema: NewUUIDSchema(), Serialization: map[string]interface{}{ "type": "string", "format": "uuid", @@ -286,7 +285,7 @@ var schemaExamples = []schemaExample{ { Title: "STRING: format 'date-time'", - Schema: openapi3.NewDateTimeSchema(), + Schema: NewDateTimeSchema(), Serialization: map[string]interface{}{ "type": "string", "format": "date-time", @@ -311,7 +310,7 @@ var schemaExamples = []schemaExample{ { Title: "STRING: format 'date-time'", - Schema: openapi3.NewBytesSchema(), + Schema: NewBytesSchema(), Serialization: map[string]interface{}{ "type": "string", "format": "byte", @@ -343,12 +342,12 @@ var schemaExamples = []schemaExample{ { Title: "ARRAY", - Schema: &openapi3.Schema{ + Schema: &Schema{ Type: "array", MinItems: 2, - MaxItems: openapi3.Uint64Ptr(3), + MaxItems: Uint64Ptr(3), UniqueItems: true, - Items: openapi3.NewFloat64Schema().NewRef(), + Items: NewFloat64Schema().NewRef(), }, Serialization: map[string]interface{}{ "type": "array", @@ -383,13 +382,13 @@ var schemaExamples = []schemaExample{ }, { Title: "ARRAY : items format 'object'", - Schema: &openapi3.Schema{ + Schema: &Schema{ Type: "array", UniqueItems: true, - Items: (&openapi3.Schema{ + Items: (&Schema{ Type: "object", - Properties: map[string]*openapi3.SchemaRef{ - "key1": openapi3.NewFloat64Schema().NewRef(), + Properties: map[string]*SchemaRef{ + "key1": NewFloat64Schema().NewRef(), }, }).NewRef(), }, @@ -440,16 +439,16 @@ var schemaExamples = []schemaExample{ { Title: "ARRAY : items format 'object' and object with a property of array type ", - Schema: &openapi3.Schema{ + Schema: &Schema{ Type: "array", UniqueItems: true, - Items: (&openapi3.Schema{ + Items: (&Schema{ Type: "object", - Properties: map[string]*openapi3.SchemaRef{ - "key1": (&openapi3.Schema{ + Properties: map[string]*SchemaRef{ + "key1": (&Schema{ Type: "array", UniqueItems: true, - Items: openapi3.NewFloat64Schema().NewRef(), + Items: NewFloat64Schema().NewRef(), }).NewRef(), }, }).NewRef(), @@ -526,13 +525,13 @@ var schemaExamples = []schemaExample{ { Title: "ARRAY : items format 'array'", - Schema: &openapi3.Schema{ + Schema: &Schema{ Type: "array", UniqueItems: true, - Items: (&openapi3.Schema{ + Items: (&Schema{ Type: "array", UniqueItems: true, - Items: openapi3.NewFloat64Schema().NewRef(), + Items: NewFloat64Schema().NewRef(), }).NewRef(), }, Serialization: map[string]interface{}{ @@ -570,16 +569,16 @@ var schemaExamples = []schemaExample{ { Title: "ARRAY : items format 'array' and array with object type items", - Schema: &openapi3.Schema{ + Schema: &Schema{ Type: "array", UniqueItems: true, - Items: (&openapi3.Schema{ + Items: (&Schema{ Type: "array", UniqueItems: true, - Items: (&openapi3.Schema{ + Items: (&Schema{ Type: "object", - Properties: map[string]*openapi3.SchemaRef{ - "key1": openapi3.NewFloat64Schema().NewRef(), + Properties: map[string]*SchemaRef{ + "key1": NewFloat64Schema().NewRef(), }, }).NewRef(), }).NewRef(), @@ -674,11 +673,11 @@ var schemaExamples = []schemaExample{ { Title: "OBJECT", - Schema: &openapi3.Schema{ + Schema: &Schema{ Type: "object", - MaxProps: openapi3.Uint64Ptr(2), - Properties: map[string]*openapi3.SchemaRef{ - "numberProperty": openapi3.NewFloat64Schema().NewRef(), + MaxProps: Uint64Ptr(2), + Properties: map[string]*SchemaRef{ + "numberProperty": NewFloat64Schema().NewRef(), }, }, Serialization: map[string]interface{}{ @@ -718,10 +717,10 @@ var schemaExamples = []schemaExample{ }, }, { - Schema: &openapi3.Schema{ + Schema: &Schema{ Type: "object", - AdditionalProperties: &openapi3.SchemaRef{ - Value: &openapi3.Schema{ + AdditionalProperties: &SchemaRef{ + Value: &Schema{ Type: "number", }, }, @@ -746,9 +745,9 @@ var schemaExamples = []schemaExample{ }, }, { - Schema: &openapi3.Schema{ + Schema: &Schema{ Type: "object", - AdditionalPropertiesAllowed: openapi3.BoolPtr(true), + AdditionalPropertiesAllowed: BoolPtr(true), }, Serialization: map[string]interface{}{ "type": "object", @@ -765,9 +764,9 @@ var schemaExamples = []schemaExample{ { Title: "NOT", - Schema: &openapi3.Schema{ - Not: &openapi3.SchemaRef{ - Value: &openapi3.Schema{ + Schema: &Schema{ + Not: &SchemaRef{ + Value: &Schema{ Enum: []interface{}{ nil, true, @@ -802,15 +801,15 @@ var schemaExamples = []schemaExample{ { Title: "ANY OF", - Schema: &openapi3.Schema{ - AnyOf: []*openapi3.SchemaRef{ + Schema: &Schema{ + AnyOf: []*SchemaRef{ { - Value: openapi3.NewFloat64Schema(). + Value: NewFloat64Schema(). WithMin(1). WithMax(2), }, { - Value: openapi3.NewFloat64Schema(). + Value: NewFloat64Schema(). WithMin(2). WithMax(3), }, @@ -843,15 +842,15 @@ var schemaExamples = []schemaExample{ { Title: "ALL OF", - Schema: &openapi3.Schema{ - AllOf: []*openapi3.SchemaRef{ + Schema: &Schema{ + AllOf: []*SchemaRef{ { - Value: openapi3.NewFloat64Schema(). + Value: NewFloat64Schema(). WithMin(1). WithMax(2), }, { - Value: openapi3.NewFloat64Schema(). + Value: NewFloat64Schema(). WithMin(2). WithMax(3), }, @@ -884,15 +883,15 @@ var schemaExamples = []schemaExample{ { Title: "ONE OF", - Schema: &openapi3.Schema{ - OneOf: []*openapi3.SchemaRef{ + Schema: &Schema{ + OneOf: []*SchemaRef{ { - Value: openapi3.NewFloat64Schema(). + Value: NewFloat64Schema(). WithMin(1). WithMax(2), }, { - Value: openapi3.NewFloat64Schema(). + Value: NewFloat64Schema(). WithMin(2). WithMax(3), }, @@ -926,7 +925,7 @@ var schemaExamples = []schemaExample{ type schemaTypeExample struct { Title string - Schema *openapi3.Schema + Schema *Schema AllValid []string AllInvalid []string } @@ -942,12 +941,12 @@ func testType(t *testing.T, example schemaTypeExample) func(*testing.T) { baseSchema := example.Schema for _, typ := range example.AllValid { schema := baseSchema.WithFormat(typ) - err := schema.Validate(context.TODO()) + err := schema.Validate(context.Background()) require.NoError(t, err) } for _, typ := range example.AllInvalid { schema := baseSchema.WithFormat(typ) - err := schema.Validate(context.TODO()) + err := schema.Validate(context.Background()) require.Error(t, err) } } @@ -956,7 +955,7 @@ func testType(t *testing.T, example schemaTypeExample) func(*testing.T) { var typeExamples = []schemaTypeExample{ { Title: "STRING", - Schema: openapi3.NewStringSchema(), + Schema: NewStringSchema(), AllValid: []string{ "", "byte", @@ -974,7 +973,7 @@ var typeExamples = []schemaTypeExample{ { Title: "NUMBER", - Schema: openapi3.NewFloat64Schema(), + Schema: NewFloat64Schema(), AllValid: []string{ "", "float", @@ -987,7 +986,7 @@ var typeExamples = []schemaTypeExample{ { Title: "INTEGER", - Schema: openapi3.NewIntegerSchema(), + Schema: NewIntegerSchema(), AllValid: []string{ "", "int32", @@ -1014,60 +1013,32 @@ func testSchemaError(t *testing.T, example schemaErrorExample) func(*testing.T) type schemaErrorExample struct { Title string - Error *openapi3.SchemaError + Error *SchemaError Want string } var schemaErrorExamples = []schemaErrorExample{ { Title: "SIMPLE", - Error: &openapi3.SchemaError{ + Error: &SchemaError{ Value: 1, - Schema: &openapi3.Schema{}, + Schema: &Schema{}, Reason: "SIMPLE", }, Want: "SIMPLE", }, { Title: "NEST", - Error: &openapi3.SchemaError{ + Error: &SchemaError{ Value: 1, - Schema: &openapi3.Schema{}, + Schema: &Schema{}, Reason: "PARENT", - Origin: &openapi3.SchemaError{ + Origin: &SchemaError{ Value: 1, - Schema: &openapi3.Schema{}, + Schema: &Schema{}, Reason: "NEST", }, }, Want: "NEST", }, } - -func TestRegisterArrayUniqueItemsChecker(t *testing.T) { - var ( - checker = func(items []interface{}) bool { - return false - } - scheme = openapi3.Schema{ - Type: "array", - UniqueItems: true, - Items: openapi3.NewStringSchema().NewRef(), - } - val = []interface{}{"1", "2", "3"} - err error - ) - - // Fist checked by predefined function - err = scheme.VisitJSON(val) - require.NoError(t, err) - - // Register a function will always return false when check if a - // slice has unique items, then use a slice indeed has unique - // items to verify that check unique items will failed. - openapi3.RegisterArrayUniqueItemsChecker(checker) - - err = scheme.VisitJSON(val) - require.Error(t, err) - require.True(t, strings.HasPrefix(err.Error(), "Duplicate items found")) -} diff --git a/openapi3/security_scheme_test.go b/openapi3/security_scheme_test.go index 7f013be4c..2a6420877 100644 --- a/openapi3/security_scheme_test.go +++ b/openapi3/security_scheme_test.go @@ -1,10 +1,9 @@ -package openapi3_test +package openapi3 import ( "context" "testing" - "github.com/getkin/kin-openapi/openapi3" "github.com/stretchr/testify/require" ) @@ -23,10 +22,10 @@ func TestSecuritySchemaExample(t *testing.T) { func testSecuritySchemaExample(t *testing.T, e securitySchemeExample) func(*testing.T) { return func(t *testing.T) { var err error - ss := &openapi3.SecurityScheme{} + ss := &SecurityScheme{} err = ss.UnmarshalJSON(e.raw) require.NoError(t, err) - err = ss.Validate(context.TODO()) + err = ss.Validate(context.Background()) if e.valid { require.NoError(t, err) } else { diff --git a/openapi3/server.go b/openapi3/server.go index 2594d2b30..c6cd44353 100644 --- a/openapi3/server.go +++ b/openapi3/server.go @@ -11,6 +11,7 @@ import ( // Servers is specified by OpenAPI/Swagger standard version 3.0. type Servers []*Server +// Validate ensures servers are per the OpenAPIv3 specification. func (servers Servers) Validate(c context.Context) error { for _, v := range servers { if err := v.Validate(c); err != nil { @@ -141,7 +142,7 @@ func (serverVariable *ServerVariable) Validate(c context.Context) error { switch item.(type) { case float64, string: default: - return errors.New("Every variable 'enum' item must be number of string") + return errors.New("All 'enum' items must be either a number or a string") } } return nil diff --git a/openapi3/server_test.go b/openapi3/server_test.go index beafcaa63..550eacbd9 100644 --- a/openapi3/server_test.go +++ b/openapi3/server_test.go @@ -1,16 +1,15 @@ -package openapi3_test +package openapi3 import ( "context" "errors" "testing" - "github.com/getkin/kin-openapi/openapi3" "github.com/stretchr/testify/require" ) func TestServerParamNames(t *testing.T) { - server := &openapi3.Server{ + server := &Server{ URL: "http://{x}.{y}.example.com", } values, err := server.ParameterNames() @@ -19,7 +18,7 @@ func TestServerParamNames(t *testing.T) { } func TestServerParamValuesWithPath(t *testing.T) { - server := &openapi3.Server{ + server := &Server{ URL: "http://{arg0}.{arg1}.example.com/a/{arg3}-version/{arg4}c{arg5}", } for input, expected := range map[string]*serverMatch{ @@ -41,7 +40,7 @@ func TestServerParamValuesWithPath(t *testing.T) { } func TestServerParamValuesNoPath(t *testing.T) { - server := &openapi3.Server{ + server := &Server{ URL: "https://{arg0}.{arg1}.example.com/", } for input, expected := range map[string]*serverMatch{ @@ -51,20 +50,20 @@ func TestServerParamValuesNoPath(t *testing.T) { } } -func validServer() *openapi3.Server { - return &openapi3.Server{ +func validServer() *Server { + return &Server{ URL: "http://my.cool.website", } } -func invalidServer() *openapi3.Server { - return &openapi3.Server{} +func invalidServer() *Server { + return &Server{} } func TestServerValidation(t *testing.T) { tests := []struct { name string - input *openapi3.Server + input *Server expectedError error }{ { @@ -89,7 +88,7 @@ func TestServerValidation(t *testing.T) { } } -func testServerParamValues(t *testing.T, server *openapi3.Server, input string, expected *serverMatch) func(*testing.T) { +func testServerParamValues(t *testing.T, server *Server, input string, expected *serverMatch) func(*testing.T) { return func(t *testing.T) { args, remaining, ok := server.MatchRawURL(input) if expected == nil { diff --git a/openapi3/swagger_loader.go b/openapi3/swagger_loader.go index aae028065..44d98ab7a 100644 --- a/openapi3/swagger_loader.go +++ b/openapi3/swagger_loader.go @@ -17,15 +17,15 @@ import ( ) func foundUnresolvedRef(ref string) error { - return fmt.Errorf("Found unresolved ref: '%s'", ref) + return fmt.Errorf("found unresolved ref: %q", ref) } func failedToResolveRefFragment(value string) error { - return fmt.Errorf("Failed to resolve fragment in URI: '%s'", value) + return fmt.Errorf("failed to resolve fragment in URI: %q", value) } func failedToResolveRefFragmentPart(value string, what string) error { - return fmt.Errorf("Failed to resolve '%s' in fragment in URI: '%s'", what, value) + return fmt.Errorf("failed to resolve %q in fragment in URI: %q", what, value) } type SwaggerLoader struct { @@ -65,7 +65,7 @@ func (swaggerLoader *SwaggerLoader) loadSwaggerFromURIInternal(location *url.URL // passed element. func (swaggerLoader *SwaggerLoader) loadSingleElementFromURI(ref string, rootPath *url.URL, element json.Unmarshaler) error { if !swaggerLoader.IsExternalRefsAllowed { - return fmt.Errorf("encountered non-allowed external reference: '%s'", ref) + return fmt.Errorf("encountered non-allowed external reference: %q", ref) } parsedURL, err := url.Parse(ref) @@ -107,7 +107,7 @@ func readURL(location *url.URL) ([]byte, error) { return data, nil } if location.Scheme != "" || location.Host != "" || location.RawQuery != "" { - return nil, fmt.Errorf("Unsupported URI: '%s'", location.String()) + return nil, fmt.Errorf("unsupported URI: %q", location.String()) } data, err := ioutil.ReadFile(location.Path) if err != nil { @@ -123,18 +123,16 @@ func (swaggerLoader *SwaggerLoader) LoadSwaggerFromFile(path string) (*Swagger, func (swaggerLoader *SwaggerLoader) loadSwaggerFromFileInternal(path string) (*Swagger, error) { f := swaggerLoader.LoadSwaggerFromURIFunc + pathAsURL := &url.URL{Path: path} if f != nil { - return f(swaggerLoader, &url.URL{ - Path: path, - }) + x, err := f(swaggerLoader, pathAsURL) + return x, err } data, err := ioutil.ReadFile(path) if err != nil { return nil, err } - return swaggerLoader.loadSwaggerFromDataWithPathInternal(data, &url.URL{ - Path: path, - }) + return swaggerLoader.loadSwaggerFromDataWithPathInternal(data, pathAsURL) } func (swaggerLoader *SwaggerLoader) LoadSwaggerFromData(data []byte) (*Swagger, error) { @@ -266,11 +264,11 @@ func (swaggerLoader *SwaggerLoader) resolveComponent(swagger *Swagger, ref strin parsedURL, err := url.Parse(ref) if err != nil { - return nil, nil, fmt.Errorf("Can't parse reference: '%s': %v", ref, parsedURL) + return nil, nil, fmt.Errorf("cannot parse reference: %q: %v", ref, parsedURL) } fragment := parsedURL.Fragment if !strings.HasPrefix(fragment, "/") { - err := fmt.Errorf("expected fragment prefix '#/' in URI '%s'", ref) + err := fmt.Errorf("expected fragment prefix '#/' in URI %q", ref) return nil, nil, err } @@ -279,7 +277,7 @@ func (swaggerLoader *SwaggerLoader) resolveComponent(swagger *Swagger, ref strin pathPart = unescapeRefString(pathPart) if cursor, err = drillIntoSwaggerField(cursor, pathPart); err != nil { - return nil, nil, fmt.Errorf("Failed to resolve '%s' in fragment in URI: '%s': %v", ref, pathPart, err.Error()) + return nil, nil, fmt.Errorf("failed to resolve %q in fragment in URI: %q: %v", ref, pathPart, err.Error()) } if cursor == nil { return nil, nil, failedToResolveRefFragmentPart(ref, pathPart) @@ -294,7 +292,7 @@ func drillIntoSwaggerField(cursor interface{}, fieldName string) (interface{}, e case reflect.Map: elementValue := val.MapIndex(reflect.ValueOf(fieldName)) if !elementValue.IsValid() { - return nil, fmt.Errorf("Map key not found: %v", fieldName) + return nil, fmt.Errorf("map key %q not found", fieldName) } return elementValue.Interface(), nil @@ -324,7 +322,7 @@ func drillIntoSwaggerField(cursor interface{}, fieldName string) (interface{}, e return drillIntoSwaggerField(val.FieldByName("Value").Interface(), fieldName) // recurse into .Value } // give up - return nil, fmt.Errorf("Struct field not found: %v", fieldName) + return nil, fmt.Errorf("struct field %q not found", fieldName) default: return nil, errors.New("not a map, slice nor struct") @@ -335,24 +333,24 @@ func (swaggerLoader *SwaggerLoader) resolveRefSwagger(swagger *Swagger, ref stri componentPath := path if !strings.HasPrefix(ref, "#") { if !swaggerLoader.IsExternalRefsAllowed { - return nil, "", nil, fmt.Errorf("Encountered non-allowed external reference: '%s'", ref) + return nil, "", nil, fmt.Errorf("encountered non-allowed external reference: %q", ref) } parsedURL, err := url.Parse(ref) if err != nil { - return nil, "", nil, fmt.Errorf("Can't parse reference: '%s': %v", ref, parsedURL) + return nil, "", nil, fmt.Errorf("cannot parse reference: %q: %v", ref, parsedURL) } fragment := parsedURL.Fragment parsedURL.Fragment = "" resolvedPath, err := resolvePath(path, parsedURL) if err != nil { - return nil, "", nil, fmt.Errorf("Error while resolving path: %v", err) + return nil, "", nil, fmt.Errorf("error resolving path: %v", err) } if swagger, err = swaggerLoader.loadSwaggerFromURIInternal(resolvedPath); err != nil { - return nil, "", nil, fmt.Errorf("Error while resolving reference '%s': %v", ref, err) + return nil, "", nil, fmt.Errorf("error resolving reference %q: %v", ref, err) } - ref = fmt.Sprintf("#%s", fragment) + ref = "#" + fragment componentPath = resolvedPath } return swagger, ref, componentPath, nil @@ -449,7 +447,7 @@ func (swaggerLoader *SwaggerLoader) resolveParameterRef(swagger *Swagger, compon } if value.Content != nil && value.Schema != nil { - return errors.New("Cannot contain both schema and content in a parameter") + return errors.New("cannot contain both schema and content in a parameter") } for _, contentType := range value.Content { if schema := contentType.Schema; schema != nil { @@ -822,7 +820,7 @@ func (swaggerLoader *SwaggerLoader) resolvePathItemRef(swagger *Swagger, entrypo } if !strings.HasPrefix(ref, prefix) { - err = fmt.Errorf("expected prefix '%s' in URI '%s'", prefix, ref) + err = fmt.Errorf("expected prefix %q in URI %q", prefix, ref) return } id := unescapeRefString(ref[len(prefix):]) diff --git a/openapi3/swagger_loader_empty_response_description_test.go b/openapi3/swagger_loader_empty_response_description_test.go index 5199ac169..c75ad8aae 100644 --- a/openapi3/swagger_loader_empty_response_description_test.go +++ b/openapi3/swagger_loader_empty_response_description_test.go @@ -1,11 +1,10 @@ -package openapi3_test +package openapi3 import ( "encoding/json" "strings" "testing" - "github.com/getkin/kin-openapi/openapi3" "github.com/stretchr/testify/require" ) @@ -34,7 +33,7 @@ func TestJSONSpecResponseDescriptionEmptiness(t *testing.T) { { spec := []byte(spec) - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() doc, err := loader.LoadSwaggerFromData(spec) require.NoError(t, err) got := doc.Paths["/path1"].Get.Responses["200"].Value.Description @@ -47,7 +46,7 @@ func TestJSONSpecResponseDescriptionEmptiness(t *testing.T) { { spec := []byte(strings.Replace(spec, `"description": ""`, `"description": "My response"`, 1)) - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() doc, err := loader.LoadSwaggerFromData(spec) require.NoError(t, err) got := doc.Paths["/path1"].Get.Responses["200"].Value.Description @@ -58,8 +57,8 @@ func TestJSONSpecResponseDescriptionEmptiness(t *testing.T) { require.NoError(t, err) } - noDescriptionIsInvalid := func(data []byte) *openapi3.Swagger { - loader := openapi3.NewSwaggerLoader() + noDescriptionIsInvalid := func(data []byte) *Swagger { + loader := NewSwaggerLoader() doc, err := loader.LoadSwaggerFromData(data) require.NoError(t, err) got := doc.Paths["/path1"].Get.Responses["200"].Value.Description @@ -70,7 +69,7 @@ func TestJSONSpecResponseDescriptionEmptiness(t *testing.T) { return doc } - var docWithNoResponseDescription *openapi3.Swagger + var docWithNoResponseDescription *Swagger { spec := []byte(strings.Replace(spec, `"description": ""`, ``, 1)) docWithNoResponseDescription = noDescriptionIsInvalid(spec) diff --git a/openapi3/swagger_loader_paths_test.go b/openapi3/swagger_loader_paths_test.go index 9605b07a4..babd52c25 100644 --- a/openapi3/swagger_loader_paths_test.go +++ b/openapi3/swagger_loader_paths_test.go @@ -1,10 +1,9 @@ -package openapi3_test +package openapi3 import ( "strings" "testing" - "github.com/getkin/kin-openapi/openapi3" "github.com/stretchr/testify/require" ) @@ -27,7 +26,7 @@ paths: "foo/bar": "invalid paths: path \"foo/bar\" does not start with a forward slash (/)", "/foo/bar": "", } { - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() doc, err := loader.LoadSwaggerFromData([]byte(strings.Replace(spec, "PATH", path, 1))) require.NoError(t, err) err = doc.Validate(loader.Context) diff --git a/openapi3/swagger_loader_relative_refs_test.go b/openapi3/swagger_loader_relative_refs_test.go index 5ad7585ae..071938908 100644 --- a/openapi3/swagger_loader_relative_refs_test.go +++ b/openapi3/swagger_loader_relative_refs_test.go @@ -1,33 +1,31 @@ -package openapi3_test +package openapi3 import ( "fmt" - "net/url" "testing" - "github.com/getkin/kin-openapi/openapi3" "github.com/stretchr/testify/require" ) type refTestDataEntry struct { name string contentTemplate string - testFunc func(t *testing.T, swagger *openapi3.Swagger) + testFunc func(t *testing.T, swagger *Swagger) } type refTestDataEntryWithErrorMessage struct { name string contentTemplate string errorMessage *string - testFunc func(t *testing.T, swagger *openapi3.Swagger) + testFunc func(t *testing.T, swagger *Swagger) } var refTestDataEntries = []refTestDataEntry{ { name: "SchemaRef", contentTemplate: externalSchemaRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Components.Schemas["TestSchema"].Value.Type) require.Equal(t, "string", swagger.Components.Schemas["TestSchema"].Value.Type) }, @@ -35,7 +33,7 @@ var refTestDataEntries = []refTestDataEntry{ { name: "ResponseRef", contentTemplate: externalResponseRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { desc := "description" require.Equal(t, &desc, swagger.Components.Responses["TestResponse"].Value.Description) }, @@ -43,7 +41,7 @@ var refTestDataEntries = []refTestDataEntry{ { name: "ParameterRef", contentTemplate: externalParameterRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Components.Parameters["TestParameter"].Value.Name) require.Equal(t, "id", swagger.Components.Parameters["TestParameter"].Value.Name) }, @@ -51,7 +49,7 @@ var refTestDataEntries = []refTestDataEntry{ { name: "ExampleRef", contentTemplate: externalExampleRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Components.Examples["TestExample"].Value.Description) require.Equal(t, "description", swagger.Components.Examples["TestExample"].Value.Description) }, @@ -59,14 +57,14 @@ var refTestDataEntries = []refTestDataEntry{ { name: "RequestBodyRef", contentTemplate: externalRequestBodyRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Components.RequestBodies["TestRequestBody"].Value.Content) }, }, { name: "SecuritySchemeRef", contentTemplate: externalSecuritySchemeRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Components.SecuritySchemes["TestSecurityScheme"].Value.Description) require.Equal(t, "description", swagger.Components.SecuritySchemes["TestSecurityScheme"].Value.Description) }, @@ -74,7 +72,7 @@ var refTestDataEntries = []refTestDataEntry{ { name: "ExternalHeaderRef", contentTemplate: externalHeaderRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Components.Headers["TestHeader"].Value.Description) require.Equal(t, "description", swagger.Components.Headers["TestHeader"].Value.Description) }, @@ -82,7 +80,7 @@ var refTestDataEntries = []refTestDataEntry{ { name: "PathParameterRef", contentTemplate: externalPathParameterRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Paths["/test/{id}"].Parameters[0].Value.Name) require.Equal(t, "id", swagger.Paths["/test/{id}"].Parameters[0].Value.Name) }, @@ -90,7 +88,7 @@ var refTestDataEntries = []refTestDataEntry{ { name: "PathOperationParameterRef", contentTemplate: externalPathOperationParameterRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Paths["/test/{id}"].Get.Parameters[0].Value) require.Equal(t, "id", swagger.Paths["/test/{id}"].Get.Parameters[0].Value.Name) }, @@ -98,7 +96,7 @@ var refTestDataEntries = []refTestDataEntry{ { name: "PathOperationRequestBodyRef", contentTemplate: externalPathOperationRequestBodyRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Paths["/test"].Post.RequestBody.Value) require.NotNil(t, swagger.Paths["/test"].Post.RequestBody.Value.Content) }, @@ -106,7 +104,7 @@ var refTestDataEntries = []refTestDataEntry{ { name: "PathOperationResponseRef", contentTemplate: externalPathOperationResponseRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Paths["/test"].Post.Responses["default"].Value) desc := "description" require.Equal(t, &desc, swagger.Paths["/test"].Post.Responses["default"].Value.Description) @@ -115,7 +113,7 @@ var refTestDataEntries = []refTestDataEntry{ { name: "PathOperationParameterSchemaRef", contentTemplate: externalPathOperationParameterSchemaRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Paths["/test/{id}"].Get.Parameters[0].Value.Schema.Value) require.Equal(t, "string", swagger.Paths["/test/{id}"].Get.Parameters[0].Value.Schema.Value.Type) require.Equal(t, "id", swagger.Paths["/test/{id}"].Get.Parameters[0].Value.Name) @@ -125,7 +123,7 @@ var refTestDataEntries = []refTestDataEntry{ { name: "PathOperationParameterRefWithContentInQuery", contentTemplate: externalPathOperationParameterWithContentInQueryTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { schemaRef := swagger.Paths["/test/{id}"].Get.Parameters[0].Value.Content["application/json"].Schema require.NotNil(t, schemaRef.Value) require.Equal(t, "string", schemaRef.Value.Type) @@ -135,7 +133,7 @@ var refTestDataEntries = []refTestDataEntry{ { name: "PathOperationRequestBodyExampleRef", contentTemplate: externalPathOperationRequestBodyExampleRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Paths["/test"].Post.RequestBody.Value.Content["application/json"].Examples["application/json"].Value) require.Equal(t, "description", swagger.Paths["/test"].Post.RequestBody.Value.Content["application/json"].Examples["application/json"].Value.Description) }, @@ -143,7 +141,7 @@ var refTestDataEntries = []refTestDataEntry{ { name: "PathOperationReqestBodyContentSchemaRef", contentTemplate: externalPathOperationReqestBodyContentSchemaRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Paths["/test"].Post.RequestBody.Value.Content["application/json"].Schema.Value) require.Equal(t, "string", swagger.Paths["/test"].Post.RequestBody.Value.Content["application/json"].Schema.Value.Type) }, @@ -151,7 +149,7 @@ var refTestDataEntries = []refTestDataEntry{ { name: "PathOperationResponseExampleRef", contentTemplate: externalPathOperationResponseExampleRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Paths["/test"].Post.Responses["default"].Value) desc := "testdescription" require.Equal(t, &desc, swagger.Paths["/test"].Post.Responses["default"].Value.Description) @@ -161,7 +159,7 @@ var refTestDataEntries = []refTestDataEntry{ { name: "PathOperationResponseSchemaRef", contentTemplate: externalPathOperationResponseSchemaRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Paths["/test"].Post.Responses["default"].Value) desc := "testdescription" require.Equal(t, &desc, swagger.Paths["/test"].Post.Responses["default"].Value.Description) @@ -171,7 +169,7 @@ var refTestDataEntries = []refTestDataEntry{ { name: "ComponentHeaderSchemaRef", contentTemplate: externalComponentHeaderSchemaRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Components.Headers["TestHeader"].Value) require.Equal(t, "string", swagger.Components.Headers["TestHeader"].Value.Schema.Value.Type) }, @@ -179,7 +177,7 @@ var refTestDataEntries = []refTestDataEntry{ { name: "RequestResponseHeaderRef", contentTemplate: externalRequestResponseHeaderRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Paths["/test"].Post.Responses["default"].Value.Headers["X-TEST-HEADER"].Value.Description) require.Equal(t, "description", swagger.Paths["/test"].Post.Responses["default"].Value.Headers["X-TEST-HEADER"].Value.Description) }, @@ -190,8 +188,8 @@ var refTestDataEntriesResponseError = []refTestDataEntryWithErrorMessage{ { name: "CannotContainBothSchemaAndContentInAParameter", contentTemplate: externalCannotContainBothSchemaAndContentInAParameter, - errorMessage: &(&struct{ x string }{"Cannot contain both schema and content in a parameter"}).x, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + errorMessage: &(&struct{ x string }{"cannot contain both schema and content in a parameter"}).x, + testFunc: func(t *testing.T, swagger *Swagger) { }, }, } @@ -201,7 +199,7 @@ func TestLoadFromDataWithExternalRef(t *testing.T) { t.Logf("testcase '%s'", td.name) spec := []byte(fmt.Sprintf(td.contentTemplate, "components.openapi.json")) - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() loader.IsExternalRefsAllowed = true swagger, err := loader.LoadSwaggerFromDataWithPath(spec, &url.URL{Path: "testdata/testfilename.openapi.json"}) require.NoError(t, err) @@ -214,7 +212,7 @@ func TestLoadFromDataWithExternalRefResponseError(t *testing.T) { t.Logf("testcase '%s'", td.name) spec := []byte(fmt.Sprintf(td.contentTemplate, "components.openapi.json")) - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() loader.IsExternalRefsAllowed = true swagger, err := loader.LoadSwaggerFromDataWithPath(spec, &url.URL{Path: "testdata/testfilename.openapi.json"}) require.EqualError(t, err, *td.errorMessage) @@ -227,7 +225,7 @@ func TestLoadFromDataWithExternalNestedRef(t *testing.T) { t.Logf("testcase '%s'", td.name) spec := []byte(fmt.Sprintf(td.contentTemplate, "nesteddir/nestedcomponents.openapi.json")) - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() loader.IsExternalRefsAllowed = true swagger, err := loader.LoadSwaggerFromDataWithPath(spec, &url.URL{Path: "testdata/testfilename.openapi.json"}) require.NoError(t, err) @@ -725,7 +723,7 @@ var relativeDocRefsTestDataEntries = []refTestDataEntry{ { name: "SchemaRef", contentTemplate: relativeSchemaDocsRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Components.Schemas["TestSchema"].Value.Type) require.Equal(t, "string", swagger.Components.Schemas["TestSchema"].Value.Type) }, @@ -733,7 +731,7 @@ var relativeDocRefsTestDataEntries = []refTestDataEntry{ { name: "ResponseRef", contentTemplate: relativeResponseDocsRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { desc := "description" require.Equal(t, &desc, swagger.Components.Responses["TestResponse"].Value.Description) }, @@ -741,7 +739,7 @@ var relativeDocRefsTestDataEntries = []refTestDataEntry{ { name: "ParameterRef", contentTemplate: relativeParameterDocsRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Components.Parameters["TestParameter"].Value.Name) require.Equal(t, "param", swagger.Components.Parameters["TestParameter"].Value.Name) require.Equal(t, true, swagger.Components.Parameters["TestParameter"].Value.Required) @@ -750,7 +748,7 @@ var relativeDocRefsTestDataEntries = []refTestDataEntry{ { name: "ExampleRef", contentTemplate: relativeExampleDocsRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, "param", swagger.Components.Examples["TestExample"].Value.Summary) require.NotNil(t, "param", swagger.Components.Examples["TestExample"].Value.Value) require.Equal(t, "An example", swagger.Components.Examples["TestExample"].Value.Summary) @@ -759,7 +757,7 @@ var relativeDocRefsTestDataEntries = []refTestDataEntry{ { name: "RequestRef", contentTemplate: relativeRequestDocsRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, "param", swagger.Components.RequestBodies["TestRequestBody"].Value.Description) require.Equal(t, "example request", swagger.Components.RequestBodies["TestRequestBody"].Value.Description) }, @@ -767,7 +765,7 @@ var relativeDocRefsTestDataEntries = []refTestDataEntry{ { name: "HeaderRef", contentTemplate: relativeHeaderDocsRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, "param", swagger.Components.Headers["TestHeader"].Value.Description) require.Equal(t, "description", swagger.Components.Headers["TestHeader"].Value.Description) }, @@ -775,7 +773,7 @@ var relativeDocRefsTestDataEntries = []refTestDataEntry{ { name: "HeaderRef", contentTemplate: relativeHeaderDocsRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, "param", swagger.Components.Headers["TestHeader"].Value.Description) require.Equal(t, "description", swagger.Components.Headers["TestHeader"].Value.Description) }, @@ -783,7 +781,7 @@ var relativeDocRefsTestDataEntries = []refTestDataEntry{ { name: "SecuritySchemeRef", contentTemplate: relativeSecuritySchemeDocsRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Components.SecuritySchemes["TestSecurityScheme"].Value.Type) require.NotNil(t, swagger.Components.SecuritySchemes["TestSecurityScheme"].Value.Scheme) require.Equal(t, "http", swagger.Components.SecuritySchemes["TestSecurityScheme"].Value.Type) @@ -793,7 +791,7 @@ var relativeDocRefsTestDataEntries = []refTestDataEntry{ { name: "PathRef", contentTemplate: relativePathDocsRefTemplate, - testFunc: func(t *testing.T, swagger *openapi3.Swagger) { + testFunc: func(t *testing.T, swagger *Swagger) { require.NotNil(t, swagger.Paths["/pets"]) require.NotNil(t, swagger.Paths["/pets"].Get.Responses["200"]) require.NotNil(t, swagger.Paths["/pets"].Get.Responses["200"].Value.Content["application/json"]) @@ -806,7 +804,7 @@ func TestLoadSpecWithRelativeDocumentRefs(t *testing.T) { t.Logf("testcase '%s'", td.name) spec := []byte(td.contentTemplate) - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() loader.IsExternalRefsAllowed = true swagger, err := loader.LoadSwaggerFromDataWithPath(spec, &url.URL{Path: "testdata/"}) require.NoError(t, err) @@ -908,7 +906,7 @@ paths: ` func TestLoadSpecWithRelativeDocumentRefs2(t *testing.T) { - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() loader.IsExternalRefsAllowed = true swagger, err := loader.LoadSwaggerFromFile("testdata/relativeDocsUseDocumentPath/openapi/openapi.yml") diff --git a/openapi3/swagger_loader_test.go b/openapi3/swagger_loader_test.go index 960383260..692ebd2b8 100644 --- a/openapi3/swagger_loader_test.go +++ b/openapi3/swagger_loader_test.go @@ -1,4 +1,4 @@ -package openapi3_test +package openapi3 import ( "fmt" @@ -8,7 +8,6 @@ import ( "net/url" "testing" - "github.com/getkin/kin-openapi/openapi3" "github.com/stretchr/testify/require" ) @@ -54,7 +53,7 @@ paths: $ref: '#/components/schemas/ErrorModel' `) - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() doc, err := loader.LoadSwaggerFromData(spec) require.NoError(t, err) require.Equal(t, "An API", doc.Info.Title) @@ -69,7 +68,7 @@ paths: func ExampleSwaggerLoader() { source := `{"info":{"description":"An API"}}` - swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromData([]byte(source)) + swagger, err := NewSwaggerLoader().LoadSwaggerFromData([]byte(source)) if err != nil { panic(err) } @@ -80,7 +79,7 @@ func ExampleSwaggerLoader() { func TestResolveSchemaRef(t *testing.T) { source := []byte(`{"openapi":"3.0.0","info":{"title":"MyAPI","version":"0.1",description":"An API"},"paths":{},"components":{"schemas":{"B":{"type":"string"},"A":{"allOf":[{"$ref":"#/components/schemas/B"}]}}}}`) - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() doc, err := loader.LoadSwaggerFromData(source) require.NoError(t, err) err = doc.Validate(loader.Context) @@ -93,11 +92,11 @@ func TestResolveSchemaRef(t *testing.T) { func TestResolveSchemaRefWithNullSchemaRef(t *testing.T) { source := []byte(`{"openapi":"3.0.0","info":{"title":"MyAPI","version":"0.1","description":"An API"},"paths":{"/foo":{"post":{"requestBody":{"content":{"application/json":{"schema":null}}}}}}}`) - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() doc, err := loader.LoadSwaggerFromData(source) require.NoError(t, err) err = doc.Validate(loader.Context) - require.EqualError(t, err, "invalid paths: Found unresolved ref: ''") + require.EqualError(t, err, `invalid paths: found unresolved ref: ""`) } func TestResolveResponseExampleRef(t *testing.T) { @@ -122,7 +121,7 @@ paths: examples: test: $ref: '#/components/examples/test'`) - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() doc, err := loader.LoadSwaggerFromData(source) require.NoError(t, err) @@ -144,9 +143,9 @@ type multipleSourceSwaggerLoaderExample struct { } func (l *multipleSourceSwaggerLoaderExample) LoadSwaggerFromURI( - loader *openapi3.SwaggerLoader, + loader *SwaggerLoader, location *url.URL, -) (*openapi3.Swagger, error) { +) (*Swagger, error) { source := l.resolveSourceFromURI(location) if source == nil { return nil, fmt.Errorf("Unsupported URI: '%s'", location.String()) @@ -184,7 +183,7 @@ func TestResolveSchemaExternalRef(t *testing.T) { }, }, } - loader := &openapi3.SwaggerLoader{ + loader := &SwaggerLoader{ IsExternalRefsAllowed: true, LoadSwaggerFromURIFunc: multipleSourceLoader.LoadSwaggerFromURI, } @@ -223,7 +222,7 @@ paths: $ref: '#/components/schemas/Thing' `) - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() _, err := loader.LoadSwaggerFromData(spec) require.Error(t, err) } @@ -251,7 +250,7 @@ paths: description: Test call. `) - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() swagger, err := loader.LoadSwaggerFromData(spec) require.NoError(t, err) @@ -283,7 +282,7 @@ paths: description: Test call. `) - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() swagger, err := loader.LoadSwaggerFromData(spec) require.NoError(t, err) @@ -305,7 +304,7 @@ func TestLoadFromRemoteURL(t *testing.T) { ts.Start() defer ts.Close() - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() loader.IsExternalRefsAllowed = true url, err := url.Parse("http://" + addr + "/test.openapi.json") require.NoError(t, err) @@ -317,7 +316,7 @@ func TestLoadFromRemoteURL(t *testing.T) { } func TestLoadFileWithExternalSchemaRef(t *testing.T) { - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() loader.IsExternalRefsAllowed = true swagger, err := loader.LoadSwaggerFromFile("testdata/testref.openapi.json") require.NoError(t, err) @@ -326,7 +325,7 @@ func TestLoadFileWithExternalSchemaRef(t *testing.T) { } func TestLoadFileWithExternalSchemaRefSingleComponent(t *testing.T) { - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() loader.IsExternalRefsAllowed = true swagger, err := loader.LoadSwaggerFromFile("testdata/testrefsinglecomponent.openapi.json") require.NoError(t, err) @@ -369,7 +368,7 @@ func TestLoadRequestResponseHeaderRef(t *testing.T) { } }`) - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() swagger, err := loader.LoadSwaggerFromData(spec) require.NoError(t, err) @@ -408,7 +407,7 @@ func TestLoadFromDataWithExternalRequestResponseHeaderRemoteRef(t *testing.T) { ts.Start() defer ts.Close() - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() loader.IsExternalRefsAllowed = true swagger, err := loader.LoadSwaggerFromDataWithPath(spec, &url.URL{Path: "testdata/testfilename.openapi.json"}) require.NoError(t, err) @@ -418,7 +417,7 @@ func TestLoadFromDataWithExternalRequestResponseHeaderRemoteRef(t *testing.T) { } func TestLoadYamlFile(t *testing.T) { - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() loader.IsExternalRefsAllowed = true swagger, err := loader.LoadSwaggerFromFile("testdata/test.openapi.yml") require.NoError(t, err) @@ -427,7 +426,7 @@ func TestLoadYamlFile(t *testing.T) { } func TestLoadYamlFileWithExternalSchemaRef(t *testing.T) { - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() loader.IsExternalRefsAllowed = true swagger, err := loader.LoadSwaggerFromFile("testdata/testref.openapi.yml") require.NoError(t, err) @@ -436,7 +435,7 @@ func TestLoadYamlFileWithExternalSchemaRef(t *testing.T) { } func TestLoadYamlFileWithExternalPathRef(t *testing.T) { - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() loader.IsExternalRefsAllowed = true swagger, err := loader.LoadSwaggerFromFile("testdata/pathref.openapi.yml") require.NoError(t, err) @@ -476,7 +475,7 @@ paths: father: $ref: '#/components/links/Father' `) - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() doc, err := loader.LoadSwaggerFromData(source) require.NoError(t, err) @@ -545,7 +544,7 @@ paths: $ref: '#/components/schemas/ErrorModel' `) - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() doc, err := loader.LoadSwaggerFromData(spec) require.NoError(t, err) err = doc.Validate(loader.Context) diff --git a/openapi3/swagger_test.go b/openapi3/swagger_test.go index 06c478c76..0117cea6e 100644 --- a/openapi3/swagger_test.go +++ b/openapi3/swagger_test.go @@ -1,39 +1,38 @@ -package openapi3_test +package openapi3 import ( "context" "encoding/json" - "errors" + "strings" "testing" - "github.com/getkin/kin-openapi/openapi3" "github.com/ghodss/yaml" "github.com/stretchr/testify/require" ) func TestRefsJSON(t *testing.T) { - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() - t.Log("Marshal *openapi3.Swagger to JSON") + t.Log("Marshal *Swagger to JSON") data, err := json.Marshal(spec()) require.NoError(t, err) require.NotEmpty(t, data) - t.Log("Unmarshal *openapi3.Swagger from JSON") - docA := &openapi3.Swagger{} - err = json.Unmarshal([]byte(specJSON), &docA) + t.Log("Unmarshal *Swagger from JSON") + docA := &Swagger{} + err = json.Unmarshal(specJSON, &docA) require.NoError(t, err) require.NotEmpty(t, data) - t.Log("Resolve refs in unmarshalled *openapi3.Swagger") + t.Log("Resolve refs in unmarshalled *Swagger") err = loader.ResolveRefsIn(docA, nil) require.NoError(t, err) - t.Log("Resolve refs in marshalled *openapi3.Swagger") + t.Log("Resolve refs in marshalled *Swagger") docB, err := loader.LoadSwaggerFromData(data) require.NoError(t, err) require.NotEmpty(t, docB) - t.Log("Validate *openapi3.Swagger") + t.Log("Validate *Swagger") err = docA.Validate(loader.Context) require.NoError(t, err) err = docB.Validate(loader.Context) @@ -44,34 +43,34 @@ func TestRefsJSON(t *testing.T) { require.NoError(t, err) dataB, err := json.Marshal(docB) require.NoError(t, err) - require.JSONEq(t, string(data), specJSON) + require.JSONEq(t, string(data), string(specJSON)) require.JSONEq(t, string(data), string(dataA)) require.JSONEq(t, string(data), string(dataB)) } func TestRefsYAML(t *testing.T) { - loader := openapi3.NewSwaggerLoader() + loader := NewSwaggerLoader() - t.Log("Marshal *openapi3.Swagger to YAML") + t.Log("Marshal *Swagger to YAML") data, err := yaml.Marshal(spec()) require.NoError(t, err) require.NotEmpty(t, data) - t.Log("Unmarshal *openapi3.Swagger from YAML") - docA := &openapi3.Swagger{} - err = yaml.Unmarshal([]byte(specYAML), &docA) + t.Log("Unmarshal *Swagger from YAML") + docA := &Swagger{} + err = yaml.Unmarshal(specYAML, &docA) require.NoError(t, err) require.NotEmpty(t, data) - t.Log("Resolve refs in unmarshalled *openapi3.Swagger") + t.Log("Resolve refs in unmarshalled *Swagger") err = loader.ResolveRefsIn(docA, nil) require.NoError(t, err) - t.Log("Resolve refs in marshalled *openapi3.Swagger") + t.Log("Resolve refs in marshalled *Swagger") docB, err := loader.LoadSwaggerFromData(data) require.NoError(t, err) require.NotEmpty(t, docB) - t.Log("Validate *openapi3.Swagger") + t.Log("Validate *Swagger") err = docA.Validate(loader.Context) require.NoError(t, err) err = docB.Validate(loader.Context) @@ -82,7 +81,7 @@ func TestRefsYAML(t *testing.T) { require.NoError(t, err) dataB, err := yaml.Marshal(docB) require.NoError(t, err) - eqYAML(t, data, []byte(specYAML)) + eqYAML(t, data, specYAML) eqYAML(t, data, dataA) eqYAML(t, data, dataB) } @@ -96,7 +95,7 @@ func eqYAML(t *testing.T, expected, actual []byte) { require.Equal(t, e, a) } -var specYAML = ` +var specYAML = []byte(` openapi: '3.0' info: title: MyAPI @@ -148,9 +147,9 @@ components: name: token someSecurityScheme: "$ref": "#/components/securitySchemes/otherSecurityScheme" -` +`) -var specJSON = ` +var specJSON = []byte(` { "openapi": "3.0", "info": { @@ -236,55 +235,55 @@ var specJSON = ` } } } -` +`) -func spec() *openapi3.Swagger { - parameter := &openapi3.Parameter{ +func spec() *Swagger { + parameter := &Parameter{ Description: "Some parameter", Name: "example", In: "query", - Schema: &openapi3.SchemaRef{ + Schema: &SchemaRef{ Ref: "#/components/schemas/someSchema", }, } - requestBody := &openapi3.RequestBody{ + requestBody := &RequestBody{ Description: "Some request body", } responseDescription := "Some response" - response := &openapi3.Response{ + response := &Response{ Description: &responseDescription, } - schema := &openapi3.Schema{ + schema := &Schema{ Description: "Some schema", } example := map[string]string{"name": "Some example"} - return &openapi3.Swagger{ + return &Swagger{ OpenAPI: "3.0", - Info: &openapi3.Info{ + Info: &Info{ Title: "MyAPI", Version: "0.1", }, - Paths: openapi3.Paths{ - "/hello": &openapi3.PathItem{ - Post: &openapi3.Operation{ - Parameters: openapi3.Parameters{ + Paths: Paths{ + "/hello": &PathItem{ + Post: &Operation{ + Parameters: Parameters{ { Ref: "#/components/parameters/someParameter", Value: parameter, }, }, - RequestBody: &openapi3.RequestBodyRef{ + RequestBody: &RequestBodyRef{ Ref: "#/components/requestBodies/someRequestBody", Value: requestBody, }, - Responses: openapi3.Responses{ - "200": &openapi3.ResponseRef{ + Responses: Responses{ + "200": &ResponseRef{ Ref: "#/components/responses/someResponse", Value: response, }, }, }, - Parameters: openapi3.Parameters{ + Parameters: Parameters{ { Ref: "#/components/parameters/someParameter", Value: parameter, @@ -292,49 +291,49 @@ func spec() *openapi3.Swagger { }, }, }, - Components: openapi3.Components{ - Parameters: map[string]*openapi3.ParameterRef{ + Components: Components{ + Parameters: map[string]*ParameterRef{ "someParameter": { Value: parameter, }, }, - RequestBodies: map[string]*openapi3.RequestBodyRef{ + RequestBodies: map[string]*RequestBodyRef{ "someRequestBody": { Value: requestBody, }, }, - Responses: map[string]*openapi3.ResponseRef{ + Responses: map[string]*ResponseRef{ "someResponse": { Value: response, }, }, - Schemas: map[string]*openapi3.SchemaRef{ + Schemas: map[string]*SchemaRef{ "someSchema": { Value: schema, }, }, - Headers: map[string]*openapi3.HeaderRef{ + Headers: map[string]*HeaderRef{ "someHeader": { Ref: "#/components/headers/otherHeader", }, "otherHeader": { - Value: &openapi3.Header{}, + Value: &Header{}, }, }, - Examples: map[string]*openapi3.ExampleRef{ + Examples: map[string]*ExampleRef{ "someExample": { Ref: "#/components/examples/otherExample", }, "otherExample": { - Value: openapi3.NewExample(example), + Value: NewExample(example), }, }, - SecuritySchemes: map[string]*openapi3.SecuritySchemeRef{ + SecuritySchemes: map[string]*SecuritySchemeRef{ "someSecurityScheme": { Ref: "#/components/securitySchemes/otherSecurityScheme", }, "otherSecurityScheme": { - Value: &openapi3.SecurityScheme{ + Value: &SecurityScheme{ Description: "Some security scheme", Type: "apiKey", In: "query", @@ -346,20 +345,13 @@ func spec() *openapi3.Swagger { } } -// TestValidation tests validation of properties in the root of the OpenAPI -// file. func TestValidation(t *testing.T) { - tests := []struct { - name string - input string - expectedError error - }{ - { - "when no OpenAPI property is supplied", - ` + info := ` info: title: "Hello World REST APIs" version: "1.0" +` + paths := ` paths: "/api/v2/greetings.json": get: @@ -380,103 +372,10 @@ paths: responses: 200: description: "Get a single greeting object" -`, - errors.New("value of openapi must be a non-empty JSON string"), - }, - { - "when an empty OpenAPI property is supplied", - ` -openapi: '' -info: - title: "Hello World REST APIs" - version: "1.0" -paths: - "/api/v2/greetings.json": - get: - operationId: listGreetings - responses: - 200: - description: "List different greetings" - "/api/v2/greetings/{id}.json": - parameters: - - name: id - in: path - required: true - schema: - type: string - example: "greeting" - get: - operationId: showGreeting - responses: - 200: - description: "Get a single greeting object" -`, - errors.New("value of openapi must be a non-empty JSON string"), - }, - { - "when the Info property is not supplied", - ` -openapi: '1.0' -paths: - "/api/v2/greetings.json": - get: - operationId: listGreetings - responses: - 200: - description: "List different greetings" - "/api/v2/greetings/{id}.json": - parameters: - - name: id - in: path - required: true - schema: - type: string - example: "greeting" - get: - operationId: showGreeting - responses: - 200: - description: "Get a single greeting object" -`, - errors.New("invalid info: must be a JSON object"), - }, - { - "when the Paths property is not supplied", - ` -openapi: '1.0' -info: - title: "Hello World REST APIs" - version: "1.0" -`, - errors.New("invalid paths: must be a JSON object"), - }, - { - "when a valid spec is supplied", - ` +` + spec := ` openapi: 3.0.2 -info: - title: "Hello World REST APIs" - version: "1.0" -paths: - "/api/v2/greetings.json": - get: - operationId: listGreetings - responses: - 200: - description: "List different greetings" - "/api/v2/greetings/{id}.json": - parameters: - - name: id - in: path - required: true - schema: - type: string - example: "greeting" - get: - operationId: showGreeting - responses: - 200: - description: "Get a single greeting object" +` + info + paths + ` components: schemas: GreetingObject: @@ -490,21 +389,28 @@ components: properties: description: type: string -`, - nil, - }, +` + + tests := map[string]string{ + spec: "", + strings.Replace(spec, `openapi: 3.0.2`, ``, 1): "value of openapi must be a non-empty JSON string", + strings.Replace(spec, `openapi: 3.0.2`, `openapi: ''`, 1): "value of openapi must be a non-empty JSON string", + strings.Replace(spec, info, ``, 1): "invalid info: must be a JSON object", + strings.Replace(spec, paths, ``, 1): "invalid paths: must be a JSON object", } - for _, test := range tests { - t.Run(test.name, func(t *testing.T) { - doc := &openapi3.Swagger{} - err := yaml.Unmarshal([]byte(test.input), &doc) + for spec, expectedErr := range tests { + t.Run(expectedErr, func(t *testing.T) { + doc := &Swagger{} + err := yaml.Unmarshal([]byte(spec), &doc) require.NoError(t, err) - c := context.Background() - validationErr := doc.Validate(c) - - require.Equal(t, test.expectedError, validationErr, "expected errors (or lack of) to match") + err = doc.Validate(context.Background()) + if expectedErr != "" { + require.EqualError(t, err, expectedErr) + } else { + require.NoError(t, err) + } }) } } diff --git a/openapi3/unique_items_checker_test.go b/openapi3/unique_items_checker_test.go new file mode 100644 index 000000000..c2dc6f381 --- /dev/null +++ b/openapi3/unique_items_checker_test.go @@ -0,0 +1,36 @@ +package openapi3_test + +import ( + "strings" + "testing" + + "github.com/getkin/kin-openapi/openapi3" + "github.com/stretchr/testify/require" +) + +func TestRegisterArrayUniqueItemsChecker(t *testing.T) { + var ( + schema = openapi3.Schema{ + Type: "array", + UniqueItems: true, + Items: openapi3.NewStringSchema().NewRef(), + } + val = []interface{}{"1", "2", "3"} + ) + + // Fist checked by predefined function + err := schema.VisitJSON(val) + require.NoError(t, err) + + // Register a function will always return false when check if a + // slice has unique items, then use a slice indeed has unique + // items to verify that check unique items will failed. + openapi3.RegisterArrayUniqueItemsChecker(func(items []interface{}) bool { + return false + }) + defer openapi3.RegisterArrayUniqueItemsChecker(nil) // Reset for other tests + + err = schema.VisitJSON(val) + require.Error(t, err) + require.True(t, strings.HasPrefix(err.Error(), "Duplicate items found")) +} diff --git a/openapi3filter/validation_test.go b/openapi3filter/validation_test.go index c4e6e0f17..4de536ef1 100644 --- a/openapi3filter/validation_test.go +++ b/openapi3filter/validation_test.go @@ -1,4 +1,4 @@ -package openapi3filter_test +package openapi3filter import ( "bytes" @@ -15,7 +15,6 @@ import ( "testing" "github.com/getkin/kin-openapi/openapi3" - "github.com/getkin/kin-openapi/openapi3filter" "github.com/stretchr/testify/require" ) @@ -155,8 +154,8 @@ func TestFilter(t *testing.T) { }, } - router := openapi3filter.NewRouter().WithSwagger(swagger) - expectWithDecoder := func(req ExampleRequest, resp ExampleResponse, decoder openapi3filter.ContentParameterDecoder) error { + router := NewRouter().WithSwagger(swagger) + expectWithDecoder := func(req ExampleRequest, resp ExampleResponse, decoder ContentParameterDecoder) error { t.Logf("Request: %s %s", req.Method, req.URL) httpReq, _ := http.NewRequest(req.Method, req.URL, marshalReader(req.Body)) httpReq.Header.Set("Content-Type", req.ContentType) @@ -166,17 +165,17 @@ func TestFilter(t *testing.T) { require.NoError(t, err) // Validate request - requestValidationInput := &openapi3filter.RequestValidationInput{ + requestValidationInput := &RequestValidationInput{ Request: httpReq, PathParams: pathParams, Route: route, ParamDecoder: decoder, } - if err := openapi3filter.ValidateRequest(context.TODO(), requestValidationInput); err != nil { + if err := ValidateRequest(context.Background(), requestValidationInput); err != nil { return err } t.Logf("Response: %d", resp.Status) - responseValidationInput := &openapi3filter.ResponseValidationInput{ + responseValidationInput := &ResponseValidationInput{ RequestValidationInput: requestValidationInput, Status: resp.Status, Header: http.Header{ @@ -190,7 +189,7 @@ func TestFilter(t *testing.T) { require.NoError(t, err) responseValidationInput.SetBodyBytes(data) } - err = openapi3filter.ValidateResponse(context.TODO(), responseValidationInput) + err = ValidateResponse(context.Background(), responseValidationInput) require.NoError(t, err) return err } @@ -220,7 +219,7 @@ func TestFilter(t *testing.T) { URL: "http://example.com/api/prefix/EXCEEDS_MAX_LENGTH/suffix", } err = expect(req, resp) - require.IsType(t, &openapi3filter.RequestError{}, err) + require.IsType(t, &RequestError{}, err) // Test query parameter openapi3filter req = ExampleRequest{ @@ -235,14 +234,14 @@ func TestFilter(t *testing.T) { URL: "http://example.com/api/prefix/v/suffix?queryArg=EXCEEDS_MAX_LENGTH", } err = expect(req, resp) - require.IsType(t, &openapi3filter.RequestError{}, err) + require.IsType(t, &RequestError{}, err) req = ExampleRequest{ Method: "GET", URL: "http://example.com/api/issue151?par2=par1_is_missing", } err = expect(req, resp) - require.IsType(t, &openapi3filter.RequestError{}, err) + require.IsType(t, &RequestError{}, err) // Test query parameter openapi3filter req = ExampleRequest{ @@ -264,28 +263,28 @@ func TestFilter(t *testing.T) { URL: "http://example.com/api/prefix/v/suffix?queryArgAnyOf=123", } err = expect(req, resp) - require.IsType(t, &openapi3filter.RequestError{}, err) + require.IsType(t, &RequestError{}, err) req = ExampleRequest{ Method: "POST", URL: "http://example.com/api/prefix/v/suffix?queryArgOneOf=567", } err = expect(req, resp) - require.IsType(t, &openapi3filter.RequestError{}, err) + require.IsType(t, &RequestError{}, err) req = ExampleRequest{ Method: "POST", URL: "http://example.com/api/prefix/v/suffix?queryArgOneOf=2017-12-31T11:59:59", } err = expect(req, resp) - require.IsType(t, &openapi3filter.RequestError{}, err) + require.IsType(t, &RequestError{}, err) req = ExampleRequest{ Method: "POST", URL: "http://example.com/api/prefix/v/suffix?queryArgAllOf=abdfg", } err = expect(req, resp) - require.IsType(t, &openapi3filter.RequestError{}, err) + require.IsType(t, &RequestError{}, err) // TODO(decode not): handle decoding "not" JSON Schema // req = ExampleRequest{ @@ -293,7 +292,7 @@ func TestFilter(t *testing.T) { // URL: "http://example.com/api/prefix/v/suffix?queryArgNot=abdfg", // } // err = expect(req, resp) - // require.IsType(t, &openapi3filter.RequestError{}, err) + // require.IsType(t, &RequestError{}, err) // TODO(decode not): handle decoding "not" JSON Schema // req = ExampleRequest{ @@ -301,14 +300,14 @@ func TestFilter(t *testing.T) { // URL: "http://example.com/api/prefix/v/suffix?queryArgNot=123", // } // err = expect(req, resp) - // require.IsType(t, &openapi3filter.RequestError{}, err) + // require.IsType(t, &RequestError{}, err) req = ExampleRequest{ Method: "POST", URL: "http://example.com/api/prefix/v/suffix?queryArg=EXCEEDS_MAX_LENGTH", } err = expect(req, resp) - require.IsType(t, &openapi3filter.RequestError{}, err) + require.IsType(t, &RequestError{}, err) req = ExampleRequest{ Method: "POST", @@ -318,7 +317,7 @@ func TestFilter(t *testing.T) { Status: 200, } err = expect(req, resp) - // require.IsType(t, &openapi3filter.ResponseError{}, err) + // require.IsType(t, &ResponseError{}, err) require.NoError(t, err) // Check that content validation works. This should pass, as ID is short @@ -336,7 +335,7 @@ func TestFilter(t *testing.T) { URL: "http://example.com/api/prefix/v/suffix?contentArg={\"name\":\"bob\", \"id\":\"EXCEEDS_MAX_LENGTH\"}", } err = expect(req, resp) - require.IsType(t, &openapi3filter.RequestError{}, err) + require.IsType(t, &RequestError{}, err) // Now, repeat the above two test cases using a custom parameter decoder. customDecoder := func(param *openapi3.Parameter, values []string) (interface{}, *openapi3.Schema, error) { @@ -359,7 +358,7 @@ func TestFilter(t *testing.T) { URL: "http://example.com/api/prefix/v/suffix?contentArg2={\"name\":\"bob\", \"id\":\"EXCEEDS_MAX_LENGTH\"}", } err = expectWithDecoder(req, resp, customDecoder) - require.IsType(t, &openapi3filter.RequestError{}, err) + require.IsType(t, &RequestError{}, err) } func marshalReader(value interface{}) io.ReadCloser { @@ -403,7 +402,7 @@ func TestValidateRequestBody(t *testing.T) { { name: "required empty", body: requiredReqBody, - wantErr: &openapi3filter.RequestError{RequestBody: requiredReqBody, Err: openapi3filter.ErrInvalidRequired}, + wantErr: &RequestError{RequestBody: requiredReqBody, Err: ErrInvalidRequired}, }, { name: "required not empty", @@ -436,8 +435,8 @@ func TestValidateRequestBody(t *testing.T) { if tc.mime != "" { req.Header.Set(http.CanonicalHeaderKey("Content-Type"), tc.mime) } - inp := &openapi3filter.RequestValidationInput{Request: req} - err := openapi3filter.ValidateRequestBody(context.Background(), inp, tc.body) + inp := &RequestValidationInput{Request: req} + err := ValidateRequestBody(context.Background(), inp, tc.body) if tc.wantErr == nil { require.NoError(t, err) @@ -453,11 +452,11 @@ func matchReqBodyError(want, got error) bool { if want == got { return true } - wErr, ok := want.(*openapi3filter.RequestError) + wErr, ok := want.(*RequestError) if !ok { return false } - gErr, ok := got.(*openapi3filter.RequestError) + gErr, ok := got.(*RequestError) if !ok { return false } @@ -572,7 +571,7 @@ func TestOperationOrSwaggerSecurity(t *testing.T) { } // Declare the router - router := openapi3filter.NewRouter().WithSwagger(swagger) + router := NewRouter().WithSwagger(swagger) // Test each case for _, path := range tc { @@ -592,11 +591,11 @@ func TestOperationOrSwaggerSecurity(t *testing.T) { require.NoError(t, err) route, _, err := router.FindRoute(http.MethodGet, pathURL) require.NoError(t, err) - req := openapi3filter.RequestValidationInput{ + req := RequestValidationInput{ Request: httptest.NewRequest(http.MethodGet, path.name, emptyBody), Route: route, - Options: &openapi3filter.Options{ - AuthenticationFunc: func(c context.Context, input *openapi3filter.AuthenticationInput) error { + Options: &Options{ + AuthenticationFunc: func(c context.Context, input *AuthenticationInput) error { if schemesValidated != nil { if validated, ok := (*schemesValidated)[input.SecurityScheme]; ok { if validated { @@ -617,7 +616,7 @@ func TestOperationOrSwaggerSecurity(t *testing.T) { } // Validate the request - err = openapi3filter.ValidateRequest(context.TODO(), &req) + err = ValidateRequest(context.Background(), &req) require.NoError(t, err) for securityRequirement, validated := range *schemesValidated { @@ -703,7 +702,7 @@ func TestAnySecurityRequirementMet(t *testing.T) { } // Create the router - router := openapi3filter.NewRouter().WithSwagger(&swagger) + router := NewRouter().WithSwagger(&swagger) // Create the authentication function authFunc := makeAuthFunc(schemes) @@ -714,15 +713,15 @@ func TestAnySecurityRequirementMet(t *testing.T) { require.NoError(t, err) route, _, err := router.FindRoute(http.MethodGet, tcURL) require.NoError(t, err) - req := openapi3filter.RequestValidationInput{ + req := RequestValidationInput{ Route: route, - Options: &openapi3filter.Options{ + Options: &Options{ AuthenticationFunc: authFunc, }, } // Validate the security requirements - err = openapi3filter.ValidateSecurityRequirements(context.TODO(), &req, *route.Operation.Security) + err = ValidateSecurityRequirements(context.Background(), &req, *route.Operation.Security) // If there should have been an error if tc.error { @@ -803,7 +802,7 @@ func TestAllSchemesMet(t *testing.T) { } // Create the router from the swagger - router := openapi3filter.NewRouter().WithSwagger(&swagger) + router := NewRouter().WithSwagger(&swagger) // Create the authentication function authFunc := makeAuthFunc(schemes) @@ -814,15 +813,15 @@ func TestAllSchemesMet(t *testing.T) { require.NoError(t, err) route, _, err := router.FindRoute(http.MethodGet, tcURL) require.NoError(t, err) - req := openapi3filter.RequestValidationInput{ + req := RequestValidationInput{ Route: route, - Options: &openapi3filter.Options{ + Options: &Options{ AuthenticationFunc: authFunc, }, } // Validate the security requirements - err = openapi3filter.ValidateSecurityRequirements(context.TODO(), &req, *route.Operation.Security) + err = ValidateSecurityRequirements(context.Background(), &req, *route.Operation.Security) // If there should have been an error if tc.error { @@ -836,8 +835,8 @@ func TestAllSchemesMet(t *testing.T) { // makeAuthFunc creates an authentication function that accepts the given valid schemes. // If an invalid or unknown scheme is encountered, an error is returned by the returned function. // Otherwise the return value of the returned function is nil. -func makeAuthFunc(schemes map[string]bool) func(c context.Context, input *openapi3filter.AuthenticationInput) error { - return func(c context.Context, input *openapi3filter.AuthenticationInput) error { +func makeAuthFunc(schemes map[string]bool) func(c context.Context, input *AuthenticationInput) error { + return func(c context.Context, input *AuthenticationInput) error { // If the scheme is valid and present in the schemes valid, present := schemes[input.SecuritySchemeName] if valid && present { diff --git a/openapi3gen/openapi3gen_test.go b/openapi3gen/openapi3gen_test.go index d94cfce9f..2a58433cb 100644 --- a/openapi3gen/openapi3gen_test.go +++ b/openapi3gen/openapi3gen_test.go @@ -1,11 +1,10 @@ -package openapi3gen_test +package openapi3gen import ( "encoding/json" "testing" "time" - "github.com/getkin/kin-openapi/openapi3gen" "github.com/stretchr/testify/require" ) @@ -17,8 +16,8 @@ type CyclicType1 struct { } func TestCyclic(t *testing.T) { - schema, refsMap, err := openapi3gen.NewSchemaRefForValue(&CyclicType0{}) - require.IsType(t, &openapi3gen.CycleError{}, err) + schema, refsMap, err := NewSchemaRefForValue(&CyclicType0{}) + require.IsType(t, &CycleError{}, err) require.Nil(t, schema) require.Empty(t, refsMap) } @@ -45,7 +44,7 @@ func TestSimple(t *testing.T) { Ptr *ExampleChild `json:"ptr"` } - schema, refsMap, err := openapi3gen.NewSchemaRefForValue(&Example{}) + schema, refsMap, err := NewSchemaRefForValue(&Example{}) require.NoError(t, err) require.Len(t, refsMap, 14) data, err := json.Marshal(schema)