Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------

using System;

namespace Microsoft.OpenApi.OData.Common
{
/// <summary>
Expand All @@ -13,37 +15,37 @@
/// <summary>
/// application/json
/// </summary>
public static string ApplicationJsonMediaType = "application/json";

Check warning on line 18 in src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs

View workflow job for this annotation

GitHub Actions / Build

Change the visibility of 'ApplicationJsonMediaType' or make it 'const' or 'readonly'. (https://rules.sonarsource.com/csharp/RSPEC-2223)

/// <summary>
/// application/xml
/// </summary>
public static string ApplicationXmlMediaType = "application/xml";

Check warning on line 23 in src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs

View workflow job for this annotation

GitHub Actions / Build

Change the visibility of 'ApplicationXmlMediaType' or make it 'const' or 'readonly'. (https://rules.sonarsource.com/csharp/RSPEC-2223)

/// <summary>
/// application/octet-stream
/// </summary>
public static string ApplicationOctetStreamMediaType = "application/octet-stream";

Check warning on line 28 in src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs

View workflow job for this annotation

GitHub Actions / Build

Change the visibility of 'ApplicationOctetStreamMediaType' or make it 'const' or 'readonly'. (https://rules.sonarsource.com/csharp/RSPEC-2223)

/// <summary>
/// Status code class: 2XX
/// </summary>
public static string StatusCodeClass2XX = "2XX";

Check warning on line 33 in src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs

View workflow job for this annotation

GitHub Actions / Build

Change the visibility of 'StatusCodeClass2XX' or make it 'const' or 'readonly'. (https://rules.sonarsource.com/csharp/RSPEC-2223)

/// <summary>
/// Status code: 200
/// </summary>
public static string StatusCode200 = "200";

Check warning on line 38 in src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs

View workflow job for this annotation

GitHub Actions / Build

Change the visibility of 'StatusCode200' or make it 'const' or 'readonly'. (https://rules.sonarsource.com/csharp/RSPEC-2223)

/// <summary>
/// Status code: 201
/// </summary>
public static string StatusCode201 = "201";

Check warning on line 43 in src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs

View workflow job for this annotation

GitHub Actions / Build

Change the visibility of 'StatusCode201' or make it 'const' or 'readonly'. (https://rules.sonarsource.com/csharp/RSPEC-2223)

/// <summary>
/// Status code: 204
/// </summary>
public static string StatusCode204 = "204";

Check warning on line 48 in src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs

View workflow job for this annotation

GitHub Actions / Build

Change the visibility of 'StatusCode204' or make it 'const' or 'readonly'. (https://rules.sonarsource.com/csharp/RSPEC-2223)

/// <summary>
/// Status code: default
Expand All @@ -58,7 +60,7 @@
/// <summary>
/// Status code class: 5XX
/// </summary>
public static string StatusCodeClass5XX = "5XX";

Check warning on line 63 in src/Microsoft.OpenApi.OData.Reader/Common/Constants.cs

View workflow job for this annotation

GitHub Actions / Build

Change the visibility of 'StatusCodeClass5XX' or make it 'const' or 'readonly'. (https://rules.sonarsource.com/csharp/RSPEC-2223)

/// <summary>
/// Edm model error extension key.
Expand Down Expand Up @@ -168,6 +170,7 @@
/// <summary>
/// integer type
/// </summary>
[Obsolete("integer is not a valid OpenAPI type. Use number instead.")]
public static string IntegerType = "integer";

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,17 @@ public static OpenApiSchema CreateEdmTypeSchema(this ODataContext context, IEdmT
Utils.CheckArgumentNull(edmTypeReference, nameof(edmTypeReference));

switch (edmTypeReference.TypeKind())
{
// Collection-valued structural and navigation are represented as Schema Objects of type array.
// The value of the items keyword is a Schema Object specifying the type of the items.
{
// Collection-valued structural and navigation are represented as Schema Objects of type array.
// The value of the items keyword is a Schema Object specifying the type of the items.
case EdmTypeKind.Collection:

IEdmTypeReference typeRef = edmTypeReference.AsCollection().ElementType();
OpenApiSchema schema;
schema = typeRef.TypeKind() == EdmTypeKind.Complex || typeRef.TypeKind() == EdmTypeKind.Entity
? context.CreateStructuredTypeSchema(typeRef.AsStructured(), true)
: context.CreateEdmTypeSchema(typeRef);
schema = typeRef.TypeKind() == EdmTypeKind.Complex || typeRef.TypeKind() == EdmTypeKind.Entity
? context.CreateStructuredTypeSchema(typeRef.AsStructured(), true)
: context.CreateEdmTypeSchema(typeRef);

return new OpenApiSchema
{
Type = "array",
Expand Down Expand Up @@ -133,7 +133,8 @@ public static OpenApiSchema CreateSchema(this ODataContext context, IEdmPrimitiv
}

// Nullable properties are marked with the keyword nullable and a value of true.
schema.Nullable = primitiveType.IsNullable ? true : false;
// nullable cannot be true when type is empty, often common in anyof/allOf since individual entries are nullable
schema.Nullable = !string.IsNullOrEmpty(schema.Type) && primitiveType.IsNullable;
}

return schema;
Expand Down Expand Up @@ -169,7 +170,7 @@ public static OpenApiSchema CreateSchema(this ODataContext context, IEdmPrimitiv
schema.Default = new OpenApiBoolean(false);
break;
case EdmPrimitiveTypeKind.Byte: // byte
schema.Type = Constants.IntegerType;
schema.Type = Constants.NumberType;
schema.Format = "uint8";
break;
case EdmPrimitiveTypeKind.DateTimeOffset: // datetime offset
Expand All @@ -182,8 +183,8 @@ public static OpenApiSchema CreateSchema(this ODataContext context, IEdmPrimitiv
{
schema.OneOf = new List<OpenApiSchema>
{
new OpenApiSchema { Type = Constants.NumberType, Format = Constants.DecimalFormat },
new OpenApiSchema { Type = Constants.StringType },
new OpenApiSchema { Type = Constants.NumberType, Format = Constants.DecimalFormat, Nullable = true },
new OpenApiSchema { Type = Constants.StringType, Nullable = true },
};
}
else
Expand All @@ -195,8 +196,8 @@ public static OpenApiSchema CreateSchema(this ODataContext context, IEdmPrimitiv
case EdmPrimitiveTypeKind.Double: // double
schema.OneOf = new List<OpenApiSchema>
{
new OpenApiSchema { Type = Constants.NumberType, Format = "double" },
new OpenApiSchema { Type = Constants.StringType },
new OpenApiSchema { Type = Constants.NumberType, Format = "double", Nullable = true },
new OpenApiSchema { Type = Constants.StringType, Nullable = true },
new OpenApiSchema
{
UnresolvedReference = true,
Expand All @@ -211,8 +212,8 @@ public static OpenApiSchema CreateSchema(this ODataContext context, IEdmPrimitiv
case EdmPrimitiveTypeKind.Single: // single
schema.OneOf = new List<OpenApiSchema>
{
new OpenApiSchema { Type = Constants.NumberType, Format = "float" },
new OpenApiSchema { Type = Constants.StringType },
new OpenApiSchema { Type = Constants.NumberType, Format = "float", Nullable = true },
new OpenApiSchema { Type = Constants.StringType, Nullable = true },
new OpenApiSchema
{
UnresolvedReference = true,
Expand All @@ -230,13 +231,13 @@ public static OpenApiSchema CreateSchema(this ODataContext context, IEdmPrimitiv
schema.Pattern = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$";
break;
case EdmPrimitiveTypeKind.Int16:
schema.Type = Constants.IntegerType;
schema.Type = Constants.NumberType;
schema.Format = "int16";
schema.Minimum = Int16.MinValue; // -32768
schema.Maximum = Int16.MaxValue; // 32767
break;
case EdmPrimitiveTypeKind.Int32:
schema.Type = Constants.IntegerType;
schema.Type = Constants.NumberType;
schema.Format = "int32";
schema.Minimum = Int32.MinValue; // -2147483648
schema.Maximum = Int32.MaxValue; // 2147483647
Expand All @@ -246,18 +247,18 @@ public static OpenApiSchema CreateSchema(this ODataContext context, IEdmPrimitiv
{
schema.OneOf = new List<OpenApiSchema>
{
new OpenApiSchema { Type = Constants.IntegerType, Format = Constants.Int64Format },
new OpenApiSchema { Type = Constants.StringType }
new OpenApiSchema { Type = Constants.NumberType, Format = Constants.Int64Format, Nullable = true },
new OpenApiSchema { Type = Constants.StringType, Nullable = true }
};
}
else
{
schema.Type = Constants.IntegerType;
schema.Type = Constants.NumberType;
schema.Format = Constants.Int64Format;
}
break;
case EdmPrimitiveTypeKind.SByte:
schema.Type = Constants.IntegerType;
schema.Type = Constants.NumberType;
schema.Format = "int8";
schema.Minimum = SByte.MinValue; // -128
schema.Maximum = SByte.MaxValue; // 127
Expand Down Expand Up @@ -469,47 +470,47 @@ private static OpenApiSchema CreateEnumTypeSchema(this ODataContext context, IEd
private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext context, IEdmStructuredTypeReference typeReference, bool isTypeCollection = false)
{
Debug.Assert(context != null);
Debug.Assert(typeReference != null);
OpenApiSchema schema = new OpenApiSchema();
// AnyOf will only be valid openApi for version 3
// otherwise the reference should be set directly
// as per OASIS documentation for openApi version 2
// Collections of structured types cannot be nullable
if (typeReference.IsNullable && !isTypeCollection &&
(context.Settings.OpenApiSpecVersion >= OpenApiSpecVersion.OpenApi3_0))
{
schema.Reference = null;
schema.AnyOf = new List<OpenApiSchema>
{
new OpenApiSchema
{
UnresolvedReference = true,
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = typeReference.Definition.FullTypeName()
}
},
new OpenApiSchema
{
Type = "object",
Nullable = true
}
};
}
else
{
schema.Type = null;
schema.AnyOf = null;
schema.Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = typeReference.Definition.FullTypeName()
};
schema.UnresolvedReference = true;
schema.Nullable = typeReference.IsNullable;
Debug.Assert(typeReference != null);

OpenApiSchema schema = new OpenApiSchema();

// AnyOf will only be valid openApi for version 3
// otherwise the reference should be set directly
// as per OASIS documentation for openApi version 2
// Collections of structured types cannot be nullable
if (typeReference.IsNullable && !isTypeCollection &&
(context.Settings.OpenApiSpecVersion >= OpenApiSpecVersion.OpenApi3_0))
{
schema.Reference = null;
schema.AnyOf = new List<OpenApiSchema>
{
new OpenApiSchema
{
UnresolvedReference = true,
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = typeReference.Definition.FullTypeName()
}
},
new OpenApiSchema
{
Type = "object",
Nullable = true
}
};
}
else
{
schema.Type = null;
schema.AnyOf = null;
schema.Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = typeReference.Definition.FullTypeName()
};
schema.UnresolvedReference = true;
schema.Nullable = typeReference.IsNullable;
}

return schema;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,14 @@

schemas[Constants.ReferenceNumericName] = new()
{
Enum = new List<IOpenApiAny>
{
Type = Constants.StringType,
Nullable = true,
Enum =
[
new OpenApiString("-INF"),
new OpenApiString("INF"),
new OpenApiString("NaN")
}
]
};

if (context.Settings.EnableODataAnnotationReferencesForResponses)
Expand Down Expand Up @@ -631,7 +633,7 @@
// properties
foreach (var property in structuredType.Properties())
{
// IOpenApiAny item;

Check warning on line 636 in src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs

View workflow job for this annotation

GitHub Actions / Build

Remove this commented out code. (https://rules.sonarsource.com/csharp/RSPEC-125)
IEdmTypeReference propertyType = property.Type;

IOpenApiAny item = GetTypeNameForExample(context, propertyType);
Expand Down Expand Up @@ -757,7 +759,7 @@
// The type 'System.Double' is not supported in Open API document.
case EdmPrimitiveTypeKind.Double:
/*
{

Check warning on line 762 in src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs

View workflow job for this annotation

GitHub Actions / Build

Remove this commented out code. (https://rules.sonarsource.com/csharp/RSPEC-125)
double result;
if (Double.TryParse(property.DefaultValueString, out result))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ public void CreateEdmTypeSchemaReturnSchemaForNullableCollectionPrimitiveType()
""items"": {
""maximum"": 2147483647,
""minimum"": -2147483648,
""type"": ""integer"",
""type"": ""number"",
""format"": ""int32"",
""nullable"": true
}
Expand Down Expand Up @@ -358,7 +358,7 @@ public void CreateEdmTypeSchemaReturnSchemaForInt32(bool isNullable)
Assert.Equal(@"{
""maximum"": 2147483647,
""minimum"": -2147483648,
""type"": ""integer"",
""type"": ""number"",
""format"": ""int32"",
""nullable"": true
}".ChangeLineBreaks(), json);
Expand All @@ -368,7 +368,7 @@ public void CreateEdmTypeSchemaReturnSchemaForInt32(bool isNullable)
Assert.Equal(@"{
""maximum"": 2147483647,
""minimum"": -2147483648,
""type"": ""integer"",
""type"": ""number"",
""format"": ""int32""
}".ChangeLineBreaks(), json);
}
Expand Down Expand Up @@ -401,15 +401,20 @@ public void CreateEdmTypeSchemaReturnSchemaForDecimal(bool isNullable, bool IEEE
Assert.Null(schema.Type);
Assert.NotNull(schema.OneOf);
Assert.Equal(2, schema.OneOf.Count);
Assert.Equal(new[] { "number", "string" }, schema.OneOf.Select(a => a.Type));
var numberSchema = schema.OneOf.FirstOrDefault(x => x.Type.Equals("number", StringComparison.OrdinalIgnoreCase));
Assert.NotNull(numberSchema);
Assert.True(numberSchema.Nullable);
var stringSchema = schema.OneOf.FirstOrDefault(x => x.Type.Equals("string", StringComparison.OrdinalIgnoreCase));
Assert.NotNull(stringSchema);
Assert.True(stringSchema.Nullable);
Assert.False(schema.Nullable);
}
else
{
Assert.Equal("number", schema.Type);
Assert.Null(schema.OneOf);
Assert.Equal(isNullable, schema.Nullable);
}

Assert.Equal(isNullable, schema.Nullable);
}

[Theory]
Expand Down Expand Up @@ -439,15 +444,20 @@ public void CreateEdmTypeSchemaReturnSchemaForInt64(bool isNullable, bool IEEE75
Assert.Null(schema.Type);
Assert.NotNull(schema.OneOf);
Assert.Equal(2, schema.OneOf.Count);
Assert.Equal(new[] { "integer", "string" }, schema.OneOf.Select(a => a.Type));
var numberSchema = schema.OneOf.FirstOrDefault(x => x.Type.Equals("number", StringComparison.OrdinalIgnoreCase));
Assert.NotNull(numberSchema);
Assert.True(numberSchema.Nullable);
var stringSchema = schema.OneOf.FirstOrDefault(x => x.Type.Equals("string", StringComparison.OrdinalIgnoreCase));
Assert.NotNull(stringSchema);
Assert.True(stringSchema.Nullable);
Assert.False(schema.Nullable);
}
else
{
Assert.Equal("integer", schema.Type);
Assert.Equal("number", schema.Type);
Assert.Null(schema.AnyOf);
Assert.Equal(isNullable, schema.Nullable);
}

Assert.Equal(isNullable, schema.Nullable);
}

[Theory]
Expand Down Expand Up @@ -502,8 +512,16 @@ public void CreateEdmTypeSchemaReturnSchemaForDouble(bool isNullable)
// & Assert
Assert.Null(schema.Type);

Assert.Equal("double", schema.OneOf.FirstOrDefault(x => !string.IsNullOrEmpty(x.Format))?.Format);
Assert.Equal(isNullable, schema.Nullable);
var numberSchema = schema.OneOf.FirstOrDefault(x => x.Type.Equals("number", StringComparison.OrdinalIgnoreCase));
Assert.NotNull(numberSchema);
Assert.True(numberSchema.Nullable);
Assert.Equal("double", numberSchema.Format, StringComparer.OrdinalIgnoreCase);

var stringSchema = schema.OneOf.FirstOrDefault(x => x.Type.Equals("string", StringComparison.OrdinalIgnoreCase));
Assert.NotNull(stringSchema);
Assert.True(stringSchema.Nullable);

Assert.False(schema.Nullable);

Assert.Null(schema.AnyOf);

Expand All @@ -528,8 +546,16 @@ public void CreateEdmTypeSchemaReturnSchemaForSingle(bool isNullable)
// & Assert
Assert.Null(schema.Type);

Assert.Equal("float", schema.OneOf.FirstOrDefault(x => !string.IsNullOrEmpty(x.Format))?.Format);
Assert.Equal(isNullable, schema.Nullable);
var numberSchema = schema.OneOf.FirstOrDefault(x => x.Type.Equals("number", StringComparison.OrdinalIgnoreCase));
Assert.NotNull(numberSchema);
Assert.True(numberSchema.Nullable);
Assert.Equal("float", numberSchema.Format, StringComparer.OrdinalIgnoreCase);

var stringSchema = schema.OneOf.FirstOrDefault(x => x.Type.Equals("string", StringComparison.OrdinalIgnoreCase));
Assert.NotNull(stringSchema);
Assert.True(stringSchema.Nullable);

Assert.False(schema.Nullable);

Assert.Null(schema.AnyOf);

Expand Down
Loading
Loading