From d5474845c301aabb4378ed34f41e16eb0cf1d868 Mon Sep 17 00:00:00 2001 From: Emond Papegaaij Date: Mon, 19 Jun 2023 09:39:39 +0200 Subject: [PATCH 1/2] Add testcase demonstrating broken inhertance chain This is described in #2781 --- .../Kiota.Builder.Tests/KiotaBuilderTests.cs | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs index 457127d7ac..bee5a4f265 100644 --- a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs +++ b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs @@ -6849,4 +6849,107 @@ public async Task SupportsMultiPartFormAsRequestBody() var addressClass = codeModel.FindChildByName("Address"); Assert.NotNull(addressClass); } + [Fact] + public async Task ComplexInheritanceStructures() + { + var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + await using var fs = await GetDocumentStream(@"openapi: 3.0.1 +info: + title: Broken inheritance + version: '1' +servers: +- url: http://localhost +paths: + '/groupclassification': + get: + summary: Example + description: Example + responses: + '200': + description: default response + content: + application/vnd.topicus.keyhub+json;version=latest: + schema: + '$ref': '#/components/schemas/group.GroupClassification' +components: + schemas: + Linkable: + required: + - '$type' + type: object + properties: + '$type': + type: string + discriminator: + propertyName: '$type' + mapping: + group.GroupPrimer: '#/components/schemas/group.GroupPrimer' + group.GroupClassificationPrimer: '#/components/schemas/group.GroupClassificationPrimer' + group.GroupClassification: '#/components/schemas/group.GroupClassification' + group.GroupPrimer: + allOf: + - '$ref': '#/components/schemas/Linkable' + - type: object + properties: + markers: + '$ref': '#/components/schemas/mark.ItemMarkers' + NonLinkable: + required: + - '$type' + type: object + properties: + '$type': + type: string + discriminator: + propertyName: '$type' + mapping: + mark.ItemMarkers: '#/components/schemas/mark.ItemMarkers' + group.GroupsAuditStats: '#/components/schemas/group.GroupsAuditStats' + mark.ItemMarkers: + allOf: + - '$ref': '#/components/schemas/NonLinkable' + - type: object + group.GroupClassificationPrimer: + allOf: + - '$ref': '#/components/schemas/Linkable' + - required: + - '$type' + - name + type: object + properties: + '$type': + type: string + name: + type: string + discriminator: + propertyName: '$type' + mapping: + group.GroupClassification: '#/components/schemas/group.GroupClassification' + group.GroupClassification: + allOf: + - '$ref': '#/components/schemas/group.GroupClassificationPrimer' + - type: object + properties: + description: + type: string + group.GroupsAuditStats: + allOf: + - '$ref': '#/components/schemas/NonLinkable' + - type: object + properties: + classification: + '$ref': '#/components/schemas/group.GroupClassification'"); + var mockLogger = new Mock>(); + var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "Graph", OpenAPIFilePath = tempFilePath }, _httpClient); + var document = await builder.CreateOpenApiDocumentAsync(fs); + var node = builder.CreateUriSpace(document); + var codeModel = builder.CreateSourceModel(node); + Assert.NotNull(codeModel.FindChildByName("Linkable")); + var classificationClass = codeModel.FindChildByName("GroupClassification"); + Assert.Single(classificationClass.Properties.Where(x => x.Name.Equals("description", StringComparison.OrdinalIgnoreCase))); + Assert.NotNull(classificationClass); + var classificationPrimerClass = codeModel.FindChildByName("GroupClassificationPrimer"); + Assert.NotNull(classificationPrimerClass); + Assert.Single(classificationPrimerClass.Properties.Where(x => x.Name.Equals("name", StringComparison.OrdinalIgnoreCase))); + } } From 8a94e84a7c430dcf3c9155ed7c115162946df735 Mon Sep 17 00:00:00 2001 From: Vincent Biret Date: Thu, 28 Sep 2023 14:39:19 -0400 Subject: [PATCH 2/2] - fixes a bug where inherited types would not generate properly Signed-off-by: Vincent Biret --- CHANGELOG.md | 1 + .../Extensions/OpenApiSchemaExtensions.cs | 13 ++++++++----- src/Kiota.Builder/KiotaBuilder.cs | 2 +- tests/Kiota.Builder.Tests/KiotaBuilderTests.cs | 4 ++-- 4 files changed, 12 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa74d27e10..077afc5b53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Updated constructor for request builders in Python to set passed path parameters. [#3352](https://github.com/microsoft/kiota/issues/3352) +- Fixed inherited type definition generation where some cases would not generate properly. [#2745](https://github.com/microsoft/kiota/issues/2745) - Localhost based descriptions are not cached anymore to facilitate development workflows. [#3316](https://github.com/microsoft/kiota/issues/3316) - Fixed a bug where the hints would miss quotes for paths and always use the API manifest. [#3342](https://github.com/microsoft/kiota/issues/3342) - Fixed a bug where inline composed types for components schemas would have the wrong name. [#3067](https://github.com/microsoft/kiota/issues/3067) diff --git a/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs index f20a7e136d..527be4cdd3 100644 --- a/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs @@ -30,12 +30,15 @@ public static IEnumerable GetSchemaNames(this OpenApiSchema schema) return new[] { schema.Xml.Name }; return Enumerable.Empty(); } - private static IEnumerable FlattenIfRequired(this IList schemas, Func> subsequentGetter) + internal static IEnumerable FlattenSchemaIfRequired(this IList schemas, Func> subsequentGetter) { - return (schemas.Count == 1 && string.IsNullOrEmpty(schemas[0].Title) ? + return schemas.Count == 1 && string.IsNullOrEmpty(schemas[0].Title) ? schemas.FlattenEmptyEntries(subsequentGetter, 1) : - schemas) - .Select(static x => x.Title).Where(static x => !string.IsNullOrEmpty(x)); + schemas; + } + private static IEnumerable FlattenIfRequired(this IList schemas, Func> subsequentGetter) + { + return schemas.FlattenSchemaIfRequired(subsequentGetter).Where(static x => !string.IsNullOrEmpty(x.Title)).Select(static x => x.Title); } public static string GetSchemaName(this OpenApiSchema schema) @@ -154,7 +157,7 @@ public static IEnumerable GetSchemaReferenceIds(this OpenApiSchema schem return Enumerable.Empty(); } - internal static IEnumerable FlattenEmptyEntries(this IEnumerable schemas, Func> subsequentGetter, int? maxDepth = default) + private static IEnumerable FlattenEmptyEntries(this IEnumerable schemas, Func> subsequentGetter, int? maxDepth = default) { if (schemas == null) return Enumerable.Empty(); ArgumentNullException.ThrowIfNull(subsequentGetter); diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs index a2f621bfc1..dea2f6cc11 100644 --- a/src/Kiota.Builder/KiotaBuilder.cs +++ b/src/Kiota.Builder/KiotaBuilder.cs @@ -1552,7 +1552,7 @@ private CodeType CreateModelDeclarationAndType(OpenApiUrlTreeNode currentNode, O } private CodeTypeBase CreateInheritedModelDeclaration(OpenApiUrlTreeNode currentNode, OpenApiSchema schema, OpenApiOperation? operation, string classNameSuffix, CodeNamespace codeNamespace, bool isRequestBody) { - var allOfs = schema.AllOf.FlattenEmptyEntries(static x => x.AllOf); + var allOfs = schema.AllOf.FlattenSchemaIfRequired(static x => x.AllOf); CodeElement? codeDeclaration = null; var className = string.Empty; var codeNamespaceFromParent = GetShortestNamespace(codeNamespace, schema); diff --git a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs index bee5a4f265..4a3ec155e2 100644 --- a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs +++ b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs @@ -6946,10 +6946,10 @@ public async Task ComplexInheritanceStructures() var codeModel = builder.CreateSourceModel(node); Assert.NotNull(codeModel.FindChildByName("Linkable")); var classificationClass = codeModel.FindChildByName("GroupClassification"); - Assert.Single(classificationClass.Properties.Where(x => x.Name.Equals("description", StringComparison.OrdinalIgnoreCase))); + Assert.Single(classificationClass.Properties.Where(static x => x.Name.Equals("description", StringComparison.OrdinalIgnoreCase))); Assert.NotNull(classificationClass); var classificationPrimerClass = codeModel.FindChildByName("GroupClassificationPrimer"); Assert.NotNull(classificationPrimerClass); - Assert.Single(classificationPrimerClass.Properties.Where(x => x.Name.Equals("name", StringComparison.OrdinalIgnoreCase))); + Assert.Single(classificationPrimerClass.Properties.Where(static x => x.Name.Equals("name", StringComparison.OrdinalIgnoreCase))); } }