c25df986ac
* Introduce setting hidden from UI, such that openApiSpec version 2 has the nullable references properly serialized. AnyOf does not exist in v2, and those references are currently lost. * Updating existing tests for nullable/schema areas where v2 and v3 differ Making them theories to properly test both openApi specifications Adding relevant yaml, json test files Modifying code to ensure enums and entities also generate openApi with no anyOf for openApi v2 (not supported) * Fix "Succeeded" typo in output for util Fix tab spacing in util Add version setting in util with documentation * Remove tabs * Refactor tests to take SpecVersion directly in InlineData Modify 2 existing tests to test json schema generation by passed spec version
528 lines
19 KiB
C#
528 lines
19 KiB
C#
// ------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
|
|
// ------------------------------------------------------------
|
|
|
|
using System;
|
|
using System.Linq;
|
|
using Microsoft.OData.Edm;
|
|
using Microsoft.OpenApi.Extensions;
|
|
using Microsoft.OpenApi.Models;
|
|
using Microsoft.OpenApi.OData.Edm;
|
|
using Microsoft.OpenApi.OData.Generator;
|
|
using Xunit;
|
|
using Xunit.Abstractions;
|
|
|
|
namespace Microsoft.OpenApi.OData.Tests
|
|
{
|
|
public class OpenApiEdmTypeSchemaGeneratorTest
|
|
{
|
|
private ITestOutputHelper _output;
|
|
public OpenApiEdmTypeSchemaGeneratorTest(ITestOutputHelper output)
|
|
{
|
|
_output = output;
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateEdmTypeSchemaThrowArgumentNullContext()
|
|
{
|
|
// Arrange
|
|
ODataContext context = null;
|
|
|
|
// Act & Assert
|
|
Assert.Throws<ArgumentNullException>("context", () => context.CreateEdmTypeSchema(edmTypeReference: null));
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateEdmTypeSchemaThrowArgumentNullEdmTypeReference()
|
|
{
|
|
// Arrange
|
|
ODataContext context = new ODataContext(EdmCoreModel.Instance);
|
|
|
|
// Act & Assert
|
|
Assert.Throws<ArgumentNullException>("edmTypeReference", () => context.CreateEdmTypeSchema(edmTypeReference: null));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(OpenApiSpecVersion.OpenApi2_0)]
|
|
[InlineData(OpenApiSpecVersion.OpenApi3_0)]
|
|
public void CreateEdmTypeSchemaReturnSchemaForNullableCollectionComplexType(OpenApiSpecVersion specVersion)
|
|
{
|
|
// Arrange
|
|
IEdmModel model = EdmModelHelper.TripServiceModel;
|
|
IEdmComplexType complex = model.SchemaElements.OfType<IEdmComplexType>().First(c => c.Name == "AirportLocation");
|
|
ODataContext context = new ODataContext(model);
|
|
|
|
context.Settings.OpenApiSpecVersion = specVersion;
|
|
|
|
IEdmCollectionTypeReference collectionType = new EdmCollectionTypeReference(
|
|
new EdmCollectionType(new EdmComplexTypeReference(complex, true)));
|
|
|
|
// Act
|
|
var schema = context.CreateEdmTypeSchema(collectionType);
|
|
Assert.NotNull(schema);
|
|
string json = schema.SerializeAsJson(context.Settings.OpenApiSpecVersion);
|
|
|
|
// & Assert
|
|
if (specVersion == OpenApiSpecVersion.OpenApi2_0)
|
|
{
|
|
Assert.Equal(@"{
|
|
""type"": ""array"",
|
|
""items"": {
|
|
""$ref"": ""#/definitions/Microsoft.OData.Service.Sample.TrippinInMemory.Models.AirportLocation""
|
|
}
|
|
}".ChangeLineBreaks(), json);
|
|
}
|
|
else
|
|
{
|
|
Assert.Equal(@"{
|
|
""type"": ""array"",
|
|
""items"": {
|
|
""anyOf"": [
|
|
{
|
|
""$ref"": ""#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.AirportLocation""
|
|
}
|
|
],
|
|
""nullable"": true
|
|
}
|
|
}".ChangeLineBreaks(), json);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateEdmTypeSchemaReturnSchemaForNonNullableCollectionComplexType()
|
|
{
|
|
// Arrange
|
|
IEdmModel model = EdmModelHelper.TripServiceModel;
|
|
IEdmComplexType complex = model.SchemaElements.OfType<IEdmComplexType>().First(c => c.Name == "AirportLocation");
|
|
ODataContext context = new ODataContext(model);
|
|
IEdmCollectionTypeReference collectionType = new EdmCollectionTypeReference(
|
|
new EdmCollectionType(new EdmComplexTypeReference(complex, false)));
|
|
|
|
// Act
|
|
var schema = context.CreateEdmTypeSchema(collectionType);
|
|
Assert.NotNull(schema);
|
|
string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);
|
|
|
|
// & Assert
|
|
Assert.Equal(@"{
|
|
""type"": ""array"",
|
|
""items"": {
|
|
""$ref"": ""#/components/schemas/Microsoft.OData.Service.Sample.TrippinInMemory.Models.AirportLocation""
|
|
}
|
|
}".ChangeLineBreaks(), json);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateEdmTypeSchemaReturnSchemaForNonNullableCollectionPrimitiveType()
|
|
{
|
|
// Arrange
|
|
IEdmModel model = EdmCoreModel.Instance;
|
|
ODataContext context = new ODataContext(model);
|
|
IEdmCollectionTypeReference collectionType = new EdmCollectionTypeReference(
|
|
new EdmCollectionType(EdmCoreModel.Instance.GetString(false)));
|
|
|
|
// Act
|
|
var schema = context.CreateEdmTypeSchema(collectionType);
|
|
Assert.NotNull(schema);
|
|
string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);
|
|
|
|
// & Assert
|
|
Assert.Equal(@"{
|
|
""type"": ""array"",
|
|
""items"": {
|
|
""type"": ""string""
|
|
}
|
|
}".ChangeLineBreaks(), json);
|
|
}
|
|
|
|
[Fact]
|
|
public void CreateEdmTypeSchemaReturnSchemaForNullableCollectionPrimitiveType()
|
|
{
|
|
// Arrange
|
|
IEdmModel model = EdmCoreModel.Instance;
|
|
ODataContext context = new ODataContext(model);
|
|
IEdmCollectionTypeReference collectionType = new EdmCollectionTypeReference(
|
|
new EdmCollectionType(EdmCoreModel.Instance.GetInt32(true)));
|
|
|
|
// Act
|
|
var schema = context.CreateEdmTypeSchema(collectionType);
|
|
Assert.NotNull(schema);
|
|
string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);
|
|
|
|
// & Assert
|
|
Assert.Equal(@"{
|
|
""type"": ""array"",
|
|
""items"": {
|
|
""maximum"": 2147483647,
|
|
""minimum"": -2147483648,
|
|
""type"": ""integer"",
|
|
""format"": ""int32"",
|
|
""nullable"": true
|
|
}
|
|
}".ChangeLineBreaks(), json);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(true, OpenApiSpecVersion.OpenApi2_0)]
|
|
[InlineData(true, OpenApiSpecVersion.OpenApi3_0)]
|
|
[InlineData(false, OpenApiSpecVersion.OpenApi2_0)]
|
|
[InlineData(false, OpenApiSpecVersion.OpenApi3_0)]
|
|
public void CreateEdmTypeSchemaReturnSchemaForEnumType(bool isNullable, OpenApiSpecVersion specVersion)
|
|
{
|
|
// Arrange
|
|
IEdmModel model = EdmModelHelper.TripServiceModel;
|
|
IEdmEnumType enumType = model.SchemaElements.OfType<IEdmEnumType>().First(c => c.Name == "PersonGender");
|
|
Assert.NotNull(enumType); // guard
|
|
IEdmEnumTypeReference enumTypeReference = new EdmEnumTypeReference(enumType, isNullable);
|
|
ODataContext context = new ODataContext(model);
|
|
|
|
context.Settings.OpenApiSpecVersion = specVersion;
|
|
|
|
// Act
|
|
var schema = context.CreateEdmTypeSchema(enumTypeReference);
|
|
|
|
// & Assert
|
|
Assert.NotNull(schema);
|
|
|
|
// Although the schema will be set
|
|
// for openApiV2 nullable will not be serialized
|
|
Assert.Equal(isNullable, schema.Nullable);
|
|
|
|
if (specVersion == OpenApiSpecVersion.OpenApi2_0)
|
|
{
|
|
Assert.NotNull(schema.Reference);
|
|
Assert.Null(schema.AnyOf);
|
|
Assert.Equal(ReferenceType.Schema, schema.Reference.Type);
|
|
Assert.Equal(enumType.FullTypeName(), schema.Reference.Id);
|
|
}
|
|
else
|
|
{
|
|
Assert.Null(schema.Reference);
|
|
Assert.NotNull(schema.AnyOf);
|
|
Assert.NotEmpty(schema.AnyOf);
|
|
var anyOf = Assert.Single(schema.AnyOf);
|
|
Assert.NotNull(anyOf.Reference);
|
|
Assert.Equal(ReferenceType.Schema, anyOf.Reference.Type);
|
|
Assert.Equal(enumType.FullTypeName(), anyOf.Reference.Id);
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(true, OpenApiSpecVersion.OpenApi2_0)]
|
|
[InlineData(true, OpenApiSpecVersion.OpenApi3_0)]
|
|
[InlineData(false, OpenApiSpecVersion.OpenApi2_0)]
|
|
[InlineData(false, OpenApiSpecVersion.OpenApi3_0)]
|
|
public void CreateEdmTypeSchemaReturnSchemaForComplexType(bool isNullable, OpenApiSpecVersion specVersion)
|
|
{
|
|
// Arrange
|
|
IEdmModel model = EdmModelHelper.TripServiceModel;
|
|
IEdmComplexType complex = model.SchemaElements.OfType<IEdmComplexType>().First(c => c.Name == "AirportLocation");
|
|
Assert.NotNull(complex); // guard
|
|
IEdmComplexTypeReference complexTypeReference = new EdmComplexTypeReference(complex, isNullable);
|
|
ODataContext context = new ODataContext(model);
|
|
|
|
context.Settings.OpenApiSpecVersion = specVersion;
|
|
|
|
// Act
|
|
var schema = context.CreateEdmTypeSchema(complexTypeReference);
|
|
|
|
// & Assert
|
|
Assert.NotNull(schema);
|
|
|
|
if (specVersion == OpenApiSpecVersion.OpenApi2_0 || isNullable == false)
|
|
{
|
|
Assert.Null(schema.AnyOf);
|
|
Assert.NotNull(schema.Reference);
|
|
Assert.Equal(ReferenceType.Schema, schema.Reference.Type);
|
|
Assert.Equal(complex.FullTypeName(), schema.Reference.Id);
|
|
}
|
|
else
|
|
{
|
|
Assert.Null(schema.Reference);
|
|
Assert.NotNull(schema.AnyOf);
|
|
Assert.NotEmpty(schema.AnyOf);
|
|
var anyOf = Assert.Single(schema.AnyOf);
|
|
Assert.NotNull(anyOf.Reference);
|
|
Assert.Equal(ReferenceType.Schema, anyOf.Reference.Type);
|
|
Assert.Equal(complex.FullTypeName(), anyOf.Reference.Id);
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(true, OpenApiSpecVersion.OpenApi3_0)]
|
|
[InlineData(true, OpenApiSpecVersion.OpenApi2_0)]
|
|
[InlineData(false, OpenApiSpecVersion.OpenApi2_0)]
|
|
[InlineData(false, OpenApiSpecVersion.OpenApi3_0)]
|
|
public void CreateEdmTypeSchemaReturnSchemaForEntityType(bool isNullable, OpenApiSpecVersion specVersion)
|
|
{
|
|
// Arrange
|
|
IEdmModel model = EdmModelHelper.TripServiceModel;
|
|
IEdmEntityType entity = model.SchemaElements.OfType<IEdmEntityType>().First(c => c.Name == "Manager");
|
|
Assert.NotNull(entity); // guard
|
|
IEdmEntityTypeReference entityTypeReference = new EdmEntityTypeReference(entity, isNullable);
|
|
ODataContext context = new ODataContext(model);
|
|
|
|
context.Settings.OpenApiSpecVersion = specVersion;
|
|
|
|
// Act
|
|
var schema = context.CreateEdmTypeSchema(entityTypeReference);
|
|
|
|
// & Assert
|
|
Assert.NotNull(schema);
|
|
|
|
if (specVersion == OpenApiSpecVersion.OpenApi2_0 || isNullable == false)
|
|
{
|
|
Assert.Null(schema.AnyOf);
|
|
Assert.NotNull(schema.Reference);
|
|
Assert.Equal(ReferenceType.Schema, schema.Reference.Type);
|
|
Assert.Equal(entity.FullTypeName(), schema.Reference.Id);
|
|
}
|
|
else
|
|
{
|
|
Assert.Null(schema.Reference);
|
|
Assert.NotNull(schema.AnyOf);
|
|
Assert.NotEmpty(schema.AnyOf);
|
|
var anyOf = Assert.Single(schema.AnyOf);
|
|
Assert.NotNull(anyOf.Reference);
|
|
Assert.Equal(ReferenceType.Schema, anyOf.Reference.Type);
|
|
Assert.Equal(entity.FullTypeName(), anyOf.Reference.Id);
|
|
}
|
|
}
|
|
|
|
#region Primitive type schema
|
|
|
|
[Theory]
|
|
[InlineData(true)]
|
|
[InlineData(false)]
|
|
public void CreateEdmTypeSchemaReturnSchemaForString(bool isNullable)
|
|
{
|
|
// Arrange
|
|
IEdmModel model = EdmCoreModel.Instance;
|
|
ODataContext context = new ODataContext(model);
|
|
IEdmTypeReference edmTypeReference = EdmCoreModel.Instance.GetString(isNullable);
|
|
|
|
// Act
|
|
var schema = context.CreateEdmTypeSchema(edmTypeReference);
|
|
Assert.NotNull(schema); // guard
|
|
string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);
|
|
|
|
// & Assert
|
|
if (isNullable)
|
|
{
|
|
Assert.Equal(@"{
|
|
""type"": ""string"",
|
|
""nullable"": true
|
|
}".ChangeLineBreaks(), json);
|
|
}
|
|
else
|
|
{
|
|
Assert.Equal(@"{
|
|
""type"": ""string""
|
|
}".ChangeLineBreaks(), json);
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(true)]
|
|
[InlineData(false)]
|
|
public void CreateEdmTypeSchemaReturnSchemaForInt32(bool isNullable)
|
|
{
|
|
// Arrange
|
|
IEdmModel model = EdmCoreModel.Instance;
|
|
ODataContext context = new ODataContext(model);
|
|
IEdmTypeReference edmTypeReference = EdmCoreModel.Instance.GetInt32(isNullable);
|
|
|
|
// Act
|
|
var schema = context.CreateEdmTypeSchema(edmTypeReference);
|
|
Assert.NotNull(schema); // guard
|
|
string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);
|
|
|
|
// & Assert
|
|
if (isNullable)
|
|
{
|
|
Assert.Equal(@"{
|
|
""maximum"": 2147483647,
|
|
""minimum"": -2147483648,
|
|
""type"": ""integer"",
|
|
""format"": ""int32"",
|
|
""nullable"": true
|
|
}".ChangeLineBreaks(), json);
|
|
}
|
|
else
|
|
{
|
|
Assert.Equal(@"{
|
|
""maximum"": 2147483647,
|
|
""minimum"": -2147483648,
|
|
""type"": ""integer"",
|
|
""format"": ""int32""
|
|
}".ChangeLineBreaks(), json);
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(true, true)]
|
|
[InlineData(true, false)]
|
|
[InlineData(false, true)]
|
|
[InlineData(false, false)]
|
|
public void CreateEdmTypeSchemaReturnSchemaForDecimal(bool isNullable, bool IEEE754Compatible)
|
|
{
|
|
// Arrange
|
|
IEdmModel model = EdmCoreModel.Instance;
|
|
OpenApiConvertSettings settings = new OpenApiConvertSettings
|
|
{
|
|
IEEE754Compatible = IEEE754Compatible
|
|
};
|
|
|
|
ODataContext context = new ODataContext(model, settings);
|
|
IEdmTypeReference edmTypeReference = EdmCoreModel.Instance.GetDecimal(isNullable);
|
|
|
|
// Act
|
|
var schema = context.CreateEdmTypeSchema(edmTypeReference);
|
|
Assert.NotNull(schema); // guard
|
|
|
|
// & Assert
|
|
if (IEEE754Compatible)
|
|
{
|
|
Assert.Null(schema.Type);
|
|
Assert.NotNull(schema.AnyOf);
|
|
Assert.Equal(2, schema.AnyOf.Count);
|
|
Assert.Equal(new[] { "number", "string" }, schema.AnyOf.Select(a => a.Type));
|
|
}
|
|
else
|
|
{
|
|
Assert.Equal("number", schema.Type);
|
|
Assert.Null(schema.AnyOf);
|
|
}
|
|
|
|
Assert.Equal(isNullable, schema.Nullable);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(true, true)]
|
|
[InlineData(true, false)]
|
|
[InlineData(false, true)]
|
|
[InlineData(false, false)]
|
|
public void CreateEdmTypeSchemaReturnSchemaForInt64(bool isNullable, bool IEEE754Compatible)
|
|
{
|
|
// Arrange
|
|
IEdmModel model = EdmCoreModel.Instance;
|
|
OpenApiConvertSettings settings = new OpenApiConvertSettings
|
|
{
|
|
IEEE754Compatible = IEEE754Compatible
|
|
};
|
|
|
|
ODataContext context = new ODataContext(model, settings);
|
|
IEdmTypeReference edmTypeReference = EdmCoreModel.Instance.GetInt64(isNullable);
|
|
|
|
// Act
|
|
var schema = context.CreateEdmTypeSchema(edmTypeReference);
|
|
Assert.NotNull(schema); // guard
|
|
|
|
// & Assert
|
|
if (IEEE754Compatible)
|
|
{
|
|
Assert.Null(schema.Type);
|
|
Assert.NotNull(schema.AnyOf);
|
|
Assert.Equal(2, schema.AnyOf.Count);
|
|
Assert.Equal(new[] { "integer", "string" }, schema.AnyOf.Select(a => a.Type));
|
|
}
|
|
else
|
|
{
|
|
Assert.Equal("integer", schema.Type);
|
|
Assert.Null(schema.AnyOf);
|
|
}
|
|
|
|
Assert.Equal(isNullable, schema.Nullable);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(true)]
|
|
[InlineData(false)]
|
|
public void CreateEdmTypeSchemaReturnSchemaForGuid(bool isNullable)
|
|
{
|
|
// Arrange
|
|
IEdmModel model = EdmCoreModel.Instance;
|
|
ODataContext context = new ODataContext(model);
|
|
IEdmTypeReference edmTypeReference = EdmCoreModel.Instance.GetGuid(isNullable);
|
|
|
|
// Act
|
|
var schema = context.CreateEdmTypeSchema(edmTypeReference);
|
|
Assert.NotNull(schema); // guard
|
|
string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0);
|
|
|
|
// & Assert
|
|
if (isNullable)
|
|
{
|
|
Assert.Equal(@"{
|
|
""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}$"",
|
|
""type"": ""string"",
|
|
""format"": ""uuid"",
|
|
""nullable"": true
|
|
}".ChangeLineBreaks(), json);
|
|
}
|
|
else
|
|
{
|
|
Assert.Equal(@"{
|
|
""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}$"",
|
|
""type"": ""string"",
|
|
""format"": ""uuid""
|
|
}".ChangeLineBreaks(), json);
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(true)]
|
|
[InlineData(false)]
|
|
public void CreateEdmTypeSchemaReturnSchemaForDouble(bool isNullable)
|
|
{
|
|
// Arrange
|
|
IEdmModel model = EdmCoreModel.Instance;
|
|
ODataContext context = new ODataContext(model);
|
|
IEdmTypeReference edmTypeReference = EdmCoreModel.Instance.GetDouble(isNullable);
|
|
|
|
// Act
|
|
var schema = context.CreateEdmTypeSchema(edmTypeReference);
|
|
Assert.NotNull(schema); // guard
|
|
|
|
// & Assert
|
|
Assert.Null(schema.Type);
|
|
|
|
Assert.Equal("double", schema.Format);
|
|
Assert.Equal(isNullable, schema.Nullable);
|
|
|
|
Assert.Null(schema.OneOf);
|
|
|
|
Assert.NotNull(schema.AnyOf);
|
|
Assert.Equal(3, schema.AnyOf.Count);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(true)]
|
|
[InlineData(false)]
|
|
public void CreateEdmTypeSchemaReturnSchemaForSingle(bool isNullable)
|
|
{
|
|
// Arrange
|
|
IEdmModel model = EdmCoreModel.Instance;
|
|
ODataContext context = new ODataContext(model);
|
|
IEdmTypeReference edmTypeReference = EdmCoreModel.Instance.GetSingle(isNullable);
|
|
|
|
// Act
|
|
var schema = context.CreateEdmTypeSchema(edmTypeReference);
|
|
Assert.NotNull(schema); // guard
|
|
|
|
// & Assert
|
|
Assert.Null(schema.Type);
|
|
|
|
Assert.Equal("float", schema.Format);
|
|
Assert.Equal(isNullable, schema.Nullable);
|
|
|
|
Assert.Null(schema.OneOf);
|
|
|
|
Assert.NotNull(schema.AnyOf);
|
|
Assert.Equal(3, schema.AnyOf.Count);
|
|
}
|
|
#endregion
|
|
}
|
|
}
|