diff --git a/CHANGELOG.md b/CHANGELOG.md index 68607e75e9..1a4befd77e 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 - Fixed a bug in generation when a referenced schema in an allOf was a primitive [#5701](https://github.com/microsoft/kiota/issues/5701). - Fixed a bug where inherited error models would be missing interface declarations. [#5888](https://github.com/microsoft/kiota/issues/5888) +- Fixed a bug where oneOf/anyOf schemas with single references to inheritance or intersections would be missing properties. [#5921](https://github.com/microsoft/kiota/issues/5921) ## [1.21.0] - 2024-12-05 diff --git a/src/Kiota.Builder/Extensions/IListExtensions.cs b/src/Kiota.Builder/Extensions/IListExtensions.cs new file mode 100644 index 0000000000..ec2aed7711 --- /dev/null +++ b/src/Kiota.Builder/Extensions/IListExtensions.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; + +namespace Kiota.Builder.Extensions; + +public static class IListExtensions +{ + /// + /// Returns the only element of this list when it has count of exactly 1 + /// + /// The contained item type. + /// The items. + /// The only element or null. + internal static T? OnlyOneOrDefault(this IList items) => + items.Count == 1 ? items[0] : default; + + /// + /// Adds the provided to this list. + /// + /// The contained item type. + /// The items. + /// The values to add. + internal static void AddRange(this IList items, IEnumerable values) + { + foreach (var item in values) + { + items.Add(item); + } + } +} diff --git a/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs index cec1a3cf2b..ec9d9d2f6a 100644 --- a/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs @@ -98,13 +98,7 @@ public static bool IsInherited(this OpenApiSchema? schema) if (schema is null || !schema.IsInclusiveUnion(0)) return null; var result = new OpenApiSchema(schema); result.AnyOf.Clear(); - foreach (var subSchema in schema.AnyOf) - { - foreach (var property in subSchema.Properties) - { - result.Properties.TryAdd(property.Key, property.Value); - } - } + result.TryAddProperties(schema.AnyOf.SelectMany(static x => x.Properties)); return result; } @@ -113,14 +107,42 @@ public static bool IsInherited(this OpenApiSchema? schema) if (schema is null || !schema.IsExclusiveUnion(0)) return null; var result = new OpenApiSchema(schema); result.OneOf.Clear(); - foreach (var subSchema in schema.OneOf) + result.TryAddProperties(schema.OneOf.SelectMany(static x => x.Properties)); + return result; + } + + internal static OpenApiSchema? MergeSingleInclusiveUnionInheritanceOrIntersectionSchemaEntries(this OpenApiSchema? schema) + { + if (schema is not null + && schema.IsInclusiveUnion(0) + && schema.AnyOf.OnlyOneOrDefault() is OpenApiSchema subSchema + && (subSchema.IsInherited() || subSchema.IsIntersection())) { - foreach (var property in subSchema.Properties) - { - result.Properties.TryAdd(property.Key, property.Value); - } + var result = new OpenApiSchema(schema); + result.AnyOf.Clear(); + result.TryAddProperties(subSchema.Properties); + result.AllOf.AddRange(subSchema.AllOf); + return result; } - return result; + + return null; + } + + internal static OpenApiSchema? MergeSingleExclusiveUnionInheritanceOrIntersectionSchemaEntries(this OpenApiSchema? schema) + { + if (schema is not null + && schema.IsExclusiveUnion(0) + && schema.OneOf.OnlyOneOrDefault() is OpenApiSchema subSchema + && (subSchema.IsInherited() || subSchema.IsIntersection())) + { + var result = new OpenApiSchema(schema); + result.OneOf.Clear(); + result.TryAddProperties(subSchema.Properties); + result.AllOf.AddRange(subSchema.AllOf); + return result; + } + + return null; } internal static OpenApiSchema? MergeIntersectionSchemaEntries(this OpenApiSchema? schema, HashSet? schemasToExclude = default, bool overrideIntersection = false, Func? filter = default) @@ -144,11 +166,17 @@ public static bool IsInherited(this OpenApiSchema? schema) else if (discriminator.Mapping?.Any() ?? false) result.Discriminator.Mapping = discriminator.Mapping.ToDictionary(static x => x.Key, static x => x.Value); - foreach (var propertyToMerge in entriesToMerge.SelectMany(static x => x.Properties)) + result.TryAddProperties(entriesToMerge.SelectMany(static x => x.Properties)); + + return result; + } + + internal static void TryAddProperties(this OpenApiSchema schema, IEnumerable> properties) + { + foreach (var property in properties) { - result.Properties.TryAdd(propertyToMerge.Key, propertyToMerge.Value); + schema.Properties.TryAdd(property.Key, property.Value); } - return result; } public static bool IsIntersection(this OpenApiSchema? schema) diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs index b4466a5bf0..450e392103 100644 --- a/src/Kiota.Builder/KiotaBuilder.cs +++ b/src/Kiota.Builder/KiotaBuilder.cs @@ -958,7 +958,7 @@ x.Parent is CodeIndexer || var parentNS = x.Parent?.Parent?.Parent as CodeNamespace; CodeClass[] exceptions = x.Parent?.Parent is CodeClass parentClass ? [parentClass] : []; x.TypeDefinition = parentNS?.FindChildrenByName(x.Name) - .Except(exceptions)// the property method should not reference itself as a return type. + .Except(exceptions)// the property method should not reference itself as a return type. .MinBy(shortestNamespaceOrder); // searching down first because most request builder properties on a request builder are just sub paths on the API if (x.TypeDefinition == null) @@ -1833,6 +1833,18 @@ private CodeTypeBase CreateModelDeclarations(OpenApiUrlTreeNode currentNode, Ope return CreateComposedModelDeclaration(currentNode, schema, operation, suffix, codeNamespace, isRequestBody, typeNameForInlineSchema); } + // type: object with single oneOf referring to inheritance or intersection + if (schema.IsObjectType() && schema.MergeSingleExclusiveUnionInheritanceOrIntersectionSchemaEntries() is OpenApiSchema mergedExclusiveUnionSchema) + { + return CreateModelDeclarations(currentNode, mergedExclusiveUnionSchema, operation, parentElement, suffixForInlineSchema, response, typeNameForInlineSchema, isRequestBody); + } + + // type: object with single anyOf referring to inheritance or intersection + if (schema.IsObjectType() && schema.MergeSingleInclusiveUnionInheritanceOrIntersectionSchemaEntries() is OpenApiSchema mergedInclusiveUnionSchema) + { + return CreateModelDeclarations(currentNode, mergedInclusiveUnionSchema, operation, parentElement, suffixForInlineSchema, response, typeNameForInlineSchema, isRequestBody); + } + if (schema.IsObjectType() || schema.HasAnyProperty() || schema.IsEnum() || !string.IsNullOrEmpty(schema.AdditionalProperties?.Type)) { // no inheritance or union type, often empty definitions with only additional properties are used as property bags. @@ -1840,7 +1852,7 @@ private CodeTypeBase CreateModelDeclarations(OpenApiUrlTreeNode currentNode, Ope } if (schema.IsArray() && - !schema.Items.IsArray()) // Only handle collections of primitives and complex types. Otherwise, multi-dimensional arrays would be recursively unwrapped undesirably to lead to incorrect serialization types. + !schema.Items.IsArray()) // Only handle collections of primitives and complex types. Otherwise, multi-dimensional arrays would be recursively unwrapped undesirably to lead to incorrect serialization types. { // collections at root return CreateCollectionModelDeclaration(currentNode, schema, operation, codeNamespace, typeNameForInlineSchema, isRequestBody); @@ -2230,7 +2242,7 @@ internal static void AddDiscriminatorMethod(CodeClass newClass, string discrimin logger.LogWarning("Discriminator {ComponentKey} not found in the OpenAPI document.", componentKey); return null; } - // Call CreateModelDeclarations with isViaDiscriminator=true. This is for a special case where we always generate a base class when types are referenced via a oneOf discriminator. + // Call CreateModelDeclarations with isViaDiscriminator=true. This is for a special case where we always generate a base class when types are referenced via a oneOf discriminator. if (CreateModelDeclarations(currentNode, discriminatorSchema, currentOperation, GetShortestNamespace(currentNamespace, discriminatorSchema), string.Empty, null, string.Empty, false, true) is not CodeType result) { logger.LogWarning("Discriminator {ComponentKey} is not a valid model and points to a union type.", componentKey); @@ -2238,7 +2250,7 @@ internal static void AddDiscriminatorMethod(CodeClass newClass, string discrimin } if (baseClass is not null && (result.TypeDefinition is not CodeClass codeClass || codeClass.StartBlock.Inherits is null)) { - if (!baseClass.Equals(result.TypeDefinition))// don't log warning if the discriminator points to the base type itself as this is implicitly the default case. + if (!baseClass.Equals(result.TypeDefinition))// don't log warning if the discriminator points to the base type itself as this is implicitly the default case. logger.LogWarning("Discriminator {ComponentKey} is not inherited from {ClassName}.", componentKey, baseClass.Name); return null; } diff --git a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs index a62089926f..bd7caa00c5 100644 --- a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs +++ b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs @@ -8619,11 +8619,266 @@ public async Task ExclusiveUnionSingleEntriesMergingAsync() Assert.NotNull(oneProperty); var withoutObjectClass = codeModel.FindChildByName("Component2"); - Assert.NotNull(withObjectClass); + Assert.NotNull(withoutObjectClass); var twoProperty = withoutObjectClass.FindChildByName("two", false); Assert.NotNull(twoProperty); } + [Fact] + public async Task ExclusiveUnionInheritanceEntriesMergingAsync() + { + var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + await using var fs = await GetDocumentStreamAsync( +""" +openapi: 3.0.0 +info: + title: "Generator not generating oneOf if the containing schema has type: object" + version: "1.0.0" +servers: + - url: https://mytodos.doesnotexist/ +paths: + /uses-components: + post: + description: Return something + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" +components: + schemas: + ExampleWithSingleOneOfWithTypeObject: + description: "ExampleWithSingleOneOfWithTypeObject" + type: object + oneOf: + - $ref: "#/components/schemas/Component1" + discriminator: + propertyName: objectType + + ExampleWithSingleOneOfWithoutTypeObject: + description: "ExampleWithSingleOneOfWithoutTypeObject" + oneOf: + - $ref: "#/components/schemas/Component2" + discriminator: + propertyName: objectType + + UsesComponents: + type: object + properties: + component_with_single_oneof_with_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithTypeObject" + component_with_single_oneof_without_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithoutTypeObject" + + ComponentCommon: + description: "ComponentCommon" + type: object + required: + - objectType + properties: + objectType: + type: string + common: + type: string + + Component1: + description: "Component1" + type: object + allOf: + - $ref: "#/components/schemas/ComponentCommon" + - type: object + description: "Component1Inner" + properties: + one: + type: string + properties: + anotherOne: + type: string + + Component2: + description: "Component2" + type: object + allOf: + - $ref: "#/components/schemas/ComponentCommon" + - type: object + description: "Component2Inner" + properties: + two: + type: string + properties: + anotherTwo: + 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); + + // Verify that all three classes referenced by the discriminator inherit from baseDirectoryObject + var withObjectClass = codeModel.FindChildByName("ExampleWithSingleOneOfWithTypeObject"); + Assert.NotNull(withObjectClass); + // ExampleWithSingleOneOfWithTypeObject inherits from ComponentCommon + Assert.Equal("ComponentCommon", withObjectClass.BaseClass?.Name); + var withObjectClassOneProperty = withObjectClass.FindChildByName("one", false); + Assert.NotNull(withObjectClassOneProperty); + var withObjectClassAnotherOneProperty = withObjectClass.FindChildByName("anotherOne", false); + Assert.NotNull(withObjectClassAnotherOneProperty); + + var withoutObjectClass = codeModel.FindChildByName("Component2"); + Assert.NotNull(withoutObjectClass); + // Component2 inherits from ComponentCommon + Assert.Equal("ComponentCommon", withoutObjectClass.BaseClass?.Name); + var withoutObjectClassTwoProperty = withoutObjectClass.FindChildByName("two", false); + Assert.NotNull(withoutObjectClassTwoProperty); + var withoutObjectClassClassAnotherTwoProperty = withoutObjectClass.FindChildByName("anotherTwo", false); + Assert.NotNull(withoutObjectClassClassAnotherTwoProperty); + } + + [Fact] + public async Task ExclusiveUnionIntersectionEntriesMergingAsync() + { + var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + await using var fs = await GetDocumentStreamAsync( +""" +openapi: 3.0.0 +info: + title: "Generator not generating oneOf if the containing schema has type: object" + version: "1.0.0" +servers: + - url: https://mytodos.doesnotexist/ +paths: + /uses-components: + post: + description: Return something + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" +components: + schemas: + ExampleWithSingleOneOfWithTypeObject: + description: "ExampleWithSingleOneOfWithTypeObject" + type: object + oneOf: + - $ref: "#/components/schemas/Component1" + discriminator: + propertyName: objectType + + ExampleWithSingleOneOfWithoutTypeObject: + description: "ExampleWithSingleOneOfWithoutTypeObject" + oneOf: + - $ref: "#/components/schemas/Component2" + discriminator: + propertyName: objectType + + UsesComponents: + type: object + properties: + component_with_single_oneof_with_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithTypeObject" + component_with_single_oneof_without_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithoutTypeObject" + + ComponentCommon: + description: "ComponentCommon" + type: object + required: + - objectType + properties: + objectType: + type: string + common: + type: string + + ComponentCommon2: + description: "ComponentCommon2" + type: object + properties: + common2: + type: string + + Component1: + description: "Component1" + type: object + allOf: + - $ref: "#/components/schemas/ComponentCommon" + - $ref: "#/components/schemas/ComponentCommon2" + - type: object + description: "Component1Self" + properties: + one: + type: string + properties: + anotherOne: + type: string + + Component2: + description: "Component2" + type: object + required: + - objectType + allOf: + - $ref: "#/components/schemas/ComponentCommon" + - $ref: "#/components/schemas/ComponentCommon2" + - type: object + description: "Component2Self" + properties: + two: + type: string + properties: + anotherTwo: + 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); + + // Verify both scenarios have all the properties available from all schemas + var withObjectClass = codeModel.FindChildByName("ExampleWithSingleOneOfWithTypeObject"); + Assert.NotNull(withObjectClass); + var withObjectClassOneProperty = withObjectClass.FindChildByName("one", false); + Assert.NotNull(withObjectClassOneProperty); + var withObjectClassCommonProperty = withObjectClass.FindChildByName("common", false); + Assert.NotNull(withObjectClassCommonProperty); + var withObjectClassCommon2Property = withObjectClass.FindChildByName("common2", false); + Assert.NotNull(withObjectClassCommon2Property); + var withObjectClassObjectTypeProperty = withObjectClass.FindChildByName("objectType", false); + Assert.NotNull(withObjectClassObjectTypeProperty); + var withObjectClassAnotherOneProperty = withObjectClass.FindChildByName("anotherOne", false); + Assert.NotNull(withObjectClassAnotherOneProperty); + + var withoutObjectClass = codeModel.FindChildByName("Component2"); + Assert.NotNull(withoutObjectClass); + var withoutObjectClassTwoProperty = withoutObjectClass.FindChildByName("two", false); + Assert.NotNull(withoutObjectClassTwoProperty); + var withoutObjectClassCommonProperty = withoutObjectClass.FindChildByName("common", false); + Assert.NotNull(withoutObjectClassCommonProperty ); + var withoutObjectClassCommon2Property = withoutObjectClass.FindChildByName("common2", false); + Assert.NotNull(withoutObjectClassCommon2Property); + var withoutObjectClassObjectTypeProperty = withoutObjectClass.FindChildByName("objectType", false); + Assert.NotNull(withoutObjectClassObjectTypeProperty); + var withoutObjectClassClassAnotherTwoProperty = withoutObjectClass.FindChildByName("anotherTwo", false); + Assert.NotNull(withoutObjectClassClassAnotherTwoProperty); + } + [Fact] public async Task InclusiveUnionSingleEntriesMergingAsync() { @@ -8712,6 +8967,261 @@ public async Task InclusiveUnionSingleEntriesMergingAsync() Assert.NotNull(twoProperty); } + [Fact] + public async Task InclusiveUnionInheritanceEntriesMergingAsync() + { + var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + await using var fs = await GetDocumentStreamAsync( +""" +openapi: 3.0.0 +info: + title: "Generator not generating oneOf if the containing schema has type: object" + version: "1.0.0" +servers: + - url: https://mytodos.doesnotexist/ +paths: + /uses-components: + post: + description: Return something + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" +components: + schemas: + ExampleWithSingleOneOfWithTypeObject: + description: "ExampleWithSingleOneOfWithTypeObject" + type: object + anyOf: + - $ref: "#/components/schemas/Component1" + discriminator: + propertyName: objectType + + ExampleWithSingleOneOfWithoutTypeObject: + description: "ExampleWithSingleOneOfWithoutTypeObject" + anyOf: + - $ref: "#/components/schemas/Component2" + discriminator: + propertyName: objectType + + UsesComponents: + type: object + properties: + component_with_single_oneof_with_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithTypeObject" + component_with_single_oneof_without_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithoutTypeObject" + + ComponentCommon: + description: "ComponentCommon" + type: object + required: + - objectType + properties: + objectType: + type: string + common: + type: string + + Component1: + description: "Component1" + type: object + allOf: + - $ref: "#/components/schemas/ComponentCommon" + - type: object + description: "Component1Inner" + properties: + one: + type: string + properties: + anotherOne: + type: string + + Component2: + description: "Component2" + type: object + allOf: + - $ref: "#/components/schemas/ComponentCommon" + - type: object + description: "Component2Inner" + properties: + two: + type: string + properties: + anotherTwo: + 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); + + // Verify that all three classes referenced by the discriminator inherit from baseDirectoryObject + var withObjectClass = codeModel.FindChildByName("ExampleWithSingleOneOfWithTypeObject"); + Assert.NotNull(withObjectClass); + // ExampleWithSingleOneOfWithTypeObject inherits from ComponentCommon + Assert.Equal("ComponentCommon", withObjectClass.BaseClass?.Name); + var withObjectClassOneProperty = withObjectClass.FindChildByName("one", false); + Assert.NotNull(withObjectClassOneProperty); + var withObjectClassAnotherOneProperty = withObjectClass.FindChildByName("anotherOne", false); + Assert.NotNull(withObjectClassAnotherOneProperty); + + var withoutObjectClass = codeModel.FindChildByName("Component2"); + Assert.NotNull(withoutObjectClass); + // Component2 inherits from ComponentCommon + Assert.Equal("ComponentCommon", withoutObjectClass.BaseClass?.Name); + var withoutObjectClassTwoProperty = withoutObjectClass.FindChildByName("two", false); + Assert.NotNull(withoutObjectClassTwoProperty); + var withoutObjectClassClassAnotherTwoProperty = withoutObjectClass.FindChildByName("anotherTwo", false); + Assert.NotNull(withoutObjectClassClassAnotherTwoProperty); + } + + [Fact] + public async Task InclusiveUnionIntersectionEntriesMergingAsync() + { + var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + await using var fs = await GetDocumentStreamAsync( +""" +openapi: 3.0.0 +info: + title: "Generator not generating oneOf if the containing schema has type: object" + version: "1.0.0" +servers: + - url: https://mytodos.doesnotexist/ +paths: + /uses-components: + post: + description: Return something + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" +components: + schemas: + ExampleWithSingleOneOfWithTypeObject: + description: "ExampleWithSingleOneOfWithTypeObject" + type: object + anyOf: + - $ref: "#/components/schemas/Component1" + discriminator: + propertyName: objectType + + ExampleWithSingleOneOfWithoutTypeObject: + description: "ExampleWithSingleOneOfWithoutTypeObject" + anyOf: + - $ref: "#/components/schemas/Component2" + discriminator: + propertyName: objectType + + UsesComponents: + type: object + properties: + component_with_single_oneof_with_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithTypeObject" + component_with_single_oneof_without_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithoutTypeObject" + + ComponentCommon: + description: "ComponentCommon" + type: object + required: + - objectType + properties: + objectType: + type: string + common: + type: string + + ComponentCommon2: + description: "ComponentCommon2" + type: object + properties: + common2: + type: string + + Component1: + description: "Component1" + type: object + allOf: + - $ref: "#/components/schemas/ComponentCommon" + - $ref: "#/components/schemas/ComponentCommon2" + - type: object + description: "Component1Self" + properties: + one: + type: string + properties: + anotherOne: + type: string + + Component2: + description: "Component2" + type: object + required: + - objectType + allOf: + - $ref: "#/components/schemas/ComponentCommon" + - $ref: "#/components/schemas/ComponentCommon2" + - type: object + description: "Component2Self" + properties: + two: + type: string + properties: + anotherTwo: + 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); + + // Verify both scenarios have all the properties available from all schemas + var withObjectClass = codeModel.FindChildByName("ExampleWithSingleOneOfWithTypeObject"); + Assert.NotNull(withObjectClass); + var withObjectClassOneProperty = withObjectClass.FindChildByName("one", false); + Assert.NotNull(withObjectClassOneProperty); + var withObjectClassCommonProperty = withObjectClass.FindChildByName("common", false); + Assert.NotNull(withObjectClassCommonProperty); + var withObjectClassCommon2Property = withObjectClass.FindChildByName("common2", false); + Assert.NotNull(withObjectClassCommon2Property); + var withObjectClassObjectTypeProperty = withObjectClass.FindChildByName("objectType", false); + Assert.NotNull(withObjectClassObjectTypeProperty); + var withObjectClassAnotherOneProperty = withObjectClass.FindChildByName("anotherOne", false); + Assert.NotNull(withObjectClassAnotherOneProperty); + + var withoutObjectClass = codeModel.FindChildByName("Component2"); + Assert.NotNull(withoutObjectClass); + var withoutObjectClassTwoProperty = withoutObjectClass.FindChildByName("two", false); + Assert.NotNull(withoutObjectClassTwoProperty); + var withoutObjectClassCommonProperty = withoutObjectClass.FindChildByName("common", false); + Assert.NotNull(withoutObjectClassCommonProperty ); + var withoutObjectClassCommon2Property = withoutObjectClass.FindChildByName("common2", false); + Assert.NotNull(withoutObjectClassCommon2Property); + var withoutObjectClassObjectTypeProperty = withoutObjectClass.FindChildByName("objectType", false); + Assert.NotNull(withoutObjectClassObjectTypeProperty); + var withoutObjectClassClassAnotherTwoProperty = withoutObjectClass.FindChildByName("anotherTwo", false); + Assert.NotNull(withoutObjectClassClassAnotherTwoProperty); + } + [Fact] public async Task NestedIntersectionTypeAllOfAsync() { @@ -9022,14 +9532,14 @@ public async Task InheritanceWithAllOfWith3Parts1Schema2InlineAsync(bool reverse '#microsoft.graph.group': '#/components/schemas/microsoft.graph.group' microsoft.graph.group: allOf:" - + (reverseOrder ? "" : @" + + (reverseOrder ? "" : @" - '$ref': '#/components/schemas/microsoft.graph.directoryObject'") + @" - properties: groupprop1: type: 'string' - properties: groupprop2: - type: 'string'" + (!reverseOrder ? "" : @" + type: 'string'" + (!reverseOrder ? "" : @" - '$ref': '#/components/schemas/microsoft.graph.directoryObject'")); var mockLogger = new Mock>(); var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "Graph", OpenAPIFilePath = tempFilePath }, _httpClient);