Move the functions to OpenApiSchemaGenerator and add unit test for the Enum type schema
This commit is contained in:
parent
033d166490
commit
5ee41ab4df
|
@ -3,8 +3,11 @@
|
|||
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.OData.Edm;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.OData.Properties;
|
||||
using Microsoft.OpenApi.Models;
|
||||
|
||||
namespace Microsoft.OpenApi.OData.Generator
|
||||
|
@ -39,7 +42,7 @@ namespace Microsoft.OpenApi.OData.Generator
|
|||
case EdmSchemaElementKind.TypeDefinition: // Type definition
|
||||
{
|
||||
IEdmType reference = (IEdmType)element;
|
||||
schemas.Add(reference.FullTypeName(), context.Model.CreateEdmTypeSchema(reference));
|
||||
schemas.Add(reference.FullTypeName(), context.CreateEdmTypeSchema(reference));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -49,5 +52,165 @@ namespace Microsoft.OpenApi.OData.Generator
|
|||
|
||||
return schemas;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="OpenApiSchema"/> for a <see cref="IEdmType"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The OData context.</param>
|
||||
/// <param name="edmType">The Edm type.</param>
|
||||
/// <returns>The created <see cref="OpenApiSchema"/>.</returns>
|
||||
public static OpenApiSchema CreateEdmTypeSchema(this ODataContext context, IEdmType edmType)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw Error.ArgumentNull(nameof(context));
|
||||
}
|
||||
|
||||
if (edmType == null)
|
||||
{
|
||||
throw Error.ArgumentNull(nameof(edmType));
|
||||
}
|
||||
|
||||
switch (edmType.TypeKind)
|
||||
{
|
||||
case EdmTypeKind.Complex: // complex type
|
||||
case EdmTypeKind.Entity: // entity type
|
||||
return context.CreateStructuredTypeSchema((IEdmStructuredType)edmType, true);
|
||||
|
||||
case EdmTypeKind.Enum: // enum type
|
||||
return context.CreateEnumTypeSchema((IEdmEnumType)edmType);
|
||||
|
||||
case EdmTypeKind.TypeDefinition: // type definition
|
||||
return context.CreateTypeDefinitionSchema((IEdmTypeDefinition)edmType);
|
||||
|
||||
case EdmTypeKind.None:
|
||||
default:
|
||||
throw Error.NotSupported(String.Format(SRResource.NotSupportedEdmTypeKind, edmType.TypeKind));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="OpenApiSchema"/> for a <see cref="IEdmStructuredType"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The OData context.</param>
|
||||
/// <param name="structuredType">The Edm structured type.</param>
|
||||
/// <param name="processBase">The process the based.</param>
|
||||
/// <returns>The created <see cref="OpenApiSchema"/>.</returns>
|
||||
public static OpenApiSchema CreateStructuredTypeSchema(this ODataContext context, IEdmStructuredType structuredType, bool processBase)
|
||||
{
|
||||
if (processBase && structuredType.BaseType != null)
|
||||
{
|
||||
// A structured type with a base type is represented as a Schema Object
|
||||
// that contains the keyword allOf whose value is an array with two items:
|
||||
return new OpenApiSchema
|
||||
{
|
||||
AllOf = new List<OpenApiSchema>
|
||||
{
|
||||
// 1. a JSON Reference to the Schema Object of the base type
|
||||
new OpenApiSchema
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.Schema,
|
||||
Id = structuredType.BaseType.FullTypeName()
|
||||
}
|
||||
},
|
||||
|
||||
// 2. a Schema Object describing the derived type
|
||||
context.CreateStructuredTypeSchema(structuredType, false)
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
// A structured type without a base type is represented as a Schema Object of type object
|
||||
return new OpenApiSchema
|
||||
{
|
||||
Title = (structuredType as IEdmSchemaElement).Name,
|
||||
|
||||
Type = "object",
|
||||
|
||||
// Each structural property and navigation property is represented
|
||||
// as a name/value pair of the standard OpenAPI properties object.
|
||||
Properties = context.CreateStructuredTypePropertiesSchema(structuredType),
|
||||
|
||||
// It optionally can contain the field description,
|
||||
// whose value is the value of the unqualified annotation Core.Description of the structured type.
|
||||
// However, ODL doesn't support the Core.Description on structure type.
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a <see cref="OpenApiSchema"/> for a <see cref="IEdmEnumType"/>.
|
||||
/// An enumeration type is represented as a Schema Object of type string containing the OpenAPI Specification enum keyword.
|
||||
/// Its value is an array that contains a string with the member name for each enumeration member.
|
||||
/// </summary>
|
||||
/// <param name="context">The OData context.</param>
|
||||
/// <param name="enumType">The Edm enum type.</param>
|
||||
/// <returns>The created <see cref="OpenApiSchema"/>.</returns>
|
||||
public static OpenApiSchema CreateEnumTypeSchema(this ODataContext context, IEdmEnumType enumType)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw Error.ArgumentNull(nameof(context));
|
||||
}
|
||||
|
||||
if (enumType == null)
|
||||
{
|
||||
throw Error.ArgumentNull(nameof(enumType));
|
||||
}
|
||||
|
||||
OpenApiSchema schema = new OpenApiSchema
|
||||
{
|
||||
// An enumeration type is represented as a Schema Object of type string
|
||||
Type = "string",
|
||||
|
||||
// containing the OpenAPI Specification enum keyword.
|
||||
Enum = new List<IOpenApiAny>(),
|
||||
|
||||
// It optionally can contain the field description,
|
||||
// whose value is the value of the unqualified annotation Core.Description of the enumeration type.
|
||||
Description = context.Model.GetDescriptionAnnotation(enumType)
|
||||
};
|
||||
|
||||
// Enum value is an array that contains a string with the member name for each enumeration member.
|
||||
foreach (IEdmEnumMember member in enumType.Members)
|
||||
{
|
||||
schema.Enum.Add(new OpenApiString(member.Name));
|
||||
}
|
||||
|
||||
schema.Title = enumType.Name;
|
||||
return schema;
|
||||
}
|
||||
|
||||
// 4.6.1.1 Properties
|
||||
public static IDictionary<string, OpenApiSchema> CreateStructuredTypePropertiesSchema(this ODataContext context, IEdmStructuredType structuredType)
|
||||
{
|
||||
// The name is the property name, the value is a Schema Object describing the allowed values of the property.
|
||||
IDictionary<string, OpenApiSchema> properties = new Dictionary<string, OpenApiSchema>();
|
||||
|
||||
// structure properties
|
||||
foreach (var property in structuredType.DeclaredStructuralProperties())
|
||||
{
|
||||
// OpenApiSchema propertySchema = property.Type.CreateSchema();
|
||||
// propertySchema.Default = property.DefaultValueString != null ? new OpenApiString(property.DefaultValueString) : null;
|
||||
properties.Add(property.Name, property.CreatePropertySchema());
|
||||
}
|
||||
|
||||
// navigation properties
|
||||
foreach (var property in structuredType.DeclaredNavigationProperties())
|
||||
{
|
||||
OpenApiSchema propertySchema = property.Type.CreateSchema();
|
||||
properties.Add(property.Name, propertySchema);
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
public static OpenApiSchema CreateTypeDefinitionSchema(this ODataContext context, IEdmTypeDefinition typeDefinition)
|
||||
{
|
||||
return typeDefinition?.UnderlyingType?.CreateSchema();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,125 +18,6 @@ namespace Microsoft.OpenApi.OData.Generator
|
|||
{
|
||||
private static string _externalResource = "https://raw.githubusercontent.com/oasis-tcs/odata-openapi/master/examples/odata-definitions.json";
|
||||
|
||||
public static OpenApiSchema CreateEdmTypeSchema(this IEdmModel model, IEdmType definition)
|
||||
{
|
||||
switch (definition.TypeKind)
|
||||
{
|
||||
case EdmTypeKind.Complex: // complex type
|
||||
case EdmTypeKind.Entity: // entity type
|
||||
return model.CreateStructuredTypeSchema((IEdmStructuredType)definition, true);
|
||||
|
||||
case EdmTypeKind.Enum: // enum type
|
||||
return model.CreateEnumTypeSchema((IEdmEnumType)definition);
|
||||
|
||||
case EdmTypeKind.TypeDefinition: // type definition
|
||||
return model.CreateTypeDefinitionSchema((IEdmTypeDefinition)definition);
|
||||
|
||||
case EdmTypeKind.None:
|
||||
default:
|
||||
throw Error.NotSupported(String.Format("Not supported {0} type kind.", definition.TypeKind));
|
||||
}
|
||||
}
|
||||
|
||||
public static OpenApiSchema CreateStructuredTypeSchema(this IEdmModel model, IEdmStructuredType structuredType, bool processBase)
|
||||
{
|
||||
if (processBase && structuredType.BaseType != null)
|
||||
{
|
||||
// A structured type with a base type is represented as a Schema Object
|
||||
// that contains the keyword allOf whose value is an array with two items:
|
||||
return new OpenApiSchema
|
||||
{
|
||||
AllOf = new List<OpenApiSchema>
|
||||
{
|
||||
// 1. a JSON Reference to the Schema Object of the base type
|
||||
new OpenApiSchema
|
||||
{
|
||||
Reference = new OpenApiReference
|
||||
{
|
||||
Type = ReferenceType.Schema,
|
||||
Id = structuredType.BaseType.FullTypeName()
|
||||
}
|
||||
},
|
||||
|
||||
// 2. a Schema Object describing the derived type
|
||||
model.CreateStructuredTypeSchema(structuredType, false)
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
// A structured type without a base type is represented as a Schema Object of type object
|
||||
return new OpenApiSchema
|
||||
{
|
||||
Title = (structuredType as IEdmSchemaElement).Name,
|
||||
|
||||
Type = "object",
|
||||
|
||||
// Each structural property and navigation property is represented
|
||||
// as a name/value pair of the standard OpenAPI properties object.
|
||||
Properties = model.CreateStrucutredTypePropertiesSchema(structuredType),
|
||||
|
||||
// It optionally can contain the field description,
|
||||
// whose value is the value of the unqualified annotation Core.Description of the structured type.
|
||||
// However, ODL doesn't support the Core.Description on structure type.
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 4.6.1.1 Properties
|
||||
public static IDictionary<string, OpenApiSchema> CreateStrucutredTypePropertiesSchema(this IEdmModel model, IEdmStructuredType structuredType)
|
||||
{
|
||||
// The name is the property name, the value is a Schema Object describing the allowed values of the property.
|
||||
IDictionary<string, OpenApiSchema> properties = new Dictionary<string, OpenApiSchema>();
|
||||
|
||||
// structure properties
|
||||
foreach (var property in structuredType.DeclaredStructuralProperties())
|
||||
{
|
||||
// OpenApiSchema propertySchema = property.Type.CreateSchema();
|
||||
// propertySchema.Default = property.DefaultValueString != null ? new OpenApiString(property.DefaultValueString) : null;
|
||||
properties.Add(property.Name, property.CreatePropertySchema());
|
||||
}
|
||||
|
||||
// navigation properties
|
||||
foreach (var property in structuredType.DeclaredNavigationProperties())
|
||||
{
|
||||
OpenApiSchema propertySchema = property.Type.CreateSchema();
|
||||
properties.Add(property.Name, propertySchema);
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
public static OpenApiSchema CreateEnumTypeSchema(this IEdmModel model, IEdmEnumType enumType)
|
||||
{
|
||||
OpenApiSchema schema = new OpenApiSchema
|
||||
{
|
||||
// An enumeration type is represented as a Schema Object of type string
|
||||
Type = "string",
|
||||
|
||||
// containing the OpenAPI Specification enum keyword.
|
||||
Enum = new List<IOpenApiAny>(),
|
||||
|
||||
// It optionally can contain the field description,
|
||||
// whose value is the value of the unqualified annotation Core.Description of the enumeration type.
|
||||
Description = model.GetDescription(enumType)
|
||||
};
|
||||
|
||||
// Enum value is an array that contains a string with the member name for each enumeration member.
|
||||
foreach (IEdmEnumMember member in enumType.Members)
|
||||
{
|
||||
schema.Enum.Add(new OpenApiString(member.Name));
|
||||
}
|
||||
|
||||
schema.Title = (enumType as IEdmSchemaElement)?.Name;
|
||||
return schema;
|
||||
}
|
||||
|
||||
public static OpenApiSchema CreateTypeDefinitionSchema(this IEdmModel model, IEdmTypeDefinition typeDefinition)
|
||||
{
|
||||
return typeDefinition?.UnderlyingType?.CreateSchema();
|
||||
}
|
||||
|
||||
public static OpenApiSchema CreatePropertySchema(this IEdmStructuralProperty property)
|
||||
{
|
||||
if (property == null)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<AssemblyName>Microsoft.OpenApi.OData.Reader</AssemblyName>
|
||||
<RootNamespace>Microsoft.OpenApi.OData.Reader</RootNamespace>
|
||||
<RootNamespace>Microsoft.OpenApi.OData</RootNamespace>
|
||||
<TargetFrameworks>net46; netstandard2.0</TargetFrameworks>
|
||||
<Company>Microsoft</Company>
|
||||
<Product>Microsoft.OpenApi.OData.Reader</Product>
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace Microsoft.OpenApi.OData.Properties {
|
|||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.OData.OpenApi.Properties.SRResource", typeof(SRResource).Assembly);
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.OpenApi.OData.Reader.Properties.SRResource", typeof(SRResource).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
|
@ -78,6 +78,15 @@ namespace Microsoft.OpenApi.OData.Properties {
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Not supported {0} Edm type kind..
|
||||
/// </summary>
|
||||
internal static string NotSupportedEdmTypeKind {
|
||||
get {
|
||||
return ResourceManager.GetString("NotSupportedEdmTypeKind", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to An error occurred while processing the OData message..
|
||||
/// </summary>
|
||||
|
|
|
@ -123,6 +123,9 @@
|
|||
<data name="ExtensionFieldNameMustBeginWithXMinus" xml:space="preserve">
|
||||
<value>The filed name of extension doesn't begin with x-.</value>
|
||||
</data>
|
||||
<data name="NotSupportedEdmTypeKind" xml:space="preserve">
|
||||
<value>Not supported {0} Edm type kind.</value>
|
||||
</data>
|
||||
<data name="OpenApiExceptionGeneralError" xml:space="preserve">
|
||||
<value>An error occurred while processing the OData message.</value>
|
||||
</data>
|
||||
|
|
|
@ -41,11 +41,16 @@ namespace Microsoft.OpenApi.OData.Tests
|
|||
{
|
||||
var model = new EdmModel();
|
||||
|
||||
var coreDescription = CoreVocabularyModel.DescriptionTerm;
|
||||
|
||||
var enumType = new EdmEnumType("DefaultNs", "Color");
|
||||
var blue = enumType.AddMember("Blue", new EdmEnumMemberValue(0));
|
||||
enumType.AddMember("White", new EdmEnumMemberValue(1));
|
||||
model.AddElement(enumType);
|
||||
|
||||
var annotation = new EdmVocabularyAnnotation(enumType, coreDescription, new EdmStringConstant("Enum type 'Color' description."));
|
||||
model.AddVocabularyAnnotation(annotation);
|
||||
|
||||
var person = new EdmEntityType("DefaultNs", "Person");
|
||||
var entityId = person.AddStructuralProperty("UserName", EdmCoreModel.Instance.GetString(false));
|
||||
person.AddKeys(entityId);
|
||||
|
@ -103,8 +108,7 @@ namespace Microsoft.OpenApi.OData.Tests
|
|||
entityContainer.AddElement(countriesOrRegions);
|
||||
entityContainer.AddElement(me);
|
||||
|
||||
var coreDescription = CoreVocabularyModel.DescriptionTerm;
|
||||
var annotation = new EdmVocabularyAnnotation(people, coreDescription, new EdmStringConstant("People's description."));
|
||||
annotation = new EdmVocabularyAnnotation(people, coreDescription, new EdmStringConstant("People's description."));
|
||||
model.AddVocabularyAnnotation(annotation);
|
||||
|
||||
var coreLongDescription = CoreVocabularyModel.LongDescriptionTerm;
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
// ------------------------------------------------------------
|
||||
// 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 Microsoft.OpenApi.OData.Tests;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.OpenApi.OData.Generator.Tests
|
||||
{
|
||||
public class ODataContextTest
|
||||
{
|
||||
[Fact]
|
||||
public void CtorThrowArgumentNullModel()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
Assert.Throws<ArgumentNullException>("model", () => new ODataContext(model: null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CtorThrowArgumentNullsetting()
|
||||
{
|
||||
// Arrange & Act & Assert
|
||||
Assert.Throws<ArgumentNullException>("settings", () => new ODataContext(EdmModelHelper.EmptyModel, settings: null));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,8 +14,6 @@ namespace Microsoft.OpenApi.OData.Generator.Tests
|
|||
{
|
||||
public class OpenApiParameterGeneratorTest
|
||||
{
|
||||
private OpenApiConvertSettings _settings = new OpenApiConvertSettings();
|
||||
|
||||
[Fact]
|
||||
public void CreateParametersThrowArgumentNullContext()
|
||||
{
|
||||
|
|
|
@ -3,7 +3,11 @@
|
|||
// 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.Any;
|
||||
using Microsoft.OpenApi.Extensions;
|
||||
using Microsoft.OpenApi.OData.Generator;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
@ -18,6 +22,76 @@ namespace Microsoft.OpenApi.OData.Tests
|
|||
_output = output;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateSchemasThrowArgumentNullContext()
|
||||
{
|
||||
// Arrange
|
||||
ODataContext context = null;
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentNullException>("context", () => context.CreateSchemas());
|
||||
}
|
||||
|
||||
#region EnumTypeSchema
|
||||
[Fact]
|
||||
public void CreateEnumTypeThrowArgumentNullContext()
|
||||
{
|
||||
// Arrange
|
||||
ODataContext context = null;
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentNullException>("context", () => context.CreateEnumTypeSchema(enumType: null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateEnumTypeThrowArgumentNullEnumType()
|
||||
{
|
||||
// Arrange
|
||||
ODataContext context = new ODataContext(EdmCoreModel.Instance);
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentNullException>("enumType", () => context.CreateEnumTypeSchema(enumType: null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateEnumTypeReturnCorrectSchema()
|
||||
{
|
||||
// Arrange
|
||||
IEdmModel model = EdmModelHelper.BasicEdmModel;
|
||||
ODataContext context = new ODataContext(model);
|
||||
IEdmEnumType enumType = model.SchemaElements.OfType<IEdmEnumType>().First(t => t.Name == "Color");
|
||||
Assert.NotNull(enumType); // Guard
|
||||
|
||||
// Act
|
||||
var schema = context.CreateEnumTypeSchema(enumType);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(schema);
|
||||
Assert.Equal("string", schema.Type);
|
||||
Assert.Equal("Enum type 'Color' description.", schema.Description);
|
||||
Assert.Equal("Color", schema.Title);
|
||||
|
||||
Assert.NotNull(schema.Enum);
|
||||
Assert.Equal(2, schema.Enum.Count);
|
||||
Assert.Equal(new string[] { "Blue", "White" }, schema.Enum.Select(e => ((OpenApiString)e).Value));
|
||||
|
||||
// Act
|
||||
string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0_0);
|
||||
|
||||
// Act
|
||||
Assert.NotNull(json);
|
||||
Assert.Equal(@"{
|
||||
""title"": ""Color"",
|
||||
""enum"": [
|
||||
""Blue"",
|
||||
""White""
|
||||
],
|
||||
""type"": ""string"",
|
||||
""description"": ""Enum type 'Color' description.""
|
||||
}".Replace(), json);
|
||||
}
|
||||
#endregion
|
||||
|
||||
[Fact]
|
||||
public void NonNullableBooleanPropertyWithDefaultValueWorks()
|
||||
{
|
||||
|
|
|
@ -895,7 +895,8 @@
|
|||
"Blue",
|
||||
"White"
|
||||
],
|
||||
"type": "string"
|
||||
"type": "string",
|
||||
"description": "Enum type 'Color' description."
|
||||
},
|
||||
"DefaultNs.Person": {
|
||||
"title": "Person",
|
||||
|
|
|
@ -566,6 +566,7 @@ components:
|
|||
- Blue
|
||||
- White
|
||||
type: string
|
||||
description: Enum type 'Color' description.
|
||||
DefaultNs.Person:
|
||||
title: Person
|
||||
type: object
|
||||
|
|
Loading…
Reference in a new issue