Skip to content

Commit

Permalink
- fixes enums projection
Browse files Browse the repository at this point in the history
Signed-off-by: Vincent Biret <[email protected]>
  • Loading branch information
baywet committed Dec 19, 2023
1 parent dcbf4f0 commit 9a1891e
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 9 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed

- Fixed a bug where the discriminator validation rule would report false positives on nullable union types.
- Fixed a bug where the order of enum declaration might results in a missing enum type. [#3935](https://github.com/microsoft/kiota/issues/3935)

## [1.9.1] - 2023-12-13

Expand Down
12 changes: 6 additions & 6 deletions src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,17 +125,17 @@ public static bool IsEnum(this OpenApiSchema schema)
{
if (schema is null) return false;
return schema.Enum.OfType<OpenApiString>().Any(static x => !string.IsNullOrEmpty(x.Value)) &&
(string.IsNullOrEmpty(schema.Type) || "string".Equals(schema.Type, StringComparison.OrdinalIgnoreCase)) ||
schema.AnyOf.Where(static x => x.IsSemanticallyMeaningful(true)).Count(static x => x.IsEnum()) == 1 && !schema.AnyOf.Where(static x => x.IsSemanticallyMeaningful(true)).Any(static x => !x.IsEnum()) ||
schema.OneOf.Where(static x => x.IsSemanticallyMeaningful(true)).Count(static x => x.IsEnum()) == 1 && !schema.OneOf.Where(static x => x.IsSemanticallyMeaningful(true)).Any(static x => !x.IsEnum())
; // number and boolean enums are not supported
(string.IsNullOrEmpty(schema.Type) || "string".Equals(schema.Type, StringComparison.OrdinalIgnoreCase)); // number and boolean enums are not supported
}
public static bool IsComposedEnum(this OpenApiSchema schema)
{
return (schema.IsInclusiveUnion() && schema.AnyOf.Any(static x => x.IsEnum())) || (schema.IsExclusiveUnion() && schema.OneOf.Any(static x => x.IsEnum()));
if (schema is null) return false;
return schema.AnyOf.Count(static x => !x.IsSemanticallyMeaningful(true)) == 1 && schema.AnyOf.Count(static x => x.IsEnum()) == 1 ||
schema.OneOf.Count(static x => !x.IsSemanticallyMeaningful(true)) == 1 && schema.OneOf.Count(static x => x.IsEnum()) == 1;
}
private static bool IsSemanticallyMeaningful(this OpenApiSchema schema, bool ignoreNullableObjects = false)
public static bool IsSemanticallyMeaningful(this OpenApiSchema schema, bool ignoreNullableObjects = false)
{
if (schema is null) return false;
return schema.Properties.Any() ||
schema.Items != null ||
(!string.IsNullOrEmpty(schema.Type) &&
Expand Down
2 changes: 1 addition & 1 deletion src/Kiota.Builder/KiotaBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1831,7 +1831,7 @@ private CodeTypeBase CreateComposedModelDeclaration(OpenApiUrlTreeNode currentNo
if (!string.IsNullOrEmpty(schema.Type) || !string.IsNullOrEmpty(schema.Format))
return GetPrimitiveType(schema, string.Empty);
if (schema.AnyOf.Any() || schema.OneOf.Any() || schema.AllOf.Any()) // we have an empty node because of some local override for schema properties and need to unwrap it.
return CreateModelDeclarations(currentNode, (schema.AnyOf.FirstOrDefault() ?? schema.OneOf.FirstOrDefault() ?? schema.AllOf.FirstOrDefault())!, operation, parentElement, suffixForInlineSchema, response, typeNameForInlineSchema, isRequestBody);
return CreateModelDeclarations(currentNode, (schema.AnyOf.FirstOrDefault(static x => x.IsSemanticallyMeaningful(true)) ?? schema.OneOf.FirstOrDefault(static x => x.IsSemanticallyMeaningful(true)) ?? schema.AllOf.FirstOrDefault(static x => x.IsSemanticallyMeaningful(true)))!, operation, parentElement, suffixForInlineSchema, response, typeNameForInlineSchema, isRequestBody);
return null;
}
private CodeTypeBase? CreateCollectionModelDeclaration(OpenApiUrlTreeNode currentNode, OpenApiSchema schema, OpenApiOperation? operation, CodeNamespace codeNamespace, string typeNameForInlineSchema, bool isRequestBody)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ public void IsEnumIgnoresNullableUnions()
}
}
};
Assert.True(schema.IsEnum());
Assert.False(schema.IsEnum());
}
[Fact]
public void IsEnumFailsOnNullableInheritance()
Expand Down Expand Up @@ -591,7 +591,7 @@ public void IsEnumIgnoresNullableExclusiveUnions()
}
}
};
Assert.True(schema.IsEnum());
Assert.False(schema.IsEnum());
}
private static readonly OpenApiSchema numberSchema = new OpenApiSchema
{
Expand Down
126 changes: 126 additions & 0 deletions tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7299,6 +7299,132 @@ public async Task InheritanceWithAllOfWith3Parts()
Assert.Single(resultClass.Properties.Where(x => x.Name.Equals("groupprop1", StringComparison.OrdinalIgnoreCase)));
Assert.Single(resultClass.Properties.Where(x => x.Name.Equals("groupprop2", StringComparison.OrdinalIgnoreCase)));
}
[Fact]
public async Task EnumsWithNullableDoesNotResultInInlineType()
{
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:
'/communications/calls/{call-id}/reject':
post:
requestBody:
description: Action parameters
content:
application/json:
schema:
type: object
properties:
reason:
anyOf:
- $ref: '#/components/schemas/microsoft.graph.rejectReason'
- type: object
nullable: true
callbackUri:
type: string
nullable: true
required: true
responses:
'204':
description: Success,
components:
schemas:
microsoft.graph.rejectReason:
title: rejectReason
enum:
- none
- busy
- forbidden
- unknownFutureValue
type: string");
var mockLogger = new Mock<ILogger<KiotaBuilder>>();
var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "Graph", OpenAPIFilePath = tempFilePath, IncludeAdditionalData = false }, _httpClient);
var document = await builder.CreateOpenApiDocumentAsync(fs);
var node = builder.CreateUriSpace(document);
var codeModel = builder.CreateSourceModel(node);
Assert.NotNull(codeModel);
var requestBuilderNS = codeModel.FindNamespaceByName("ApiSdk.communications.calls.item.reject");
Assert.NotNull(requestBuilderNS);
var requestBuilderClass = requestBuilderNS.FindChildByName<CodeClass>("RejectRequestBuilder", false);
Assert.NotNull(requestBuilderClass);
var reasonCandidate = requestBuilderNS.FindChildByName<CodeEnum>("RejectPostRequestBody_reason", false);
Assert.Null(reasonCandidate);
var modelsNS = codeModel.FindNamespaceByName("ApiSdk.Models");
Assert.NotNull(modelsNS);
var graphModelsNS = modelsNS.FindNamespaceByName("ApiSdk.Models.Microsoft.Graph");
Assert.NotNull(graphModelsNS);
var rejectReasonEnum = graphModelsNS.FindChildByName<CodeEnum>("RejectReason", false);
Assert.NotNull(rejectReasonEnum);
}

[Fact]
public async Task EnumsWithNullableDoesNotResultInInlineTypeInReveredOrder()
{
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:
'/communications/calls/{call-id}/reject':
post:
requestBody:
description: Action parameters
content:
application/json:
schema:
type: object
properties:
reason:
anyOf:
- type: object
nullable: true
- $ref: '#/components/schemas/microsoft.graph.rejectReason'
callbackUri:
type: string
nullable: true
required: true
responses:
'204':
description: Success,
components:
schemas:
microsoft.graph.rejectReason:
title: rejectReason
enum:
- none
- busy
- forbidden
- unknownFutureValue
type: string");
var mockLogger = new Mock<ILogger<KiotaBuilder>>();
var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "Graph", OpenAPIFilePath = tempFilePath, IncludeAdditionalData = false }, _httpClient);
var document = await builder.CreateOpenApiDocumentAsync(fs);
var node = builder.CreateUriSpace(document);
var codeModel = builder.CreateSourceModel(node);
Assert.NotNull(codeModel);
var requestBuilderNS = codeModel.FindNamespaceByName("ApiSdk.communications.calls.item.reject");
Assert.NotNull(requestBuilderNS);
var requestBuilderClass = requestBuilderNS.FindChildByName<CodeClass>("RejectRequestBuilder", false);
Assert.NotNull(requestBuilderClass);
var reasonCandidate = requestBuilderNS.FindChildByName<CodeEnum>("RejectPostRequestBody_reason", false);
Assert.Null(reasonCandidate);
var modelsNS = codeModel.FindNamespaceByName("ApiSdk.Models");
Assert.NotNull(modelsNS);
var graphModelsNS = modelsNS.FindNamespaceByName("ApiSdk.Models.Microsoft.Graph");
Assert.NotNull(graphModelsNS);
var rejectReasonEnum = graphModelsNS.FindChildByName<CodeEnum>("RejectReason", false);
Assert.NotNull(rejectReasonEnum);
}

[Fact]
public async Task AnyTypeResponse()
{
Expand Down

0 comments on commit 9a1891e

Please sign in to comment.