diff --git a/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs index 527be4cdd3..25c9074324 100644 --- a/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs @@ -32,7 +32,8 @@ public static IEnumerable GetSchemaNames(this OpenApiSchema schema) } internal static IEnumerable FlattenSchemaIfRequired(this IList schemas, Func> subsequentGetter) { - return schemas.Count == 1 && string.IsNullOrEmpty(schemas[0].Title) ? + if (schemas is null) return Enumerable.Empty(); + return schemas.Count == 1 ? schemas.FlattenEmptyEntries(subsequentGetter, 1) : schemas; } @@ -74,8 +75,9 @@ public static bool IsInclusiveUnion(this OpenApiSchema? schema) public static bool IsInherited(this OpenApiSchema? schema) { - var meaningfulSchemas = schema?.AllOf?.Where(IsSemanticallyMeaningful); - return meaningfulSchemas?.Count(static x => !string.IsNullOrEmpty(x.Reference?.Id)) == 1 && meaningfulSchemas.Count(static x => string.IsNullOrEmpty(x.Reference?.Id)) == 1; + if (schema is null) return false; + var meaningfulSchemas = schema.AllOf.FlattenSchemaIfRequired(static x => x.AllOf).Where(IsSemanticallyMeaningful).ToArray(); + return meaningfulSchemas.Count(static x => !string.IsNullOrEmpty(x.Reference?.Id)) == 1 && meaningfulSchemas.Count(static x => string.IsNullOrEmpty(x.Reference?.Id)) == 1; } internal static OpenApiSchema? MergeIntersectionSchemaEntries(this OpenApiSchema? schema) @@ -99,7 +101,7 @@ public static bool IsExclusiveUnion(this OpenApiSchema? schema) { return schema?.OneOf?.Count(IsSemanticallyMeaningful) > 1; } - private static readonly HashSet oDataTypes = new() { + private static readonly HashSet oDataTypes = new(StringComparer.OrdinalIgnoreCase) { "number", "integer", }; diff --git a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs index 1b4f362a23..b6b0eaac4f 100644 --- a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs +++ b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs @@ -6969,4 +6969,117 @@ public async Task ComplexInheritanceStructures() Assert.NotNull(classificationPrimerClass); Assert.Single(classificationPrimerClass.Properties.Where(static x => x.Name.Equals("name", StringComparison.OrdinalIgnoreCase))); } + [Fact] + public async Task InheritanceWithAllOfInBaseType() + { + var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + await using var fs = await GetDocumentStream(@"openapi: 3.0.1 +info: + title: OData Service for namespace microsoft.graph + description: This OData service is located at https://graph.microsoft.com/v1.0 + version: 1.0.1 +servers: + - url: https://graph.microsoft.com/v1.0 +paths: + /directoryObject: + get: + responses: + '200': + description: Example response + content: + application/json: + schema: + $ref: '#/components/schemas/microsoft.graph.directoryObject' +components: + schemas: + microsoft.graph.directoryObject: + type: object + allOf: + - title: 'directoryObject' + required: ['@odata.type'] + type: 'object' + properties: + '@odata.type': + type: 'string' + default: '#microsoft.graph.directoryObject' + discriminator: + propertyName: '@odata.type' + mapping: + '#microsoft.graph.user': '#/components/schemas/microsoft.graph.user' + '#microsoft.graph.group': '#/components/schemas/microsoft.graph.group' + microsoft.graph.group: + allOf: + - '$ref': '#/components/schemas/microsoft.graph.directoryObject' + - title: 'group' + type: 'object' + properties: + groupprop: + type: 'string'"); + 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("Group")); + } + [Fact] + public async Task InheritanceWithAllOfWith3Parts() + { + var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + await using var fs = await GetDocumentStream(@"openapi: 3.0.1 +info: + title: OData Service for namespace microsoft.graph + description: This OData service is located at https://graph.microsoft.com/v1.0 + version: 1.0.1 +servers: + - url: https://graph.microsoft.com/v1.0 +paths: + /directoryObject: + get: + responses: + '200': + description: Example response + content: + application/json: + schema: + $ref: '#/components/schemas/microsoft.graph.directoryObject' +components: + schemas: + microsoft.graph.directoryObject: + title: 'directoryObject' + required: ['@odata.type'] + type: 'object' + properties: + '@odata.type': + type: 'string' + default: '#microsoft.graph.directoryObject' + discriminator: + propertyName: '@odata.type' + mapping: + '#microsoft.graph.user': '#/components/schemas/microsoft.graph.user' + '#microsoft.graph.group': '#/components/schemas/microsoft.graph.group' + microsoft.graph.group: + allOf: + - '$ref': '#/components/schemas/microsoft.graph.directoryObject' + - title: 'group part 1' + type: 'object' + properties: + groupprop1: + type: 'string' + - title: 'group part 2' + type: 'object' + properties: + groupprop2: + type: 'string'"); + 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); + var resultClass = codeModel.FindChildByName("Group"); + Assert.NotNull(resultClass); + Assert.Equal(2, resultClass.Properties.Count()); + Assert.Single(resultClass.Properties.Where(x => x.Name.Equals("groupprop1", StringComparison.OrdinalIgnoreCase))); + Assert.Single(resultClass.Properties.Where(x => x.Name.Equals("groupprop2", StringComparison.OrdinalIgnoreCase))); + } }