1. Modify to use ODL api for the vocabulary. 2. Change the Schema for entity & complex type. 3. Add unit test for schema on structured type.
This commit is contained in:
parent
5ee41ab4df
commit
2a98c209a6
|
@ -1,63 +0,0 @@
|
|||
//---------------------------------------------------------------------
|
||||
// <copyright file="EdmHelper.cs" company="Microsoft">
|
||||
// Copyright (C) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
||||
// </copyright>
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
using System.Linq;
|
||||
using Microsoft.OData.Edm;
|
||||
using Microsoft.OData.Edm.Vocabularies;
|
||||
using Microsoft.OData.Edm.Vocabularies.V1;
|
||||
|
||||
namespace Microsoft.OpenApi.OData
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for <see cref="IEdmModel"/>.
|
||||
/// </summary>
|
||||
internal static class EdmModelExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the Core.Description annotation.
|
||||
/// </summary>
|
||||
/// <param name="model">The Edm model.</param>
|
||||
/// <param name="element">The vocabulary annotatable element.</param>
|
||||
/// <returns>null or the description annotation.</returns>
|
||||
public static string GetDescription(this IEdmModel model, IEdmVocabularyAnnotatable element)
|
||||
{
|
||||
return model.GetAnnotationValue(element, CoreVocabularyModel.DescriptionTerm);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the Core.LongDescription annotation.
|
||||
/// </summary>
|
||||
/// <param name="model">The Edm model.</param>
|
||||
/// <param name="element">The vocabulary annotatable element.</param>
|
||||
/// <returns>null or the description annotation.</returns>
|
||||
public static string GetLongDescription(this IEdmModel model, IEdmVocabularyAnnotatable element)
|
||||
{
|
||||
return model.GetAnnotationValue(element, CoreVocabularyModel.LongDescriptionTerm);
|
||||
}
|
||||
|
||||
private static string GetAnnotationValue(this IEdmModel model, IEdmVocabularyAnnotatable element,
|
||||
IEdmTerm term)
|
||||
{
|
||||
if (model == null || element == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
IEdmVocabularyAnnotation annotation =
|
||||
model.FindVocabularyAnnotations<IEdmVocabularyAnnotation>(element, term).FirstOrDefault();
|
||||
if (annotation != null)
|
||||
{
|
||||
IEdmStringConstantExpression stringConstant = annotation.Value as IEdmStringConstantExpression;
|
||||
if (stringConstant != null)
|
||||
{
|
||||
return stringConstant.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.OData.Edm;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.OData.Properties;
|
||||
|
@ -89,58 +90,6 @@ namespace Microsoft.OpenApi.OData.Generator
|
|||
}
|
||||
}
|
||||
|
||||
/// <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.
|
||||
|
@ -184,6 +133,27 @@ namespace Microsoft.OpenApi.OData.Generator
|
|||
return schema;
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <returns>The created <see cref="OpenApiSchema"/>.</returns>
|
||||
public static OpenApiSchema CreateStructuredTypeSchema(this ODataContext context, IEdmStructuredType structuredType)
|
||||
{
|
||||
if (context == null)
|
||||
{
|
||||
throw Error.ArgumentNull(nameof(context));
|
||||
}
|
||||
|
||||
if (structuredType == null)
|
||||
{
|
||||
throw Error.ArgumentNull(nameof(structuredType));
|
||||
}
|
||||
|
||||
return context.CreateStructuredTypeSchema(structuredType, true);
|
||||
}
|
||||
|
||||
// 4.6.1.1 Properties
|
||||
public static IDictionary<string, OpenApiSchema> CreateStructuredTypePropertiesSchema(this ODataContext context, IEdmStructuredType structuredType)
|
||||
{
|
||||
|
@ -212,5 +182,73 @@ namespace Microsoft.OpenApi.OData.Generator
|
|||
{
|
||||
return typeDefinition?.UnderlyingType?.CreateSchema();
|
||||
}
|
||||
|
||||
private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext context, IEdmStructuredType structuredType, bool processBase)
|
||||
{
|
||||
Debug.Assert(context != null);
|
||||
Debug.Assert(structuredType != null);
|
||||
|
||||
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)
|
||||
},
|
||||
|
||||
AnyOf = null,
|
||||
OneOf = null,
|
||||
Properties = null
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
// A structured type without a base type is represented as a Schema Object of type object
|
||||
OpenApiSchema schema = 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),
|
||||
|
||||
// make others null
|
||||
AllOf = null,
|
||||
OneOf = null,
|
||||
AnyOf = null
|
||||
};
|
||||
|
||||
// It optionally can contain the field description,
|
||||
// whose value is the value of the unqualified annotation Core.Description of the structured type.
|
||||
if (structuredType.TypeKind == EdmTypeKind.Complex)
|
||||
{
|
||||
IEdmComplexType complex = (IEdmComplexType)structuredType;
|
||||
schema.Description = context.Model.GetDescriptionAnnotation(complex);
|
||||
}
|
||||
else if (structuredType.TypeKind == EdmTypeKind.Entity)
|
||||
{
|
||||
IEdmEntityType entity = (IEdmEntityType)structuredType;
|
||||
schema.Description = context.Model.GetDescriptionAnnotation(entity);
|
||||
}
|
||||
|
||||
return schema;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace Microsoft.OpenApi.OData.Generator
|
|||
tags.Add(new OpenApiTag
|
||||
{
|
||||
Name = entitySet.Name,
|
||||
Description = context.Model.GetDescription(entitySet)
|
||||
Description = context.Model.GetDescriptionAnnotation(entitySet)
|
||||
});
|
||||
break;
|
||||
|
||||
|
@ -55,7 +55,7 @@ namespace Microsoft.OpenApi.OData.Generator
|
|||
tags.Add(new OpenApiTag
|
||||
{
|
||||
Name = singleton.Name,
|
||||
Description = context.Model.GetDescription(singleton)
|
||||
Description = context.Model.GetDescriptionAnnotation(singleton)
|
||||
});
|
||||
break;
|
||||
|
||||
|
@ -95,7 +95,7 @@ namespace Microsoft.OpenApi.OData.Generator
|
|||
return new OpenApiTag
|
||||
{
|
||||
Name = operationImport.Name,
|
||||
Description = context.Model.GetDescription(operationImport)
|
||||
Description = context.Model.GetDescriptionAnnotation(operationImport)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,7 +129,12 @@ namespace Microsoft.OpenApi.OData.Generator
|
|||
}
|
||||
|
||||
// Spec has different configure for double, AnyOf or OneOf?
|
||||
OpenApiSchema schema = new OpenApiSchema();
|
||||
OpenApiSchema schema = new OpenApiSchema
|
||||
{
|
||||
AllOf = null,
|
||||
OneOf = null,
|
||||
AnyOf = null
|
||||
};
|
||||
switch (primitiveType.PrimitiveKind)
|
||||
{
|
||||
case EdmPrimitiveTypeKind.Binary: // binary
|
||||
|
|
|
@ -8,16 +8,24 @@ using Microsoft.OData.Edm;
|
|||
using Microsoft.OData.Edm.Csdl;
|
||||
using Microsoft.OData.Edm.Vocabularies;
|
||||
using Microsoft.OData.Edm.Vocabularies.V1;
|
||||
using Xunit;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.OData.Edm.Validation;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Microsoft.OpenApi.OData.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Edm model helpers
|
||||
/// </summary>
|
||||
public static class EdmModelHelper
|
||||
public class EdmModelHelper
|
||||
{
|
||||
public static IEdmModel EmptyModel { get; } = new EdmModel();
|
||||
|
||||
public static IEdmModel MultipleInheritanceEdmModel { get; }
|
||||
|
||||
public static IEdmModel BasicEdmModel { get; }
|
||||
|
||||
public static IEdmModel CompositeKeyModel { get; }
|
||||
|
@ -26,6 +34,7 @@ namespace Microsoft.OpenApi.OData.Tests
|
|||
|
||||
static EdmModelHelper()
|
||||
{
|
||||
MultipleInheritanceEdmModel = CreateMultipleInheritanceEdmModel();
|
||||
BasicEdmModel = CreateEdmModel();
|
||||
CompositeKeyModel = CreateCompositeKeyModel();
|
||||
TripServiceModel = LoadTripServiceModel();
|
||||
|
@ -37,6 +46,112 @@ namespace Microsoft.OpenApi.OData.Tests
|
|||
return CsdlReader.Parse(XElement.Parse(csdl).CreateReader());
|
||||
}
|
||||
|
||||
private static IEdmModel CreateMultipleInheritanceEdmModel()
|
||||
{
|
||||
var model = new EdmModel();
|
||||
|
||||
// enum type
|
||||
var colorEnumType = new EdmEnumType("NS", "Color");
|
||||
colorEnumType.AddMember("Blue", new EdmEnumMemberValue(0));
|
||||
colorEnumType.AddMember("While", new EdmEnumMemberValue(1));
|
||||
colorEnumType.AddMember("Red", new EdmEnumMemberValue(2));
|
||||
colorEnumType.AddMember("Yellow", new EdmEnumMemberValue(3));
|
||||
model.AddElement(colorEnumType);
|
||||
|
||||
var oceanEnumType = new EdmEnumType("NS", "Ocean");
|
||||
oceanEnumType.AddMember("Atlantic", new EdmEnumMemberValue(0));
|
||||
oceanEnumType.AddMember("Pacific", new EdmEnumMemberValue(1));
|
||||
oceanEnumType.AddMember("India", new EdmEnumMemberValue(2));
|
||||
oceanEnumType.AddMember("Arctic", new EdmEnumMemberValue(3));
|
||||
model.AddElement(oceanEnumType);
|
||||
|
||||
var continentEnumType = new EdmEnumType("NS", "Continent");
|
||||
continentEnumType.AddMember("Asia", new EdmEnumMemberValue(0));
|
||||
continentEnumType.AddMember("Europe", new EdmEnumMemberValue(1));
|
||||
continentEnumType.AddMember("Antarctica", new EdmEnumMemberValue(2));
|
||||
model.AddElement(continentEnumType);
|
||||
|
||||
// top level entity type
|
||||
var zoo = new EdmEntityType("NS", "Zoo");
|
||||
var zooId = zoo.AddStructuralProperty("Id", EdmCoreModel.Instance.GetInt32(false));
|
||||
zoo.AddKeys(zooId);
|
||||
model.AddElement(zoo);
|
||||
|
||||
// abstract entity type "Creature"
|
||||
var creature = new EdmEntityType("NS", "Creature", null, true, true);
|
||||
creature.AddKeys(creature.AddStructuralProperty("Id", EdmCoreModel.Instance.GetInt32(false)));
|
||||
model.AddElement(creature);
|
||||
|
||||
var animal = new EdmEntityType("NS", "Animal", creature, true, true);
|
||||
animal.AddStructuralProperty("Age", EdmCoreModel.Instance.GetInt32(false));
|
||||
model.AddElement(animal);
|
||||
|
||||
var human = new EdmEntityType("NS", "Human", animal, false, true);
|
||||
human.AddStructuralProperty("Name", EdmCoreModel.Instance.GetString(false));
|
||||
model.AddElement(human);
|
||||
|
||||
var horse = new EdmEntityType("NS", "Horse", animal, false, true);
|
||||
horse.AddStructuralProperty("Height", EdmCoreModel.Instance.GetDecimal(false));
|
||||
model.AddElement(horse);
|
||||
|
||||
EdmNavigationPropertyInfo navInfo = new EdmNavigationPropertyInfo
|
||||
{
|
||||
Name = "Creatures",
|
||||
Target = creature,
|
||||
TargetMultiplicity = EdmMultiplicity.Many,
|
||||
};
|
||||
zoo.AddUnidirectionalNavigation(navInfo);
|
||||
|
||||
// complex type
|
||||
var plant = new EdmComplexType("NS", "Plant", null, true, true);
|
||||
plant.AddStructuralProperty("Color", new EdmEnumTypeReference(colorEnumType, isNullable: false));
|
||||
model.AddElement(plant);
|
||||
|
||||
// ocean plant
|
||||
var oceanPlant = new EdmComplexType("NS", "OceanPlant", plant, true, true);
|
||||
oceanPlant.AddStructuralProperty("Ocean", new EdmEnumTypeReference(oceanEnumType, isNullable: false));
|
||||
model.AddElement(oceanPlant);
|
||||
|
||||
var kelp = new EdmComplexType("NS", "Kelp", oceanPlant, false, true);
|
||||
kelp.AddStructuralProperty("Length", EdmCoreModel.Instance.GetDouble(false));
|
||||
model.AddElement(kelp);
|
||||
|
||||
// land plant
|
||||
var landPlant = new EdmComplexType("NS", "LandPlant", plant, true, true);
|
||||
landPlant.AddStructuralProperty("Continent", new EdmEnumTypeReference(continentEnumType, isNullable: false));
|
||||
landPlant.AddStructuralProperty("Name", EdmCoreModel.Instance.GetString(false));
|
||||
model.AddElement(landPlant);
|
||||
|
||||
var tree = new EdmComplexType("NS", "Tree", landPlant, false, true);
|
||||
tree.AddStructuralProperty("Price", EdmCoreModel.Instance.GetDecimal(false));
|
||||
model.AddElement(tree);
|
||||
|
||||
var flower = new EdmComplexType("NS", "Flower", landPlant, false, true);
|
||||
flower.AddStructuralProperty("Height", EdmCoreModel.Instance.GetDouble(false));
|
||||
model.AddElement(flower);
|
||||
|
||||
// address
|
||||
var address = new EdmComplexType("NS", "Address");
|
||||
address.AddStructuralProperty("Street", EdmCoreModel.Instance.GetString(true));
|
||||
address.AddStructuralProperty("City", EdmCoreModel.Instance.GetString(true));
|
||||
model.AddElement(address);
|
||||
|
||||
var coreDescription = CoreVocabularyModel.DescriptionTerm;
|
||||
var annotation = new EdmVocabularyAnnotation(address, coreDescription, new EdmStringConstant("Complex type 'Address' description."));
|
||||
model.AddVocabularyAnnotation(annotation);
|
||||
|
||||
annotation = new EdmVocabularyAnnotation(tree, coreDescription, new EdmStringConstant("Complex type 'Tree' description."));
|
||||
model.AddVocabularyAnnotation(annotation);
|
||||
|
||||
annotation = new EdmVocabularyAnnotation(zoo, coreDescription, new EdmStringConstant("Entity type 'Zoo' description."));
|
||||
model.AddVocabularyAnnotation(annotation);
|
||||
|
||||
annotation = new EdmVocabularyAnnotation(human, coreDescription, new EdmStringConstant("Entity type 'Human' description."));
|
||||
model.AddVocabularyAnnotation(annotation);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
private static IEdmModel CreateEdmModel()
|
||||
{
|
||||
var model = new EdmModel();
|
||||
|
@ -133,5 +248,128 @@ namespace Microsoft.OpenApi.OData.Tests
|
|||
model.AddElement(container);
|
||||
return model;
|
||||
}
|
||||
|
||||
private ITestOutputHelper _output;
|
||||
public EdmModelHelper(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MultipleInheritanceEdmModelMetadataDocumentTest()
|
||||
{
|
||||
// Arrange
|
||||
string expected = @"<?xml version=""1.0"" encoding=""utf-16""?>
|
||||
<edmx:Edmx Version=""4.0"" xmlns:edmx=""http://docs.oasis-open.org/odata/ns/edmx"">
|
||||
<edmx:DataServices>
|
||||
<Schema Namespace=""NS"" xmlns=""http://docs.oasis-open.org/odata/ns/edm"">
|
||||
<EnumType Name=""Color"">
|
||||
<Member Name=""Blue"" Value=""0"" />
|
||||
<Member Name=""While"" Value=""1"" />
|
||||
<Member Name=""Red"" Value=""2"" />
|
||||
<Member Name=""Yellow"" Value=""3"" />
|
||||
</EnumType>
|
||||
<EnumType Name=""Ocean"">
|
||||
<Member Name=""Atlantic"" Value=""0"" />
|
||||
<Member Name=""Pacific"" Value=""1"" />
|
||||
<Member Name=""India"" Value=""2"" />
|
||||
<Member Name=""Arctic"" Value=""3"" />
|
||||
</EnumType>
|
||||
<EnumType Name=""Continent"">
|
||||
<Member Name=""Asia"" Value=""0"" />
|
||||
<Member Name=""Europe"" Value=""1"" />
|
||||
<Member Name=""Antarctica"" Value=""2"" />
|
||||
</EnumType>
|
||||
<EntityType Name=""Zoo"">
|
||||
<Key>
|
||||
<PropertyRef Name=""Id"" />
|
||||
</Key>
|
||||
<Property Name=""Id"" Type=""Edm.Int32"" Nullable=""false"" />
|
||||
<NavigationProperty Name=""Creatures"" Type=""Collection(NS.Creature)"" />
|
||||
</EntityType>
|
||||
<EntityType Name=""Creature"" Abstract=""true"" OpenType=""true"">
|
||||
<Key>
|
||||
<PropertyRef Name=""Id"" />
|
||||
</Key>
|
||||
<Property Name=""Id"" Type=""Edm.Int32"" Nullable=""false"" />
|
||||
</EntityType>
|
||||
<EntityType Name=""Animal"" BaseType=""NS.Creature"" Abstract=""true"" OpenType=""true"">
|
||||
<Property Name=""Age"" Type=""Edm.Int32"" Nullable=""false"" />
|
||||
</EntityType>
|
||||
<EntityType Name=""Human"" BaseType=""NS.Animal"" OpenType=""true"">
|
||||
<Property Name=""Name"" Type=""Edm.String"" Nullable=""false"" />
|
||||
</EntityType>
|
||||
<EntityType Name=""Horse"" BaseType=""NS.Animal"" OpenType=""true"">
|
||||
<Property Name=""Height"" Type=""Edm.Decimal"" Nullable=""false"" />
|
||||
</EntityType>
|
||||
<ComplexType Name=""Plant"" Abstract=""true"" OpenType=""true"">
|
||||
<Property Name=""Color"" Type=""NS.Color"" Nullable=""false"" />
|
||||
</ComplexType>
|
||||
<ComplexType Name=""OceanPlant"" BaseType=""NS.Plant"" Abstract=""true"" OpenType=""true"">
|
||||
<Property Name=""Ocean"" Type=""NS.Ocean"" Nullable=""false"" />
|
||||
</ComplexType>
|
||||
<ComplexType Name=""Kelp"" BaseType=""NS.OceanPlant"" OpenType=""true"">
|
||||
<Property Name=""Length"" Type=""Edm.Double"" Nullable=""false"" />
|
||||
</ComplexType>
|
||||
<ComplexType Name=""LandPlant"" BaseType=""NS.Plant"" Abstract=""true"" OpenType=""true"">
|
||||
<Property Name=""Continent"" Type=""NS.Continent"" Nullable=""false"" />
|
||||
<Property Name=""Name"" Type=""Edm.String"" Nullable=""false"" />
|
||||
</ComplexType>
|
||||
<ComplexType Name=""Tree"" BaseType=""NS.LandPlant"" OpenType=""true"">
|
||||
<Property Name=""Price"" Type=""Edm.Decimal"" Nullable=""false"" />
|
||||
</ComplexType>
|
||||
<ComplexType Name=""Flower"" BaseType=""NS.LandPlant"" OpenType=""true"">
|
||||
<Property Name=""Height"" Type=""Edm.Double"" Nullable=""false"" />
|
||||
</ComplexType>
|
||||
<ComplexType Name=""Address"">
|
||||
<Property Name=""Street"" Type=""Edm.String"" />
|
||||
<Property Name=""City"" Type=""Edm.String"" />
|
||||
</ComplexType>
|
||||
<Annotations Target=""NS.Address"">
|
||||
<Annotation Term=""Org.OData.Core.V1.Description"" String=""Complex type 'Address' description."" />
|
||||
</Annotations>
|
||||
<Annotations Target=""NS.Tree"">
|
||||
<Annotation Term=""Org.OData.Core.V1.Description"" String=""Complex type 'Tree' description."" />
|
||||
</Annotations>
|
||||
<Annotations Target=""NS.Zoo"">
|
||||
<Annotation Term=""Org.OData.Core.V1.Description"" String=""Entity type 'Zoo' description."" />
|
||||
</Annotations>
|
||||
<Annotations Target=""NS.Human"">
|
||||
<Annotation Term=""Org.OData.Core.V1.Description"" String=""Entity type 'Human' description."" />
|
||||
</Annotations>
|
||||
</Schema>
|
||||
</edmx:DataServices>
|
||||
</edmx:Edmx>";
|
||||
|
||||
// Act
|
||||
string actual = GetCsdl(MultipleInheritanceEdmModel);
|
||||
_output.WriteLine(actual);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, actual);
|
||||
}
|
||||
|
||||
private string GetCsdl(IEdmModel model)
|
||||
{
|
||||
string edmx = string.Empty;
|
||||
|
||||
using (StringWriter sw = new StringWriter())
|
||||
{
|
||||
XmlWriterSettings settings = new XmlWriterSettings();
|
||||
settings.Encoding = System.Text.Encoding.UTF8;
|
||||
settings.Indent = true;
|
||||
|
||||
using (XmlWriter xw = XmlWriter.Create(sw, settings))
|
||||
{
|
||||
IEnumerable<EdmError> errors;
|
||||
CsdlWriter.TryWriteCsdl(model, xw, CsdlTarget.OData, out errors);
|
||||
xw.Flush();
|
||||
}
|
||||
|
||||
edmx = sw.ToString();
|
||||
}
|
||||
|
||||
return edmx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,23 +3,13 @@
|
|||
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.OData.Edm;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Microsoft.OpenApi.OData.Tests
|
||||
{
|
||||
public class EdmModelExtensionsTests
|
||||
public class EdmModelExtensionsTest
|
||||
{
|
||||
private ITestOutputHelper _output;
|
||||
public EdmModelExtensionsTests(ITestOutputHelper output)
|
||||
{
|
||||
_output = output;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetDescriptionReturnsNullForElementWithoutCoreDescription()
|
||||
{
|
||||
|
@ -29,7 +19,7 @@ namespace Microsoft.OpenApi.OData.Tests
|
|||
Assert.NotNull(me); // Guard
|
||||
|
||||
// Act
|
||||
string description = model.GetDescription(me);
|
||||
string description = model.GetDescriptionAnnotation(me);
|
||||
|
||||
// Assert
|
||||
Assert.Null(description);
|
||||
|
@ -44,7 +34,7 @@ namespace Microsoft.OpenApi.OData.Tests
|
|||
Assert.NotNull(people); // Guard
|
||||
|
||||
// Act
|
||||
string description = model.GetDescription(people);
|
||||
string description = model.GetDescriptionAnnotation(people);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("People's description.", description);
|
||||
|
@ -59,7 +49,7 @@ namespace Microsoft.OpenApi.OData.Tests
|
|||
Assert.NotNull(people); // Guard
|
||||
|
||||
// Act
|
||||
string description = model.GetLongDescription(people);
|
||||
string description = model.GetLongDescriptionAnnotation(people);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("People's Long description.", description);
|
||||
|
|
|
@ -8,6 +8,7 @@ using System.Linq;
|
|||
using Microsoft.OData.Edm;
|
||||
using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Extensions;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Microsoft.OpenApi.OData.Generator;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
@ -32,9 +33,273 @@ namespace Microsoft.OpenApi.OData.Tests
|
|||
Assert.Throws<ArgumentNullException>("context", () => context.CreateSchemas());
|
||||
}
|
||||
|
||||
#region StructuredTypeSchema
|
||||
[Fact]
|
||||
public void CreateStructuredTypeSchemaThrowArgumentNullContext()
|
||||
{
|
||||
// Arrange
|
||||
ODataContext context = null;
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentNullException>("context", () => context.CreateStructuredTypeSchema(structuredType: null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateStructuredTypeSchemaThrowArgumentNullEnumType()
|
||||
{
|
||||
// Arrange
|
||||
ODataContext context = new ODataContext(EdmCoreModel.Instance);
|
||||
|
||||
// Act & Assert
|
||||
Assert.Throws<ArgumentNullException>("structuredType", () => context.CreateStructuredTypeSchema(structuredType: null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateComplexTypeWithoutBaseSchemaReturnCorrectSchema()
|
||||
{
|
||||
// Arrange
|
||||
IEdmModel model = EdmModelHelper.MultipleInheritanceEdmModel;
|
||||
ODataContext context = new ODataContext(model);
|
||||
IEdmComplexType complex = model.SchemaElements.OfType<IEdmComplexType>().First(t => t.Name == "Address");
|
||||
Assert.NotNull(complex); // Guard
|
||||
|
||||
// Act
|
||||
var schema = context.CreateStructuredTypeSchema(complex);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(schema);
|
||||
Assert.Equal("object", schema.Type);
|
||||
Assert.Null(schema.AllOf);
|
||||
|
||||
Assert.NotNull(schema.Properties);
|
||||
Assert.Equal(2, schema.Properties.Count);
|
||||
Assert.Equal(new string[] { "Street", "City" }, schema.Properties.Select(e => e.Key));
|
||||
Assert.Equal("Complex type 'Address' description.", schema.Description);
|
||||
Assert.Equal("Address", schema.Title);
|
||||
|
||||
// Act
|
||||
string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0_0);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(json);
|
||||
Assert.Equal(@"{
|
||||
""title"": ""Address"",
|
||||
""type"": ""object"",
|
||||
""properties"": {
|
||||
""Street"": {
|
||||
""type"": ""string"",
|
||||
""nullable"": true
|
||||
},
|
||||
""City"": {
|
||||
""type"": ""string"",
|
||||
""nullable"": true
|
||||
}
|
||||
},
|
||||
""description"": ""Complex type 'Address' description.""
|
||||
}"
|
||||
.Replace(), json);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateComplexTypeWithBaseSchemaReturnCorrectSchema()
|
||||
{
|
||||
// Arrange
|
||||
IEdmModel model = EdmModelHelper.MultipleInheritanceEdmModel;
|
||||
ODataContext context = new ODataContext(model);
|
||||
IEdmComplexType complex = model.SchemaElements.OfType<IEdmComplexType>().First(t => t.Name == "Tree");
|
||||
Assert.NotNull(complex); // Guard
|
||||
|
||||
// Act
|
||||
var schema = context.CreateStructuredTypeSchema(complex);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(schema);
|
||||
Assert.True(String.IsNullOrEmpty(schema.Type));
|
||||
|
||||
Assert.NotNull(schema.AllOf);
|
||||
Assert.Null(schema.AnyOf);
|
||||
Assert.Null(schema.OneOf);
|
||||
Assert.Null(schema.Properties);
|
||||
|
||||
Assert.Equal(2, schema.AllOf.Count);
|
||||
var baseSchema = schema.AllOf.First();
|
||||
Assert.NotNull(baseSchema.Reference);
|
||||
Assert.Equal(ReferenceType.Schema, baseSchema.Reference.Type);
|
||||
Assert.Equal("NS.LandPlant", baseSchema.Reference.Id);
|
||||
|
||||
var declaredSchema = schema.AllOf.Last();
|
||||
Assert.Equal("object", declaredSchema.Type);
|
||||
Assert.Null(declaredSchema.AllOf);
|
||||
Assert.Null(declaredSchema.AnyOf);
|
||||
Assert.Null(declaredSchema.OneOf);
|
||||
|
||||
Assert.NotNull(declaredSchema.Properties);
|
||||
Assert.Equal(1, declaredSchema.Properties.Count);
|
||||
var property = Assert.Single(declaredSchema.Properties);
|
||||
Assert.Equal("Price", property.Key);
|
||||
Assert.Equal("decimal", property.Value.Format);
|
||||
Assert.NotNull(property.Value.OneOf);
|
||||
Assert.Equal(new string[] { "number", "string" }, property.Value.OneOf.Select(e => e.Type));
|
||||
|
||||
Assert.Equal("Complex type 'Tree' description.", declaredSchema.Description);
|
||||
Assert.Equal("Tree", declaredSchema.Title);
|
||||
|
||||
// Act
|
||||
string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0_0);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(json);
|
||||
Assert.Equal(@"{
|
||||
""allOf"": [
|
||||
{
|
||||
""$ref"": ""#/components/schemas/NS.LandPlant""
|
||||
},
|
||||
{
|
||||
""title"": ""Tree"",
|
||||
""type"": ""object"",
|
||||
""properties"": {
|
||||
""Price"": {
|
||||
""multipleOf"": 1,
|
||||
""oneOf"": [
|
||||
{
|
||||
""type"": ""number""
|
||||
},
|
||||
{
|
||||
""type"": ""string""
|
||||
}
|
||||
],
|
||||
""format"": ""decimal""
|
||||
}
|
||||
},
|
||||
""description"": ""Complex type 'Tree' description.""
|
||||
}
|
||||
]
|
||||
}"
|
||||
.Replace(), json);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateEntityTypeWithoutBaseSchemaReturnCorrectSchema()
|
||||
{
|
||||
// Arrange
|
||||
IEdmModel model = EdmModelHelper.MultipleInheritanceEdmModel;
|
||||
ODataContext context = new ODataContext(model);
|
||||
IEdmEntityType entity = model.SchemaElements.OfType<IEdmEntityType>().First(t => t.Name == "Zoo");
|
||||
Assert.NotNull(entity); // Guard
|
||||
|
||||
// Act
|
||||
var schema = context.CreateStructuredTypeSchema(entity);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(schema);
|
||||
Assert.Equal("object", schema.Type);
|
||||
Assert.Null(schema.AllOf);
|
||||
|
||||
Assert.NotNull(schema.Properties);
|
||||
Assert.Equal(2, schema.Properties.Count);
|
||||
Assert.Equal(new string[] { "Id", "Creatures" }, schema.Properties.Select(e => e.Key));
|
||||
Assert.Equal("Entity type 'Zoo' description.", schema.Description);
|
||||
Assert.Equal("Zoo", schema.Title);
|
||||
|
||||
// Act
|
||||
string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0_0);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(json);
|
||||
Assert.Equal(@"{
|
||||
""title"": ""Zoo"",
|
||||
""type"": ""object"",
|
||||
""properties"": {
|
||||
""Id"": {
|
||||
""maximum"": 2147483647,
|
||||
""minimum"": -2147483648,
|
||||
""type"": ""integer"",
|
||||
""format"": ""int32""
|
||||
},
|
||||
""Creatures"": {
|
||||
""type"": ""array"",
|
||||
""items"": {
|
||||
""$ref"": ""#/components/schemas/NS.Creature""
|
||||
}
|
||||
}
|
||||
},
|
||||
""description"": ""Entity type 'Zoo' description.""
|
||||
}"
|
||||
.Replace(), json);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateEntityTypeWithBaseSchemaReturnCorrectSchema()
|
||||
{
|
||||
// Arrange
|
||||
IEdmModel model = EdmModelHelper.MultipleInheritanceEdmModel;
|
||||
ODataContext context = new ODataContext(model);
|
||||
IEdmEntityType entity = model.SchemaElements.OfType<IEdmEntityType>().First(t => t.Name == "Human");
|
||||
Assert.NotNull(entity); // Guard
|
||||
|
||||
// Act
|
||||
var schema = context.CreateStructuredTypeSchema(entity);
|
||||
|
||||
// Assert
|
||||
Assert.NotNull(schema);
|
||||
Assert.True(String.IsNullOrEmpty(schema.Type));
|
||||
|
||||
Assert.NotNull(schema.AllOf);
|
||||
Assert.Null(schema.AnyOf);
|
||||
Assert.Null(schema.OneOf);
|
||||
Assert.Null(schema.Properties);
|
||||
|
||||
Assert.Equal(2, schema.AllOf.Count);
|
||||
var baseSchema = schema.AllOf.First();
|
||||
Assert.NotNull(baseSchema.Reference);
|
||||
Assert.Equal(ReferenceType.Schema, baseSchema.Reference.Type);
|
||||
Assert.Equal("NS.Animal", baseSchema.Reference.Id);
|
||||
|
||||
var declaredSchema = schema.AllOf.Last();
|
||||
Assert.Equal("object", declaredSchema.Type);
|
||||
Assert.Null(declaredSchema.AllOf);
|
||||
Assert.Null(declaredSchema.AnyOf);
|
||||
Assert.Null(declaredSchema.OneOf);
|
||||
|
||||
Assert.NotNull(declaredSchema.Properties);
|
||||
Assert.Equal(1, declaredSchema.Properties.Count);
|
||||
var property = Assert.Single(declaredSchema.Properties);
|
||||
Assert.Equal("Name", property.Key);
|
||||
Assert.Equal("string", property.Value.Type);
|
||||
Assert.Null(property.Value.OneOf);
|
||||
|
||||
Assert.Equal("Entity type 'Human' description.", declaredSchema.Description);
|
||||
Assert.Equal("Human", declaredSchema.Title);
|
||||
|
||||
// Act
|
||||
string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0_0);
|
||||
_output.WriteLine(json);
|
||||
// Assert
|
||||
Assert.NotNull(json);
|
||||
Assert.Equal(@"{
|
||||
""allOf"": [
|
||||
{
|
||||
""$ref"": ""#/components/schemas/NS.Animal""
|
||||
},
|
||||
{
|
||||
""title"": ""Human"",
|
||||
""type"": ""object"",
|
||||
""properties"": {
|
||||
""Name"": {
|
||||
""type"": ""string""
|
||||
}
|
||||
},
|
||||
""description"": ""Entity type 'Human' description.""
|
||||
}
|
||||
]
|
||||
}"
|
||||
.Replace(), json);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region EnumTypeSchema
|
||||
[Fact]
|
||||
public void CreateEnumTypeThrowArgumentNullContext()
|
||||
public void CreateEnumTypeSchemaThrowArgumentNullContext()
|
||||
{
|
||||
// Arrange
|
||||
ODataContext context = null;
|
||||
|
@ -44,7 +309,7 @@ namespace Microsoft.OpenApi.OData.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateEnumTypeThrowArgumentNullEnumType()
|
||||
public void CreateEnumTypeSchemaThrowArgumentNullEnumType()
|
||||
{
|
||||
// Arrange
|
||||
ODataContext context = new ODataContext(EdmCoreModel.Instance);
|
||||
|
@ -54,7 +319,7 @@ namespace Microsoft.OpenApi.OData.Tests
|
|||
}
|
||||
|
||||
[Fact]
|
||||
public void CreateEnumTypeReturnCorrectSchema()
|
||||
public void CreateEnumTypeSchemaReturnCorrectSchema()
|
||||
{
|
||||
// Arrange
|
||||
IEdmModel model = EdmModelHelper.BasicEdmModel;
|
||||
|
@ -78,7 +343,7 @@ namespace Microsoft.OpenApi.OData.Tests
|
|||
// Act
|
||||
string json = schema.SerializeAsJson(OpenApiSpecVersion.OpenApi3_0_0);
|
||||
|
||||
// Act
|
||||
// Assert
|
||||
Assert.NotNull(json);
|
||||
Assert.Equal(@"{
|
||||
""title"": ""Color"",
|
||||
|
|
Loading…
Reference in a new issue