diff --git a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs index 2224f6f96..df632b78a 100644 --- a/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs +++ b/src/Microsoft.OpenApi.Hidi/Formatters/PowerShellFormatter.cs @@ -243,7 +243,6 @@ private static void CopySchema(OpenApiSchema schema, OpenApiSchema newSchema) schema.Enum ??= newSchema.Enum; schema.ReadOnly = !schema.ReadOnly ? newSchema.ReadOnly : schema.ReadOnly; schema.WriteOnly = !schema.WriteOnly ? newSchema.WriteOnly : schema.WriteOnly; - schema.Nullable = !schema.Nullable ? newSchema.Nullable : schema.Nullable; schema.Deprecated = !schema.Deprecated ? newSchema.Deprecated : schema.Deprecated; } } diff --git a/src/Microsoft.OpenApi/Extensions/OpenApiTypeMapper.cs b/src/Microsoft.OpenApi/Extensions/OpenApiTypeMapper.cs index e47eff496..857de1d16 100644 --- a/src/Microsoft.OpenApi/Extensions/OpenApiTypeMapper.cs +++ b/src/Microsoft.OpenApi/Extensions/OpenApiTypeMapper.cs @@ -87,19 +87,19 @@ public static JsonSchemaType ToJsonSchemaType(this string identifier) [typeof(char)] = () => new() { Type = JsonSchemaType.String }, // Nullable types - [typeof(bool?)] = () => new() { Type = JsonSchemaType.Boolean, Nullable = true }, - [typeof(byte?)] = () => new() { Type = JsonSchemaType.String, Format = "byte", Nullable = true }, - [typeof(int?)] = () => new() { Type = JsonSchemaType.Integer, Format = "int32", Nullable = true }, - [typeof(uint?)] = () => new() { Type = JsonSchemaType.Integer, Format = "int32", Nullable = true }, - [typeof(long?)] = () => new() { Type = JsonSchemaType.Integer, Format = "int64", Nullable = true }, - [typeof(ulong?)] = () => new() { Type = JsonSchemaType.Integer, Format = "int64", Nullable = true }, - [typeof(float?)] = () => new() { Type = JsonSchemaType.Number, Format = "float", Nullable = true }, - [typeof(double?)] = () => new() { Type = JsonSchemaType.Number, Format = "double", Nullable = true }, - [typeof(decimal?)] = () => new() { Type = JsonSchemaType.Number, Format = "double", Nullable = true }, - [typeof(DateTime?)] = () => new() { Type = JsonSchemaType.String, Format = "date-time", Nullable = true }, - [typeof(DateTimeOffset?)] = () => new() { Type = JsonSchemaType.String, Format = "date-time", Nullable = true }, - [typeof(Guid?)] = () => new() { Type = JsonSchemaType.String, Format = "uuid", Nullable = true }, - [typeof(char?)] = () => new() { Type = JsonSchemaType.String, Nullable = true }, + [typeof(bool?)] = () => new() { Type = JsonSchemaType.Boolean | JsonSchemaType.Null }, + [typeof(byte?)] = () => new() { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "byte" }, + [typeof(int?)] = () => new() { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int32" }, + [typeof(uint?)] = () => new() { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int32" }, + [typeof(long?)] = () => new() { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int64" }, + [typeof(ulong?)] = () => new() { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int64" }, + [typeof(float?)] = () => new() { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "float" }, + [typeof(double?)] = () => new() { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "double" }, + [typeof(decimal?)] = () => new() { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "double" }, + [typeof(DateTime?)] = () => new() { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "date-time" }, + [typeof(DateTimeOffset?)] = () => new() { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "date-time" }, + [typeof(Guid?)] = () => new() { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "uuid" }, + [typeof(char?)] = () => new() { Type = JsonSchemaType.String | JsonSchemaType.Null }, [typeof(Uri)] = () => new() { Type = JsonSchemaType.String, Format = "uri" }, // Uri is treated as simple string [typeof(string)] = () => new() { Type = JsonSchemaType.String }, @@ -153,37 +153,37 @@ public static Type MapOpenApiPrimitiveTypeToSimpleType(this OpenApiSchema schema throw new ArgumentNullException(nameof(schema)); } - var type = (schema.Type.ToIdentifier(), schema.Format?.ToLowerInvariant(), schema.Nullable) switch + var type = ((schema.Type.Value ^ JsonSchemaType.Null).ToIdentifier(), schema.Format?.ToLowerInvariant(), schema.Type.Value & JsonSchemaType.Null) switch { - ("boolean", null, false) => typeof(bool), + ("integer" or "number", "int32", JsonSchemaType.Null) => typeof(int?), + ("integer" or "number", "int64", JsonSchemaType.Null) => typeof(long?), + ("integer", null, JsonSchemaType.Null) => typeof(long?), + ("number", "float", JsonSchemaType.Null) => typeof(float?), + ("number", "double", JsonSchemaType.Null) => typeof(double?), + ("number", null, JsonSchemaType.Null) => typeof(double?), + ("number", "decimal", JsonSchemaType.Null) => typeof(decimal?), + ("string", "byte", JsonSchemaType.Null) => typeof(byte?), + ("string", "date-time", JsonSchemaType.Null) => typeof(DateTimeOffset?), + ("string", "uuid", JsonSchemaType.Null) => typeof(Guid?), + ("string", "char", JsonSchemaType.Null) => typeof(char?), + ("boolean", null, JsonSchemaType.Null) => typeof(bool?), + ("boolean", null, _) => typeof(bool), // integer is technically not valid with format, but we must provide some compatibility - ("integer" or "number", "int32", false) => typeof(int), - ("integer" or "number", "int64", false) => typeof(long), - ("integer", null, false) => typeof(long), - ("number", "float", false) => typeof(float), - ("number", "double", false) => typeof(double), - ("number", "decimal", false) => typeof(decimal), - ("number", null, false) => typeof(double), - ("string", "byte", false) => typeof(byte), - ("string", "date-time", false) => typeof(DateTimeOffset), - ("string", "uuid", false) => typeof(Guid), - ("string", "duration", false) => typeof(TimeSpan), - ("string", "char", false) => typeof(char), - ("string", null, false) => typeof(string), - ("object", null, false) => typeof(object), - ("string", "uri", false) => typeof(Uri), - ("integer" or "number", "int32", true) => typeof(int?), - ("integer" or "number", "int64", true) => typeof(long?), - ("integer", null, true) => typeof(long?), - ("number", "float", true) => typeof(float?), - ("number", "double", true) => typeof(double?), - ("number", null, true) => typeof(double?), - ("number", "decimal", true) => typeof(decimal?), - ("string", "byte", true) => typeof(byte?), - ("string", "date-time", true) => typeof(DateTimeOffset?), - ("string", "uuid", true) => typeof(Guid?), - ("string", "char", true) => typeof(char?), - ("boolean", null, true) => typeof(bool?), + ("integer" or "number", "int32", _) => typeof(int), + ("integer" or "number", "int64", _) => typeof(long), + ("integer", null, _) => typeof(long), + ("number", "float", _) => typeof(float), + ("number", "double", _) => typeof(double), + ("number", "decimal", _) => typeof(decimal), + ("number", null, _) => typeof(double), + ("string", "byte", _) => typeof(byte), + ("string", "date-time", _) => typeof(DateTimeOffset), + ("string", "uuid", _) => typeof(Guid), + ("string", "duration", _) => typeof(TimeSpan), + ("string", "char", _) => typeof(char), + ("string", null, _) => typeof(string), + ("object", null, _) => typeof(object), + ("string", "uri", _) => typeof(Uri), _ => typeof(string), }; diff --git a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs index b548e300d..9ff8e8389 100644 --- a/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/Interfaces/IOpenApiSchema.cs @@ -267,11 +267,6 @@ public interface IOpenApiSchema : IOpenApiDescribedElement, IOpenApiSerializable /// public IList Enum { get; } - /// - /// Allows sending a null value for the defined schema. Default value is false. - /// - public bool Nullable { get; } - /// /// Follow JSON Schema definition: https://tools.ietf.org/html/draft-fge-json-schema-validation-00 /// diff --git a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs index b8dfcefd4..86fbc89ed 100644 --- a/src/Microsoft.OpenApi/Models/OpenApiSchema.cs +++ b/src/Microsoft.OpenApi/Models/OpenApiSchema.cs @@ -155,9 +155,6 @@ public class OpenApiSchema : IOpenApiReferenceable, IOpenApiExtensible, IOpenApi /// public IList Enum { get; set; } = new List(); - /// - public bool Nullable { get; set; } - /// public bool UnevaluatedProperties { get; set;} @@ -236,7 +233,6 @@ internal OpenApiSchema(IOpenApiSchema schema) Example = schema.Example != null ? JsonNodeCloneHelper.Clone(schema.Example) : null; Examples = schema.Examples != null ? new List(schema.Examples) : null; Enum = schema.Enum != null ? new List(schema.Enum) : null; - Nullable = schema.Nullable; ExternalDocs = schema.ExternalDocs != null ? new(schema.ExternalDocs) : null; Deprecated = schema.Deprecated; Xml = schema.Xml != null ? new(schema.Xml) : null; @@ -633,8 +629,7 @@ private void SerializeAsV2( private void SerializeTypeProperty(JsonSchemaType? type, IOpenApiWriter writer, OpenApiSpecVersion version) { // check whether nullable is true for upcasting purposes - var isNullable = Nullable || - (Type.HasValue && Type.Value.HasFlag(JsonSchemaType.Null)) || + var isNullable = (Type.HasValue && Type.Value.HasFlag(JsonSchemaType.Null)) || Extensions is not null && Extensions.TryGetValue(OpenApiConstants.NullableExtension, out var nullExtRawValue) && nullExtRawValue is OpenApiAny { Node: JsonNode jsonNode} && @@ -679,10 +674,6 @@ Extensions is not null && var list = (from JsonSchemaType flag in jsonSchemaTypeValues where type.Value.HasFlag(flag) select flag).ToList(); - if (Nullable && !list.Contains(JsonSchemaType.Null)) - { - list.Add(JsonSchemaType.Null); - } writer.WriteOptionalCollection(OpenApiConstants.Type, list, (w, s) => w.WriteValue(s.ToIdentifier())); } } @@ -735,7 +726,9 @@ private void DowncastTypeArrayToV2OrV3(JsonSchemaType schemaType, IOpenApiWriter ? OpenApiConstants.NullableExtension : OpenApiConstants.Nullable; - if (!HasMultipleTypes(schemaType ^ JsonSchemaType.Null) && (schemaType & JsonSchemaType.Null) == JsonSchemaType.Null) // checks for two values and one is null + var nullable = (schemaType & JsonSchemaType.Null) == JsonSchemaType.Null; + + if (!HasMultipleTypes(schemaType ^ JsonSchemaType.Null) && nullable) // checks for two values and one is null { foreach (JsonSchemaType flag in jsonSchemaTypeValues) { @@ -746,7 +739,7 @@ private void DowncastTypeArrayToV2OrV3(JsonSchemaType schemaType, IOpenApiWriter writer.WriteProperty(OpenApiConstants.Type, flag.ToIdentifier()); } } - if (!Nullable) + if (!nullable || version is not OpenApiSpecVersion.OpenApi2_0) { writer.WriteProperty(nullableProp, true); } diff --git a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs index 8fbeadd50..f0c9a9f47 100644 --- a/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs +++ b/src/Microsoft.OpenApi/Models/References/OpenApiSchemaReference.cs @@ -142,8 +142,6 @@ public string Description /// public IList Enum { get => Target?.Enum; } /// - public bool Nullable { get => Target?.Nullable ?? false; } - /// public bool UnevaluatedProperties { get => Target?.UnevaluatedProperties ?? false; } /// public OpenApiExternalDocs ExternalDocs { get => Target?.ExternalDocs; } diff --git a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs index ff2706f00..25d68b477 100644 --- a/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs +++ b/src/Microsoft.OpenApi/Reader/V3/OpenApiSchemaDeserializer.cs @@ -86,7 +86,14 @@ internal static partial class OpenApiV3Deserializer }, { "type", - (o, n, _) => o.Type = n.GetScalarValue().ToJsonSchemaType() + (o, n, _) => { + var type = n.GetScalarValue().ToJsonSchemaType(); + // so we don't loose the value from nullable + if (o.Type.HasValue) + o.Type |= type; + else + o.Type = type; + } }, { "allOf", @@ -139,7 +146,16 @@ internal static partial class OpenApiV3Deserializer }, { "nullable", - (o, n, _) => o.Nullable = bool.Parse(n.GetScalarValue()) + (o, n, _) => + { + if (bool.TryParse(n.GetScalarValue(), out var parsed) && parsed) + { + if (o.Type.HasValue) + o.Type |= JsonSchemaType.Null; + else + o.Type = JsonSchemaType.Null; + } + } }, { "discriminator", diff --git a/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs b/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs index 62ab79406..63ca4d05e 100644 --- a/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs +++ b/src/Microsoft.OpenApi/Validations/Rules/RuleHelpers.cs @@ -57,11 +57,10 @@ public static void ValidateDataTypeMismatch( var type = schema.Type.ToIdentifier(); var format = schema.Format; - var nullable = schema.Nullable; // Before checking the type, check first if the schema allows null. // If so and the data given is also null, this is allowed for any type. - if (nullable && valueKind is JsonValueKind.Null) + if ((schema.Type.Value & JsonSchemaType.Null) is JsonSchemaType.Null && valueKind is JsonValueKind.Null) { return; } diff --git a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs index f868dfa07..cad3b4548 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/Formatters/PowerShellFormatterTests.cs @@ -58,21 +58,23 @@ public void RemoveAnyOfAndOneOfFromSchema() var walker = new OpenApiWalker(powerShellFormatter); walker.Walk(openApiDocument); - var testSchema = openApiDocument.Components?.Schemas?["TestSchema"]; - var averageAudioDegradationProperty = testSchema?.Properties["averageAudioDegradation"]; - var defaultPriceProperty = testSchema?.Properties["defaultPrice"]; + Assert.NotNull(openApiDocument.Components); + Assert.NotNull(openApiDocument.Components.Schemas); + var testSchema = openApiDocument.Components.Schemas["TestSchema"]; + var averageAudioDegradationProperty = testSchema.Properties["averageAudioDegradation"]; + var defaultPriceProperty = testSchema.Properties["defaultPrice"]; // Assert Assert.NotNull(openApiDocument.Components); Assert.NotNull(openApiDocument.Components.Schemas); Assert.NotNull(testSchema); - Assert.Null(averageAudioDegradationProperty?.AnyOf); - Assert.Equal(JsonSchemaType.Number, averageAudioDegradationProperty?.Type); - Assert.Equal("float", averageAudioDegradationProperty?.Format); - Assert.True(averageAudioDegradationProperty?.Nullable); - Assert.Null(defaultPriceProperty?.OneOf); - Assert.Equal(JsonSchemaType.Number, defaultPriceProperty?.Type); - Assert.Equal("double", defaultPriceProperty?.Format); + Assert.Null(averageAudioDegradationProperty.AnyOf); + Assert.Equal(JsonSchemaType.Number, averageAudioDegradationProperty.Type); + Assert.Equal("float", averageAudioDegradationProperty.Format); + Assert.Equal(JsonSchemaType.Null, averageAudioDegradationProperty.Type & JsonSchemaType.Null); + Assert.Null(defaultPriceProperty.OneOf); + Assert.Equal(JsonSchemaType.Number, defaultPriceProperty.Type); + Assert.Equal("double", defaultPriceProperty.Format); Assert.NotNull(testSchema.AdditionalProperties); } @@ -165,7 +167,7 @@ private static OpenApiDocument GetSampleOpenApiDocument() new OpenApiSchema() { Type = JsonSchemaType.String } }, Format = "float", - Nullable = true + Type = JsonSchemaType.Number | JsonSchemaType.Null | JsonSchemaType.String } }, { diff --git a/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs b/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs index b5289c1ef..3f81c71a3 100644 --- a/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs +++ b/test/Microsoft.OpenApi.Hidi.Tests/UtilityFiles/OpenApiDocumentMock.cs @@ -377,14 +377,7 @@ public static OpenApiDocument CreateOpenApiDocument() { Schema = new OpenApiSchema() { - AnyOf = new List - { - new OpenApiSchema() - { - Type = JsonSchemaType.String - } - }, - Nullable = true + Type = JsonSchemaType.String | JsonSchemaType.Null } } } @@ -627,9 +620,8 @@ public static OpenApiDocument CreateOpenApiDocument() { "description", new OpenApiSchema { - Type = JsonSchemaType.String, + Type = JsonSchemaType.String | JsonSchemaType.Null, Description = "Description of the NIC (e.g. Ethernet adapter, Wireless LAN adapter Local Area Connection <#>, etc.).", - Nullable = true } } } diff --git a/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs b/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs index c41bd6e98..dead3b27c 100644 --- a/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs +++ b/test/Microsoft.OpenApi.Tests/Extensions/OpenApiTypeMapperTests.cs @@ -15,45 +15,45 @@ public class OpenApiTypeMapperTests { new object[] { typeof(int), new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int32" } }, new object[] { typeof(decimal), new OpenApiSchema { Type = JsonSchemaType.Number, Format = "double" } }, - new object[] { typeof(decimal?), new OpenApiSchema { Type = JsonSchemaType.Number, Format = "double", Nullable = true } }, - new object[] { typeof(bool?), new OpenApiSchema { Type = JsonSchemaType.Boolean, Nullable = true } }, + new object[] { typeof(decimal?), new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "double" } }, + new object[] { typeof(bool?), new OpenApiSchema { Type = JsonSchemaType.Boolean | JsonSchemaType.Null } }, new object[] { typeof(Guid), new OpenApiSchema { Type = JsonSchemaType.String, Format = "uuid" } }, - new object[] { typeof(Guid?), new OpenApiSchema { Type = JsonSchemaType.String, Format = "uuid", Nullable = true } }, + new object[] { typeof(Guid?), new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "uuid" } }, new object[] { typeof(uint), new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int32" } }, new object[] { typeof(long), new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int64" } }, - new object[] { typeof(long?), new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int64", Nullable = true } }, + new object[] { typeof(long?), new OpenApiSchema { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int64" } }, new object[] { typeof(ulong), new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int64" } }, new object[] { typeof(string), new OpenApiSchema { Type = JsonSchemaType.String } }, new object[] { typeof(double), new OpenApiSchema { Type = JsonSchemaType.Number, Format = "double" } }, - new object[] { typeof(float?), new OpenApiSchema { Type = JsonSchemaType.Number, Format = "float", Nullable = true } }, - new object[] { typeof(byte?), new OpenApiSchema { Type = JsonSchemaType.String, Format = "byte", Nullable = true } }, - new object[] { typeof(int?), new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int32", Nullable = true } }, - new object[] { typeof(uint?), new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int32", Nullable = true } }, - new object[] { typeof(DateTimeOffset?), new OpenApiSchema { Type = JsonSchemaType.String, Format = "date-time", Nullable = true } }, - new object[] { typeof(double?), new OpenApiSchema { Type = JsonSchemaType.Number, Format = "double", Nullable = true } }, - new object[] { typeof(char?), new OpenApiSchema { Type = JsonSchemaType.String, Nullable = true } }, + new object[] { typeof(float?), new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "float" } }, + new object[] { typeof(byte?), new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "byte" } }, + new object[] { typeof(int?), new OpenApiSchema { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int32" } }, + new object[] { typeof(uint?), new OpenApiSchema { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int32" } }, + new object[] { typeof(DateTimeOffset?), new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "date-time" } }, + new object[] { typeof(double?), new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "double" } }, + new object[] { typeof(char?), new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null } }, new object[] { typeof(DateTimeOffset), new OpenApiSchema { Type = JsonSchemaType.String, Format = "date-time" } } }; public static IEnumerable OpenApiDataTypes => new List { - new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int32", Nullable = false}, typeof(int) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int32", Nullable = true}, typeof(int?) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int64", Nullable = false}, typeof(long) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int64", Nullable = true}, typeof(long?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int32" }, typeof(int) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int32"}, typeof(int?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer, Format = "int64" }, typeof(long) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = "int64"}, typeof(long?) }, new object[] { new OpenApiSchema { Type = JsonSchemaType.Number, Format = "decimal"}, typeof(decimal) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer, Format = null, Nullable = false}, typeof(long) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer, Format = null, Nullable = true}, typeof(long?) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Number, Format = null, Nullable = false}, typeof(double) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Number, Format = null, Nullable = true}, typeof(double?) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Number, Format = "decimal", Nullable = true}, typeof(decimal?) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Number, Format = "double", Nullable = true}, typeof(double?) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.String, Format = "date-time", Nullable = true}, typeof(DateTimeOffset?) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.String, Format = "char", Nullable = true}, typeof(char?) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.String, Format = "uuid", Nullable = true}, typeof(Guid?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer, Format = null }, typeof(long) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Integer | JsonSchemaType.Null, Format = null}, typeof(long?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Number, Format = null }, typeof(double) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = null}, typeof(double?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "decimal"}, typeof(decimal?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "double"}, typeof(double?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "date-time"}, typeof(DateTimeOffset?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "char"}, typeof(char?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.String | JsonSchemaType.Null, Format = "uuid"}, typeof(Guid?) }, new object[] { new OpenApiSchema { Type = JsonSchemaType.String }, typeof(string) }, new object[] { new OpenApiSchema { Type = JsonSchemaType.Number, Format = "double" }, typeof(double) }, - new object[] { new OpenApiSchema { Type = JsonSchemaType.Number, Format = "float", Nullable = true }, typeof(float?) }, + new object[] { new OpenApiSchema { Type = JsonSchemaType.Number | JsonSchemaType.Null, Format = "float" }, typeof(float?) }, new object[] { new OpenApiSchema { Type = JsonSchemaType.String, Format = "date-time" }, typeof(DateTimeOffset) } }; diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt index 852e12e71..aac504993 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=False.verified.txt @@ -4,8 +4,8 @@ "maximum": 42, "minimum": 10, "exclusiveMinimum": true, - "nullable": true, "type": "integer", + "nullable": true, "default": 15, "externalDocs": { "url": "http://example.com/externalDocs" diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt index bfea35bdd..3ed4ce5c8 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3JsonWorksAsync_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"title":"title1","multipleOf":3,"maximum":42,"minimum":10,"exclusiveMinimum":true,"nullable":true,"type":"integer","default":15,"externalDocs":{"url":"http://example.com/externalDocs"}} \ No newline at end of file +{"title":"title1","multipleOf":3,"maximum":42,"minimum":10,"exclusiveMinimum":true,"type":"integer","nullable":true,"default":15,"externalDocs":{"url":"http://example.com/externalDocs"}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=False.verified.txt index 852e12e71..aac504993 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=False.verified.txt @@ -4,8 +4,8 @@ "maximum": 42, "minimum": 10, "exclusiveMinimum": true, - "nullable": true, "type": "integer", + "nullable": true, "default": 15, "externalDocs": { "url": "http://example.com/externalDocs" diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=True.verified.txt index bfea35bdd..3ed4ce5c8 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeReferencedSchemaAsV3WithoutReferenceJsonWorksAsync_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"title":"title1","multipleOf":3,"maximum":42,"minimum":10,"exclusiveMinimum":true,"nullable":true,"type":"integer","default":15,"externalDocs":{"url":"http://example.com/externalDocs"}} \ No newline at end of file +{"title":"title1","multipleOf":3,"maximum":42,"minimum":10,"exclusiveMinimum":true,"type":"integer","nullable":true,"default":15,"externalDocs":{"url":"http://example.com/externalDocs"}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt index e9543ede7..4e4e0200b 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=False.verified.txt @@ -1,4 +1,5 @@ { + "type": "object", "title": "title1", "required": [ "property1" diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt index 9ea88dee8..864b97656 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.SerializeSchemaWRequiredPropertiesAsV2JsonWorksAsync_produceTerseOutput=True.verified.txt @@ -1 +1 @@ -{"title":"title1","required":["property1"],"properties":{"property1":{"required":["property3"],"properties":{"property2":{"type":"integer"},"property3":{"type":"string","maxLength":15}}},"property4":{"properties":{"property5":{"properties":{"property6":{"type":"boolean"}}},"property7":{"type":"string","minLength":2}},"readOnly":true}},"externalDocs":{"url":"http://example.com/externalDocs"}} \ No newline at end of file +{"type":"object","title":"title1","required":["property1"],"properties":{"property1":{"required":["property3"],"properties":{"property2":{"type":"integer"},"property3":{"type":"string","maxLength":15}}},"property4":{"properties":{"property5":{"properties":{"property6":{"type":"boolean"}}},"property7":{"type":"string","minLength":2}},"readOnly":true}},"externalDocs":{"url":"http://example.com/externalDocs"}} \ No newline at end of file diff --git a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs index bc3a78a7c..3e6ed2f2e 100644 --- a/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs +++ b/test/Microsoft.OpenApi.Tests/Models/OpenApiSchemaTests.cs @@ -33,9 +33,8 @@ public class OpenApiSchemaTests ExclusiveMinimum = true, Minimum = 10, Default = 15, - Type = JsonSchemaType.Integer, + Type = JsonSchemaType.Integer | JsonSchemaType.Null, - Nullable = true, ExternalDocs = new() { Url = new("http://example.com/externalDocs") @@ -85,7 +84,7 @@ public class OpenApiSchemaTests }, }, }, - Nullable = true, + Type = JsonSchemaType.Object | JsonSchemaType.Null, ExternalDocs = new() { Url = new("http://example.com/externalDocs") @@ -134,10 +133,10 @@ public class OpenApiSchemaTests MinLength = 2 } }, - Nullable = true + Type = JsonSchemaType.Object | JsonSchemaType.Null, }, }, - Nullable = true, + Type = JsonSchemaType.Object | JsonSchemaType.Null, ExternalDocs = new() { Url = new("http://example.com/externalDocs") @@ -152,9 +151,8 @@ public class OpenApiSchemaTests ExclusiveMinimum = true, Minimum = 10, Default = 15, - Type = JsonSchemaType.Integer, + Type = JsonSchemaType.Integer | JsonSchemaType.Null, - Nullable = true, ExternalDocs = new() { Url = new("http://example.com/externalDocs") @@ -208,7 +206,7 @@ public class OpenApiSchemaTests ReadOnly = true, }, }, - Nullable = true, + Type = JsonSchemaType.Object | JsonSchemaType.Null, ExternalDocs = new() { Url = new("http://example.com/externalDocs") @@ -472,11 +470,11 @@ public void OpenApiSchemaCopyConstructorSucceeds() }; var actualSchema = baseSchema.CreateShallowCopy() as OpenApiSchema; - actualSchema.Nullable = true; + actualSchema.Type |= JsonSchemaType.Null; Assert.Equal(JsonSchemaType.String, actualSchema.Type); Assert.Equal("date", actualSchema.Format); - Assert.True(actualSchema.Nullable); + Assert.Equal(JsonSchemaType.Null, actualSchema.Type & JsonSchemaType.Null); } [Fact] diff --git a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt index 69956d663..343b8731c 100644 --- a/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt +++ b/test/Microsoft.OpenApi.Tests/PublicApi/PublicApi.approved.txt @@ -443,7 +443,6 @@ namespace Microsoft.OpenApi.Models.Interfaces decimal? Minimum { get; } decimal? MultipleOf { get; } Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Not { get; } - bool Nullable { get; } System.Collections.Generic.IList OneOf { get; } string Pattern { get; } System.Collections.Generic.IDictionary PatternProperties { get; } @@ -1046,7 +1045,6 @@ namespace Microsoft.OpenApi.Models public decimal? Minimum { get; set; } public decimal? MultipleOf { get; set; } public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Not { get; set; } - public bool Nullable { get; set; } public System.Collections.Generic.IList OneOf { get; set; } public string Pattern { get; set; } public System.Collections.Generic.IDictionary PatternProperties { get; set; } @@ -1400,7 +1398,6 @@ namespace Microsoft.OpenApi.Models.References public decimal? Minimum { get; } public decimal? MultipleOf { get; } public Microsoft.OpenApi.Models.Interfaces.IOpenApiSchema Not { get; } - public bool Nullable { get; } public System.Collections.Generic.IList OneOf { get; } public string Pattern { get; } public System.Collections.Generic.IDictionary PatternProperties { get; }