diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs
index d1036dc..7631419 100644
--- a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs
+++ b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmModelExtensions.cs
@@ -162,7 +162,7 @@ namespace Microsoft.OpenApi.OData.Edm
}
///
- /// Check whether the operaiton is overload in the model.
+ /// Check whether the operation is overload in the model.
///
/// The Edm model.
/// The test operations.
@@ -172,7 +172,7 @@ namespace Microsoft.OpenApi.OData.Edm
Utils.CheckArgumentNull(model, nameof(model));
Utils.CheckArgumentNull(operation, nameof(operation));
- return model.SchemaElements.OfType()
+ return model.GetAllElements().OfType()
.Where(o => o.IsBound == operation.IsBound && o.FullName() == operation.FullName() &&
o.Parameters.First().Type.Definition == operation.Parameters.First().Type.Definition
).Count() > 1;
@@ -197,5 +197,28 @@ namespace Microsoft.OpenApi.OData.Edm
return model.EntityContainer.OperationImports()
.Where(o => o.Operation.IsBound == operationImport.Operation.IsBound && o.Name == operationImport.Name).Count() > 1;
}
+
+ ///
+ /// Get all of the elements in the model and its referenced models.
+ ///
+ /// All the elements.
+ public static IEnumerable GetAllElements(this IEdmModel model)
+ {
+ foreach (var element in model.SchemaElements.Where(el =>
+ !ODataConstants.StandardNamespaces.Any(std => el.Namespace.StartsWith(std))))
+ {
+ yield return element;
+ }
+
+ foreach (var refModel in model.ReferencedModels)
+ {
+ foreach (var element in refModel.SchemaElements.Where(el =>
+ !ODataConstants.StandardNamespaces.Any(std => el.Namespace.StartsWith(std))))
+ {
+ yield return element;
+ }
+ }
+ }
+
}
}
diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmOperationProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmOperationProvider.cs
index 7ebdd84..fd92847 100644
--- a/src/Microsoft.OpenApi.OData.Reader/Edm/EdmOperationProvider.cs
+++ b/src/Microsoft.OpenApi.OData.Reader/Edm/EdmOperationProvider.cs
@@ -71,7 +71,7 @@ namespace Microsoft.OpenApi.OData.Edm
{
IDictionary> edmOperationDict = new Dictionary>();
- foreach (var edmOperation in Model.SchemaElements.OfType().Where(e => e.IsBound))
+ foreach (var edmOperation in Model.GetAllElements().OfType().Where(e => e.IsBound))
{
IEdmOperationParameter bindingParameter = edmOperation.Parameters.First();
diff --git a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs
index 4273bb7..dac4070 100644
--- a/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs
+++ b/src/Microsoft.OpenApi.OData.Reader/Edm/ODataPathProvider.cs
@@ -294,7 +294,7 @@ namespace Microsoft.OpenApi.OData.Edm
///
private void RetrieveBoundOperationPaths()
{
- foreach (var edmOperation in _model.SchemaElements.OfType().Where(e => e.IsBound))
+ foreach (var edmOperation in _model.GetAllElements().OfType().Where(e => e.IsBound))
{
if (!CanFilter(edmOperation))
{
diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/EdmSpatialTypeVisitor.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/EdmSpatialTypeVisitor.cs
index 9788247..ffcec70 100644
--- a/src/Microsoft.OpenApi.OData.Reader/Generator/EdmSpatialTypeVisitor.cs
+++ b/src/Microsoft.OpenApi.OData.Reader/Generator/EdmSpatialTypeVisitor.cs
@@ -4,6 +4,7 @@
// ------------------------------------------------------------
using Microsoft.OData.Edm;
+using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Generator
{
@@ -30,7 +31,7 @@ namespace Microsoft.OpenApi.OData.Generator
return;
}
- foreach (var element in model.SchemaElements)
+ foreach (var element in model.GetAllElements())
{
switch (element.SchemaElementKind)
{
diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiExampleGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiExampleGenerator.cs
index c9bb380..fb73d1a 100644
--- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiExampleGenerator.cs
+++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiExampleGenerator.cs
@@ -34,7 +34,11 @@ namespace Microsoft.OpenApi.OData.Generator
// Each entity type, complex type, enumeration type, and type definition directly
// or indirectly used in the paths field is represented as a name / value pair of the schemas map.
- foreach (var element in context.Model.SchemaElements.Where(c => !c.Namespace.StartsWith("Org.OData.")))
+ // Ideally this would be driven off the types used in the paths, but in practice, it is simply
+ // all of the types present in the model.
+ IEnumerable elements = context.Model.GetAllElements();
+
+ foreach (var element in elements)
{
switch (element.SchemaElementKind)
{
diff --git a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs
index 8bffc0a..c989b15 100644
--- a/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs
+++ b/src/Microsoft.OpenApi.OData.Reader/Generator/OpenApiSchemaGenerator.cs
@@ -38,7 +38,11 @@ namespace Microsoft.OpenApi.OData.Generator
// Each entity type, complex type, enumeration type, and type definition directly
// or indirectly used in the paths field is represented as a name / value pair of the schemas map.
- foreach (var element in context.Model.SchemaElements.Where(c => !c.Namespace.StartsWith("Org.OData.")))
+ // Ideally this would be driven off the types used in the paths, but in practice, it is simply
+ // all of the types present in the model.
+ IEnumerable elements = context.Model.GetAllElements();
+
+ foreach (var element in elements)
{
switch (element.SchemaElementKind)
{
diff --git a/src/Microsoft.OpenApi.OData.Reader/OData/ODataConstants.cs b/src/Microsoft.OpenApi.OData.Reader/OData/ODataConstants.cs
new file mode 100644
index 0000000..89a0d70
--- /dev/null
+++ b/src/Microsoft.OpenApi.OData.Reader/OData/ODataConstants.cs
@@ -0,0 +1,27 @@
+// ------------------------------------------------------------
+// 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.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Microsoft.OpenApi.OData
+{
+ internal static class ODataConstants
+ {
+ ///
+ /// Namespaces used in standard included models.
+ ///
+ public static IList StandardNamespaces = new List
+ {
+ "Org.OData.",
+ "Edm",
+ "OData.Community.",
+ };
+
+ }
+}
diff --git a/src/OoasUtil/ComLineProcesser.cs b/src/OoasUtil/ComLineProcesser.cs
index 8e5628d..02966f3 100644
--- a/src/OoasUtil/ComLineProcesser.cs
+++ b/src/OoasUtil/ComLineProcesser.cs
@@ -45,6 +45,11 @@ namespace OoasUtil
///
public OpenApiFormat? Format { get; private set; }
+ ///
+ /// Whether KeyAsSegment is used.
+ ///
+ public bool? KeyAsSegment { get; private set; }
+
///
/// Output OpenApi Specification Version.
///
@@ -60,6 +65,31 @@ namespace OoasUtil
///
public bool IsLocalFile { get; private set; }
+ ///
+ /// Set the output to produce all derived types in responses.
+ ///
+ public bool? DerivedTypesReferencesForResponses { get; private set; }
+
+ ///
+ /// Set the output to expect all derived types in request bodies.
+ ///
+ public bool? DerivedTypesReferencesForRequestBody { get; private set; }
+
+ ///
+ /// Set the output to expose pagination for collections.
+ ///
+ public bool? EnablePagination { get; private set; }
+
+ ///
+ /// tSet the output to use unqualified calls for bound operations.
+ ///
+ public bool? EnableUnqualifiedCall { get; private set; }
+
+ ///
+ /// tDisable examples in the schema.
+ ///
+ public bool? DisableSchemaExamples { get; private set; }
+
///
/// Process the arguments.
///
@@ -98,6 +128,14 @@ namespace OoasUtil
i++;
break;
+ case "--keyassegment":
+ case "-k":
+ if (!ProcessKeyAsSegment(true))
+ {
+ return false;
+ }
+ break;
+
case "--yaml":
case "-y":
if (!ProcessTarget(OpenApiFormat.Yaml))
@@ -132,6 +170,46 @@ namespace OoasUtil
i++;
break;
+ case "--derivedtypesreferencesforresponses":
+ case "-drs":
+ if (!ProcessDerivedTypesReferencesForResponses(true))
+ {
+ return false;
+ }
+ break;
+
+ case "--derivedtypesreferencesforrequestbody":
+ case "-drq":
+ if (!ProcessDerivedTypesReferencesForRequestBody(true))
+ {
+ return false;
+ }
+ break;
+
+ case "--enablepagination":
+ case "-p":
+ if (!ProcessEnablePagination(true))
+ {
+ return false;
+ }
+ break;
+
+ case "--enableunqualifiedcall":
+ case "-u":
+ if (!ProcessEnableUnqualifiedCall(true))
+ {
+ return false;
+ }
+ break;
+
+ case "--disableschemaexamples":
+ case "-x":
+ if (!ProcessDisableSchemaExamples(true))
+ {
+ return false;
+ }
+ break;
+
default:
PrintUsage();
return false;
@@ -155,6 +233,36 @@ namespace OoasUtil
Version = OpenApiSpecVersion.OpenApi3_0;
}
+ if (KeyAsSegment == null)
+ {
+ KeyAsSegment = false;
+ }
+
+ if (DerivedTypesReferencesForResponses == null)
+ {
+ DerivedTypesReferencesForResponses = false;
+ }
+
+ if (DerivedTypesReferencesForRequestBody == null)
+ {
+ DerivedTypesReferencesForRequestBody = false;
+ }
+
+ if (EnablePagination == null)
+ {
+ EnablePagination = false;
+ }
+
+ if (EnableUnqualifiedCall == null)
+ {
+ EnableUnqualifiedCall = false;
+ }
+
+ if (DisableSchemaExamples == null)
+ {
+ DisableSchemaExamples = false;
+ }
+
_continue = ValidateArguments();
return _continue;
}
@@ -198,6 +306,84 @@ namespace OoasUtil
return true;
}
+ private bool ProcessKeyAsSegment(bool keyAsSegment)
+ {
+ if (KeyAsSegment != null)
+ {
+ Console.WriteLine("[Error:] Multiple [--keyassegment|-k] are not allowed.\n");
+ PrintUsage();
+ return false;
+ }
+
+ KeyAsSegment = keyAsSegment;
+ return true;
+ }
+
+ private bool ProcessDerivedTypesReferencesForResponses(bool derivedTypesReferencesForResponses)
+ {
+ if (DerivedTypesReferencesForResponses != null)
+ {
+ Console.WriteLine("[Error:] Multiple [--derivedtypesreferencesforresponses|-drs] are not allowed.\n");
+ PrintUsage();
+ return false;
+ }
+
+ DerivedTypesReferencesForResponses = derivedTypesReferencesForResponses;
+ return true;
+ }
+
+ private bool ProcessDerivedTypesReferencesForRequestBody(bool derivedTypesReferencesForRequestBody)
+ {
+ if (DerivedTypesReferencesForRequestBody != null)
+ {
+ Console.WriteLine("[Error:] Multiple [--derivedtypesreferencesforrequestbody|-drq] are not allowed.\n");
+ PrintUsage();
+ return false;
+ }
+
+ DerivedTypesReferencesForRequestBody = derivedTypesReferencesForRequestBody;
+ return true;
+ }
+
+ private bool ProcessEnablePagination(bool enablePagination)
+ {
+ if (EnablePagination != null)
+ {
+ Console.WriteLine("[Error:] Multiple [--enablepagination|-p] are not allowed.\n");
+ PrintUsage();
+ return false;
+ }
+
+ EnablePagination = enablePagination;
+ return true;
+ }
+
+ private bool ProcessEnableUnqualifiedCall(bool enableUnqualifiedCall)
+ {
+ if (EnableUnqualifiedCall != null)
+ {
+ Console.WriteLine("[Error:] Multiple [--enableunqualifiedcall|-u] are not allowed.\n");
+ PrintUsage();
+ return false;
+ }
+
+ EnableUnqualifiedCall = enableUnqualifiedCall;
+ return true;
+ }
+
+ private bool ProcessDisableSchemaExamples(bool disableSchemaExamples)
+ {
+ if (DisableSchemaExamples != null)
+ {
+ Console.WriteLine("[Error:] Multiple [--disableschemaexamples|-x] are not allowed.\n");
+ PrintUsage();
+ return false;
+ }
+
+ DisableSchemaExamples = disableSchemaExamples;
+ return true;
+ }
+
private bool ProcessTarget(int version)
{
if (Version != null)
@@ -256,6 +442,12 @@ namespace OoasUtil
sb.Append(" --version|-v\t\t\tDisplay version.\n");
sb.Append(" --input|-i CsdlFileOrUrl\tSet the CSDL file name or the OData Service Url.\n");
sb.Append(" --output|-o OutputFile\tSet the output file name.\n");
+ sb.Append(" --keyassegment|-k\t\t\tSet the output to use key-as-segment style URLs.\n");
+ sb.Append(" --derivedtypesreferencesforresponses|-drs\t\t\tSet the output to produce all derived types in responses.\n");
+ sb.Append(" --derivedtypesreferencesforrequestbody|-drq\t\t\tSet the output to expect all derived types in request bodies.\n");
+ sb.Append(" --enablepagination|-p\t\t\tSet the output to expose pagination for collections.\n");
+ sb.Append(" --enableunqualifiedcall|-u\t\t\tSet the output to use unqualified calls for bound operations.\n");
+ sb.Append(" --disableschemaexamples|-x\t\t\tDisable examples in the schema.\n");
sb.Append(" --json|-j\t\t\tSet the output format as JSON.\n");
sb.Append(" --yaml|-y\t\t\tSet the output format as YAML.\n");
sb.Append(" --specversion|-s IntVersion\tSet the OpenApi Specification version of the output. Only 2 or 3 are supported.\n");
diff --git a/src/OoasUtil/FileOpenApiGenerator.cs b/src/OoasUtil/FileOpenApiGenerator.cs
index 5ac58ee..f820a58 100644
--- a/src/OoasUtil/FileOpenApiGenerator.cs
+++ b/src/OoasUtil/FileOpenApiGenerator.cs
@@ -6,10 +6,13 @@
using System;
using System.IO;
+using System.Linq;
+using System.Xml;
using System.Xml.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
using Microsoft.OpenApi;
+using Microsoft.OpenApi.OData;
namespace OoasUtil
{
@@ -28,9 +31,10 @@ namespace OoasUtil
///
/// The input.
/// The output.
- /// The output target.
- public FileOpenApiGenerator(string input, string output, OpenApiFormat format, OpenApiSpecVersion version)
- : base(output, format, version)
+ /// The format.
+ /// Conversion settings.
+ public FileOpenApiGenerator(string input, string output, OpenApiFormat format, OpenApiConvertSettings settings)
+ : base(output, format, settings)
{
Input = input;
}
@@ -43,7 +47,32 @@ namespace OoasUtil
try
{
string csdl = File.ReadAllText(Input);
- return CsdlReader.Parse(XElement.Parse(csdl).CreateReader());
+ var directory = Path.GetDirectoryName(Input);
+ var parsed = XElement.Parse(csdl);
+ using (XmlReader mainReader = parsed.CreateReader())
+ {
+ return CsdlReader.Parse(mainReader, u =>
+ {
+ // Currently only support relative paths
+ if (u.IsAbsoluteUri)
+ {
+ Console.WriteLine($"Referenced model must use relative paths to the main model.");
+ return null;
+ }
+
+ var file = Path.Combine(directory, u.OriginalString);
+ string referenceText = File.ReadAllText(file);
+ var referenceParsed = XElement.Parse(referenceText);
+ XmlReader referenceReader = referenceParsed.CreateReader();
+ return referenceReader;
+ });
+ }
+ }
+ catch (EdmParseException parseException)
+ {
+ Console.WriteLine("Failed to parse the CSDL file.");
+ Console.WriteLine(string.Join(Environment.NewLine, parseException.Errors.Select(e => e.ToString())));
+ return null;
}
catch (Exception e)
{
diff --git a/src/OoasUtil/OpenApiGenerator.cs b/src/OoasUtil/OpenApiGenerator.cs
index 37a08c6..fd17025 100644
--- a/src/OoasUtil/OpenApiGenerator.cs
+++ b/src/OoasUtil/OpenApiGenerator.cs
@@ -24,27 +24,27 @@ namespace OoasUtil
///
public OpenApiFormat Format { get; }
- ///
- /// Output specification version.
- ///
- public OpenApiSpecVersion Version { get; }
-
///
/// Output file.
///
public string Output { get; }
+ ///
+ /// Settings to use for conversion.
+ ///
+ public OpenApiConvertSettings Settings { get; }
+
///
/// Initializes a new instance of the class.
///
- /// The input.
/// The output.
- /// The output target.
- public OpenApiGenerator(string output, OpenApiFormat format, OpenApiSpecVersion version)
+ /// The output format.
+ /// Conversion settings.
+ public OpenApiGenerator(string output, OpenApiFormat format, OpenApiConvertSettings settings)
{
Output = output;
Format = format;
- Version = version;
+ Settings = settings;
}
///
@@ -56,14 +56,12 @@ namespace OoasUtil
{
IEdmModel edmModel = GetEdmModel();
- OpenApiConvertSettings settings = GetSettings();
-
- settings.OpenApiSpecVersion = Version;
+ this.ModifySettings();
using (FileStream fs = File.Create(Output))
{
- OpenApiDocument document = edmModel.ConvertToOpenApi(settings);
- document.Serialize(fs, settings.OpenApiSpecVersion, Format);
+ OpenApiDocument document = edmModel.ConvertToOpenApi(Settings);
+ document.Serialize(fs, Settings.OpenApiSpecVersion, Format);
fs.Flush();
}
}
@@ -76,9 +74,8 @@ namespace OoasUtil
return true;
}
- protected virtual OpenApiConvertSettings GetSettings()
+ protected virtual void ModifySettings()
{
- return new OpenApiConvertSettings();
}
protected abstract IEdmModel GetEdmModel();
diff --git a/src/OoasUtil/Program.cs b/src/OoasUtil/Program.cs
index 8688c0e..eae7817 100644
--- a/src/OoasUtil/Program.cs
+++ b/src/OoasUtil/Program.cs
@@ -5,6 +5,8 @@
//---------------------------------------------------------------------
using System;
+using System.Reflection;
+using Microsoft.OpenApi.OData;
namespace OoasUtil
{
@@ -29,13 +31,25 @@ namespace OoasUtil
}
OpenApiGenerator generator;
+
+ OpenApiConvertSettings settings = new OpenApiConvertSettings
+ {
+ EnableKeyAsSegment = processer.KeyAsSegment,
+ EnableDerivedTypesReferencesForResponses = processer.DerivedTypesReferencesForResponses.Value,
+ EnableDerivedTypesReferencesForRequestBody = processer.DerivedTypesReferencesForRequestBody.Value,
+ EnablePagination = processer.EnablePagination.Value,
+ EnableUnqualifiedCall = processer.EnableUnqualifiedCall.Value,
+ ShowSchemaExamples = !processer.DisableSchemaExamples.Value,
+ OpenApiSpecVersion = processer.Version.Value,
+ };
+
if (processer.IsLocalFile)
{
- generator = new FileOpenApiGenerator(processer.Input, processer.Output, processer.Format.Value, processer.Version.Value);
+ generator = new FileOpenApiGenerator(processer.Input, processer.Output, processer.Format.Value, settings);
}
else
{
- generator = new UrlOpenApiGenerator(new Uri(processer.Input), processer.Output, processer.Format.Value, processer.Version.Value);
+ generator = new UrlOpenApiGenerator(new Uri(processer.Input), processer.Output, processer.Format.Value, settings);
}
if (generator.Generate())
diff --git a/src/OoasUtil/README.md b/src/OoasUtil/README.md
index d4904c6..b659741 100644
--- a/src/OoasUtil/README.md
+++ b/src/OoasUtil/README.md
@@ -25,14 +25,38 @@ Output the "JSON" format Open API document;
Output the "YAML" format Open API document;
-### [--specversion|-s int]
+### [--keyassegment|-k]
-Indicate which version, either 2 or 3, of the OpenApi specification to output. Only 2 or 3 are supported;
+Output the document using key-as-segment style URLs.;
+
+### [--derivedtypesreferencesforresponses|-drs]
+
+Output the document to expect all derived types in responses.;
+
+### [--derivedtypesreferencesforrequestbody|-drq]
+
+Output the document to expect all derived types in request bodies.;
+
+### [--enablepagination|-p]
+
+Output the document to expose pagination for collections.;
+
+### [--enableunqualifiedcall|-u]
+
+Output the document to use unqualified calls for bound operations.;
+
+### [--disableschemaexamples|-x]
+
+Output the document without examples in the schema.;
### [--yaml|-y]
Output the "YAML" format Open API document;
+### [--specversion|-s int]
+
+Indicate which version, either 2 or 3, of the OpenApi specification to output. Only 2 or 3 are supported;
+
### [--input|-i file]
Indicate to where to get CSDL, from file or from Uri.
@@ -44,7 +68,7 @@ Indicate to output file name.
## Examples
-`OoasUtil.exe -j -s 3 -i http://services.odata.org/TrippinRESTierService -o trip.json`
+`OoasUtil.exe -j -k -drs -drq -p -u -s 3 -i http://services.odata.org/TrippinRESTierService -o trip.json`
The content of `trip.json` is similar at https://github.com/xuzhg/OData.OpenAPI/blob/master/Microsoft.OData.OpenAPI/Microsoft.OData.OpenAPI.Tests/Resources/TripService.OpenApi.json
diff --git a/src/OoasUtil/UrlOpenApiGenerator.cs b/src/OoasUtil/UrlOpenApiGenerator.cs
index 37ddf30..5165be0 100644
--- a/src/OoasUtil/UrlOpenApiGenerator.cs
+++ b/src/OoasUtil/UrlOpenApiGenerator.cs
@@ -31,9 +31,10 @@ namespace OoasUtil
///
/// The input.
/// The output.
- /// The output target.
- public UrlOpenApiGenerator(Uri input, string output, OpenApiFormat format, OpenApiSpecVersion version)
- : base(output, format, version)
+ /// The format.
+ /// Conversion settings.
+ public UrlOpenApiGenerator(Uri input, string output, OpenApiFormat format, OpenApiConvertSettings settings)
+ : base(output, format, settings)
{
Input = input;
}
@@ -58,12 +59,10 @@ namespace OoasUtil
return CsdlReader.Parse(XElement.Parse(csdl).CreateReader());
}
- protected override OpenApiConvertSettings GetSettings()
+ protected override void ModifySettings()
{
- return new OpenApiConvertSettings
- {
- ServiceRoot = Input
- };
+ base.ModifySettings();
+ Settings.ServiceRoot = Input;
}
}
}
diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Common/EdmModelHelper.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Common/EdmModelHelper.cs
index 411c96a..d98d45c 100644
--- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Common/EdmModelHelper.cs
+++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Common/EdmModelHelper.cs
@@ -3,6 +3,7 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
+using System;
using System.Xml.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Csdl;
@@ -12,6 +13,8 @@ using Xunit;
using System.IO;
using System.Xml;
using System.Collections.Generic;
+using System.Net;
+using System.Text;
using Microsoft.OData.Edm.Validation;
using Xunit.Abstractions;
@@ -26,6 +29,8 @@ namespace Microsoft.OpenApi.OData.Tests
public static IEdmModel MultipleInheritanceEdmModel { get; }
+ public static IEdmModel InheritanceEdmModelAcrossReferences { get; }
+
public static IEdmModel BasicEdmModel { get; }
public static IEdmModel MultipleSchemasEdmModel { get; }
@@ -46,6 +51,7 @@ namespace Microsoft.OpenApi.OData.Tests
ContractServiceModel = LoadEdmModel("Contract.OData.xml");
GraphBetaModel = LoadEdmModel("Graph.Beta.OData.xml");
MultipleSchemasEdmModel = LoadEdmModel("Multiple.Schema.OData.xml");
+ InheritanceEdmModelAcrossReferences = CreateInheritanceEdmModelAcrossReferences();
}
private static IEdmModel LoadEdmModel(string source)
@@ -160,6 +166,50 @@ namespace Microsoft.OpenApi.OData.Tests
return model;
}
+ public static IEdmModel CreateInheritanceEdmModelAcrossReferences()
+ {
+ const string modelText =
+ @"
+
+
+
+
+
+
+
+
+
+
+
+
+
+";
+ const string subModelText =
+ @"
+
+
+
+
+
+
+
+
+
+
+";
+
+ IEdmModel model;
+ IEnumerable errors;
+
+ XElement parsed = XElement.Parse(modelText);
+ bool result = CsdlReader.TryParse(parsed.CreateReader(),
+ uri => XElement.Parse(subModelText).CreateReader(),
+ out model,
+ out errors);
+ Assert.True(result);
+ return model;
+ }
+
private static IEdmModel CreateEdmModel()
{
var model = new EdmModel();
@@ -359,12 +409,12 @@ namespace Microsoft.OpenApi.OData.Tests
public static string GetCsdl(IEdmModel model)
{
- string edmx = string.Empty;
+ string edmx = String.Empty;
using (StringWriter sw = new StringWriter())
{
XmlWriterSettings settings = new XmlWriterSettings();
- settings.Encoding = System.Text.Encoding.UTF8;
+ settings.Encoding = Encoding.UTF8;
settings.Indent = true;
using (XmlWriter xw = XmlWriter.Create(sw, settings))
diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Edm/EdmModelExtensionsTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Edm/EdmModelExtensionsTests.cs
index b85b702..a9e919c 100644
--- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Edm/EdmModelExtensionsTests.cs
+++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Edm/EdmModelExtensionsTests.cs
@@ -3,8 +3,12 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
+using System.Collections.Generic;
using System.Linq;
+using System.Xml.Linq;
using Microsoft.OData.Edm;
+using Microsoft.OData.Edm.Csdl;
+using Microsoft.OData.Edm.Validation;
using Microsoft.OpenApi.OData.Tests;
using Xunit;
@@ -55,5 +59,21 @@ namespace Microsoft.OpenApi.OData.Edm.Tests
Assert.Equal(2, baseTypes.Count());
Assert.Equal(new[] { subEntityType, baseEntityType }, baseTypes);
}
+
+ [Fact]
+ public void GetAllElementsReturnsElementsFromAllModels()
+ {
+ // Arrange
+ IEdmModel model = EdmModelHelper.InheritanceEdmModelAcrossReferences;
+
+ // Act
+ var elements = model.GetAllElements();
+
+ // Assert
+ Assert.Collection(elements,
+ e => Assert.Equal("Customer", e.Name),
+ e => Assert.Equal("Default", e.Name),
+ e => Assert.Equal("CustomerBase", e.Name));
+ }
}
}
diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiSchemaGeneratorTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiSchemaGeneratorTests.cs
index 4d975d8..331d23e 100644
--- a/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiSchemaGeneratorTests.cs
+++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/Generator/OpenApiSchemaGeneratorTests.cs
@@ -335,6 +335,52 @@ namespace Microsoft.OpenApi.OData.Tests
}"
.ChangeLineBreaks(), json);
}
+
+ [Fact]
+ public void CreateEntityTypeWithCrossReferenceBaseSchemaReturnCorrectSchema()
+ {
+ // Arrange
+ IEdmModel model = EdmModelHelper.InheritanceEdmModelAcrossReferences;
+ ODataContext context = new ODataContext(model, new OpenApiConvertSettings
+ {
+ ShowSchemaExamples = true
+ });
+ IEdmEntityType entity = model.SchemaElements.OfType().First(t => t.Name == "Customer");
+ 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("SubNS.CustomerBase", 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("Extra", property.Key);
+ Assert.Equal("integer", property.Value.Type);
+ Assert.Null(property.Value.OneOf);
+
+ Assert.Equal("Customer", declaredSchema.Title);
+ }
#endregion
#region EnumTypeSchema
diff --git a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/EntityPathItemHandlerTests.cs b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/EntityPathItemHandlerTests.cs
index 9534afc..a12a536 100644
--- a/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/EntityPathItemHandlerTests.cs
+++ b/test/Microsoft.OpenAPI.OData.Reader.Tests/PathItem/EntityPathItemHandlerTests.cs
@@ -9,6 +9,7 @@ using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Properties;
+using Microsoft.OpenApi.OData.Tests;
using Xunit;
namespace Microsoft.OpenApi.OData.PathItem.Tests
@@ -75,6 +76,31 @@ namespace Microsoft.OpenApi.OData.PathItem.Tests
pathItem.Operations.Select(o => o.Key));
}
+ [Fact]
+ public void CreateEntityPathItemReturnsCorrectPathItemWithReferences()
+ {
+ // Test that references don't disturb the paths.
+
+ // Arrange
+ IEdmModel model = EdmModelHelper.InheritanceEdmModelAcrossReferences;
+ ODataContext context = new ODataContext(model);
+ IEdmEntitySet entitySet = model.EntityContainer.FindEntitySet("Customers");
+ Assert.NotNull(entitySet); // guard
+ ODataPath path = new ODataPath(new ODataNavigationSourceSegment(entitySet), new ODataKeySegment(entitySet.EntityType()));
+
+ // Act
+ var pathItem = _pathItemHandler.CreatePathItem(context, path);
+
+ // Assert
+ Assert.NotNull(pathItem);
+
+ Assert.NotNull(pathItem.Operations);
+ Assert.NotEmpty(pathItem.Operations);
+ Assert.Equal(3, pathItem.Operations.Count);
+ Assert.Equal(new OperationType[] { OperationType.Get, OperationType.Patch, OperationType.Delete },
+ pathItem.Operations.Select(o => o.Key));
+ }
+
[Theory]
[InlineData(true, new OperationType[] { OperationType.Get, OperationType.Patch, OperationType.Delete })]
[InlineData(false, new OperationType[] { OperationType.Patch, OperationType.Delete })]