From 2e847ab08ed05dc596337c00cf69d8f624d9db36 Mon Sep 17 00:00:00 2001 From: maurei Date: Mon, 6 Dec 2021 15:39:18 +0100 Subject: [PATCH 01/15] Fix failing test when run in parallel, respect naming convention as set in SerializerSettings for properties in swagger doc --- .../JsonApiSchemaIdSelector.cs | 75 +- .../ServiceCollectionExtensions.cs | 8 +- .../JsonApiSchemaGenerator.cs | 2 +- .../NullableReferenceSchemaGenerator.cs | 100 +- .../ResourceFieldObjectSchemaBuilder.cs | 16 +- .../ResourceObjectSchemaGenerator.cs | 5 +- .../ResourceTypeSchemaGenerator.cs | 18 +- .../OpenApiClientTests.csproj | 21 +- .../KebabCaseNamingConventionStartup.cs | 21 + .../KebabCase/KebabCaseTests.cs | 527 ++++++ .../NamingConvention/KebabCase/swagger.json | 1466 +++++++++++++++++ .../NamingConventionDbContext.cs | 16 + .../NamingConvention/StaffMember.cs | 15 + .../NamingConvention/Supermarket.cs | 25 + .../NamingConvention/SupermarketType.cs | 8 + test/OpenApiTests/OpenApiTests.csproj | 4 +- .../SourceGeneratorTests.csproj | 2 +- .../JsonDocumentExtensions.cs | 15 + .../JsonElementExtensions.cs | 82 + .../TestBuildingBlocks.csproj | 3 +- 20 files changed, 2317 insertions(+), 112 deletions(-) create mode 100644 test/OpenApiTests/NamingConvention/KebabCase/KebabCaseNamingConventionStartup.cs create mode 100644 test/OpenApiTests/NamingConvention/KebabCase/KebabCaseTests.cs create mode 100644 test/OpenApiTests/NamingConvention/KebabCase/swagger.json create mode 100644 test/OpenApiTests/NamingConvention/NamingConventionDbContext.cs create mode 100644 test/OpenApiTests/NamingConvention/StaffMember.cs create mode 100644 test/OpenApiTests/NamingConvention/Supermarket.cs create mode 100644 test/OpenApiTests/NamingConvention/SupermarketType.cs create mode 100644 test/TestBuildingBlocks/JsonDocumentExtensions.cs create mode 100644 test/TestBuildingBlocks/JsonElementExtensions.cs diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiSchemaIdSelector.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiSchemaIdSelector.cs index 6c1dcf1920..89955b9b64 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiSchemaIdSelector.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiSchemaIdSelector.cs @@ -1,3 +1,4 @@ +using System.Text.Json; using Humanizer; using JsonApiDotNetCore.Configuration; using JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents; @@ -10,42 +11,41 @@ internal sealed class JsonApiSchemaIdSelector { private static readonly IDictionary OpenTypeToSchemaTemplateMap = new Dictionary { - [typeof(ResourcePostRequestDocument<>)] = "###-post-request-document", - [typeof(ResourcePatchRequestDocument<>)] = "###-patch-request-document", - [typeof(ResourceObjectInPostRequest<>)] = "###-data-in-post-request", - [typeof(AttributesInPostRequest<>)] = "###-attributes-in-post-request", - [typeof(RelationshipsInPostRequest<>)] = "###-relationships-in-post-request", - [typeof(ResourceObjectInPatchRequest<>)] = "###-data-in-patch-request", - [typeof(AttributesInPatchRequest<>)] = "###-attributes-in-patch-request", - [typeof(RelationshipsInPatchRequest<>)] = "###-relationships-in-patch-request", - [typeof(ToOneRelationshipInRequest<>)] = "to-one-###-in-request", - [typeof(NullableToOneRelationshipInRequest<>)] = "nullable-to-one-###-in-request", - [typeof(ToManyRelationshipInRequest<>)] = "to-many-###-in-request", - [typeof(PrimaryResourceResponseDocument<>)] = "###-primary-response-document", - [typeof(SecondaryResourceResponseDocument<>)] = "###-secondary-response-document", - [typeof(NullableSecondaryResourceResponseDocument<>)] = "nullable-###-secondary-response-document", - [typeof(ResourceCollectionResponseDocument<>)] = "###-collection-response-document", - [typeof(ResourceIdentifierResponseDocument<>)] = "###-identifier-response-document", - [typeof(NullableResourceIdentifierResponseDocument<>)] = "nullable-###-identifier-response-document", - [typeof(ResourceIdentifierCollectionResponseDocument<>)] = "###-identifier-collection-response-document", - [typeof(ToOneRelationshipInResponse<>)] = "to-one-###-in-response", - [typeof(NullableToOneRelationshipInResponse<>)] = "nullable-to-one-###-in-response", - [typeof(ToManyRelationshipInResponse<>)] = "to-many-###-in-response", - [typeof(ResourceObjectInResponse<>)] = "###-data-in-response", - [typeof(AttributesInResponse<>)] = "###-attributes-in-response", - [typeof(RelationshipsInResponse<>)] = "###-relationships-in-response", - [typeof(ResourceIdentifierObject<>)] = "###-identifier" + [typeof(ResourcePostRequestDocument<>)] = "[ResourceName] Post Request Document", + [typeof(ResourcePatchRequestDocument<>)] = "[ResourceName] Patch Request Document", + [typeof(ResourceObjectInPostRequest<>)] = "[ResourceName] Data In Post Request", + [typeof(AttributesInPostRequest<>)] = "[ResourceName] Attributes In Post Request", + [typeof(RelationshipsInPostRequest<>)] = "[ResourceName] Relationships In Post Request", + [typeof(ResourceObjectInPatchRequest<>)] = "[ResourceName] Data In Patch Request", + [typeof(AttributesInPatchRequest<>)] = "[ResourceName] Attributes In Patch Request", + [typeof(RelationshipsInPatchRequest<>)] = "[ResourceName] Relationships In Patch Request", + [typeof(ToOneRelationshipInRequest<>)] = "To One [ResourceName] In Request", + [typeof(NullableToOneRelationshipInRequest<>)] = "Nullable To One [ResourceName] In Request", + [typeof(ToManyRelationshipInRequest<>)] = "To Many [ResourceName] In Request", + [typeof(PrimaryResourceResponseDocument<>)] = "[ResourceName] Primary Response Document", + [typeof(SecondaryResourceResponseDocument<>)] = "[ResourceName] Secondary Response Document", + [typeof(NullableSecondaryResourceResponseDocument<>)] = "Nullable [ResourceName] Secondary Response Document", + [typeof(ResourceCollectionResponseDocument<>)] = "[ResourceName] Collection Response Document", + [typeof(ResourceIdentifierResponseDocument<>)] = "[ResourceName] Identifier Response Document", + [typeof(NullableResourceIdentifierResponseDocument<>)] = "Nullable [ResourceName] Identifier Response Document", + [typeof(ResourceIdentifierCollectionResponseDocument<>)] = "[ResourceName] Identifier Collection Response Document", + [typeof(ToOneRelationshipInResponse<>)] = "To One [ResourceName] In Response", + [typeof(NullableToOneRelationshipInResponse<>)] = "Nullable To One [ResourceName] In Response", + [typeof(ToManyRelationshipInResponse<>)] = "To Many [ResourceName] In Response", + [typeof(ResourceObjectInResponse<>)] = "[ResourceName] Data In Response", + [typeof(AttributesInResponse<>)] = "[ResourceName] Attributes In Response", + [typeof(RelationshipsInResponse<>)] = "[ResourceName] Relationships In Response", + [typeof(ResourceIdentifierObject<>)] = "[ResourceName] Identifier" }; - private readonly ResourceNameFormatter _formatter; + private readonly JsonNamingPolicy? _namingPolicy; private readonly IResourceGraph _resourceGraph; - public JsonApiSchemaIdSelector(ResourceNameFormatter formatter, IResourceGraph resourceGraph) + public JsonApiSchemaIdSelector(JsonNamingPolicy? namingPolicy, IResourceGraph resourceGraph) { - ArgumentGuard.NotNull(formatter, nameof(formatter)); ArgumentGuard.NotNull(resourceGraph, nameof(resourceGraph)); - _formatter = formatter; + _namingPolicy = namingPolicy; _resourceGraph = resourceGraph; } @@ -62,14 +62,21 @@ public string GetSchemaId(Type type) if (type.IsConstructedGenericType && OpenTypeToSchemaTemplateMap.ContainsKey(type.GetGenericTypeDefinition())) { + Type openType = type.GetGenericTypeDefinition(); Type resourceClrType = type.GetGenericArguments().First(); - string resourceName = _formatter.FormatResourceName(resourceClrType).Singularize(); + resourceType = _resourceGraph.FindResourceType(resourceClrType); - string template = OpenTypeToSchemaTemplateMap[type.GetGenericTypeDefinition()]; - return template.Replace("###", resourceName); + if (resourceType == null) + { + throw new UnreachableCodeException(); + } + + string pascalCaseSchemaId = OpenTypeToSchemaTemplateMap[openType].Replace("[ResourceName]", resourceType.PublicName.Singularize()).Pascalize(); + + return _namingPolicy != null ? _namingPolicy.ConvertName(pascalCaseSchemaId) : pascalCaseSchemaId; } - // Used for a fixed set of types, such as jsonapi-object, links-in-many-resource-document etc. - return _formatter.FormatResourceName(type).Singularize(); + // Used for a fixed set of types, such as JsonApiObject, LinksInResourceCollectionDocument etc. + return _namingPolicy != null ? _namingPolicy.ConvertName(type.Name) : type.Name; } } diff --git a/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs b/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs index 425617bdf8..7140d714ca 100644 --- a/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs @@ -41,6 +41,7 @@ private static void AddCustomApiExplorer(IServiceCollection services, IMvcCoreBu var apiDescriptionProviders = provider.GetRequiredService>(); JsonApiActionDescriptorCollectionProvider descriptorCollectionProviderWrapper = new(controllerResourceMapping, actionDescriptorCollectionProvider); + return new ApiDescriptionGroupCollectionProvider(descriptorCollectionProviderWrapper, apiDescriptionProviders); }); @@ -55,7 +56,6 @@ private static void AddSwaggerGenerator(IServiceScope scope, IServiceCollection var resourceGraph = scope.ServiceProvider.GetRequiredService(); var jsonApiOptions = scope.ServiceProvider.GetRequiredService(); JsonNamingPolicy? namingPolicy = jsonApiOptions.SerializerOptions.PropertyNamingPolicy; - ResourceNameFormatter resourceNameFormatter = new(namingPolicy); AddSchemaGenerator(services); @@ -63,7 +63,7 @@ private static void AddSwaggerGenerator(IServiceScope scope, IServiceCollection { swaggerGenOptions.SupportNonNullableReferenceTypes(); SetOperationInfo(swaggerGenOptions, controllerResourceMapping, namingPolicy); - SetSchemaIdSelector(swaggerGenOptions, resourceGraph, resourceNameFormatter); + SetSchemaIdSelector(swaggerGenOptions, resourceGraph, namingPolicy); swaggerGenOptions.DocumentFilter(); setupSwaggerGenAction?.Invoke(swaggerGenOptions); @@ -101,9 +101,9 @@ private static IList GetOperationTags(ApiDescription description, IContr }; } - private static void SetSchemaIdSelector(SwaggerGenOptions swaggerGenOptions, IResourceGraph resourceGraph, ResourceNameFormatter resourceNameFormatter) + private static void SetSchemaIdSelector(SwaggerGenOptions swaggerGenOptions, IResourceGraph resourceGraph, JsonNamingPolicy? namingPolicy) { - JsonApiSchemaIdSelector jsonApiObjectSchemaSelector = new(resourceNameFormatter, resourceGraph); + JsonApiSchemaIdSelector jsonApiObjectSchemaSelector = new(namingPolicy, resourceGraph); swaggerGenOptions.CustomSchemaIds(type => jsonApiObjectSchemaSelector.GetSchemaId(type)); } diff --git a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/JsonApiSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/JsonApiSchemaGenerator.cs index 4f85affcfd..a0e7159a89 100644 --- a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/JsonApiSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/JsonApiSchemaGenerator.cs @@ -38,7 +38,7 @@ public JsonApiSchemaGenerator(SchemaGenerator defaultSchemaGenerator, IResourceG ArgumentGuard.NotNull(options, nameof(options)); _defaultSchemaGenerator = defaultSchemaGenerator; - _nullableReferenceSchemaGenerator = new NullableReferenceSchemaGenerator(_schemaRepositoryAccessor); + _nullableReferenceSchemaGenerator = new NullableReferenceSchemaGenerator(_schemaRepositoryAccessor, options.SerializerOptions.PropertyNamingPolicy); _resourceObjectSchemaGenerator = new ResourceObjectSchemaGenerator(defaultSchemaGenerator, resourceGraph, options, _schemaRepositoryAccessor); } diff --git a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/NullableReferenceSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/NullableReferenceSchemaGenerator.cs index c8e0fe79db..04fabe1807 100644 --- a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/NullableReferenceSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/NullableReferenceSchemaGenerator.cs @@ -1,20 +1,27 @@ +using System.Text.Json; using Microsoft.OpenApi.Models; namespace JsonApiDotNetCore.OpenApi.SwaggerComponents; internal sealed class NullableReferenceSchemaGenerator { - private static readonly NullableReferenceSchemaStrategy NullableReferenceStrategy = + private const string PascalCaseNullableSchemaReferenceId = "NullValue"; + + private readonly NullableReferenceSchemaStrategy _nullableReferenceStrategy = Enum.Parse(NullableReferenceSchemaStrategy.Implicit.ToString()); - private static OpenApiSchema? _referenceSchemaForNullValue; + private readonly string _nullableSchemaReferenceId; private readonly ISchemaRepositoryAccessor _schemaRepositoryAccessor; - public NullableReferenceSchemaGenerator(ISchemaRepositoryAccessor schemaRepositoryAccessor) + private OpenApiSchema? _referenceSchemaForExplicitNullValue; + + public NullableReferenceSchemaGenerator(ISchemaRepositoryAccessor schemaRepositoryAccessor, JsonNamingPolicy? namingPolicy) { ArgumentGuard.NotNull(schemaRepositoryAccessor, nameof(schemaRepositoryAccessor)); _schemaRepositoryAccessor = schemaRepositoryAccessor; + + _nullableSchemaReferenceId = namingPolicy != null ? namingPolicy.ConvertName(PascalCaseNullableSchemaReferenceId) : PascalCaseNullableSchemaReferenceId; } public OpenApiSchema GenerateSchema(OpenApiSchema referenceSchema) @@ -26,20 +33,13 @@ public OpenApiSchema GenerateSchema(OpenApiSchema referenceSchema) OneOf = new List { referenceSchema, - GetNullableReferenceSchema() + _nullableReferenceStrategy == NullableReferenceSchemaStrategy.Explicit ? GetExplicitNullSchema() : GetImplicitNullSchema() } }; } - private OpenApiSchema GetNullableReferenceSchema() - { - return NullableReferenceStrategy == NullableReferenceSchemaStrategy.Explicit - ? GetNullableReferenceSchemaUsingExplicitNullType() - : GetNullableReferenceSchemaUsingImplicitNullType(); - } - // This approach is supported in OAS starting from v3.1. See https://github.com/OAI/OpenAPI-Specification/issues/1368#issuecomment-580103688 - private static OpenApiSchema GetNullableReferenceSchemaUsingExplicitNullType() + private static OpenApiSchema GetExplicitNullSchema() { return new OpenApiSchema { @@ -48,47 +48,57 @@ private static OpenApiSchema GetNullableReferenceSchemaUsingExplicitNullType() } // This approach is supported starting from OAS v3.0. See https://github.com/OAI/OpenAPI-Specification/issues/1368#issuecomment-487314681 - private OpenApiSchema GetNullableReferenceSchemaUsingImplicitNullType() + private OpenApiSchema GetImplicitNullSchema() { - if (_referenceSchemaForNullValue != null) + EnsureFullSchemaForNullValueExists(); + + return _referenceSchemaForExplicitNullValue ??= new OpenApiSchema { - return _referenceSchemaForNullValue; - } + Reference = new OpenApiReference + { + Id = _nullableSchemaReferenceId, + Type = ReferenceType.Schema + } + }; + } - var fullSchemaForNullValue = new OpenApiSchema + private void EnsureFullSchemaForNullValueExists() + { + if (!_schemaRepositoryAccessor.Current.Schemas.ContainsKey(_nullableSchemaReferenceId)) { - Nullable = true, - Not = new OpenApiSchema + var fullSchemaForNullValue = new OpenApiSchema { - AnyOf = new List + Nullable = true, + Not = new OpenApiSchema { - new() - { - Type = "string" - }, - new() - { - Type = "number" - }, - new() - { - Type = "boolean" - }, - new() + AnyOf = new List { - Type = "object" + new() + { + Type = "string" + }, + new() + { + Type = "number" + }, + new() + { + Type = "boolean" + }, + new() + { + Type = "object" + }, + new() + { + Type = "array" + } }, - new() - { - Type = "array" - } - }, - Items = new OpenApiSchema() - } - }; - - _referenceSchemaForNullValue = _schemaRepositoryAccessor.Current.AddDefinition("null-value", fullSchemaForNullValue); + Items = new OpenApiSchema() + } + }; - return _referenceSchemaForNullValue; + _schemaRepositoryAccessor.Current.AddDefinition(_nullableSchemaReferenceId, fullSchemaForNullValue); + } } } diff --git a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceFieldObjectSchemaBuilder.cs b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceFieldObjectSchemaBuilder.cs index 50d56c0965..ef8c705424 100644 --- a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceFieldObjectSchemaBuilder.cs +++ b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceFieldObjectSchemaBuilder.cs @@ -1,5 +1,6 @@ using System.ComponentModel.DataAnnotations; using System.Reflection; +using System.Text.Json; using JsonApiDotNetCore.OpenApi.JsonApiObjects; using JsonApiDotNetCore.OpenApi.JsonApiObjects.Relationships; using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects; @@ -11,8 +12,6 @@ namespace JsonApiDotNetCore.OpenApi.SwaggerComponents; internal sealed class ResourceFieldObjectSchemaBuilder { - private static readonly SchemaRepository ResourceSchemaRepository = new(); - private static readonly Type[] RelationshipInResponseOpenTypes = { typeof(ToOneRelationshipInResponse<>), @@ -24,11 +23,12 @@ internal sealed class ResourceFieldObjectSchemaBuilder private readonly ISchemaRepositoryAccessor _schemaRepositoryAccessor; private readonly SchemaGenerator _defaultSchemaGenerator; private readonly ResourceTypeSchemaGenerator _resourceTypeSchemaGenerator; + private readonly SchemaRepository _resourceSchemaRepository = new(); private readonly NullableReferenceSchemaGenerator _nullableReferenceSchemaGenerator; private readonly IDictionary _schemasForResourceFields; public ResourceFieldObjectSchemaBuilder(ResourceTypeInfo resourceTypeInfo, ISchemaRepositoryAccessor schemaRepositoryAccessor, - SchemaGenerator defaultSchemaGenerator, ResourceTypeSchemaGenerator resourceTypeSchemaGenerator) + SchemaGenerator defaultSchemaGenerator, ResourceTypeSchemaGenerator resourceTypeSchemaGenerator, JsonNamingPolicy? namingPolicy) { ArgumentGuard.NotNull(resourceTypeInfo, nameof(resourceTypeInfo)); ArgumentGuard.NotNull(schemaRepositoryAccessor, nameof(schemaRepositoryAccessor)); @@ -40,18 +40,18 @@ public ResourceFieldObjectSchemaBuilder(ResourceTypeInfo resourceTypeInfo, ISche _defaultSchemaGenerator = defaultSchemaGenerator; _resourceTypeSchemaGenerator = resourceTypeSchemaGenerator; - _nullableReferenceSchemaGenerator = new NullableReferenceSchemaGenerator(schemaRepositoryAccessor); + _nullableReferenceSchemaGenerator = new NullableReferenceSchemaGenerator(schemaRepositoryAccessor, namingPolicy); _schemasForResourceFields = GetFieldSchemas(); } private IDictionary GetFieldSchemas() { - if (!ResourceSchemaRepository.TryLookupByType(_resourceTypeInfo.ResourceType.ClrType, out OpenApiSchema referenceSchemaForResource)) + if (!_resourceSchemaRepository.TryLookupByType(_resourceTypeInfo.ResourceType.ClrType, out OpenApiSchema referenceSchemaForResource)) { - referenceSchemaForResource = _defaultSchemaGenerator.GenerateSchema(_resourceTypeInfo.ResourceType.ClrType, ResourceSchemaRepository); + referenceSchemaForResource = _defaultSchemaGenerator.GenerateSchema(_resourceTypeInfo.ResourceType.ClrType, _resourceSchemaRepository); } - OpenApiSchema fullSchemaForResource = ResourceSchemaRepository.Schemas[referenceSchemaForResource.Reference.Id]; + OpenApiSchema fullSchemaForResource = _resourceSchemaRepository.Schemas[referenceSchemaForResource.Reference.Id]; return fullSchemaForResource.Properties; } @@ -96,7 +96,7 @@ private void AddAttributeSchemaToResourceObject(AttrAttribute attribute, OpenApi private void ExposeSchema(OpenApiReference openApiReference, Type typeRepresentedBySchema) { - OpenApiSchema fullSchema = ResourceSchemaRepository.Schemas[openApiReference.Id]; + OpenApiSchema fullSchema = _resourceSchemaRepository.Schemas[openApiReference.Id]; _schemaRepositoryAccessor.Current.AddDefinition(openApiReference.Id, fullSchema); _schemaRepositoryAccessor.Current.RegisterType(typeRepresentedBySchema, openApiReference.Id); } diff --git a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceObjectSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceObjectSchemaGenerator.cs index 540517b59c..616b98ef63 100644 --- a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceObjectSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceObjectSchemaGenerator.cs @@ -26,11 +26,12 @@ public ResourceObjectSchemaGenerator(SchemaGenerator defaultSchemaGenerator, IRe _resourceGraph = resourceGraph; _schemaRepositoryAccessor = schemaRepositoryAccessor; - _resourceTypeSchemaGenerator = new ResourceTypeSchemaGenerator(schemaRepositoryAccessor, resourceGraph); + _resourceTypeSchemaGenerator = new ResourceTypeSchemaGenerator(schemaRepositoryAccessor, resourceGraph, options.SerializerOptions.PropertyNamingPolicy); + _allowClientGeneratedIds = options.AllowClientGeneratedIds; _resourceFieldObjectSchemaBuilderFactory = resourceTypeInfo => new ResourceFieldObjectSchemaBuilder(resourceTypeInfo, schemaRepositoryAccessor, - defaultSchemaGenerator, _resourceTypeSchemaGenerator); + defaultSchemaGenerator, _resourceTypeSchemaGenerator, options.SerializerOptions.PropertyNamingPolicy); } public OpenApiSchema GenerateSchema(Type resourceObjectType) diff --git a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceTypeSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceTypeSchemaGenerator.cs index d110511880..8a7118147e 100644 --- a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceTypeSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceTypeSchemaGenerator.cs @@ -1,3 +1,5 @@ +using System.Text.Json; +using Humanizer; using JsonApiDotNetCore.Configuration; using Microsoft.OpenApi.Any; using Microsoft.OpenApi.Models; @@ -6,17 +8,20 @@ namespace JsonApiDotNetCore.OpenApi.SwaggerComponents; internal sealed class ResourceTypeSchemaGenerator { + private const string ResourceTypeSchemaIdTemplate = "[ResourceName] Resource Type"; private readonly ISchemaRepositoryAccessor _schemaRepositoryAccessor; private readonly IResourceGraph _resourceGraph; + private readonly JsonNamingPolicy? _namingPolicy; private readonly Dictionary _resourceClrTypeSchemaCache = new(); - public ResourceTypeSchemaGenerator(ISchemaRepositoryAccessor schemaRepositoryAccessor, IResourceGraph resourceGraph) + public ResourceTypeSchemaGenerator(ISchemaRepositoryAccessor schemaRepositoryAccessor, IResourceGraph resourceGraph, JsonNamingPolicy? namingPolicy) { ArgumentGuard.NotNull(schemaRepositoryAccessor, nameof(schemaRepositoryAccessor)); ArgumentGuard.NotNull(resourceGraph, nameof(resourceGraph)); _schemaRepositoryAccessor = schemaRepositoryAccessor; _resourceGraph = resourceGraph; + _namingPolicy = namingPolicy; } public OpenApiSchema Get(Type resourceClrType) @@ -39,11 +44,13 @@ public OpenApiSchema Get(Type resourceClrType) } }; + string schemaId = GetSchemaId(resourceType); + referenceSchema = new OpenApiSchema { Reference = new OpenApiReference { - Id = $"{resourceType.PublicName}-resource-type", + Id = schemaId, Type = ReferenceType.Schema } }; @@ -53,4 +60,11 @@ public OpenApiSchema Get(Type resourceClrType) return referenceSchema; } + + private string GetSchemaId(ResourceType resourceType) + { + string pascalCaseSchemaId = ResourceTypeSchemaIdTemplate.Replace("[ResourceName]", resourceType.PublicName.Singularize()).Pascalize(); + + return _namingPolicy != null ? _namingPolicy.ConvertName(pascalCaseSchemaId) : pascalCaseSchemaId; + } } diff --git a/test/OpenApiClientTests/OpenApiClientTests.csproj b/test/OpenApiClientTests/OpenApiClientTests.csproj index 005d70d251..5927a4c00e 100644 --- a/test/OpenApiClientTests/OpenApiClientTests.csproj +++ b/test/OpenApiClientTests/OpenApiClientTests.csproj @@ -31,19 +31,16 @@ OpenApiClientTests.LegacyClient.GeneratedCode OpenApiClient + OpenApiClient.cs NSwagCSharp - /UseBaseUrl:false /GenerateClientInterfaces:true /ClientClassAccessModifier:internal + /UseBaseUrl:false /GenerateClientInterfaces:true /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions + + + OpenApiClientTests.NamingConvention.KebabCase.GeneratedCode + KebabCaseClient + KebabCaseClient.cs + NSwagCSharp + /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions - - - - - - - - - - - diff --git a/test/OpenApiTests/NamingConvention/KebabCase/KebabCaseNamingConventionStartup.cs b/test/OpenApiTests/NamingConvention/KebabCase/KebabCaseNamingConventionStartup.cs new file mode 100644 index 0000000000..7e08683bb8 --- /dev/null +++ b/test/OpenApiTests/NamingConvention/KebabCase/KebabCaseNamingConventionStartup.cs @@ -0,0 +1,21 @@ +using System.Text.Json.Serialization; +using JetBrains.Annotations; +using JsonApiDotNetCore.Configuration; +using Microsoft.EntityFrameworkCore; +using OpenApiTests.LegacyOpenApiIntegration; + +namespace OpenApiTests.NamingConvention.KebabCase; + +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public sealed class KebabCaseNamingConventionStartup : OpenApiStartup + where TDbContext : DbContext +{ + protected override void SetJsonApiOptions(JsonApiOptions options) + { + base.SetJsonApiOptions(options); + + options.SerializerOptions.PropertyNamingPolicy = JsonKebabCaseNamingPolicy.Instance; + options.SerializerOptions.DictionaryKeyPolicy = JsonKebabCaseNamingPolicy.Instance; + options.SerializerOptions.Converters.Add(new JsonStringEnumConverter()); + } +} diff --git a/test/OpenApiTests/NamingConvention/KebabCase/KebabCaseTests.cs b/test/OpenApiTests/NamingConvention/KebabCase/KebabCaseTests.cs new file mode 100644 index 0000000000..2c3ca242ef --- /dev/null +++ b/test/OpenApiTests/NamingConvention/KebabCase/KebabCaseTests.cs @@ -0,0 +1,527 @@ +using System.Text.Json; +using OpenApiTests.Controllers; +using TestBuildingBlocks; +using Xunit; + +namespace OpenApiTests.NamingConvention.KebabCase; + +public sealed class KebabCaseTests + : IClassFixture, NamingConventionDbContext>> +{ + private static Lazy>? _lazyOpenApiDocument; + private readonly IntegrationTestContext, NamingConventionDbContext> _testContext; + + public KebabCaseTests(IntegrationTestContext, NamingConventionDbContext> testContext) + { + _testContext = testContext; + + _lazyOpenApiDocument ??= new Lazy>(async () => + { + testContext.UseController(); + + string content = await GetAsync("swagger/v1/swagger.json"); + + await WriteSwaggerDocumentToFileAsync(content); + + JsonDocument document = JsonDocument.Parse(content); + + return document.ToJsonElement(); + }, LazyThreadSafetyMode.ExecutionAndPublication); + } + + [Fact] + public async Task Kebab_casing_convention_is_applied_to_GetCollection_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./supermarkets.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("get-supermarket-collection"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("supermarket-collection-response-document").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + string? resourceDataSchemaRefId = null; + + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("links-in-resource-collection-document"); + propertiesElement.ShouldContainPath("jsonapi.$ref").ShouldBeReferenceSchemaId("jsonapi-object"); + + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.items.$ref").ShouldBeReferenceSchemaId("supermarket-data-in-response") + .SchemaReferenceId; + }); + + string? resourceAttributesInResponseSchemaRefId = null; + string? resourceRelationshipInResponseSchemaRefId = null; + string? primaryResourceTypeSchemaRefId = null; + + schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => + { + primaryResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("supermarkets-resource-type") + .SchemaReferenceId; + + resourceAttributesInResponseSchemaRefId = propertiesElement.ShouldContainPath("attributes.$ref") + .ShouldBeReferenceSchemaId("supermarket-attributes-in-response").SchemaReferenceId; + + resourceRelationshipInResponseSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref") + .ShouldBeReferenceSchemaId("supermarket-relationships-in-response").SchemaReferenceId; + + propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("links-in-resource-object"); + }); + + schemasElement.ShouldContainPath($"{primaryResourceTypeSchemaRefId}.enum[0]").With(enumValueElement => + { + enumValueElement.ShouldBeString("supermarkets"); + }); + + schemasElement.ShouldContainPath($"{resourceAttributesInResponseSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("name-of-city"); + propertiesElement.Should().ContainProperty("kind"); + propertiesElement.ShouldContainPath("kind.$ref").ShouldBeReferenceSchemaId("supermarket-type"); + }); + + string? nullableToOneResourceResponseDataSchemaRefId = null; + + schemasElement.ShouldContainPath($"{resourceRelationshipInResponseSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("store-manager"); + + propertiesElement.ShouldContainPath("store-manager.$ref").ShouldBeReferenceSchemaId("to-one-staff-member-in-response"); + + nullableToOneResourceResponseDataSchemaRefId = propertiesElement.ShouldContainPath("backup-store-manager.$ref") + .ShouldBeReferenceSchemaId("nullable-to-one-staff-member-in-response").SchemaReferenceId; + + propertiesElement.Should().ContainProperty("cashiers"); + propertiesElement.ShouldContainPath("cashiers.$ref").ShouldBeReferenceSchemaId("to-many-staff-member-in-response"); + }); + + string? relatedResourceIdentifierSchemaRefId = null; + + schemasElement.ShouldContainPath($"{nullableToOneResourceResponseDataSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("links-in-relationship-object"); + + relatedResourceIdentifierSchemaRefId = propertiesElement.ShouldContainPath("data.oneOf[0].$ref") + .ShouldBeReferenceSchemaId("staff-member-identifier").SchemaReferenceId; + + propertiesElement.ShouldContainPath("data.oneOf[1].$ref").ShouldBeReferenceSchemaId("null-value"); + }); + + string? relatedResourceTypeSchemaRefId = null; + + schemasElement.ShouldContainPath($"{relatedResourceIdentifierSchemaRefId}.properties").With(propertiesElement => + { + relatedResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("staff-members-resource-type") + .SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{relatedResourceTypeSchemaRefId}.enum[0]").ShouldBeReferenceSchemaId("staff-members"); + }); + } + + [Fact] + public async Task Kebab_casing_convention_is_applied_to_GetSingle_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./supermarkets/{id}.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("get-supermarket"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("supermarket-primary-response-document").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("links-in-resource-document"); + }); + }); + } + + [Fact] + public async Task Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./supermarkets/{id}/store-manager.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("get-supermarket-store-manager"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("staff-member-secondary-response-document").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + string? resourceDataSchemaRefId = null; + + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("staff-member-data-in-response") + .SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("staff-member-attributes-in-response"); + }); + }); + } + + [Fact] + public async Task Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./supermarkets/{id}/backup-store-manager.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("get-supermarket-backup-store-manager"); + }); + + getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("nullable-staff-member-secondary-response-document"); + }); + } + + [Fact] + public async Task Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./supermarkets/{id}/cashiers.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("get-supermarket-cashiers"); + }); + + getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("staff-member-collection-response-document"); + }); + } + + [Fact] + public async Task Kebab_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./supermarkets/{id}/relationships/store-manager.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("get-supermarket-store-manager-relationship"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("staff-member-identifier-response-document").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("links-in-resource-identifier-document"); + }); + }); + } + + [Fact] + public async Task Kebab_casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./supermarkets/{id}/relationships/backup-store-manager.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("get-supermarket-backup-store-manager-relationship"); + }); + + getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("nullable-staff-member-identifier-response-document"); + }); + } + + [Fact] + public async Task Kebab_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("get-supermarket-cashiers-relationship"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("staff-member-identifier-collection-response-document").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("links-in-resource-identifier-collection-document"); + }); + }); + } + + [Fact] + public async Task Kebab_casing_convention_is_applied_to_Post_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./supermarkets.post").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("post-supermarket"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("supermarket-post-request-document").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + string? resourceDataSchemaRefId = null; + + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("supermarket-data-in-post-request") + .SchemaReferenceId; + }); + + string? resourceRelationshipInPostRequestSchemaRefId = null; + + schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("supermarket-attributes-in-post-request"); + + resourceRelationshipInPostRequestSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref") + .ShouldBeReferenceSchemaId("supermarket-relationships-in-post-request").SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{resourceRelationshipInPostRequestSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("store-manager"); + propertiesElement.ShouldContainPath("store-manager.$ref").ShouldBeReferenceSchemaId("to-one-staff-member-in-request"); + + propertiesElement.Should().ContainProperty("backup-store-manager"); + propertiesElement.ShouldContainPath("backup-store-manager.$ref").ShouldBeReferenceSchemaId("nullable-to-one-staff-member-in-request"); + + propertiesElement.Should().ContainProperty("cashiers"); + propertiesElement.ShouldContainPath("cashiers.$ref").ShouldBeReferenceSchemaId("to-many-staff-member-in-request"); + }); + }); + } + + [Fact] + public async Task Kebab_casing_convention_is_applied_to_PostRelationship_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.post").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("post-supermarket-cashiers-relationship"); + }); + }); + } + + [Fact] + public async Task Kebab_casing_convention_is_applied_to_Patch_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./supermarkets/{id}.patch").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("patch-supermarket"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("supermarket-patch-request-document").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + string? resourceDataSchemaRefId = null; + + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("supermarket-data-in-patch-request") + .SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("supermarket-attributes-in-patch-request"); + propertiesElement.ShouldContainPath("relationships.$ref").ShouldBeReferenceSchemaId("supermarket-relationships-in-patch-request"); + }); + }); + } + + [Fact] + public async Task Kebab_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./supermarkets/{id}/relationships/store-manager.patch").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("patch-supermarket-store-manager-relationship"); + }); + }); + } + + [Fact] + public async Task Kebab_casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./supermarkets/{id}/relationships/backup-store-manager.patch").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("patch-supermarket-backup-store-manager-relationship"); + }); + }); + } + + [Fact] + public async Task Kebab_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.patch").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("patch-supermarket-cashiers-relationship"); + }); + }); + } + + [Fact] + public async Task Kebab_casing_convention_is_applied_to_Delete_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./supermarkets/{id}.delete").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("delete-supermarket"); + }); + }); + } + + [Fact] + public async Task Kebab_casing_convention_is_applied_to_DeleteRelationship_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.delete").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("delete-supermarket-cashiers-relationship"); + }); + }); + } + + private async Task GetAsync(string requestUrl) + { + var request = new HttpRequestMessage(HttpMethod.Get, requestUrl); + + using HttpClient client = _testContext.Factory.CreateClient(); + using HttpResponseMessage responseMessage = await client.SendAsync(request); + + return await responseMessage.Content.ReadAsStringAsync(); + } + + private async Task WriteSwaggerDocumentToFileAsync(string document) + { + string testSuitePath = GetTestSuitePath(); + string documentPath = Path.Join(testSuitePath, "swagger.json"); + await File.WriteAllTextAsync(documentPath, document); + } + + private string GetTestSuitePath() + { + string solutionTestDirectoryPath = Directory.GetParent(Environment.CurrentDirectory)!.Parent!.Parent!.Parent!.FullName; + string currentNamespacePathRelativeToTestDirectory = Path.Join(GetType().Namespace!.Split('.')); + + return Path.Join(solutionTestDirectoryPath, currentNamespacePathRelativeToTestDirectory); + } +} diff --git a/test/OpenApiTests/NamingConvention/KebabCase/swagger.json b/test/OpenApiTests/NamingConvention/KebabCase/swagger.json new file mode 100644 index 0000000000..e1de5e7b69 --- /dev/null +++ b/test/OpenApiTests/NamingConvention/KebabCase/swagger.json @@ -0,0 +1,1466 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenApiTests", + "version": "1.0" + }, + "paths": { + "/supermarkets": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "get-supermarket-collection", + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarket-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "head-supermarket-collection", + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarket-collection-response-document" + } + } + } + } + } + }, + "post": { + "tags": [ + "supermarkets" + ], + "operationId": "post-supermarket", + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarket-post-request-document" + } + } + } + }, + "responses": { + "201": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarket-primary-response-document" + } + } + } + }, + "204": { + "description": "Success" + } + } + } + }, + "/supermarkets/{id}": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "get-supermarket", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarket-primary-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "head-supermarket", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarket-primary-response-document" + } + } + } + } + } + }, + "patch": { + "tags": [ + "supermarkets" + ], + "operationId": "patch-supermarket", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarket-patch-request-document" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarket-primary-response-document" + } + } + } + }, + "204": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "supermarkets" + ], + "operationId": "delete-supermarket", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/supermarkets/{id}/backup-store-manager": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "get-supermarket-backup-store-manager", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullable-staff-member-secondary-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "head-supermarket-backup-store-manager", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullable-staff-member-secondary-response-document" + } + } + } + } + } + } + }, + "/supermarkets/{id}/relationships/backup-store-manager": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "get-supermarket-backup-store-manager-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullable-staff-member-identifier-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "head-supermarket-backup-store-manager-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullable-staff-member-identifier-response-document" + } + } + } + } + } + }, + "patch": { + "tags": [ + "supermarkets" + ], + "operationId": "patch-supermarket-backup-store-manager-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullable-to-one-staff-member-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/supermarkets/{id}/cashiers": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "get-supermarket-cashiers", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staff-member-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "head-supermarket-cashiers", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staff-member-collection-response-document" + } + } + } + } + } + } + }, + "/supermarkets/{id}/relationships/cashiers": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "get-supermarket-cashiers-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staff-member-identifier-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "head-supermarket-cashiers-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staff-member-identifier-collection-response-document" + } + } + } + } + } + }, + "post": { + "tags": [ + "supermarkets" + ], + "operationId": "post-supermarket-cashiers-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-staff-member-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + }, + "patch": { + "tags": [ + "supermarkets" + ], + "operationId": "patch-supermarket-cashiers-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-staff-member-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "supermarkets" + ], + "operationId": "delete-supermarket-cashiers-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-staff-member-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/supermarkets/{id}/store-manager": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "get-supermarket-store-manager", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staff-member-secondary-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "head-supermarket-store-manager", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staff-member-secondary-response-document" + } + } + } + } + } + } + }, + "/supermarkets/{id}/relationships/store-manager": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "get-supermarket-store-manager-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staff-member-identifier-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "head-supermarket-store-manager-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staff-member-identifier-response-document" + } + } + } + } + } + }, + "patch": { + "tags": [ + "supermarkets" + ], + "operationId": "patch-supermarket-store-manager-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-one-staff-member-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + } + }, + "components": { + "schemas": { + "jsonapi-object": { + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "ext": { + "type": "array", + "items": { + "type": "string" + } + }, + "profile": { + "type": "array", + "items": { + "type": "string" + } + }, + "meta": { + "type": "object", + "additionalProperties": {} + } + }, + "additionalProperties": false + }, + "links-in-relationship-object": { + "required": [ + "related", + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "related": { + "type": "string" + } + }, + "additionalProperties": false + }, + "links-in-resource-collection-document": { + "required": [ + "first", + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + }, + "first": { + "type": "string" + }, + "last": { + "type": "string" + }, + "prev": { + "type": "string" + }, + "next": { + "type": "string" + } + }, + "additionalProperties": false + }, + "links-in-resource-document": { + "required": [ + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + } + }, + "additionalProperties": false + }, + "links-in-resource-identifier-collection-document": { + "required": [ + "first", + "related", + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + }, + "related": { + "type": "string" + }, + "first": { + "type": "string" + }, + "last": { + "type": "string" + }, + "prev": { + "type": "string" + }, + "next": { + "type": "string" + } + }, + "additionalProperties": false + }, + "links-in-resource-identifier-document": { + "required": [ + "related", + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + }, + "related": { + "type": "string" + } + }, + "additionalProperties": false + }, + "links-in-resource-object": { + "required": [ + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + } + }, + "additionalProperties": false + }, + "null-value": { + "not": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "object" + }, + { + "type": "array" + } + ], + "items": {} + }, + "nullable": true + }, + "nullable-staff-member-identifier-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/staff-member-identifier" + }, + { + "$ref": "#/components/schemas/null-value" + } + ] + }, + "meta": { + "type": "object", + "additionalProperties": {} + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-identifier-document" + } + }, + "additionalProperties": false + }, + "nullable-staff-member-secondary-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/staff-member-data-in-response" + }, + { + "$ref": "#/components/schemas/null-value" + } + ] + }, + "meta": { + "type": "object", + "additionalProperties": {} + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-document" + } + }, + "additionalProperties": false + }, + "nullable-to-one-staff-member-in-request": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/staff-member-identifier" + }, + { + "$ref": "#/components/schemas/null-value" + } + ] + } + }, + "additionalProperties": false + }, + "nullable-to-one-staff-member-in-response": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/staff-member-identifier" + }, + { + "$ref": "#/components/schemas/null-value" + } + ] + }, + "links": { + "$ref": "#/components/schemas/links-in-relationship-object" + }, + "meta": { + "type": "object", + "additionalProperties": {} + } + }, + "additionalProperties": false + }, + "staff-member-attributes-in-response": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "age": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "staff-member-collection-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/staff-member-data-in-response" + } + }, + "meta": { + "type": "object", + "additionalProperties": {} + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-collection-document" + } + }, + "additionalProperties": false + }, + "staff-member-data-in-response": { + "required": [ + "id", + "links", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/staff-member-resource-type" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/staff-member-attributes-in-response" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-object" + }, + "meta": { + "type": "object", + "additionalProperties": {} + } + }, + "additionalProperties": false + }, + "staff-member-identifier": { + "required": [ + "id", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/staff-member-resource-type" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false + }, + "staff-member-identifier-collection-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/staff-member-identifier" + } + }, + "meta": { + "type": "object", + "additionalProperties": {} + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-identifier-collection-document" + } + }, + "additionalProperties": false + }, + "staff-member-identifier-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/staff-member-identifier" + }, + "meta": { + "type": "object", + "additionalProperties": {} + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-identifier-document" + } + }, + "additionalProperties": false + }, + "staff-member-resource-type": { + "enum": [ + "staff-members" + ], + "type": "string" + }, + "staff-member-secondary-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/staff-member-data-in-response" + }, + "meta": { + "type": "object", + "additionalProperties": {} + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-document" + } + }, + "additionalProperties": false + }, + "supermarket-attributes-in-patch-request": { + "type": "object", + "properties": { + "name-of-city": { + "type": "string" + }, + "kind": { + "$ref": "#/components/schemas/supermarket-type" + } + }, + "additionalProperties": false + }, + "supermarket-attributes-in-post-request": { + "required": [ + "name-of-city" + ], + "type": "object", + "properties": { + "name-of-city": { + "type": "string" + }, + "kind": { + "$ref": "#/components/schemas/supermarket-type" + } + }, + "additionalProperties": false + }, + "supermarket-attributes-in-response": { + "type": "object", + "properties": { + "name-of-city": { + "type": "string" + }, + "kind": { + "$ref": "#/components/schemas/supermarket-type" + } + }, + "additionalProperties": false + }, + "supermarket-collection-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/supermarket-data-in-response" + } + }, + "meta": { + "type": "object", + "additionalProperties": {} + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-collection-document" + } + }, + "additionalProperties": false + }, + "supermarket-data-in-patch-request": { + "required": [ + "id", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/supermarket-resource-type" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/supermarket-attributes-in-patch-request" + }, + "relationships": { + "$ref": "#/components/schemas/supermarket-relationships-in-patch-request" + } + }, + "additionalProperties": false + }, + "supermarket-data-in-post-request": { + "required": [ + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/supermarket-resource-type" + }, + "attributes": { + "$ref": "#/components/schemas/supermarket-attributes-in-post-request" + }, + "relationships": { + "$ref": "#/components/schemas/supermarket-relationships-in-post-request" + } + }, + "additionalProperties": false + }, + "supermarket-data-in-response": { + "required": [ + "id", + "links", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/supermarket-resource-type" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/supermarket-attributes-in-response" + }, + "relationships": { + "$ref": "#/components/schemas/supermarket-relationships-in-response" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-object" + }, + "meta": { + "type": "object", + "additionalProperties": {} + } + }, + "additionalProperties": false + }, + "supermarket-patch-request-document": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/supermarket-data-in-patch-request" + } + }, + "additionalProperties": false + }, + "supermarket-post-request-document": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/supermarket-data-in-post-request" + } + }, + "additionalProperties": false + }, + "supermarket-primary-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/supermarket-data-in-response" + }, + "meta": { + "type": "object", + "additionalProperties": {} + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-document" + } + }, + "additionalProperties": false + }, + "supermarket-relationships-in-patch-request": { + "type": "object", + "properties": { + "store-manager": { + "$ref": "#/components/schemas/to-one-staff-member-in-request" + }, + "backup-store-manager": { + "$ref": "#/components/schemas/nullable-to-one-staff-member-in-request" + }, + "cashiers": { + "$ref": "#/components/schemas/to-many-staff-member-in-request" + } + }, + "additionalProperties": false + }, + "supermarket-relationships-in-post-request": { + "required": [ + "store-manager" + ], + "type": "object", + "properties": { + "store-manager": { + "$ref": "#/components/schemas/to-one-staff-member-in-request" + }, + "backup-store-manager": { + "$ref": "#/components/schemas/nullable-to-one-staff-member-in-request" + }, + "cashiers": { + "$ref": "#/components/schemas/to-many-staff-member-in-request" + } + }, + "additionalProperties": false + }, + "supermarket-relationships-in-response": { + "type": "object", + "properties": { + "store-manager": { + "$ref": "#/components/schemas/to-one-staff-member-in-response" + }, + "backup-store-manager": { + "$ref": "#/components/schemas/nullable-to-one-staff-member-in-response" + }, + "cashiers": { + "$ref": "#/components/schemas/to-many-staff-member-in-response" + } + }, + "additionalProperties": false + }, + "supermarket-resource-type": { + "enum": [ + "supermarkets" + ], + "type": "string" + }, + "supermarket-type": { + "enum": [ + "Traditional", + "Budget", + "Warehouse" + ], + "type": "string" + }, + "to-many-staff-member-in-request": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/staff-member-identifier" + } + } + }, + "additionalProperties": false + }, + "to-many-staff-member-in-response": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/staff-member-identifier" + } + }, + "links": { + "$ref": "#/components/schemas/links-in-relationship-object" + }, + "meta": { + "type": "object", + "additionalProperties": {} + } + }, + "additionalProperties": false + }, + "to-one-staff-member-in-request": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/staff-member-identifier" + } + }, + "additionalProperties": false + }, + "to-one-staff-member-in-response": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/staff-member-identifier" + }, + "links": { + "$ref": "#/components/schemas/links-in-relationship-object" + }, + "meta": { + "type": "object", + "additionalProperties": {} + } + }, + "additionalProperties": false + } + } + } +} \ No newline at end of file diff --git a/test/OpenApiTests/NamingConvention/NamingConventionDbContext.cs b/test/OpenApiTests/NamingConvention/NamingConventionDbContext.cs new file mode 100644 index 0000000000..9a48f2bcb0 --- /dev/null +++ b/test/OpenApiTests/NamingConvention/NamingConventionDbContext.cs @@ -0,0 +1,16 @@ +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore; + +namespace OpenApiTests.NamingConvention; + +[UsedImplicitly(ImplicitUseTargetFlags.Members)] +public sealed class NamingConventionDbContext : DbContext +{ + public DbSet Supermarkets => Set(); + public DbSet StaffMembers => Set(); + + public NamingConventionDbContext(DbContextOptions options) + : base(options) + { + } +} diff --git a/test/OpenApiTests/NamingConvention/StaffMember.cs b/test/OpenApiTests/NamingConvention/StaffMember.cs new file mode 100644 index 0000000000..93397b01aa --- /dev/null +++ b/test/OpenApiTests/NamingConvention/StaffMember.cs @@ -0,0 +1,15 @@ +using JetBrains.Annotations; +using JsonApiDotNetCore.Resources; +using JsonApiDotNetCore.Resources.Annotations; + +namespace OpenApiTests.NamingConvention; + +[UsedImplicitly(ImplicitUseTargetFlags.Members)] +public sealed class StaffMember : Identifiable +{ + [Attr] + public string Name { get; set; } = null!; + + [Attr] + public int Age { get; set; } +} diff --git a/test/OpenApiTests/NamingConvention/Supermarket.cs b/test/OpenApiTests/NamingConvention/Supermarket.cs new file mode 100644 index 0000000000..1a22a2a937 --- /dev/null +++ b/test/OpenApiTests/NamingConvention/Supermarket.cs @@ -0,0 +1,25 @@ +using JetBrains.Annotations; +using JsonApiDotNetCore.Resources; +using JsonApiDotNetCore.Resources.Annotations; + +namespace OpenApiTests.NamingConvention; + +[UsedImplicitly(ImplicitUseTargetFlags.Members)] +[Resource] +public sealed class Supermarket : Identifiable +{ + [Attr] + public string NameOfCity { get; set; } = null!; + + [Attr] + public SupermarketType Kind { get; set; } + + [HasOne] + public StaffMember StoreManager { get; set; } = null!; + + [HasOne] + public StaffMember? BackupStoreManager { get; set; } + + [HasMany] + public ICollection Cashiers { get; set; } = new HashSet(); +} diff --git a/test/OpenApiTests/NamingConvention/SupermarketType.cs b/test/OpenApiTests/NamingConvention/SupermarketType.cs new file mode 100644 index 0000000000..551e781b22 --- /dev/null +++ b/test/OpenApiTests/NamingConvention/SupermarketType.cs @@ -0,0 +1,8 @@ +namespace OpenApiTests.NamingConvention; + +public enum SupermarketType +{ + Traditional, + Budget, + Warehouse +} diff --git a/test/OpenApiTests/OpenApiTests.csproj b/test/OpenApiTests/OpenApiTests.csproj index e85a2fb288..532c372ade 100644 --- a/test/OpenApiTests/OpenApiTests.csproj +++ b/test/OpenApiTests/OpenApiTests.csproj @@ -4,8 +4,7 @@ - + @@ -14,6 +13,7 @@ + diff --git a/test/SourceGeneratorTests/SourceGeneratorTests.csproj b/test/SourceGeneratorTests/SourceGeneratorTests.csproj index fd0fb92262..4284854c44 100644 --- a/test/SourceGeneratorTests/SourceGeneratorTests.csproj +++ b/test/SourceGeneratorTests/SourceGeneratorTests.csproj @@ -1,4 +1,4 @@ - + $(TargetFrameworkName) diff --git a/test/TestBuildingBlocks/JsonDocumentExtensions.cs b/test/TestBuildingBlocks/JsonDocumentExtensions.cs new file mode 100644 index 0000000000..d70acbfd78 --- /dev/null +++ b/test/TestBuildingBlocks/JsonDocumentExtensions.cs @@ -0,0 +1,15 @@ +using System.Text.Json; + +namespace TestBuildingBlocks; + +public static class JsonDocumentExtensions +{ + public static JsonElement ToJsonElement(this JsonDocument source) + { + using (source) + { + JsonElement clonedRoot = source.RootElement.Clone(); + return clonedRoot; + } + } +} diff --git a/test/TestBuildingBlocks/JsonElementExtensions.cs b/test/TestBuildingBlocks/JsonElementExtensions.cs new file mode 100644 index 0000000000..e8f18eff30 --- /dev/null +++ b/test/TestBuildingBlocks/JsonElementExtensions.cs @@ -0,0 +1,82 @@ +using System.Text.Json; +using BlushingPenguin.JsonPath; +using FluentAssertions; +using FluentAssertions.Execution; + +namespace TestBuildingBlocks; + +public static class JsonElementExtensions +{ + public static JsonElementAssertions Should(this JsonElement source) + { + return new JsonElementAssertions(source); + } + + public static JsonElement ShouldContainPath(this JsonElement source, string path) + { + JsonElement value = default; + + Action action = () => value = source.SelectToken(path, true)!.Value; + action.Should().NotThrow(); + + return value; + } + + public static void ShouldBeString(this JsonElement source, string value) + { + source.ValueKind.Should().Be(JsonValueKind.String); + source.GetString().Should().Be(value); + } + + public static ReferenceSchemaIdAssertion ShouldBeReferenceSchemaId(this JsonElement source, string value) + { + source.ValueKind.Should().Be(JsonValueKind.String); + + string? jsonElementValue = source.GetString(); + jsonElementValue.ShouldNotBeNull(); + + string referenceSchemaId = jsonElementValue.Split('/').Last(); + referenceSchemaId.Should().Be(value); + + return new ReferenceSchemaIdAssertion + { + SchemaReferenceId = value + }; + } + + public sealed class ReferenceSchemaIdAssertion + { + public string SchemaReferenceId { get; internal init; } = null!; + } + + public sealed class JsonElementAssertions : JsonElementAssertions + { + internal JsonElementAssertions(JsonElement subject) + : base(subject) + { + } + } + + public class JsonElementAssertions + where TAssertions : JsonElementAssertions + { + private readonly JsonElement _subject; + + protected JsonElementAssertions(JsonElement subject) + { + _subject = subject; + } + + public void ContainProperty(string propertyName) + { + string json = _subject.ToString(); + + json.ShouldNotBeNull(); + + string escapedJson = json.Replace("{", "{{").Replace("}", "}}"); + + Execute.Assertion.ForCondition(_subject.TryGetProperty(propertyName, out _)) + .FailWith($"Expected JSON element '{escapedJson}' to contain a property named '{propertyName}'."); + } + } +} diff --git a/test/TestBuildingBlocks/TestBuildingBlocks.csproj b/test/TestBuildingBlocks/TestBuildingBlocks.csproj index 2c8fdd1cd5..f04147ab36 100644 --- a/test/TestBuildingBlocks/TestBuildingBlocks.csproj +++ b/test/TestBuildingBlocks/TestBuildingBlocks.csproj @@ -1,4 +1,4 @@ - + $(TargetFrameworkName) @@ -17,5 +17,6 @@ + From c4b2d179c759927c736ba070120bf2979ea2c44f Mon Sep 17 00:00:00 2001 From: maurei Date: Mon, 6 Dec 2021 15:39:38 +0100 Subject: [PATCH 02/15] Add client and swagger doc tests fixup2 --- .../ApiException.cs | 44 ++++++++++ .../LegacyClient/ApiResponse.cs | 2 +- .../LegacyClient/ResponseTests.cs | 1 + .../KebabCase/GeneratedTypesTests.cs | 80 +++++++++++++++++++ .../NamingConvention/KebabCase/swagger.json | 30 +++---- .../JsonElementAssertions.cs | 33 ++++++++ .../TestBuildingBlocks.csproj | 2 +- 7 files changed, 175 insertions(+), 17 deletions(-) create mode 100644 src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs create mode 100644 test/OpenApiClientTests/NamingConvention/KebabCase/GeneratedTypesTests.cs create mode 100644 test/TestBuildingBlocks/JsonElementAssertions.cs diff --git a/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs b/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs new file mode 100644 index 0000000000..05f340fc69 --- /dev/null +++ b/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs @@ -0,0 +1,44 @@ +using JetBrains.Annotations; + +// We cannot rely on generating ApiException as soon as we are generating multiple clients, see https://github.com/RicoSuter/NSwag/issues/2839#issuecomment-776647377. +// Instead, we take the generated code as is and use it for the various clients. +#nullable disable +// @formatter:off +// ReSharper disable All +namespace JsonApiDotNetCore.OpenApi.Client.Exceptions +{ + [UsedImplicitly(ImplicitUseTargetFlags.Members)] + internal class ApiException : Exception + { + public int StatusCode { get; } + + public string Response { get; } + + public IReadOnlyDictionary> Headers { get; } + + public ApiException(string message, int statusCode, string response, IReadOnlyDictionary> headers, Exception innerException) + : base( + message + "\n\nStatus: " + statusCode + "\nResponse: \n" + + (response == null ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException) + { + StatusCode = statusCode; + Response = response; + Headers = headers; + } + + public override string ToString() + { + return $"HTTP Response: \n\n{Response}\n\n{base.ToString()}"; + }} + + internal sealed class ApiException : ApiException + { + public TResult Result { get; } + + public ApiException(string message, int statusCode, string response, IReadOnlyDictionary> headers, TResult result, + Exception innerException) + : base(message, statusCode, response, headers, innerException) + { + Result = result; + }} +} diff --git a/test/OpenApiClientTests/LegacyClient/ApiResponse.cs b/test/OpenApiClientTests/LegacyClient/ApiResponse.cs index cb00e862a4..d009d2acee 100644 --- a/test/OpenApiClientTests/LegacyClient/ApiResponse.cs +++ b/test/OpenApiClientTests/LegacyClient/ApiResponse.cs @@ -1,5 +1,5 @@ using JsonApiDotNetCore.OpenApi.Client; -using OpenApiClientTests.LegacyClient.GeneratedCode; +using JsonApiDotNetCore.OpenApi.Client.Exceptions; #pragma warning disable AV1008 // Class should not be static diff --git a/test/OpenApiClientTests/LegacyClient/ResponseTests.cs b/test/OpenApiClientTests/LegacyClient/ResponseTests.cs index ee782c0adf..29cb28092c 100644 --- a/test/OpenApiClientTests/LegacyClient/ResponseTests.cs +++ b/test/OpenApiClientTests/LegacyClient/ResponseTests.cs @@ -2,6 +2,7 @@ using System.Net; using FluentAssertions; using FluentAssertions.Specialized; +using JsonApiDotNetCore.OpenApi.Client.Exceptions; using OpenApiClientTests.LegacyClient.GeneratedCode; using Xunit; diff --git a/test/OpenApiClientTests/NamingConvention/KebabCase/GeneratedTypesTests.cs b/test/OpenApiClientTests/NamingConvention/KebabCase/GeneratedTypesTests.cs new file mode 100644 index 0000000000..e6553a2fc7 --- /dev/null +++ b/test/OpenApiClientTests/NamingConvention/KebabCase/GeneratedTypesTests.cs @@ -0,0 +1,80 @@ +using FluentAssertions; +using OpenApiClientTests.NamingConvention.KebabCase.GeneratedCode; +using Xunit; + +namespace OpenApiClientTests.NamingConvention.KebabCase +{ + public sealed class GeneratedTypesTests + { + [Fact] + public void Generated_code_is_named_as_expected() + { + nameof(KebabCaseClient.GetSupermarketCollectionAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketCollectionAsync).Should().NotBeNull(); + nameof(KebabCaseClient.PostSupermarketAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketAsync).Should().NotBeNull(); + nameof(KebabCaseClient.PatchSupermarketAsync).Should().NotBeNull(); + nameof(KebabCaseClient.DeleteSupermarketAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketBackupStoreManagerAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketBackupStoreManagerAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.PatchSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketCashiersAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketCashiersAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.PostSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.PatchSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.DeleteSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketStoreManagerAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketStoreManagerAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.PatchSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); + + nameof(SupermarketCollectionResponseDocument).Should().NotBeNull(); + nameof(LinksInResourceCollectionDocument).Should().NotBeNull(); + nameof(JsonapiObject).Should().NotBeNull(); + nameof(SupermarketDataInResponse).Should().NotBeNull(); + nameof(SupermarketResourceType).Should().NotBeNull(); + nameof(SupermarketAttributesInResponse.NameOfCity).Should().NotBeNull(); + nameof(SupermarketRelationshipsInResponse.StoreManager).Should().NotBeNull(); + nameof(SupermarketRelationshipsInResponse.BackupStoreManager).Should().NotBeNull(); + nameof(LinksInResourceObject).Should().NotBeNull(); + nameof(SupermarketType).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketAsync).Should().NotBeNull(); + nameof(ToOneStaffMemberInResponse).Should().NotBeNull(); + nameof(NullableToOneStaffMemberInResponse).Should().NotBeNull(); + nameof(ToManyStaffMemberInResponse).Should().NotBeNull(); + nameof(LinksInRelationshipObject).Should().NotBeNull(); + nameof(StaffMemberIdentifier).Should().NotBeNull(); + nameof(StaffMemberResourceType).Should().NotBeNull(); + nameof(StaffMemberResourceType.StaffMembers).Should().NotBeNull(); + nameof(SupermarketPrimaryResponseDocument).Should().NotBeNull(); + nameof(LinksInResourceDocument).Should().NotBeNull(); + nameof(StaffMemberSecondaryResponseDocument).Should().NotBeNull(); + nameof(StaffMemberDataInResponse).Should().NotBeNull(); + nameof(StaffMemberAttributesInResponse).Should().NotBeNull(); + nameof(NullableStaffMemberSecondaryResponseDocument).Should().NotBeNull(); + nameof(StaffMemberCollectionResponseDocument).Should().NotBeNull(); + nameof(StaffMemberIdentifierResponseDocument).Should().NotBeNull(); + nameof(LinksInResourceIdentifierDocument).Should().NotBeNull(); + nameof(NullableStaffMemberIdentifierResponseDocument).Should().NotBeNull(); + nameof(StaffMemberIdentifierCollectionResponseDocument).Should().NotBeNull(); + nameof(LinksInResourceIdentifierCollectionDocument).Should().NotBeNull(); + nameof(SupermarketPostRequestDocument).Should().NotBeNull(); + nameof(SupermarketDataInPostRequest).Should().NotBeNull(); + nameof(SupermarketAttributesInPostRequest).Should().NotBeNull(); + nameof(SupermarketRelationshipsInPostRequest).Should().NotBeNull(); + nameof(ToOneStaffMemberInRequest).Should().NotBeNull(); + nameof(NullableToOneStaffMemberInRequest).Should().NotBeNull(); + nameof(ToManyStaffMemberInRequest).Should().NotBeNull(); + nameof(SupermarketPatchRequestDocument).Should().NotBeNull(); + nameof(SupermarketDataInPatchRequest).Should().NotBeNull(); + nameof(SupermarketAttributesInPatchRequest).Should().NotBeNull(); + nameof(SupermarketRelationshipsInPatchRequest).Should().NotBeNull(); + } + } +} diff --git a/test/OpenApiTests/NamingConvention/KebabCase/swagger.json b/test/OpenApiTests/NamingConvention/KebabCase/swagger.json index e1de5e7b69..1013e900a8 100644 --- a/test/OpenApiTests/NamingConvention/KebabCase/swagger.json +++ b/test/OpenApiTests/NamingConvention/KebabCase/swagger.json @@ -734,7 +734,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -880,7 +880,7 @@ "type": "array" } ], - "items": {} + "items": { } }, "nullable": true }, @@ -903,7 +903,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -933,7 +933,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -984,7 +984,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -1017,7 +1017,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -1050,7 +1050,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -1086,7 +1086,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -1109,7 +1109,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -1138,7 +1138,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -1203,7 +1203,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -1279,7 +1279,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -1320,7 +1320,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -1425,7 +1425,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -1456,7 +1456,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false diff --git a/test/TestBuildingBlocks/JsonElementAssertions.cs b/test/TestBuildingBlocks/JsonElementAssertions.cs new file mode 100644 index 0000000000..b7825358e5 --- /dev/null +++ b/test/TestBuildingBlocks/JsonElementAssertions.cs @@ -0,0 +1,33 @@ +using System.Text.Json; +using FluentAssertions.Execution; + +namespace TestBuildingBlocks +{ + public sealed class JsonElementAssertions : JsonElementAssertions + { + internal JsonElementAssertions(JsonElement subject) + : base(subject) + { + } + } + + public class JsonElementAssertions + where TAssertions : JsonElementAssertions + { + /// + /// - Gets the object which value is being asserted. + /// + private JsonElement Subject { get; } + + protected JsonElementAssertions(JsonElement subject) + { + Subject = subject; + } + + public void HaveProperty(string propertyName, string because = "", params object[] becauseArgs) + { + Execute.Assertion.ForCondition(Subject.TryGetProperty(propertyName, out _)).BecauseOf(because, becauseArgs) + .FailWith($"Expected element to have property with name '{propertyName}, but did not find it."); + } + } +} diff --git a/test/TestBuildingBlocks/TestBuildingBlocks.csproj b/test/TestBuildingBlocks/TestBuildingBlocks.csproj index f04147ab36..0cf2fec525 100644 --- a/test/TestBuildingBlocks/TestBuildingBlocks.csproj +++ b/test/TestBuildingBlocks/TestBuildingBlocks.csproj @@ -1,4 +1,4 @@ - + $(TargetFrameworkName) From 9f9f1ab8b3a2b4f05b9cf281c1e91846f61bb1e8 Mon Sep 17 00:00:00 2001 From: maurei Date: Wed, 8 Dec 2021 11:50:52 +0100 Subject: [PATCH 03/15] Added annotations to JsonApiObject types --- .../Documents/NullableResourceIdentifierResponseDocument.cs | 6 ++++++ .../Documents/NullableSecondaryResourceResponseDocument.cs | 4 ++++ .../Documents/PrimaryResourceResponseDocument.cs | 6 ++++-- .../Documents/ResourceCollectionResponseDocument.cs | 4 ++++ .../ResourceIdentifierCollectionResponseDocument.cs | 4 ++++ .../Documents/ResourceIdentifierResponseDocument.cs | 4 ++++ .../Documents/SecondaryResourceResponseDocument.cs | 4 ++++ .../JsonApiObjects/JsonapiObject.cs | 5 +++++ src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ManyData.cs | 2 ++ .../JsonApiObjects/NullableSingleData.cs | 2 ++ .../Relationships/NullableToOneRelationshipInResponse.cs | 3 +++ .../Relationships/ToManyRelationshipInResponse.cs | 3 +++ .../Relationships/ToOneRelationshipInResponse.cs | 3 +++ .../ResourceObjects/ResourceIdentifierObject.cs | 3 +++ .../ResourceObjects/ResourceObjectInPatchRequest.cs | 3 +++ .../ResourceObjects/ResourceObjectInPostRequest.cs | 3 +++ .../ResourceObjects/ResourceObjectInResponse.cs | 5 +++++ src/JsonApiDotNetCore.OpenApi/JsonApiObjects/SingleData.cs | 2 ++ .../Objects/{JsonApiObject.cs => JsonapiObject.cs} | 0 19 files changed, 64 insertions(+), 2 deletions(-) rename src/JsonApiDotNetCore/Serialization/Objects/{JsonApiObject.cs => JsonapiObject.cs} (100%) diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/NullableResourceIdentifierResponseDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/NullableResourceIdentifierResponseDocument.cs index 2eb2bff44d..ca04d0f853 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/NullableResourceIdentifierResponseDocument.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/NullableResourceIdentifierResponseDocument.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects; @@ -6,14 +7,19 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents; +// Types in the current namespace are never touched by ASP.NET ModelState validation, therefore using a non-nullable reference type for a property does not +// imply this property is required. Instead, we use [Required] explicitly, because this is how Swashbuckle is instructed to mark properties as required. [UsedImplicitly(ImplicitUseTargetFlags.Members)] internal sealed class NullableResourceIdentifierResponseDocument : NullableSingleData> where TResource : IIdentifiable { + [JsonPropertyName("meta")] public IDictionary Meta { get; set; } = null!; + [JsonPropertyName("jsonapi")] public JsonapiObject Jsonapi { get; set; } = null!; [Required] + [JsonPropertyName("links")] public LinksInResourceIdentifierDocument Links { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/NullableSecondaryResourceResponseDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/NullableSecondaryResourceResponseDocument.cs index 383e8301e9..93334854e0 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/NullableSecondaryResourceResponseDocument.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/NullableSecondaryResourceResponseDocument.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects; @@ -10,10 +11,13 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents; internal sealed class NullableSecondaryResourceResponseDocument : NullableSingleData> where TResource : IIdentifiable { + [JsonPropertyName("meta")] public IDictionary Meta { get; set; } = null!; + [JsonPropertyName("jsonapi")] public JsonapiObject Jsonapi { get; set; } = null!; [Required] + [JsonPropertyName("links")] public LinksInResourceDocument Links { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/PrimaryResourceResponseDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/PrimaryResourceResponseDocument.cs index f708972a94..fd34d149d9 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/PrimaryResourceResponseDocument.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/PrimaryResourceResponseDocument.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects; @@ -6,16 +7,17 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents; -// Types in the current namespace are never touched by ASP.NET ModelState validation, therefore using a non-nullable reference type for a property does not -// imply this property is required. Instead, we use [Required] explicitly, because this is how Swashbuckle is instructed to mark properties as required. [UsedImplicitly(ImplicitUseTargetFlags.Members)] internal sealed class PrimaryResourceResponseDocument : SingleData> where TResource : IIdentifiable { + [JsonPropertyName("meta")] public IDictionary Meta { get; set; } = null!; + [JsonPropertyName("jsonapi")] public JsonapiObject Jsonapi { get; set; } = null!; [Required] + [JsonPropertyName("links")] public LinksInResourceDocument Links { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceCollectionResponseDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceCollectionResponseDocument.cs index 92bbc88803..7547718523 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceCollectionResponseDocument.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceCollectionResponseDocument.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects; @@ -10,10 +11,13 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents; internal sealed class ResourceCollectionResponseDocument : ManyData> where TResource : IIdentifiable { + [JsonPropertyName("meta")] public IDictionary Meta { get; set; } = null!; + [JsonPropertyName("jsonapi")] public JsonapiObject Jsonapi { get; set; } = null!; [Required] + [JsonPropertyName("links")] public LinksInResourceCollectionDocument Links { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceIdentifierCollectionResponseDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceIdentifierCollectionResponseDocument.cs index 1efa833988..f2b0f3a885 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceIdentifierCollectionResponseDocument.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceIdentifierCollectionResponseDocument.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects; @@ -10,10 +11,13 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents; internal sealed class ResourceIdentifierCollectionResponseDocument : ManyData> where TResource : IIdentifiable { + [JsonPropertyName("meta")] public IDictionary Meta { get; set; } = null!; + [JsonPropertyName("jsonapi")] public JsonapiObject Jsonapi { get; set; } = null!; [Required] + [JsonPropertyName("links")] public LinksInResourceIdentifierCollectionDocument Links { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceIdentifierResponseDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceIdentifierResponseDocument.cs index bf87717555..1c99cbd517 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceIdentifierResponseDocument.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/ResourceIdentifierResponseDocument.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects; @@ -10,10 +11,13 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents; internal sealed class ResourceIdentifierResponseDocument : SingleData> where TResource : IIdentifiable { + [JsonPropertyName("meta")] public IDictionary Meta { get; set; } = null!; + [JsonPropertyName("jsonapi")] public JsonapiObject Jsonapi { get; set; } = null!; [Required] + [JsonPropertyName("links")] public LinksInResourceIdentifierDocument Links { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/SecondaryResourceResponseDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/SecondaryResourceResponseDocument.cs index 1cb601c87d..c048b34dfb 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/SecondaryResourceResponseDocument.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Documents/SecondaryResourceResponseDocument.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects; @@ -10,10 +11,13 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Documents; internal sealed class SecondaryResourceResponseDocument : SingleData> where TResource : IIdentifiable { + [JsonPropertyName("meta")] public IDictionary Meta { get; set; } = null!; + [JsonPropertyName("jsonapi")] public JsonapiObject Jsonapi { get; set; } = null!; [Required] + [JsonPropertyName("links")] public LinksInResourceDocument Links { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/JsonapiObject.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/JsonapiObject.cs index 1c7b497cb2..8ad3074e4f 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/JsonapiObject.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/JsonapiObject.cs @@ -1,3 +1,4 @@ +using System.Text.Json.Serialization; using JetBrains.Annotations; namespace JsonApiDotNetCore.OpenApi.JsonApiObjects; @@ -5,11 +6,15 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects; [UsedImplicitly(ImplicitUseTargetFlags.Members)] internal sealed class JsonapiObject { + [JsonPropertyName("version")] public string Version { get; set; } = null!; + [JsonPropertyName("ext")] public ICollection Ext { get; set; } = null!; + [JsonPropertyName("profile")] public ICollection Profile { get; set; } = null!; + [JsonPropertyName("meta")] public IDictionary Meta { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ManyData.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ManyData.cs index 6d345efe5f..5f80fd0f2b 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ManyData.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ManyData.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects; @@ -9,5 +10,6 @@ internal abstract class ManyData where TData : ResourceIdentifierObject { [Required] + [JsonPropertyName("data")] public ICollection Data { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/NullableSingleData.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/NullableSingleData.cs index 600bdf43b9..27063648cb 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/NullableSingleData.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/NullableSingleData.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects; @@ -9,5 +10,6 @@ internal abstract class NullableSingleData where TData : ResourceIdentifierObject { [Required] + [JsonPropertyName("data")] public TData? Data { get; set; } } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/NullableToOneRelationshipInResponse.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/NullableToOneRelationshipInResponse.cs index ed0cbd22fd..fdc45b811a 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/NullableToOneRelationshipInResponse.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/NullableToOneRelationshipInResponse.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects; @@ -11,7 +12,9 @@ internal sealed class NullableToOneRelationshipInResponse : NullableS where TResource : IIdentifiable { [Required] + [JsonPropertyName("links")] public LinksInRelationshipObject Links { get; set; } = null!; + [JsonPropertyName("meta")] public IDictionary Meta { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/ToManyRelationshipInResponse.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/ToManyRelationshipInResponse.cs index 381e484f0b..14380f025e 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/ToManyRelationshipInResponse.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/ToManyRelationshipInResponse.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects; @@ -11,7 +12,9 @@ internal sealed class ToManyRelationshipInResponse : ManyData Meta { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/ToOneRelationshipInResponse.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/ToOneRelationshipInResponse.cs index 962091a469..a867dffdc0 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/ToOneRelationshipInResponse.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Relationships/ToOneRelationshipInResponse.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects; @@ -11,7 +12,9 @@ internal sealed class ToOneRelationshipInResponse : SingleData Meta { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceIdentifierObject.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceIdentifierObject.cs index 5024c3ed44..783a94d647 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceIdentifierObject.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceIdentifierObject.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; using JsonApiDotNetCore.Resources; @@ -14,8 +15,10 @@ internal sealed class ResourceIdentifierObject : ResourceIdentifierOb internal class ResourceIdentifierObject { [Required] + [JsonPropertyName("type")] public string Type { get; set; } = null!; [Required] + [JsonPropertyName("id")] public string Id { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInPatchRequest.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInPatchRequest.cs index fadb20969e..7263ededd4 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInPatchRequest.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInPatchRequest.cs @@ -1,3 +1,4 @@ +using System.Text.Json.Serialization; using JetBrains.Annotations; using JsonApiDotNetCore.Resources; @@ -7,7 +8,9 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects; internal sealed class ResourceObjectInPatchRequest : ResourceIdentifierObject where TResource : IIdentifiable { + [JsonPropertyName("attributes")] public AttributesInPatchRequest Attributes { get; set; } = null!; + [JsonPropertyName("relationships")] public RelationshipsInPatchRequest Relationships { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInPostRequest.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInPostRequest.cs index 71ad0f34c9..f886883b4e 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInPostRequest.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInPostRequest.cs @@ -1,3 +1,4 @@ +using System.Text.Json.Serialization; using JetBrains.Annotations; using JsonApiDotNetCore.Resources; @@ -7,7 +8,9 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects; internal sealed class ResourceObjectInPostRequest : ResourceIdentifierObject where TResource : IIdentifiable { + [JsonPropertyName("attributes")] public AttributesInPostRequest Attributes { get; set; } = null!; + [JsonPropertyName("relationships")] public RelationshipsInPostRequest Relationships { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInResponse.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInResponse.cs index 30bf3d0ff6..ae61d9822c 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInResponse.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/ResourceObjects/ResourceObjectInResponse.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; using JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; using JsonApiDotNetCore.Resources; @@ -9,12 +10,16 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects; internal sealed class ResourceObjectInResponse : ResourceIdentifierObject where TResource : IIdentifiable { + [JsonPropertyName("attributes")] public AttributesInResponse Attributes { get; set; } = null!; + [JsonPropertyName("relationships")] public RelationshipsInResponse Relationships { get; set; } = null!; [Required] + [JsonPropertyName("links")] public LinksInResourceObject Links { get; set; } = null!; + [JsonPropertyName("meta")] public IDictionary Meta { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/SingleData.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/SingleData.cs index 9ba0cd4416..019fc58c2d 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/SingleData.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/SingleData.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; using JsonApiDotNetCore.OpenApi.JsonApiObjects.ResourceObjects; @@ -9,5 +10,6 @@ internal abstract class SingleData where TData : ResourceIdentifierObject { [Required] + [JsonPropertyName("data")] public TData Data { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore/Serialization/Objects/JsonApiObject.cs b/src/JsonApiDotNetCore/Serialization/Objects/JsonapiObject.cs similarity index 100% rename from src/JsonApiDotNetCore/Serialization/Objects/JsonApiObject.cs rename to src/JsonApiDotNetCore/Serialization/Objects/JsonapiObject.cs From 842a71ba7aec0c4856a71f04cebf53f0068b3340 Mon Sep 17 00:00:00 2001 From: maurei Date: Wed, 8 Dec 2021 12:42:11 +0100 Subject: [PATCH 04/15] Added tests for pascal and camelcase and introduced fixes to make them work. --- .../JsonApiOperationIdSelector.cs | 18 +- .../StringExtensions.cs | 11 + ...lientAttributeRegistrationLifeTimeTests.cs | 26 +- .../LegacyClient/RequestTests.cs | 24 +- .../LegacyClient/ResponseTests.cs | 34 +- .../CamelCase/GeneratedTypesTests.cs | 78 + .../KebabCase/GeneratedTypesTests.cs | 141 +- .../PascalCase/GeneratedTypesTests.cs | 78 + .../OpenApiClientTests.csproj | 20 + .../LegacyOpenApiIntegration/swagger.json | 44 +- .../CamelCaseNamingConventionStartup.cs | 21 + .../CamelCase/CamelCaseTests.cs | 527 ++++++ .../NamingConvention/CamelCase/swagger.json | 1466 +++++++++++++++++ .../KebabCase/KebabCaseTests.cs | 178 +- .../PascalCaseNamingConventionStartup.cs | 20 + .../PascalCase/PascalCaseTests.cs | 527 ++++++ .../NamingConvention/PascalCase/swagger.json | 1466 +++++++++++++++++ .../NamingConvention/SupermarketType.cs | 3 + test/OpenApiTests/OpenApiTestContext.cs | 59 + test/OpenApiTests/swagger.json | 1466 +++++++++++++++++ .../JsonElementAssertions.cs | 33 - 21 files changed, 5928 insertions(+), 312 deletions(-) create mode 100644 src/JsonApiDotNetCore.OpenApi/StringExtensions.cs create mode 100644 test/OpenApiClientTests/NamingConvention/CamelCase/GeneratedTypesTests.cs create mode 100644 test/OpenApiClientTests/NamingConvention/PascalCase/GeneratedTypesTests.cs create mode 100644 test/OpenApiTests/NamingConvention/CamelCase/CamelCaseNamingConventionStartup.cs create mode 100644 test/OpenApiTests/NamingConvention/CamelCase/CamelCaseTests.cs create mode 100644 test/OpenApiTests/NamingConvention/CamelCase/swagger.json create mode 100644 test/OpenApiTests/NamingConvention/PascalCase/PascalCaseNamingConventionStartup.cs create mode 100644 test/OpenApiTests/NamingConvention/PascalCase/PascalCaseTests.cs create mode 100644 test/OpenApiTests/NamingConvention/PascalCase/swagger.json create mode 100644 test/OpenApiTests/OpenApiTestContext.cs create mode 100644 test/OpenApiTests/swagger.json delete mode 100644 test/TestBuildingBlocks/JsonElementAssertions.cs diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiOperationIdSelector.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiOperationIdSelector.cs index 7e3e2572a5..353433e706 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiOperationIdSelector.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiOperationIdSelector.cs @@ -36,7 +36,6 @@ internal sealed class JsonApiOperationIdSelector private readonly IControllerResourceMapping _controllerResourceMapping; private readonly JsonNamingPolicy? _namingPolicy; - private readonly ResourceNameFormatter _formatter; public JsonApiOperationIdSelector(IControllerResourceMapping controllerResourceMapping, JsonNamingPolicy? namingPolicy) { @@ -44,7 +43,6 @@ public JsonApiOperationIdSelector(IControllerResourceMapping controllerResourceM _controllerResourceMapping = controllerResourceMapping; _namingPolicy = namingPolicy; - _formatter = new ResourceNameFormatter(namingPolicy); } public string GetOperationId(ApiDescription endpoint) @@ -60,7 +58,7 @@ public string GetOperationId(ApiDescription endpoint) string template = GetTemplate(primaryResourceType.ClrType, endpoint); - return ApplyTemplate(template, primaryResourceType.ClrType, endpoint); + return ApplyTemplate(template, primaryResourceType, endpoint); } private static string GetTemplate(Type resourceClrType, ApiDescription endpoint) @@ -107,28 +105,28 @@ private static Type GetDocumentType(Type primaryResourceClrType, ApiDescription return type.IsConstructedGenericType ? type.GetGenericTypeDefinition() : null; } - private string ApplyTemplate(string operationIdTemplate, Type resourceClrType, ApiDescription endpoint) + private string ApplyTemplate(string operationIdTemplate, ResourceType resourceType, ApiDescription endpoint) { if (endpoint.RelativePath == null || endpoint.HttpMethod == null) { throw new UnreachableCodeException(); } - string method = endpoint.HttpMethod.ToLowerInvariant(); - string primaryResourceName = _formatter.FormatResourceName(resourceClrType).Singularize(); + string method = endpoint.HttpMethod!.ToLowerInvariant(); string relationshipName = operationIdTemplate.Contains("[RelationshipName]") ? endpoint.RelativePath.Split("/").Last() : string.Empty; // @formatter:wrap_chained_method_calls chop_always // @formatter:keep_existing_linebreaks true - string pascalCaseId = operationIdTemplate + string pascalCaseOperationId = operationIdTemplate .Replace("[Method]", method) - .Replace("[PrimaryResourceName]", primaryResourceName) - .Replace("[RelationshipName]", relationshipName); + .Replace("[PrimaryResourceName]", resourceType.PublicName.Singularize()) + .Replace("[RelationshipName]", relationshipName) + .Pascalize(); // @formatter:keep_existing_linebreaks restore // @formatter:wrap_chained_method_calls restore - return _namingPolicy != null ? _namingPolicy.ConvertName(pascalCaseId) : pascalCaseId; + return _namingPolicy != null ? _namingPolicy.ConvertName(pascalCaseOperationId) : pascalCaseOperationId; } } diff --git a/src/JsonApiDotNetCore.OpenApi/StringExtensions.cs b/src/JsonApiDotNetCore.OpenApi/StringExtensions.cs new file mode 100644 index 0000000000..14a992c461 --- /dev/null +++ b/src/JsonApiDotNetCore.OpenApi/StringExtensions.cs @@ -0,0 +1,11 @@ +using System.Text.RegularExpressions; + +namespace JsonApiDotNetCore.OpenApi; + +internal static class StringExtensions +{ + public static string Pascalize(this string source) + { + return Regex.Replace(source, "(?:^|-|_| +)(.)", match => match.Groups[1].Value.ToUpper()); + } +} diff --git a/test/OpenApiClientTests/LegacyClient/ClientAttributeRegistrationLifeTimeTests.cs b/test/OpenApiClientTests/LegacyClient/ClientAttributeRegistrationLifeTimeTests.cs index c164aafd0f..4582f9578d 100644 --- a/test/OpenApiClientTests/LegacyClient/ClientAttributeRegistrationLifeTimeTests.cs +++ b/test/OpenApiClientTests/LegacyClient/ClientAttributeRegistrationLifeTimeTests.cs @@ -22,7 +22,7 @@ public async Task Disposed_attribute_registration_for_document_does_not_affect_r Data = new AirplaneDataInPatchRequest { Id = airplaneId, - Type = AirplanesResourceType.Airplanes, + Type = AirplaneResourceType.Airplanes, Attributes = new AirplaneAttributesInPatchRequest() } }; @@ -64,7 +64,7 @@ public async Task Attribute_registration_can_be_used_for_multiple_requests() Data = new AirplaneDataInPatchRequest { Id = airplaneId, - Type = AirplanesResourceType.Airplanes, + Type = AirplaneResourceType.Airplanes, Attributes = new AirplaneAttributesInPatchRequest { AirtimeInHours = 100 @@ -111,7 +111,7 @@ public async Task Request_is_unaffected_by_attribute_registration_for_different_ Data = new AirplaneDataInPatchRequest { Id = airplaneId1, - Type = AirplanesResourceType.Airplanes, + Type = AirplaneResourceType.Airplanes, Attributes = new AirplaneAttributesInPatchRequest() } }; @@ -123,7 +123,7 @@ public async Task Request_is_unaffected_by_attribute_registration_for_different_ Data = new AirplaneDataInPatchRequest { Id = airplaneId2, - Type = AirplanesResourceType.Airplanes, + Type = AirplaneResourceType.Airplanes, Attributes = new AirplaneAttributesInPatchRequest() } }; @@ -166,7 +166,7 @@ public async Task Attribute_values_can_be_changed_after_attribute_registration() Data = new AirplaneDataInPatchRequest { Id = airplaneId, - Type = AirplanesResourceType.Airplanes, + Type = AirplaneResourceType.Airplanes, Attributes = new AirplaneAttributesInPatchRequest { IsInMaintenance = true @@ -209,7 +209,7 @@ public async Task Attribute_registration_is_unaffected_by_successive_attribute_r Data = new AirplaneDataInPatchRequest { Id = airplaneId1, - Type = AirplanesResourceType.Airplanes, + Type = AirplaneResourceType.Airplanes, Attributes = new AirplaneAttributesInPatchRequest() } }; @@ -218,7 +218,7 @@ public async Task Attribute_registration_is_unaffected_by_successive_attribute_r { Data = new AirplaneDataInPostRequest { - Type = AirplanesResourceType.Airplanes, + Type = AirplaneResourceType.Airplanes, Attributes = new AirplaneAttributesInPostRequest() } }; @@ -260,7 +260,7 @@ public async Task Attribute_registration_is_unaffected_by_preceding_disposed_att Data = new AirplaneDataInPatchRequest { Id = airplaneId1, - Type = AirplanesResourceType.Airplanes, + Type = AirplaneResourceType.Airplanes, Attributes = new AirplaneAttributesInPatchRequest() } }; @@ -278,7 +278,7 @@ public async Task Attribute_registration_is_unaffected_by_preceding_disposed_att Data = new AirplaneDataInPatchRequest { Id = airplaneId2, - Type = AirplanesResourceType.Airplanes, + Type = AirplaneResourceType.Airplanes, Attributes = new AirplaneAttributesInPatchRequest { ManufacturedInCity = "Everett" @@ -319,7 +319,7 @@ public async Task Attribute_registration_is_unaffected_by_preceding_disposed_att { Data = new AirplaneDataInPostRequest { - Type = AirplanesResourceType.Airplanes, + Type = AirplaneResourceType.Airplanes, Attributes = new AirplaneAttributesInPostRequest() } }; @@ -337,7 +337,7 @@ public async Task Attribute_registration_is_unaffected_by_preceding_disposed_att Data = new AirplaneDataInPatchRequest { Id = airplaneId, - Type = AirplanesResourceType.Airplanes, + Type = AirplaneResourceType.Airplanes, Attributes = new AirplaneAttributesInPatchRequest { ManufacturedInCity = "Everett" @@ -381,7 +381,7 @@ public async Task Attribute_registration_is_unaffected_by_preceding_attribute_re Data = new AirplaneDataInPatchRequest { Id = airplaneId1, - Type = AirplanesResourceType.Airplanes, + Type = AirplaneResourceType.Airplanes, Attributes = new AirplaneAttributesInPatchRequest() } }; @@ -393,7 +393,7 @@ public async Task Attribute_registration_is_unaffected_by_preceding_attribute_re Data = new AirplaneDataInPatchRequest { Id = airplaneId2, - Type = AirplanesResourceType.Airplanes, + Type = AirplaneResourceType.Airplanes, Attributes = new AirplaneAttributesInPatchRequest() } }; diff --git a/test/OpenApiClientTests/LegacyClient/RequestTests.cs b/test/OpenApiClientTests/LegacyClient/RequestTests.cs index 831dfda3f7..e03e8f1015 100644 --- a/test/OpenApiClientTests/LegacyClient/RequestTests.cs +++ b/test/OpenApiClientTests/LegacyClient/RequestTests.cs @@ -63,7 +63,7 @@ public async Task Partial_posting_resource_with_selected_relationships_produces_ { Data = new FlightDataInPostRequest { - Type = FlightsResourceType.Flights, + Type = FlightResourceType.Flights, Relationships = new FlightRelationshipsInPostRequest { Purser = new ToOneFlightAttendantInRequest @@ -71,7 +71,7 @@ public async Task Partial_posting_resource_with_selected_relationships_produces_ Data = new FlightAttendantIdentifier { Id = "bBJHu", - Type = FlightAttendantsResourceType.FlightAttendants + Type = FlightAttendantResourceType.FlightAttendants } }, BackupPurser = new NullableToOneFlightAttendantInRequest @@ -79,7 +79,7 @@ public async Task Partial_posting_resource_with_selected_relationships_produces_ Data = new FlightAttendantIdentifier { Id = "NInmX", - Type = FlightAttendantsResourceType.FlightAttendants + Type = FlightAttendantResourceType.FlightAttendants } } } @@ -143,7 +143,7 @@ public async Task Partial_posting_resource_produces_expected_request() { Data = new AirplaneDataInPostRequest { - Type = AirplanesResourceType.Airplanes, + Type = AirplaneResourceType.Airplanes, Attributes = new AirplaneAttributesInPostRequest { Name = name, @@ -195,7 +195,7 @@ public async Task Partial_patching_resource_produces_expected_request() Data = new AirplaneDataInPatchRequest { Id = airplaneId, - Type = AirplanesResourceType.Airplanes, + Type = AirplaneResourceType.Airplanes, Attributes = new AirplaneAttributesInPatchRequest { LastServicedAt = lastServicedAt @@ -326,7 +326,7 @@ public async Task Patching_ToOne_relationship_produces_expected_request() Data = new FlightAttendantIdentifier { Id = "bBJHu", - Type = FlightAttendantsResourceType.FlightAttendants + Type = FlightAttendantResourceType.FlightAttendants } }; @@ -384,12 +384,12 @@ public async Task Posting_ToMany_relationship_produces_expected_request() { new() { - Type = FlightAttendantsResourceType.FlightAttendants, + Type = FlightAttendantResourceType.FlightAttendants, Id = "bBJHu" }, new() { - Type = FlightAttendantsResourceType.FlightAttendants, + Type = FlightAttendantResourceType.FlightAttendants, Id = "NInmX" } } @@ -436,12 +436,12 @@ public async Task Patching_ToMany_relationship_produces_expected_request() new() { Id = "bBJHu", - Type = FlightAttendantsResourceType.FlightAttendants + Type = FlightAttendantResourceType.FlightAttendants }, new() { Id = "NInmX", - Type = FlightAttendantsResourceType.FlightAttendants + Type = FlightAttendantResourceType.FlightAttendants } } }; @@ -487,12 +487,12 @@ public async Task Deleting_ToMany_relationship_produces_expected_request() new() { Id = "bBJHu", - Type = FlightAttendantsResourceType.FlightAttendants + Type = FlightAttendantResourceType.FlightAttendants }, new() { Id = "NInmX", - Type = FlightAttendantsResourceType.FlightAttendants + Type = FlightAttendantResourceType.FlightAttendants } } }; diff --git a/test/OpenApiClientTests/LegacyClient/ResponseTests.cs b/test/OpenApiClientTests/LegacyClient/ResponseTests.cs index 29cb28092c..10f86adca5 100644 --- a/test/OpenApiClientTests/LegacyClient/ResponseTests.cs +++ b/test/OpenApiClientTests/LegacyClient/ResponseTests.cs @@ -109,7 +109,7 @@ public async Task Getting_resource_collection_translates_response() FlightDataInResponse flight = document.Data.First(); flight.Id.Should().Be(flightId); - flight.Type.Should().Be(FlightsResourceType.Flights); + flight.Type.Should().Be(FlightResourceType.Flights); flight.Links.Self.Should().Be(flightResourceLink); flight.Meta.Should().HaveCount(1); flight.Meta["docs"].Should().Be(flightMetaValue); @@ -277,7 +277,7 @@ public async Task Posting_resource_translates_response() { Data = new FlightDataInPostRequest { - Type = FlightsResourceType.Flights, + Type = FlightResourceType.Flights, Relationships = new FlightRelationshipsInPostRequest { Purser = new ToOneFlightAttendantInRequest @@ -285,7 +285,7 @@ public async Task Posting_resource_translates_response() Data = new FlightAttendantIdentifier { Id = flightAttendantId, - Type = FlightAttendantsResourceType.FlightAttendants + Type = FlightAttendantResourceType.FlightAttendants } } } @@ -298,7 +298,7 @@ public async Task Posting_resource_translates_response() document.Data.Relationships.Purser.Data.Id.Should().Be(flightAttendantId); document.Data.Relationships.CabinCrewMembers.Data.Should().HaveCount(1); document.Data.Relationships.CabinCrewMembers.Data.First().Id.Should().Be(flightAttendantId); - document.Data.Relationships.CabinCrewMembers.Data.First().Type.Should().Be(FlightAttendantsResourceType.FlightAttendants); + document.Data.Relationships.CabinCrewMembers.Data.First().Type.Should().Be(FlightAttendantResourceType.FlightAttendants); document.Data.Relationships.Passengers.Data.Should().BeEmpty(); } @@ -330,12 +330,12 @@ public async Task Patching_resource_with_side_effects_translates_response() Data = new FlightDataInPatchRequest { Id = flightId, - Type = FlightsResourceType.Flights + Type = FlightResourceType.Flights } }); // Assert - document.Data.Type.Should().Be(FlightsResourceType.Flights); + document.Data.Type.Should().Be(FlightResourceType.Flights); document.Data.Attributes.Should().BeNull(); document.Data.Relationships.Should().BeNull(); } @@ -355,7 +355,7 @@ public async Task Patching_resource_without_side_effects_translates_response() Data = new FlightDataInPatchRequest { Id = flightId, - Type = FlightsResourceType.Flights + Type = FlightResourceType.Flights } })); @@ -538,7 +538,7 @@ public async Task Getting_ToOne_relationship_translates_response() // Assert document.Data.Should().NotBeNull(); document.Data.Id.Should().Be(purserId); - document.Data.Type.Should().Be(FlightAttendantsResourceType.FlightAttendants); + document.Data.Type.Should().Be(FlightAttendantResourceType.FlightAttendants); } [Fact] @@ -554,7 +554,7 @@ public async Task Patching_ToOne_relationship_translates_response() Data = new FlightAttendantIdentifier { Id = "Adk2a", - Type = FlightAttendantsResourceType.FlightAttendants + Type = FlightAttendantResourceType.FlightAttendants } }); } @@ -592,9 +592,9 @@ public async Task Getting_ToMany_relationship_translates_response() // Assert document.Data.Should().HaveCount(2); document.Data.First().Id.Should().Be(flightAttendantId1); - document.Data.First().Type.Should().Be(FlightAttendantsResourceType.FlightAttendants); + document.Data.First().Type.Should().Be(FlightAttendantResourceType.FlightAttendants); document.Data.Last().Id.Should().Be(flightAttendantId2); - document.Data.Last().Type.Should().Be(FlightAttendantsResourceType.FlightAttendants); + document.Data.Last().Type.Should().Be(FlightAttendantResourceType.FlightAttendants); } [Fact] @@ -612,12 +612,12 @@ public async Task Posting_ToMany_relationship_produces_empty_response() new() { Id = "Adk2a", - Type = FlightAttendantsResourceType.FlightAttendants + Type = FlightAttendantResourceType.FlightAttendants }, new() { Id = "Un37k", - Type = FlightAttendantsResourceType.FlightAttendants + Type = FlightAttendantResourceType.FlightAttendants } } }); @@ -641,12 +641,12 @@ public async Task Patching_ToMany_relationship_produces_empty_response() new() { Id = "Adk2a", - Type = FlightAttendantsResourceType.FlightAttendants + Type = FlightAttendantResourceType.FlightAttendants }, new() { Id = "Un37k", - Type = FlightAttendantsResourceType.FlightAttendants + Type = FlightAttendantResourceType.FlightAttendants } } }); @@ -670,12 +670,12 @@ public async Task Deleting_ToMany_relationship_produces_empty_response() new() { Id = "Adk2a", - Type = FlightAttendantsResourceType.FlightAttendants + Type = FlightAttendantResourceType.FlightAttendants }, new() { Id = "Un37k", - Type = FlightAttendantsResourceType.FlightAttendants + Type = FlightAttendantResourceType.FlightAttendants } } }); diff --git a/test/OpenApiClientTests/NamingConvention/CamelCase/GeneratedTypesTests.cs b/test/OpenApiClientTests/NamingConvention/CamelCase/GeneratedTypesTests.cs new file mode 100644 index 0000000000..37ca4dbe6e --- /dev/null +++ b/test/OpenApiClientTests/NamingConvention/CamelCase/GeneratedTypesTests.cs @@ -0,0 +1,78 @@ +using FluentAssertions; +using OpenApiClientTests.NamingConvention.CamelCase.GeneratedCode; +using Xunit; + +namespace OpenApiClientTests.NamingConvention.CamelCase; + +public sealed class GeneratedTypesTests +{ + [Fact] + public void Generated_code_is_named_as_expected() + { + nameof(CamelCaseClient.GetSupermarketCollectionAsync).Should().NotBeNull(); + nameof(CamelCaseClient.GetSupermarketCollectionAsync).Should().NotBeNull(); + nameof(CamelCaseClient.PostSupermarketAsync).Should().NotBeNull(); + nameof(CamelCaseClient.GetSupermarketAsync).Should().NotBeNull(); + nameof(CamelCaseClient.GetSupermarketAsync).Should().NotBeNull(); + nameof(CamelCaseClient.PatchSupermarketAsync).Should().NotBeNull(); + nameof(CamelCaseClient.DeleteSupermarketAsync).Should().NotBeNull(); + nameof(CamelCaseClient.GetSupermarketBackupStoreManagerAsync).Should().NotBeNull(); + nameof(CamelCaseClient.GetSupermarketBackupStoreManagerAsync).Should().NotBeNull(); + nameof(CamelCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(CamelCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(CamelCaseClient.PatchSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(CamelCaseClient.GetSupermarketCashiersAsync).Should().NotBeNull(); + nameof(CamelCaseClient.GetSupermarketCashiersAsync).Should().NotBeNull(); + nameof(CamelCaseClient.GetSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(CamelCaseClient.GetSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(CamelCaseClient.PostSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(CamelCaseClient.PatchSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(CamelCaseClient.DeleteSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(CamelCaseClient.GetSupermarketStoreManagerAsync).Should().NotBeNull(); + nameof(CamelCaseClient.GetSupermarketStoreManagerAsync).Should().NotBeNull(); + nameof(CamelCaseClient.GetSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(CamelCaseClient.GetSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(CamelCaseClient.PatchSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); + + nameof(SupermarketCollectionResponseDocument).Should().NotBeNull(); + nameof(LinksInResourceCollectionDocument).Should().NotBeNull(); + nameof(JsonapiObject).Should().NotBeNull(); + nameof(SupermarketDataInResponse).Should().NotBeNull(); + nameof(SupermarketResourceType).Should().NotBeNull(); + nameof(SupermarketAttributesInResponse.NameOfCity).Should().NotBeNull(); + nameof(SupermarketRelationshipsInResponse.StoreManager).Should().NotBeNull(); + nameof(SupermarketRelationshipsInResponse.BackupStoreManager).Should().NotBeNull(); + nameof(LinksInResourceObject).Should().NotBeNull(); + nameof(SupermarketType).Should().NotBeNull(); + nameof(CamelCaseClient.GetSupermarketAsync).Should().NotBeNull(); + nameof(ToOneStaffMemberInResponse).Should().NotBeNull(); + nameof(NullableToOneStaffMemberInResponse).Should().NotBeNull(); + nameof(ToManyStaffMemberInResponse).Should().NotBeNull(); + nameof(LinksInRelationshipObject).Should().NotBeNull(); + nameof(StaffMemberIdentifier).Should().NotBeNull(); + nameof(StaffMemberResourceType.StaffMembers).Should().NotBeNull(); + nameof(SupermarketPrimaryResponseDocument).Should().NotBeNull(); + nameof(LinksInResourceDocument).Should().NotBeNull(); + nameof(StaffMemberSecondaryResponseDocument).Should().NotBeNull(); + nameof(StaffMemberDataInResponse).Should().NotBeNull(); + nameof(StaffMemberAttributesInResponse).Should().NotBeNull(); + nameof(NullableStaffMemberSecondaryResponseDocument).Should().NotBeNull(); + nameof(StaffMemberCollectionResponseDocument).Should().NotBeNull(); + nameof(StaffMemberIdentifierResponseDocument).Should().NotBeNull(); + nameof(LinksInResourceIdentifierDocument).Should().NotBeNull(); + nameof(NullableStaffMemberIdentifierResponseDocument).Should().NotBeNull(); + nameof(StaffMemberIdentifierCollectionResponseDocument).Should().NotBeNull(); + nameof(LinksInResourceIdentifierCollectionDocument).Should().NotBeNull(); + nameof(SupermarketPostRequestDocument).Should().NotBeNull(); + nameof(SupermarketDataInPostRequest).Should().NotBeNull(); + nameof(SupermarketAttributesInPostRequest).Should().NotBeNull(); + nameof(SupermarketRelationshipsInPostRequest).Should().NotBeNull(); + nameof(ToOneStaffMemberInRequest).Should().NotBeNull(); + nameof(NullableToOneStaffMemberInRequest).Should().NotBeNull(); + nameof(ToManyStaffMemberInRequest).Should().NotBeNull(); + nameof(SupermarketPatchRequestDocument).Should().NotBeNull(); + nameof(SupermarketDataInPatchRequest).Should().NotBeNull(); + nameof(SupermarketAttributesInPatchRequest).Should().NotBeNull(); + nameof(SupermarketRelationshipsInPatchRequest).Should().NotBeNull(); + } +} diff --git a/test/OpenApiClientTests/NamingConvention/KebabCase/GeneratedTypesTests.cs b/test/OpenApiClientTests/NamingConvention/KebabCase/GeneratedTypesTests.cs index e6553a2fc7..c601ab0ba4 100644 --- a/test/OpenApiClientTests/NamingConvention/KebabCase/GeneratedTypesTests.cs +++ b/test/OpenApiClientTests/NamingConvention/KebabCase/GeneratedTypesTests.cs @@ -2,79 +2,78 @@ using OpenApiClientTests.NamingConvention.KebabCase.GeneratedCode; using Xunit; -namespace OpenApiClientTests.NamingConvention.KebabCase +namespace OpenApiClientTests.NamingConvention.KebabCase; + +public sealed class GeneratedTypesTests { - public sealed class GeneratedTypesTests + [Fact] + public void Generated_code_is_named_as_expected() { - [Fact] - public void Generated_code_is_named_as_expected() - { - nameof(KebabCaseClient.GetSupermarketCollectionAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketCollectionAsync).Should().NotBeNull(); - nameof(KebabCaseClient.PostSupermarketAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketAsync).Should().NotBeNull(); - nameof(KebabCaseClient.PatchSupermarketAsync).Should().NotBeNull(); - nameof(KebabCaseClient.DeleteSupermarketAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketBackupStoreManagerAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketBackupStoreManagerAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.PatchSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketCashiersAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketCashiersAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.PostSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.PatchSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.DeleteSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketStoreManagerAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketStoreManagerAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.PatchSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketCollectionAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketCollectionAsync).Should().NotBeNull(); + nameof(KebabCaseClient.PostSupermarketAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketAsync).Should().NotBeNull(); + nameof(KebabCaseClient.PatchSupermarketAsync).Should().NotBeNull(); + nameof(KebabCaseClient.DeleteSupermarketAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketBackupStoreManagerAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketBackupStoreManagerAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.PatchSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketCashiersAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketCashiersAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.PostSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.PatchSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.DeleteSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketStoreManagerAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketStoreManagerAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(KebabCaseClient.PatchSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(SupermarketCollectionResponseDocument).Should().NotBeNull(); - nameof(LinksInResourceCollectionDocument).Should().NotBeNull(); - nameof(JsonapiObject).Should().NotBeNull(); - nameof(SupermarketDataInResponse).Should().NotBeNull(); - nameof(SupermarketResourceType).Should().NotBeNull(); - nameof(SupermarketAttributesInResponse.NameOfCity).Should().NotBeNull(); - nameof(SupermarketRelationshipsInResponse.StoreManager).Should().NotBeNull(); - nameof(SupermarketRelationshipsInResponse.BackupStoreManager).Should().NotBeNull(); - nameof(LinksInResourceObject).Should().NotBeNull(); - nameof(SupermarketType).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketAsync).Should().NotBeNull(); - nameof(ToOneStaffMemberInResponse).Should().NotBeNull(); - nameof(NullableToOneStaffMemberInResponse).Should().NotBeNull(); - nameof(ToManyStaffMemberInResponse).Should().NotBeNull(); - nameof(LinksInRelationshipObject).Should().NotBeNull(); - nameof(StaffMemberIdentifier).Should().NotBeNull(); - nameof(StaffMemberResourceType).Should().NotBeNull(); - nameof(StaffMemberResourceType.StaffMembers).Should().NotBeNull(); - nameof(SupermarketPrimaryResponseDocument).Should().NotBeNull(); - nameof(LinksInResourceDocument).Should().NotBeNull(); - nameof(StaffMemberSecondaryResponseDocument).Should().NotBeNull(); - nameof(StaffMemberDataInResponse).Should().NotBeNull(); - nameof(StaffMemberAttributesInResponse).Should().NotBeNull(); - nameof(NullableStaffMemberSecondaryResponseDocument).Should().NotBeNull(); - nameof(StaffMemberCollectionResponseDocument).Should().NotBeNull(); - nameof(StaffMemberIdentifierResponseDocument).Should().NotBeNull(); - nameof(LinksInResourceIdentifierDocument).Should().NotBeNull(); - nameof(NullableStaffMemberIdentifierResponseDocument).Should().NotBeNull(); - nameof(StaffMemberIdentifierCollectionResponseDocument).Should().NotBeNull(); - nameof(LinksInResourceIdentifierCollectionDocument).Should().NotBeNull(); - nameof(SupermarketPostRequestDocument).Should().NotBeNull(); - nameof(SupermarketDataInPostRequest).Should().NotBeNull(); - nameof(SupermarketAttributesInPostRequest).Should().NotBeNull(); - nameof(SupermarketRelationshipsInPostRequest).Should().NotBeNull(); - nameof(ToOneStaffMemberInRequest).Should().NotBeNull(); - nameof(NullableToOneStaffMemberInRequest).Should().NotBeNull(); - nameof(ToManyStaffMemberInRequest).Should().NotBeNull(); - nameof(SupermarketPatchRequestDocument).Should().NotBeNull(); - nameof(SupermarketDataInPatchRequest).Should().NotBeNull(); - nameof(SupermarketAttributesInPatchRequest).Should().NotBeNull(); - nameof(SupermarketRelationshipsInPatchRequest).Should().NotBeNull(); - } + nameof(SupermarketCollectionResponseDocument).Should().NotBeNull(); + nameof(LinksInResourceCollectionDocument).Should().NotBeNull(); + nameof(JsonapiObject).Should().NotBeNull(); + nameof(SupermarketDataInResponse).Should().NotBeNull(); + nameof(SupermarketResourceType).Should().NotBeNull(); + nameof(SupermarketAttributesInResponse.NameOfCity).Should().NotBeNull(); + nameof(SupermarketRelationshipsInResponse.StoreManager).Should().NotBeNull(); + nameof(SupermarketRelationshipsInResponse.BackupStoreManager).Should().NotBeNull(); + nameof(LinksInResourceObject).Should().NotBeNull(); + nameof(SupermarketType).Should().NotBeNull(); + nameof(KebabCaseClient.GetSupermarketAsync).Should().NotBeNull(); + nameof(ToOneStaffMemberInResponse).Should().NotBeNull(); + nameof(NullableToOneStaffMemberInResponse).Should().NotBeNull(); + nameof(ToManyStaffMemberInResponse).Should().NotBeNull(); + nameof(LinksInRelationshipObject).Should().NotBeNull(); + nameof(StaffMemberIdentifier).Should().NotBeNull(); + nameof(StaffMemberResourceType).Should().NotBeNull(); + nameof(StaffMemberResourceType.StaffMembers).Should().NotBeNull(); + nameof(SupermarketPrimaryResponseDocument).Should().NotBeNull(); + nameof(LinksInResourceDocument).Should().NotBeNull(); + nameof(StaffMemberSecondaryResponseDocument).Should().NotBeNull(); + nameof(StaffMemberDataInResponse).Should().NotBeNull(); + nameof(StaffMemberAttributesInResponse).Should().NotBeNull(); + nameof(NullableStaffMemberSecondaryResponseDocument).Should().NotBeNull(); + nameof(StaffMemberCollectionResponseDocument).Should().NotBeNull(); + nameof(StaffMemberIdentifierResponseDocument).Should().NotBeNull(); + nameof(LinksInResourceIdentifierDocument).Should().NotBeNull(); + nameof(NullableStaffMemberIdentifierResponseDocument).Should().NotBeNull(); + nameof(StaffMemberIdentifierCollectionResponseDocument).Should().NotBeNull(); + nameof(LinksInResourceIdentifierCollectionDocument).Should().NotBeNull(); + nameof(SupermarketPostRequestDocument).Should().NotBeNull(); + nameof(SupermarketDataInPostRequest).Should().NotBeNull(); + nameof(SupermarketAttributesInPostRequest).Should().NotBeNull(); + nameof(SupermarketRelationshipsInPostRequest).Should().NotBeNull(); + nameof(ToOneStaffMemberInRequest).Should().NotBeNull(); + nameof(NullableToOneStaffMemberInRequest).Should().NotBeNull(); + nameof(ToManyStaffMemberInRequest).Should().NotBeNull(); + nameof(SupermarketPatchRequestDocument).Should().NotBeNull(); + nameof(SupermarketDataInPatchRequest).Should().NotBeNull(); + nameof(SupermarketAttributesInPatchRequest).Should().NotBeNull(); + nameof(SupermarketRelationshipsInPatchRequest).Should().NotBeNull(); } } diff --git a/test/OpenApiClientTests/NamingConvention/PascalCase/GeneratedTypesTests.cs b/test/OpenApiClientTests/NamingConvention/PascalCase/GeneratedTypesTests.cs new file mode 100644 index 0000000000..f1f5e35ea0 --- /dev/null +++ b/test/OpenApiClientTests/NamingConvention/PascalCase/GeneratedTypesTests.cs @@ -0,0 +1,78 @@ +using FluentAssertions; +using OpenApiClientTests.NamingConvention.PascalCase.GeneratedCode; +using Xunit; + +namespace OpenApiClientTests.NamingConvention.PascalCase; + +public sealed class GeneratedTypesTests +{ + [Fact] + public void Generated_code_is_named_as_expected() + { + nameof(PascalCaseClient.GetSupermarketCollectionAsync).Should().NotBeNull(); + nameof(PascalCaseClient.GetSupermarketCollectionAsync).Should().NotBeNull(); + nameof(PascalCaseClient.PostSupermarketAsync).Should().NotBeNull(); + nameof(PascalCaseClient.GetSupermarketAsync).Should().NotBeNull(); + nameof(PascalCaseClient.GetSupermarketAsync).Should().NotBeNull(); + nameof(PascalCaseClient.PatchSupermarketAsync).Should().NotBeNull(); + nameof(PascalCaseClient.DeleteSupermarketAsync).Should().NotBeNull(); + nameof(PascalCaseClient.GetSupermarketBackupStoreManagerAsync).Should().NotBeNull(); + nameof(PascalCaseClient.GetSupermarketBackupStoreManagerAsync).Should().NotBeNull(); + nameof(PascalCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(PascalCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(PascalCaseClient.PatchSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(PascalCaseClient.GetSupermarketCashiersAsync).Should().NotBeNull(); + nameof(PascalCaseClient.GetSupermarketCashiersAsync).Should().NotBeNull(); + nameof(PascalCaseClient.GetSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(PascalCaseClient.GetSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(PascalCaseClient.PostSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(PascalCaseClient.PatchSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(PascalCaseClient.DeleteSupermarketCashiersRelationshipAsync).Should().NotBeNull(); + nameof(PascalCaseClient.GetSupermarketStoreManagerAsync).Should().NotBeNull(); + nameof(PascalCaseClient.GetSupermarketStoreManagerAsync).Should().NotBeNull(); + nameof(PascalCaseClient.GetSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(PascalCaseClient.GetSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); + nameof(PascalCaseClient.PatchSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); + + nameof(SupermarketCollectionResponseDocument).Should().NotBeNull(); + nameof(LinksInResourceCollectionDocument).Should().NotBeNull(); + nameof(JsonapiObject).Should().NotBeNull(); + nameof(SupermarketDataInResponse).Should().NotBeNull(); + nameof(SupermarketResourceType).Should().NotBeNull(); + nameof(SupermarketAttributesInResponse.NameOfCity).Should().NotBeNull(); + nameof(SupermarketRelationshipsInResponse.StoreManager).Should().NotBeNull(); + nameof(SupermarketRelationshipsInResponse.BackupStoreManager).Should().NotBeNull(); + nameof(LinksInResourceObject).Should().NotBeNull(); + nameof(SupermarketType).Should().NotBeNull(); + nameof(PascalCaseClient.GetSupermarketAsync).Should().NotBeNull(); + nameof(ToOneStaffMemberInResponse).Should().NotBeNull(); + nameof(NullableToOneStaffMemberInResponse).Should().NotBeNull(); + nameof(ToManyStaffMemberInResponse).Should().NotBeNull(); + nameof(LinksInRelationshipObject).Should().NotBeNull(); + nameof(StaffMemberIdentifier).Should().NotBeNull(); + nameof(StaffMemberResourceType.StaffMembers).Should().NotBeNull(); + nameof(SupermarketPrimaryResponseDocument).Should().NotBeNull(); + nameof(LinksInResourceDocument).Should().NotBeNull(); + nameof(StaffMemberSecondaryResponseDocument).Should().NotBeNull(); + nameof(StaffMemberDataInResponse).Should().NotBeNull(); + nameof(StaffMemberAttributesInResponse).Should().NotBeNull(); + nameof(NullableStaffMemberSecondaryResponseDocument).Should().NotBeNull(); + nameof(StaffMemberCollectionResponseDocument).Should().NotBeNull(); + nameof(StaffMemberIdentifierResponseDocument).Should().NotBeNull(); + nameof(LinksInResourceIdentifierDocument).Should().NotBeNull(); + nameof(NullableStaffMemberIdentifierResponseDocument).Should().NotBeNull(); + nameof(StaffMemberIdentifierCollectionResponseDocument).Should().NotBeNull(); + nameof(LinksInResourceIdentifierCollectionDocument).Should().NotBeNull(); + nameof(SupermarketPostRequestDocument).Should().NotBeNull(); + nameof(SupermarketDataInPostRequest).Should().NotBeNull(); + nameof(SupermarketAttributesInPostRequest).Should().NotBeNull(); + nameof(SupermarketRelationshipsInPostRequest).Should().NotBeNull(); + nameof(ToOneStaffMemberInRequest).Should().NotBeNull(); + nameof(NullableToOneStaffMemberInRequest).Should().NotBeNull(); + nameof(ToManyStaffMemberInRequest).Should().NotBeNull(); + nameof(SupermarketPatchRequestDocument).Should().NotBeNull(); + nameof(SupermarketDataInPatchRequest).Should().NotBeNull(); + nameof(SupermarketAttributesInPatchRequest).Should().NotBeNull(); + nameof(SupermarketRelationshipsInPatchRequest).Should().NotBeNull(); + } +} diff --git a/test/OpenApiClientTests/OpenApiClientTests.csproj b/test/OpenApiClientTests/OpenApiClientTests.csproj index 5927a4c00e..958049dad4 100644 --- a/test/OpenApiClientTests/OpenApiClientTests.csproj +++ b/test/OpenApiClientTests/OpenApiClientTests.csproj @@ -42,5 +42,25 @@ NSwagCSharp /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions + + OpenApiClientTests.NamingConvention.CamelCase.GeneratedCode + CamelCaseClient + CamelCaseClient.cs + NSwagCSharp + /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions + + + OpenApiClientTests.NamingConvention.PascalCase.GeneratedCode + PascalCaseClient + PascalCaseClient.cs + NSwagCSharp + /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions + + + + + + PreserveNewest + diff --git a/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json b/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json index ac62204a53..805df97adb 100644 --- a/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json +++ b/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json @@ -2043,7 +2043,7 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/airplanes-resource-type" + "$ref": "#/components/schemas/airplane-resource-type" }, "id": { "type": "string" @@ -2064,7 +2064,7 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/airplanes-resource-type" + "$ref": "#/components/schemas/airplane-resource-type" }, "attributes": { "$ref": "#/components/schemas/airplane-attributes-in-post-request" @@ -2084,7 +2084,7 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/airplanes-resource-type" + "$ref": "#/components/schemas/airplane-resource-type" }, "id": { "type": "string" @@ -2179,7 +2179,7 @@ }, "additionalProperties": false }, - "airplanes-resource-type": { + "airplane-resource-type": { "enum": [ "airplanes" ], @@ -2291,7 +2291,7 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/flight-attendants-resource-type" + "$ref": "#/components/schemas/flight-attendant-resource-type" }, "id": { "type": "string" @@ -2312,7 +2312,7 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/flight-attendants-resource-type" + "$ref": "#/components/schemas/flight-attendant-resource-type" }, "attributes": { "$ref": "#/components/schemas/flight-attendant-attributes-in-post-request" @@ -2332,7 +2332,7 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/flight-attendants-resource-type" + "$ref": "#/components/schemas/flight-attendant-resource-type" }, "id": { "type": "string" @@ -2361,7 +2361,7 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/flight-attendants-resource-type" + "$ref": "#/components/schemas/flight-attendant-resource-type" }, "id": { "type": "string" @@ -2501,6 +2501,12 @@ }, "additionalProperties": false }, + "flight-attendant-resource-type": { + "enum": [ + "flight-attendants" + ], + "type": "string" + }, "flight-attendant-secondary-response-document": { "required": [ "data", @@ -2524,12 +2530,6 @@ }, "additionalProperties": false }, - "flight-attendants-resource-type": { - "enum": [ - "flight-attendants" - ], - "type": "string" - }, "flight-attributes-in-patch-request": { "type": "object", "properties": { @@ -2616,7 +2616,7 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/flights-resource-type" + "$ref": "#/components/schemas/flight-resource-type" }, "id": { "type": "string" @@ -2637,7 +2637,7 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/flights-resource-type" + "$ref": "#/components/schemas/flight-resource-type" }, "relationships": { "$ref": "#/components/schemas/flight-relationships-in-post-request" @@ -2654,7 +2654,7 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/flights-resource-type" + "$ref": "#/components/schemas/flight-resource-type" }, "id": { "type": "string" @@ -2683,7 +2683,7 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/flights-resource-type" + "$ref": "#/components/schemas/flight-resource-type" }, "id": { "type": "string" @@ -2821,7 +2821,7 @@ }, "additionalProperties": false }, - "flights-resource-type": { + "flight-resource-type": { "enum": [ "flights" ], @@ -3150,7 +3150,7 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/passengers-resource-type" + "$ref": "#/components/schemas/passenger-resource-type" }, "id": { "type": "string" @@ -3176,7 +3176,7 @@ "type": "object", "properties": { "type": { - "$ref": "#/components/schemas/passengers-resource-type" + "$ref": "#/components/schemas/passenger-resource-type" }, "id": { "type": "string" @@ -3210,7 +3210,7 @@ }, "additionalProperties": false }, - "passengers-resource-type": { + "passenger-resource-type": { "enum": [ "passengers" ], diff --git a/test/OpenApiTests/NamingConvention/CamelCase/CamelCaseNamingConventionStartup.cs b/test/OpenApiTests/NamingConvention/CamelCase/CamelCaseNamingConventionStartup.cs new file mode 100644 index 0000000000..54d4b0fc84 --- /dev/null +++ b/test/OpenApiTests/NamingConvention/CamelCase/CamelCaseNamingConventionStartup.cs @@ -0,0 +1,21 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using JetBrains.Annotations; +using JsonApiDotNetCore.Configuration; +using Microsoft.EntityFrameworkCore; + +namespace OpenApiTests.NamingConvention.CamelCase; + +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public sealed class CamelCaseNamingConventionStartup : OpenApiStartup + where TDbContext : DbContext +{ + protected override void SetJsonApiOptions(JsonApiOptions options) + { + base.SetJsonApiOptions(options); + + options.SerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + options.SerializerOptions.DictionaryKeyPolicy = JsonNamingPolicy.CamelCase; + options.SerializerOptions.Converters.Add(new JsonStringEnumConverter()); + } +} diff --git a/test/OpenApiTests/NamingConvention/CamelCase/CamelCaseTests.cs b/test/OpenApiTests/NamingConvention/CamelCase/CamelCaseTests.cs new file mode 100644 index 0000000000..d04e37d187 --- /dev/null +++ b/test/OpenApiTests/NamingConvention/CamelCase/CamelCaseTests.cs @@ -0,0 +1,527 @@ +using System.Text.Json; +using OpenApiTests.Controllers; +using TestBuildingBlocks; +using Xunit; + +namespace OpenApiTests.NamingConvention.CamelCase; + +public sealed class CamelCaseTests + : IClassFixture, NamingConventionDbContext>> +{ + private static Lazy>? _lazyOpenApiDocument; + private readonly IntegrationTestContext, NamingConventionDbContext> _testContext; + + public CamelCaseTests(IntegrationTestContext, NamingConventionDbContext> testContext) + { + _testContext = testContext; + + _lazyOpenApiDocument ??= new Lazy>(async () => + { + testContext.UseController(); + + string content = await GetAsync("swagger/v1/swagger.json"); + + await WriteSwaggerDocumentToFileAsync(content); + + JsonDocument document = JsonDocument.Parse(content); + + return document.ToJsonElement(); + }, LazyThreadSafetyMode.ExecutionAndPublication); + } + + [Fact] + public async Task Camel_casing_convention_is_applied_to_GetCollection_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./supermarkets.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("getSupermarketCollection"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("supermarketCollectionResponseDocument").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + string? resourceDataSchemaRefId = null; + + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("linksInResourceCollectionDocument"); + propertiesElement.ShouldContainPath("jsonapi.$ref").ShouldBeReferenceSchemaId("jsonapiObject"); + + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.items.$ref").ShouldBeReferenceSchemaId("supermarketDataInResponse") + .SchemaReferenceId; + }); + + string? resourceAttributesInResponseSchemaRefId = null; + string? resourceRelationshipInResponseSchemaRefId = null; + string? primaryResourceTypeSchemaRefId = null; + + schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => + { + primaryResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("supermarketResourceType") + .SchemaReferenceId; + + resourceAttributesInResponseSchemaRefId = propertiesElement.ShouldContainPath("attributes.$ref") + .ShouldBeReferenceSchemaId("supermarketAttributesInResponse").SchemaReferenceId; + + resourceRelationshipInResponseSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref") + .ShouldBeReferenceSchemaId("supermarketRelationshipsInResponse").SchemaReferenceId; + + propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("linksInResourceObject"); + }); + + schemasElement.ShouldContainPath($"{primaryResourceTypeSchemaRefId}.enum[0]").With(enumValueElement => + { + enumValueElement.ShouldBeString("supermarkets"); + }); + + schemasElement.ShouldContainPath($"{resourceAttributesInResponseSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("nameOfCity"); + propertiesElement.Should().ContainProperty("kind"); + propertiesElement.ShouldContainPath("kind.$ref").ShouldBeReferenceSchemaId("supermarketType"); + }); + + string? nullableToOneResourceResponseDataSchemaRefId = null; + + schemasElement.ShouldContainPath($"{resourceRelationshipInResponseSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("storeManager"); + + propertiesElement.ShouldContainPath("storeManager.$ref").ShouldBeReferenceSchemaId("toOneStaffMemberInResponse"); + + nullableToOneResourceResponseDataSchemaRefId = propertiesElement.ShouldContainPath("backupStoreManager.$ref") + .ShouldBeReferenceSchemaId("nullableToOneStaffMemberInResponse").SchemaReferenceId; + + propertiesElement.Should().ContainProperty("cashiers"); + propertiesElement.ShouldContainPath("cashiers.$ref").ShouldBeReferenceSchemaId("toManyStaffMemberInResponse"); + }); + + string? relatedResourceIdentifierSchemaRefId = null; + + schemasElement.ShouldContainPath($"{nullableToOneResourceResponseDataSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("linksInRelationshipObject"); + + relatedResourceIdentifierSchemaRefId = propertiesElement.ShouldContainPath("data.oneOf[0].$ref") + .ShouldBeReferenceSchemaId("staffMemberIdentifier").SchemaReferenceId; + + propertiesElement.ShouldContainPath("data.oneOf[1].$ref").ShouldBeReferenceSchemaId("nullValue"); + }); + + string? relatedResourceTypeSchemaRefId = null; + + schemasElement.ShouldContainPath($"{relatedResourceIdentifierSchemaRefId}.properties").With(propertiesElement => + { + relatedResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("staffMemberResourceType") + .SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{relatedResourceTypeSchemaRefId}.enum[0]").ShouldBeReferenceSchemaId("staffMembers"); + }); + } + + [Fact] + public async Task Camel_casing_convention_is_applied_to_GetSingle_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./supermarkets/{id}.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("getSupermarket"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("supermarketPrimaryResponseDocument").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("linksInResourceDocument"); + }); + }); + } + + [Fact] + public async Task Camel_casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./supermarkets/{id}/storeManager.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("getSupermarketStoreManager"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("staffMemberSecondaryResponseDocument").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + string? resourceDataSchemaRefId = null; + + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("staffMemberDataInResponse") + .SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("staffMemberAttributesInResponse"); + }); + }); + } + + [Fact] + public async Task Camel_casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./supermarkets/{id}/backupStoreManager.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("getSupermarketBackupStoreManager"); + }); + + getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("nullableStaffMemberSecondaryResponseDocument"); + }); + } + + [Fact] + public async Task Camel_casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./supermarkets/{id}/cashiers.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("getSupermarketCashiers"); + }); + + getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("staffMemberCollectionResponseDocument"); + }); + } + + [Fact] + public async Task Camel_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./supermarkets/{id}/relationships/storeManager.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("getSupermarketStoreManagerRelationship"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("staffMemberIdentifierResponseDocument").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("linksInResourceIdentifierDocument"); + }); + }); + } + + [Fact] + public async Task Camel_casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./supermarkets/{id}/relationships/backupStoreManager.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("getSupermarketBackupStoreManagerRelationship"); + }); + + getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("nullableStaffMemberIdentifierResponseDocument"); + }); + } + + [Fact] + public async Task Camel_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("getSupermarketCashiersRelationship"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("staffMemberIdentifierCollectionResponseDocument").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("linksInResourceIdentifierCollectionDocument"); + }); + }); + } + + [Fact] + public async Task Camel_casing_convention_is_applied_to_Post_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./supermarkets.post").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("postSupermarket"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("supermarketPostRequestDocument").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + string? resourceDataSchemaRefId = null; + + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("supermarketDataInPostRequest") + .SchemaReferenceId; + }); + + string? resourceRelationshipInPostRequestSchemaRefId = null; + + schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("supermarketAttributesInPostRequest"); + + resourceRelationshipInPostRequestSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref") + .ShouldBeReferenceSchemaId("supermarketRelationshipsInPostRequest").SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{resourceRelationshipInPostRequestSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("storeManager"); + propertiesElement.ShouldContainPath("storeManager.$ref").ShouldBeReferenceSchemaId("toOneStaffMemberInRequest"); + + propertiesElement.Should().ContainProperty("backupStoreManager"); + propertiesElement.ShouldContainPath("backupStoreManager.$ref").ShouldBeReferenceSchemaId("nullableToOneStaffMemberInRequest"); + + propertiesElement.Should().ContainProperty("cashiers"); + propertiesElement.ShouldContainPath("cashiers.$ref").ShouldBeReferenceSchemaId("toManyStaffMemberInRequest"); + }); + }); + } + + [Fact] + public async Task Camel_casing_convention_is_applied_to_PostRelationship_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.post").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("postSupermarketCashiersRelationship"); + }); + }); + } + + [Fact] + public async Task Camel_casing_convention_is_applied_to_Patch_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./supermarkets/{id}.patch").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("patchSupermarket"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("supermarketPatchRequestDocument").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + string? resourceDataSchemaRefId = null; + + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("supermarketDataInPatchRequest") + .SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("supermarketAttributesInPatchRequest"); + propertiesElement.ShouldContainPath("relationships.$ref").ShouldBeReferenceSchemaId("supermarketRelationshipsInPatchRequest"); + }); + }); + } + + [Fact] + public async Task Camel_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./supermarkets/{id}/relationships/storeManager.patch").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("patchSupermarketStoreManagerRelationship"); + }); + }); + } + + [Fact] + public async Task Camel_casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./supermarkets/{id}/relationships/backupStoreManager.patch").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("patchSupermarketBackupStoreManagerRelationship"); + }); + }); + } + + [Fact] + public async Task Camel_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.patch").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("patchSupermarketCashiersRelationship"); + }); + }); + } + + [Fact] + public async Task Camel_casing_convention_is_applied_to_Delete_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./supermarkets/{id}.delete").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("deleteSupermarket"); + }); + }); + } + + [Fact] + public async Task Camel_casing_convention_is_applied_to_DeleteRelationship_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.delete").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("deleteSupermarketCashiersRelationship"); + }); + }); + } + + private async Task GetAsync(string requestUrl) + { + var request = new HttpRequestMessage(HttpMethod.Get, requestUrl); + + using HttpClient client = _testContext.Factory.CreateClient(); + using HttpResponseMessage responseMessage = await client.SendAsync(request); + + return await responseMessage.Content.ReadAsStringAsync(); + } + + private async Task WriteSwaggerDocumentToFileAsync(string document) + { + string testSuitePath = GetTestSuitePath(); + string documentPath = Path.Join(testSuitePath, "swagger.json"); + await File.WriteAllTextAsync(documentPath, document); + } + + private string GetTestSuitePath() + { + string solutionTestDirectoryPath = Directory.GetParent(Environment.CurrentDirectory)!.Parent!.Parent!.Parent!.FullName; + string currentNamespacePathRelativeToTestDirectory = Path.Join(GetType().Namespace!.Split('.')); + + return Path.Join(solutionTestDirectoryPath, currentNamespacePathRelativeToTestDirectory); + } +} diff --git a/test/OpenApiTests/NamingConvention/CamelCase/swagger.json b/test/OpenApiTests/NamingConvention/CamelCase/swagger.json new file mode 100644 index 0000000000..2eaac9303c --- /dev/null +++ b/test/OpenApiTests/NamingConvention/CamelCase/swagger.json @@ -0,0 +1,1466 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenApiTests", + "version": "1.0" + }, + "paths": { + "/supermarkets": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "getSupermarketCollection", + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarketCollectionResponseDocument" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "headSupermarketCollection", + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarketCollectionResponseDocument" + } + } + } + } + } + }, + "post": { + "tags": [ + "supermarkets" + ], + "operationId": "postSupermarket", + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarketPostRequestDocument" + } + } + } + }, + "responses": { + "201": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarketPrimaryResponseDocument" + } + } + } + }, + "204": { + "description": "Success" + } + } + } + }, + "/supermarkets/{id}": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "getSupermarket", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarketPrimaryResponseDocument" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "headSupermarket", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarketPrimaryResponseDocument" + } + } + } + } + } + }, + "patch": { + "tags": [ + "supermarkets" + ], + "operationId": "patchSupermarket", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarketPatchRequestDocument" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarketPrimaryResponseDocument" + } + } + } + }, + "204": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "supermarkets" + ], + "operationId": "deleteSupermarket", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/supermarkets/{id}/backupStoreManager": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "getSupermarketBackupStoreManager", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullableStaffMemberSecondaryResponseDocument" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "headSupermarketBackupStoreManager", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullableStaffMemberSecondaryResponseDocument" + } + } + } + } + } + } + }, + "/supermarkets/{id}/relationships/backupStoreManager": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "getSupermarketBackupStoreManagerRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullableStaffMemberIdentifierResponseDocument" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "headSupermarketBackupStoreManagerRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullableStaffMemberIdentifierResponseDocument" + } + } + } + } + } + }, + "patch": { + "tags": [ + "supermarkets" + ], + "operationId": "patchSupermarketBackupStoreManagerRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullableToOneStaffMemberInRequest" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/supermarkets/{id}/cashiers": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "getSupermarketCashiers", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staffMemberCollectionResponseDocument" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "headSupermarketCashiers", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staffMemberCollectionResponseDocument" + } + } + } + } + } + } + }, + "/supermarkets/{id}/relationships/cashiers": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "getSupermarketCashiersRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staffMemberIdentifierCollectionResponseDocument" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "headSupermarketCashiersRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staffMemberIdentifierCollectionResponseDocument" + } + } + } + } + } + }, + "post": { + "tags": [ + "supermarkets" + ], + "operationId": "postSupermarketCashiersRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/toManyStaffMemberInRequest" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + }, + "patch": { + "tags": [ + "supermarkets" + ], + "operationId": "patchSupermarketCashiersRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/toManyStaffMemberInRequest" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "supermarkets" + ], + "operationId": "deleteSupermarketCashiersRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/toManyStaffMemberInRequest" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/supermarkets/{id}/storeManager": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "getSupermarketStoreManager", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staffMemberSecondaryResponseDocument" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "headSupermarketStoreManager", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staffMemberSecondaryResponseDocument" + } + } + } + } + } + } + }, + "/supermarkets/{id}/relationships/storeManager": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "getSupermarketStoreManagerRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staffMemberIdentifierResponseDocument" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "headSupermarketStoreManagerRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staffMemberIdentifierResponseDocument" + } + } + } + } + } + }, + "patch": { + "tags": [ + "supermarkets" + ], + "operationId": "patchSupermarketStoreManagerRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/toOneStaffMemberInRequest" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + } + }, + "components": { + "schemas": { + "jsonapiObject": { + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "ext": { + "type": "array", + "items": { + "type": "string" + } + }, + "profile": { + "type": "array", + "items": { + "type": "string" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "linksInRelationshipObject": { + "required": [ + "related", + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "related": { + "type": "string" + } + }, + "additionalProperties": false + }, + "linksInResourceCollectionDocument": { + "required": [ + "first", + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + }, + "first": { + "type": "string" + }, + "last": { + "type": "string" + }, + "prev": { + "type": "string" + }, + "next": { + "type": "string" + } + }, + "additionalProperties": false + }, + "linksInResourceDocument": { + "required": [ + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + } + }, + "additionalProperties": false + }, + "linksInResourceIdentifierCollectionDocument": { + "required": [ + "first", + "related", + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + }, + "related": { + "type": "string" + }, + "first": { + "type": "string" + }, + "last": { + "type": "string" + }, + "prev": { + "type": "string" + }, + "next": { + "type": "string" + } + }, + "additionalProperties": false + }, + "linksInResourceIdentifierDocument": { + "required": [ + "related", + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + }, + "related": { + "type": "string" + } + }, + "additionalProperties": false + }, + "linksInResourceObject": { + "required": [ + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + } + }, + "additionalProperties": false + }, + "nullValue": { + "not": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "object" + }, + { + "type": "array" + } + ], + "items": { } + }, + "nullable": true + }, + "nullableStaffMemberIdentifierResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/staffMemberIdentifier" + }, + { + "$ref": "#/components/schemas/nullValue" + } + ] + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapiObject" + }, + "links": { + "$ref": "#/components/schemas/linksInResourceIdentifierDocument" + } + }, + "additionalProperties": false + }, + "nullableStaffMemberSecondaryResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/staffMemberDataInResponse" + }, + { + "$ref": "#/components/schemas/nullValue" + } + ] + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapiObject" + }, + "links": { + "$ref": "#/components/schemas/linksInResourceDocument" + } + }, + "additionalProperties": false + }, + "nullableToOneStaffMemberInRequest": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/staffMemberIdentifier" + }, + { + "$ref": "#/components/schemas/nullValue" + } + ] + } + }, + "additionalProperties": false + }, + "nullableToOneStaffMemberInResponse": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/staffMemberIdentifier" + }, + { + "$ref": "#/components/schemas/nullValue" + } + ] + }, + "links": { + "$ref": "#/components/schemas/linksInRelationshipObject" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "staffMemberAttributesInResponse": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "age": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "staffMemberCollectionResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/staffMemberDataInResponse" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapiObject" + }, + "links": { + "$ref": "#/components/schemas/linksInResourceCollectionDocument" + } + }, + "additionalProperties": false + }, + "staffMemberDataInResponse": { + "required": [ + "id", + "links", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/staffMemberResourceType" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/staffMemberAttributesInResponse" + }, + "links": { + "$ref": "#/components/schemas/linksInResourceObject" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "staffMemberIdentifier": { + "required": [ + "id", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/staffMemberResourceType" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false + }, + "staffMemberIdentifierCollectionResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/staffMemberIdentifier" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapiObject" + }, + "links": { + "$ref": "#/components/schemas/linksInResourceIdentifierCollectionDocument" + } + }, + "additionalProperties": false + }, + "staffMemberIdentifierResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/staffMemberIdentifier" + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapiObject" + }, + "links": { + "$ref": "#/components/schemas/linksInResourceIdentifierDocument" + } + }, + "additionalProperties": false + }, + "staffMemberResourceType": { + "enum": [ + "staffMembers" + ], + "type": "string" + }, + "staffMemberSecondaryResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/staffMemberDataInResponse" + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapiObject" + }, + "links": { + "$ref": "#/components/schemas/linksInResourceDocument" + } + }, + "additionalProperties": false + }, + "supermarketAttributesInPatchRequest": { + "type": "object", + "properties": { + "nameOfCity": { + "type": "string" + }, + "kind": { + "$ref": "#/components/schemas/supermarketType" + } + }, + "additionalProperties": false + }, + "supermarketAttributesInPostRequest": { + "required": [ + "nameOfCity" + ], + "type": "object", + "properties": { + "nameOfCity": { + "type": "string" + }, + "kind": { + "$ref": "#/components/schemas/supermarketType" + } + }, + "additionalProperties": false + }, + "supermarketAttributesInResponse": { + "type": "object", + "properties": { + "nameOfCity": { + "type": "string" + }, + "kind": { + "$ref": "#/components/schemas/supermarketType" + } + }, + "additionalProperties": false + }, + "supermarketCollectionResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/supermarketDataInResponse" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapiObject" + }, + "links": { + "$ref": "#/components/schemas/linksInResourceCollectionDocument" + } + }, + "additionalProperties": false + }, + "supermarketDataInPatchRequest": { + "required": [ + "id", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/supermarketResourceType" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/supermarketAttributesInPatchRequest" + }, + "relationships": { + "$ref": "#/components/schemas/supermarketRelationshipsInPatchRequest" + } + }, + "additionalProperties": false + }, + "supermarketDataInPostRequest": { + "required": [ + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/supermarketResourceType" + }, + "attributes": { + "$ref": "#/components/schemas/supermarketAttributesInPostRequest" + }, + "relationships": { + "$ref": "#/components/schemas/supermarketRelationshipsInPostRequest" + } + }, + "additionalProperties": false + }, + "supermarketDataInResponse": { + "required": [ + "id", + "links", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/supermarketResourceType" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/supermarketAttributesInResponse" + }, + "relationships": { + "$ref": "#/components/schemas/supermarketRelationshipsInResponse" + }, + "links": { + "$ref": "#/components/schemas/linksInResourceObject" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "supermarketPatchRequestDocument": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/supermarketDataInPatchRequest" + } + }, + "additionalProperties": false + }, + "supermarketPostRequestDocument": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/supermarketDataInPostRequest" + } + }, + "additionalProperties": false + }, + "supermarketPrimaryResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/supermarketDataInResponse" + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapiObject" + }, + "links": { + "$ref": "#/components/schemas/linksInResourceDocument" + } + }, + "additionalProperties": false + }, + "supermarketRelationshipsInPatchRequest": { + "type": "object", + "properties": { + "storeManager": { + "$ref": "#/components/schemas/toOneStaffMemberInRequest" + }, + "backupStoreManager": { + "$ref": "#/components/schemas/nullableToOneStaffMemberInRequest" + }, + "cashiers": { + "$ref": "#/components/schemas/toManyStaffMemberInRequest" + } + }, + "additionalProperties": false + }, + "supermarketRelationshipsInPostRequest": { + "required": [ + "storeManager" + ], + "type": "object", + "properties": { + "storeManager": { + "$ref": "#/components/schemas/toOneStaffMemberInRequest" + }, + "backupStoreManager": { + "$ref": "#/components/schemas/nullableToOneStaffMemberInRequest" + }, + "cashiers": { + "$ref": "#/components/schemas/toManyStaffMemberInRequest" + } + }, + "additionalProperties": false + }, + "supermarketRelationshipsInResponse": { + "type": "object", + "properties": { + "storeManager": { + "$ref": "#/components/schemas/toOneStaffMemberInResponse" + }, + "backupStoreManager": { + "$ref": "#/components/schemas/nullableToOneStaffMemberInResponse" + }, + "cashiers": { + "$ref": "#/components/schemas/toManyStaffMemberInResponse" + } + }, + "additionalProperties": false + }, + "supermarketResourceType": { + "enum": [ + "supermarkets" + ], + "type": "string" + }, + "supermarketType": { + "enum": [ + "Traditional", + "Budget", + "Warehouse" + ], + "type": "string" + }, + "toManyStaffMemberInRequest": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/staffMemberIdentifier" + } + } + }, + "additionalProperties": false + }, + "toManyStaffMemberInResponse": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/staffMemberIdentifier" + } + }, + "links": { + "$ref": "#/components/schemas/linksInRelationshipObject" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "toOneStaffMemberInRequest": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/staffMemberIdentifier" + } + }, + "additionalProperties": false + }, + "toOneStaffMemberInResponse": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/staffMemberIdentifier" + }, + "links": { + "$ref": "#/components/schemas/linksInRelationshipObject" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + } + } + } +} \ No newline at end of file diff --git a/test/OpenApiTests/NamingConvention/KebabCase/KebabCaseTests.cs b/test/OpenApiTests/NamingConvention/KebabCase/KebabCaseTests.cs index 2c3ca242ef..38d8488f2c 100644 --- a/test/OpenApiTests/NamingConvention/KebabCase/KebabCaseTests.cs +++ b/test/OpenApiTests/NamingConvention/KebabCase/KebabCaseTests.cs @@ -1,44 +1,24 @@ -using System.Text.Json; -using OpenApiTests.Controllers; using TestBuildingBlocks; using Xunit; namespace OpenApiTests.NamingConvention.KebabCase; -public sealed class KebabCaseTests - : IClassFixture, NamingConventionDbContext>> +public sealed class KebabCaseTests : IClassFixture, NamingConventionDbContext>> { - private static Lazy>? _lazyOpenApiDocument; - private readonly IntegrationTestContext, NamingConventionDbContext> _testContext; + private readonly OpenApiTestContext, NamingConventionDbContext> _testContext; - public KebabCaseTests(IntegrationTestContext, NamingConventionDbContext> testContext) + public KebabCaseTests(OpenApiTestContext, NamingConventionDbContext> testContext) { _testContext = testContext; - - _lazyOpenApiDocument ??= new Lazy>(async () => - { - testContext.UseController(); - - string content = await GetAsync("swagger/v1/swagger.json"); - - await WriteSwaggerDocumentToFileAsync(content); - - JsonDocument document = JsonDocument.Parse(content); - - return document.ToJsonElement(); - }, LazyThreadSafetyMode.ExecutionAndPublication); } [Fact] - public async Task Kebab_casing_convention_is_applied_to_GetCollection_endpoint() + public void Kebab_casing_convention_is_applied_to_GetCollection_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./supermarkets.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -49,7 +29,7 @@ public async Task Kebab_casing_convention_is_applied_to_GetCollection_endpoint() .ShouldBeReferenceSchemaId("supermarket-collection-response-document").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; @@ -68,7 +48,7 @@ public async Task Kebab_casing_convention_is_applied_to_GetCollection_endpoint() schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => { - primaryResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("supermarkets-resource-type") + primaryResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("supermarket-resource-type") .SchemaReferenceId; resourceAttributesInResponseSchemaRefId = propertiesElement.ShouldContainPath("attributes.$ref") @@ -123,7 +103,7 @@ public async Task Kebab_casing_convention_is_applied_to_GetCollection_endpoint() schemasElement.ShouldContainPath($"{relatedResourceIdentifierSchemaRefId}.properties").With(propertiesElement => { - relatedResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("staff-members-resource-type") + relatedResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("staff-member-resource-type") .SchemaReferenceId; }); @@ -132,15 +112,12 @@ public async Task Kebab_casing_convention_is_applied_to_GetCollection_endpoint() } [Fact] - public async Task Kebab_casing_convention_is_applied_to_GetSingle_endpoint() + public void Kebab_casing_convention_is_applied_to_GetSingle_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./supermarkets/{id}.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -151,7 +128,7 @@ public async Task Kebab_casing_convention_is_applied_to_GetSingle_endpoint() .ShouldBeReferenceSchemaId("supermarket-primary-response-document").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { @@ -161,15 +138,12 @@ public async Task Kebab_casing_convention_is_applied_to_GetSingle_endpoint() } [Fact] - public async Task Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() + public void Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./supermarkets/{id}/store-manager.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/store-manager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -180,7 +154,7 @@ public async Task Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_wi .ShouldBeReferenceSchemaId("staff-member-secondary-response-document").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; @@ -198,13 +172,10 @@ public async Task Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_wi } [Fact] - public async Task Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() + public void Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./supermarkets/{id}/backup-store-manager.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/backup-store-manager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -217,13 +188,10 @@ public async Task Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_wi } [Fact] - public async Task Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() + public void Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./supermarkets/{id}/cashiers.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/cashiers.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -236,15 +204,12 @@ public async Task Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_wi } [Fact] - public async Task Kebab_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() + public void Kebab_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./supermarkets/{id}/relationships/store-manager.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/store-manager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -255,7 +220,7 @@ public async Task Kebab_casing_convention_is_applied_to_GetRelationship_endpoint .ShouldBeReferenceSchemaId("staff-member-identifier-response-document").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { @@ -265,13 +230,10 @@ public async Task Kebab_casing_convention_is_applied_to_GetRelationship_endpoint } [Fact] - public async Task Kebab_casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() + public void Kebab_casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./supermarkets/{id}/relationships/backup-store-manager.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/backup-store-manager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -284,15 +246,12 @@ public async Task Kebab_casing_convention_is_applied_to_GetRelationship_endpoint } [Fact] - public async Task Kebab_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() + public void Kebab_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -303,7 +262,7 @@ public async Task Kebab_casing_convention_is_applied_to_GetRelationship_endpoint .ShouldBeReferenceSchemaId("staff-member-identifier-collection-response-document").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { @@ -313,15 +272,12 @@ public async Task Kebab_casing_convention_is_applied_to_GetRelationship_endpoint } [Fact] - public async Task Kebab_casing_convention_is_applied_to_Post_endpoint() + public void Kebab_casing_convention_is_applied_to_Post_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./supermarkets.post").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets.post").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -332,7 +288,7 @@ public async Task Kebab_casing_convention_is_applied_to_Post_endpoint() .ShouldBeReferenceSchemaId("supermarket-post-request-document").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; @@ -367,13 +323,10 @@ public async Task Kebab_casing_convention_is_applied_to_Post_endpoint() } [Fact] - public async Task Kebab_casing_convention_is_applied_to_PostRelationship_endpoint() + public void Kebab_casing_convention_is_applied_to_PostRelationship_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.post").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.post").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -383,15 +336,12 @@ public async Task Kebab_casing_convention_is_applied_to_PostRelationship_endpoin } [Fact] - public async Task Kebab_casing_convention_is_applied_to_Patch_endpoint() + public void Kebab_casing_convention_is_applied_to_Patch_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./supermarkets/{id}.patch").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -402,7 +352,7 @@ public async Task Kebab_casing_convention_is_applied_to_Patch_endpoint() .ShouldBeReferenceSchemaId("supermarket-patch-request-document").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; @@ -421,13 +371,10 @@ public async Task Kebab_casing_convention_is_applied_to_Patch_endpoint() } [Fact] - public async Task Kebab_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() + public void Kebab_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./supermarkets/{id}/relationships/store-manager.patch").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/store-manager.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -437,13 +384,10 @@ public async Task Kebab_casing_convention_is_applied_to_PatchRelationship_endpoi } [Fact] - public async Task Kebab_casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() + public void Kebab_casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./supermarkets/{id}/relationships/backup-store-manager.patch").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/backup-store-manager.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -453,13 +397,10 @@ public async Task Kebab_casing_convention_is_applied_to_PatchRelationship_endpoi } [Fact] - public async Task Kebab_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() + public void Kebab_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.patch").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -469,13 +410,10 @@ public async Task Kebab_casing_convention_is_applied_to_PatchRelationship_endpoi } [Fact] - public async Task Kebab_casing_convention_is_applied_to_Delete_endpoint() + public void Kebab_casing_convention_is_applied_to_Delete_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./supermarkets/{id}.delete").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}.delete").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -485,13 +423,10 @@ public async Task Kebab_casing_convention_is_applied_to_Delete_endpoint() } [Fact] - public async Task Kebab_casing_convention_is_applied_to_DeleteRelationship_endpoint() + public void Kebab_casing_convention_is_applied_to_DeleteRelationship_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.delete").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.delete").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -499,29 +434,4 @@ public async Task Kebab_casing_convention_is_applied_to_DeleteRelationship_endpo }); }); } - - private async Task GetAsync(string requestUrl) - { - var request = new HttpRequestMessage(HttpMethod.Get, requestUrl); - - using HttpClient client = _testContext.Factory.CreateClient(); - using HttpResponseMessage responseMessage = await client.SendAsync(request); - - return await responseMessage.Content.ReadAsStringAsync(); - } - - private async Task WriteSwaggerDocumentToFileAsync(string document) - { - string testSuitePath = GetTestSuitePath(); - string documentPath = Path.Join(testSuitePath, "swagger.json"); - await File.WriteAllTextAsync(documentPath, document); - } - - private string GetTestSuitePath() - { - string solutionTestDirectoryPath = Directory.GetParent(Environment.CurrentDirectory)!.Parent!.Parent!.Parent!.FullName; - string currentNamespacePathRelativeToTestDirectory = Path.Join(GetType().Namespace!.Split('.')); - - return Path.Join(solutionTestDirectoryPath, currentNamespacePathRelativeToTestDirectory); - } } diff --git a/test/OpenApiTests/NamingConvention/PascalCase/PascalCaseNamingConventionStartup.cs b/test/OpenApiTests/NamingConvention/PascalCase/PascalCaseNamingConventionStartup.cs new file mode 100644 index 0000000000..6f38d9fe8d --- /dev/null +++ b/test/OpenApiTests/NamingConvention/PascalCase/PascalCaseNamingConventionStartup.cs @@ -0,0 +1,20 @@ +using System.Text.Json.Serialization; +using JetBrains.Annotations; +using JsonApiDotNetCore.Configuration; +using Microsoft.EntityFrameworkCore; + +namespace OpenApiTests.NamingConvention.PascalCase; + +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public sealed class PascalCaseNamingConventionStartup : OpenApiStartup + where TDbContext : DbContext +{ + protected override void SetJsonApiOptions(JsonApiOptions options) + { + base.SetJsonApiOptions(options); + + options.SerializerOptions.PropertyNamingPolicy = null; + options.SerializerOptions.DictionaryKeyPolicy = null; + options.SerializerOptions.Converters.Add(new JsonStringEnumConverter()); + } +} diff --git a/test/OpenApiTests/NamingConvention/PascalCase/PascalCaseTests.cs b/test/OpenApiTests/NamingConvention/PascalCase/PascalCaseTests.cs new file mode 100644 index 0000000000..b9c26cee3e --- /dev/null +++ b/test/OpenApiTests/NamingConvention/PascalCase/PascalCaseTests.cs @@ -0,0 +1,527 @@ +using System.Text.Json; +using OpenApiTests.Controllers; +using TestBuildingBlocks; +using Xunit; + +namespace OpenApiTests.NamingConvention.PascalCase; + +public sealed class PascalCaseTests + : IClassFixture, NamingConventionDbContext>> +{ + private static Lazy>? _lazyOpenApiDocument; + private readonly IntegrationTestContext, NamingConventionDbContext> _testContext; + + public PascalCaseTests(IntegrationTestContext, NamingConventionDbContext> testContext) + { + _testContext = testContext; + + _lazyOpenApiDocument ??= new Lazy>(async () => + { + testContext.UseController(); + + string content = await GetAsync("swagger/v1/swagger.json"); + + await WriteSwaggerDocumentToFileAsync(content); + + JsonDocument document = JsonDocument.Parse(content); + + return document.ToJsonElement(); + }, LazyThreadSafetyMode.ExecutionAndPublication); + } + + [Fact] + public async Task Pascal_casing_convention_is_applied_to_GetCollection_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./Supermarkets.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("GetSupermarketCollection"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("SupermarketCollectionResponseDocument").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + string? resourceDataSchemaRefId = null; + + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("LinksInResourceCollectionDocument"); + propertiesElement.ShouldContainPath("jsonapi.$ref").ShouldBeReferenceSchemaId("JsonapiObject"); + + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.items.$ref").ShouldBeReferenceSchemaId("SupermarketDataInResponse") + .SchemaReferenceId; + }); + + string? resourceAttributesInResponseSchemaRefId = null; + string? resourceRelationshipInResponseSchemaRefId = null; + string? primaryResourceTypeSchemaRefId = null; + + schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => + { + primaryResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("SupermarketResourceType") + .SchemaReferenceId; + + resourceAttributesInResponseSchemaRefId = propertiesElement.ShouldContainPath("attributes.$ref") + .ShouldBeReferenceSchemaId("SupermarketAttributesInResponse").SchemaReferenceId; + + resourceRelationshipInResponseSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref") + .ShouldBeReferenceSchemaId("SupermarketRelationshipsInResponse").SchemaReferenceId; + + propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("LinksInResourceObject"); + }); + + schemasElement.ShouldContainPath($"{primaryResourceTypeSchemaRefId}.enum[0]").With(enumValueElement => + { + enumValueElement.ShouldBeString("Supermarkets"); + }); + + schemasElement.ShouldContainPath($"{resourceAttributesInResponseSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("NameOfCity"); + propertiesElement.Should().ContainProperty("Kind"); + propertiesElement.ShouldContainPath("Kind.$ref").ShouldBeReferenceSchemaId("SupermarketType"); + }); + + string? nullableToOneResourceResponseDataSchemaRefId = null; + + schemasElement.ShouldContainPath($"{resourceRelationshipInResponseSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("StoreManager"); + + propertiesElement.ShouldContainPath("StoreManager.$ref").ShouldBeReferenceSchemaId("ToOneStaffMemberInResponse"); + + nullableToOneResourceResponseDataSchemaRefId = propertiesElement.ShouldContainPath("BackupStoreManager.$ref") + .ShouldBeReferenceSchemaId("NullableToOneStaffMemberInResponse").SchemaReferenceId; + + propertiesElement.Should().ContainProperty("Cashiers"); + propertiesElement.ShouldContainPath("Cashiers.$ref").ShouldBeReferenceSchemaId("ToManyStaffMemberInResponse"); + }); + + string? relatedResourceIdentifierSchemaRefId = null; + + schemasElement.ShouldContainPath($"{nullableToOneResourceResponseDataSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("LinksInRelationshipObject"); + + relatedResourceIdentifierSchemaRefId = propertiesElement.ShouldContainPath("data.oneOf[0].$ref") + .ShouldBeReferenceSchemaId("StaffMemberIdentifier").SchemaReferenceId; + + propertiesElement.ShouldContainPath("data.oneOf[1].$ref").ShouldBeReferenceSchemaId("NullValue"); + }); + + string? relatedResourceTypeSchemaRefId = null; + + schemasElement.ShouldContainPath($"{relatedResourceIdentifierSchemaRefId}.properties").With(propertiesElement => + { + relatedResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("StaffMemberResourceType") + .SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{relatedResourceTypeSchemaRefId}.enum[0]").ShouldBeReferenceSchemaId("StaffMembers"); + }); + } + + [Fact] + public async Task Pascal_casing_convention_is_applied_to_GetSingle_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./Supermarkets/{id}.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("GetSupermarket"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("SupermarketPrimaryResponseDocument").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("LinksInResourceDocument"); + }); + }); + } + + [Fact] + public async Task Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./Supermarkets/{id}/StoreManager.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("GetSupermarketStoreManager"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("StaffMemberSecondaryResponseDocument").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + string? resourceDataSchemaRefId = null; + + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("StaffMemberDataInResponse") + .SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("StaffMemberAttributesInResponse"); + }); + }); + } + + [Fact] + public async Task Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./Supermarkets/{id}/BackupStoreManager.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("GetSupermarketBackupStoreManager"); + }); + + getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("NullableStaffMemberSecondaryResponseDocument"); + }); + } + + [Fact] + public async Task Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./Supermarkets/{id}/Cashiers.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("GetSupermarketCashiers"); + }); + + getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("StaffMemberCollectionResponseDocument"); + }); + } + + [Fact] + public async Task Pascal_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./Supermarkets/{id}/relationships/StoreManager.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("GetSupermarketStoreManagerRelationship"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("StaffMemberIdentifierResponseDocument").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("LinksInResourceIdentifierDocument"); + }); + }); + } + + [Fact] + public async Task Pascal_casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./Supermarkets/{id}/relationships/BackupStoreManager.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("GetSupermarketBackupStoreManagerRelationship"); + }); + + getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("NullableStaffMemberIdentifierResponseDocument"); + }); + } + + [Fact] + public async Task Pascal_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.get").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("GetSupermarketCashiersRelationship"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("StaffMemberIdentifierCollectionResponseDocument").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("LinksInResourceIdentifierCollectionDocument"); + }); + }); + } + + [Fact] + public async Task Pascal_casing_convention_is_applied_to_Post_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./Supermarkets.post").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("PostSupermarket"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("SupermarketPostRequestDocument").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + string? resourceDataSchemaRefId = null; + + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("SupermarketDataInPostRequest") + .SchemaReferenceId; + }); + + string? resourceRelationshipInPostRequestSchemaRefId = null; + + schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("SupermarketAttributesInPostRequest"); + + resourceRelationshipInPostRequestSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref") + .ShouldBeReferenceSchemaId("SupermarketRelationshipsInPostRequest").SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{resourceRelationshipInPostRequestSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("StoreManager"); + propertiesElement.ShouldContainPath("StoreManager.$ref").ShouldBeReferenceSchemaId("ToOneStaffMemberInRequest"); + + propertiesElement.Should().ContainProperty("BackupStoreManager"); + propertiesElement.ShouldContainPath("BackupStoreManager.$ref").ShouldBeReferenceSchemaId("NullableToOneStaffMemberInRequest"); + + propertiesElement.Should().ContainProperty("Cashiers"); + propertiesElement.ShouldContainPath("Cashiers.$ref").ShouldBeReferenceSchemaId("ToManyStaffMemberInRequest"); + }); + }); + } + + [Fact] + public async Task Pascal_casing_convention_is_applied_to_PostRelationship_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.post").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("PostSupermarketCashiersRelationship"); + }); + }); + } + + [Fact] + public async Task Pascal_casing_convention_is_applied_to_Patch_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + string? documentSchemaRefId = null; + + document.ShouldContainPath("paths./Supermarkets/{id}.patch").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("PatchSupermarket"); + }); + + documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref") + .ShouldBeReferenceSchemaId("SupermarketPatchRequestDocument").SchemaReferenceId; + }); + + document.ShouldContainPath("components.schemas").With(schemasElement => + { + string? resourceDataSchemaRefId = null; + + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => + { + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("SupermarketDataInPatchRequest") + .SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("SupermarketAttributesInPatchRequest"); + propertiesElement.ShouldContainPath("relationships.$ref").ShouldBeReferenceSchemaId("SupermarketRelationshipsInPatchRequest"); + }); + }); + } + + [Fact] + public async Task Pascal_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./Supermarkets/{id}/relationships/StoreManager.patch").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("PatchSupermarketStoreManagerRelationship"); + }); + }); + } + + [Fact] + public async Task Pascal_casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./Supermarkets/{id}/relationships/BackupStoreManager.patch").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("PatchSupermarketBackupStoreManagerRelationship"); + }); + }); + } + + [Fact] + public async Task Pascal_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.patch").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("PatchSupermarketCashiersRelationship"); + }); + }); + } + + [Fact] + public async Task Pascal_casing_convention_is_applied_to_Delete_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./Supermarkets/{id}.delete").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("DeleteSupermarket"); + }); + }); + } + + [Fact] + public async Task Pascal_casing_convention_is_applied_to_DeleteRelationship_endpoint() + { + // Act + JsonElement document = await _lazyOpenApiDocument!.Value; + + // Assert + document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.delete").With(getElement => + { + getElement.ShouldContainPath("operationId").With(operationElement => + { + operationElement.ShouldBeString("DeleteSupermarketCashiersRelationship"); + }); + }); + } + + private async Task GetAsync(string requestUrl) + { + var request = new HttpRequestMessage(HttpMethod.Get, requestUrl); + + using HttpClient client = _testContext.Factory.CreateClient(); + using HttpResponseMessage responseMessage = await client.SendAsync(request); + + return await responseMessage.Content.ReadAsStringAsync(); + } + + private async Task WriteSwaggerDocumentToFileAsync(string document) + { + string testSuitePath = GetTestSuitePath(); + string documentPath = Path.Join(testSuitePath, "swagger.json"); + await File.WriteAllTextAsync(documentPath, document); + } + + private string GetTestSuitePath() + { + string solutionTestDirectoryPath = Directory.GetParent(Environment.CurrentDirectory)!.Parent!.Parent!.Parent!.FullName; + string currentNamespacePathRelativeToTestDirectory = Path.Join(GetType().Namespace!.Split('.')); + + return Path.Join(solutionTestDirectoryPath, currentNamespacePathRelativeToTestDirectory); + } +} diff --git a/test/OpenApiTests/NamingConvention/PascalCase/swagger.json b/test/OpenApiTests/NamingConvention/PascalCase/swagger.json new file mode 100644 index 0000000000..952cde541a --- /dev/null +++ b/test/OpenApiTests/NamingConvention/PascalCase/swagger.json @@ -0,0 +1,1466 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenApiTests", + "version": "1.0" + }, + "paths": { + "/Supermarkets": { + "get": { + "tags": [ + "Supermarkets" + ], + "operationId": "GetSupermarketCollection", + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/SupermarketCollectionResponseDocument" + } + } + } + } + } + }, + "head": { + "tags": [ + "Supermarkets" + ], + "operationId": "HeadSupermarketCollection", + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/SupermarketCollectionResponseDocument" + } + } + } + } + } + }, + "post": { + "tags": [ + "Supermarkets" + ], + "operationId": "PostSupermarket", + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/SupermarketPostRequestDocument" + } + } + } + }, + "responses": { + "201": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/SupermarketPrimaryResponseDocument" + } + } + } + }, + "204": { + "description": "Success" + } + } + } + }, + "/Supermarkets/{id}": { + "get": { + "tags": [ + "Supermarkets" + ], + "operationId": "GetSupermarket", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/SupermarketPrimaryResponseDocument" + } + } + } + } + } + }, + "head": { + "tags": [ + "Supermarkets" + ], + "operationId": "HeadSupermarket", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/SupermarketPrimaryResponseDocument" + } + } + } + } + } + }, + "patch": { + "tags": [ + "Supermarkets" + ], + "operationId": "PatchSupermarket", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/SupermarketPatchRequestDocument" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/SupermarketPrimaryResponseDocument" + } + } + } + }, + "204": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "Supermarkets" + ], + "operationId": "DeleteSupermarket", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/Supermarkets/{id}/BackupStoreManager": { + "get": { + "tags": [ + "Supermarkets" + ], + "operationId": "GetSupermarketBackupStoreManager", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/NullableStaffMemberSecondaryResponseDocument" + } + } + } + } + } + }, + "head": { + "tags": [ + "Supermarkets" + ], + "operationId": "HeadSupermarketBackupStoreManager", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/NullableStaffMemberSecondaryResponseDocument" + } + } + } + } + } + } + }, + "/Supermarkets/{id}/relationships/BackupStoreManager": { + "get": { + "tags": [ + "Supermarkets" + ], + "operationId": "GetSupermarketBackupStoreManagerRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/NullableStaffMemberIdentifierResponseDocument" + } + } + } + } + } + }, + "head": { + "tags": [ + "Supermarkets" + ], + "operationId": "HeadSupermarketBackupStoreManagerRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/NullableStaffMemberIdentifierResponseDocument" + } + } + } + } + } + }, + "patch": { + "tags": [ + "Supermarkets" + ], + "operationId": "PatchSupermarketBackupStoreManagerRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/NullableToOneStaffMemberInRequest" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/Supermarkets/{id}/Cashiers": { + "get": { + "tags": [ + "Supermarkets" + ], + "operationId": "GetSupermarketCashiers", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/StaffMemberCollectionResponseDocument" + } + } + } + } + } + }, + "head": { + "tags": [ + "Supermarkets" + ], + "operationId": "HeadSupermarketCashiers", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/StaffMemberCollectionResponseDocument" + } + } + } + } + } + } + }, + "/Supermarkets/{id}/relationships/Cashiers": { + "get": { + "tags": [ + "Supermarkets" + ], + "operationId": "GetSupermarketCashiersRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/StaffMemberIdentifierCollectionResponseDocument" + } + } + } + } + } + }, + "head": { + "tags": [ + "Supermarkets" + ], + "operationId": "HeadSupermarketCashiersRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/StaffMemberIdentifierCollectionResponseDocument" + } + } + } + } + } + }, + "post": { + "tags": [ + "Supermarkets" + ], + "operationId": "PostSupermarketCashiersRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/ToManyStaffMemberInRequest" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + }, + "patch": { + "tags": [ + "Supermarkets" + ], + "operationId": "PatchSupermarketCashiersRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/ToManyStaffMemberInRequest" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "Supermarkets" + ], + "operationId": "DeleteSupermarketCashiersRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/ToManyStaffMemberInRequest" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/Supermarkets/{id}/StoreManager": { + "get": { + "tags": [ + "Supermarkets" + ], + "operationId": "GetSupermarketStoreManager", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/StaffMemberSecondaryResponseDocument" + } + } + } + } + } + }, + "head": { + "tags": [ + "Supermarkets" + ], + "operationId": "HeadSupermarketStoreManager", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/StaffMemberSecondaryResponseDocument" + } + } + } + } + } + } + }, + "/Supermarkets/{id}/relationships/StoreManager": { + "get": { + "tags": [ + "Supermarkets" + ], + "operationId": "GetSupermarketStoreManagerRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/StaffMemberIdentifierResponseDocument" + } + } + } + } + } + }, + "head": { + "tags": [ + "Supermarkets" + ], + "operationId": "HeadSupermarketStoreManagerRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/StaffMemberIdentifierResponseDocument" + } + } + } + } + } + }, + "patch": { + "tags": [ + "Supermarkets" + ], + "operationId": "PatchSupermarketStoreManagerRelationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/ToOneStaffMemberInRequest" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + } + }, + "components": { + "schemas": { + "JsonapiObject": { + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "ext": { + "type": "array", + "items": { + "type": "string" + } + }, + "profile": { + "type": "array", + "items": { + "type": "string" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "LinksInRelationshipObject": { + "required": [ + "Related", + "Self" + ], + "type": "object", + "properties": { + "Self": { + "type": "string" + }, + "Related": { + "type": "string" + } + }, + "additionalProperties": false + }, + "LinksInResourceCollectionDocument": { + "required": [ + "First", + "Self" + ], + "type": "object", + "properties": { + "Self": { + "type": "string" + }, + "Describedby": { + "type": "string" + }, + "First": { + "type": "string" + }, + "Last": { + "type": "string" + }, + "Prev": { + "type": "string" + }, + "Next": { + "type": "string" + } + }, + "additionalProperties": false + }, + "LinksInResourceDocument": { + "required": [ + "Self" + ], + "type": "object", + "properties": { + "Self": { + "type": "string" + }, + "Describedby": { + "type": "string" + } + }, + "additionalProperties": false + }, + "LinksInResourceIdentifierCollectionDocument": { + "required": [ + "First", + "Related", + "Self" + ], + "type": "object", + "properties": { + "Self": { + "type": "string" + }, + "Describedby": { + "type": "string" + }, + "Related": { + "type": "string" + }, + "First": { + "type": "string" + }, + "Last": { + "type": "string" + }, + "Prev": { + "type": "string" + }, + "Next": { + "type": "string" + } + }, + "additionalProperties": false + }, + "LinksInResourceIdentifierDocument": { + "required": [ + "Related", + "Self" + ], + "type": "object", + "properties": { + "Self": { + "type": "string" + }, + "Describedby": { + "type": "string" + }, + "Related": { + "type": "string" + } + }, + "additionalProperties": false + }, + "LinksInResourceObject": { + "required": [ + "Self" + ], + "type": "object", + "properties": { + "Self": { + "type": "string" + } + }, + "additionalProperties": false + }, + "NullValue": { + "not": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "object" + }, + { + "type": "array" + } + ], + "items": { } + }, + "nullable": true + }, + "NullableStaffMemberIdentifierResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/StaffMemberIdentifier" + }, + { + "$ref": "#/components/schemas/NullValue" + } + ] + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/JsonapiObject" + }, + "links": { + "$ref": "#/components/schemas/LinksInResourceIdentifierDocument" + } + }, + "additionalProperties": false + }, + "NullableStaffMemberSecondaryResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/StaffMemberDataInResponse" + }, + { + "$ref": "#/components/schemas/NullValue" + } + ] + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/JsonapiObject" + }, + "links": { + "$ref": "#/components/schemas/LinksInResourceDocument" + } + }, + "additionalProperties": false + }, + "NullableToOneStaffMemberInRequest": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/StaffMemberIdentifier" + }, + { + "$ref": "#/components/schemas/NullValue" + } + ] + } + }, + "additionalProperties": false + }, + "NullableToOneStaffMemberInResponse": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/StaffMemberIdentifier" + }, + { + "$ref": "#/components/schemas/NullValue" + } + ] + }, + "links": { + "$ref": "#/components/schemas/LinksInRelationshipObject" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "StaffMemberAttributesInResponse": { + "type": "object", + "properties": { + "Name": { + "type": "string" + }, + "Age": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "StaffMemberCollectionResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StaffMemberDataInResponse" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/JsonapiObject" + }, + "links": { + "$ref": "#/components/schemas/LinksInResourceCollectionDocument" + } + }, + "additionalProperties": false + }, + "StaffMemberDataInResponse": { + "required": [ + "id", + "links", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/StaffMemberResourceType" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/StaffMemberAttributesInResponse" + }, + "links": { + "$ref": "#/components/schemas/LinksInResourceObject" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "StaffMemberIdentifier": { + "required": [ + "id", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/StaffMemberResourceType" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false + }, + "StaffMemberIdentifierCollectionResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StaffMemberIdentifier" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/JsonapiObject" + }, + "links": { + "$ref": "#/components/schemas/LinksInResourceIdentifierCollectionDocument" + } + }, + "additionalProperties": false + }, + "StaffMemberIdentifierResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/StaffMemberIdentifier" + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/JsonapiObject" + }, + "links": { + "$ref": "#/components/schemas/LinksInResourceIdentifierDocument" + } + }, + "additionalProperties": false + }, + "StaffMemberResourceType": { + "enum": [ + "StaffMembers" + ], + "type": "string" + }, + "StaffMemberSecondaryResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/StaffMemberDataInResponse" + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/JsonapiObject" + }, + "links": { + "$ref": "#/components/schemas/LinksInResourceDocument" + } + }, + "additionalProperties": false + }, + "SupermarketAttributesInPatchRequest": { + "type": "object", + "properties": { + "NameOfCity": { + "type": "string" + }, + "Kind": { + "$ref": "#/components/schemas/SupermarketType" + } + }, + "additionalProperties": false + }, + "SupermarketAttributesInPostRequest": { + "required": [ + "NameOfCity" + ], + "type": "object", + "properties": { + "NameOfCity": { + "type": "string" + }, + "Kind": { + "$ref": "#/components/schemas/SupermarketType" + } + }, + "additionalProperties": false + }, + "SupermarketAttributesInResponse": { + "type": "object", + "properties": { + "NameOfCity": { + "type": "string" + }, + "Kind": { + "$ref": "#/components/schemas/SupermarketType" + } + }, + "additionalProperties": false + }, + "SupermarketCollectionResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SupermarketDataInResponse" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/JsonapiObject" + }, + "links": { + "$ref": "#/components/schemas/LinksInResourceCollectionDocument" + } + }, + "additionalProperties": false + }, + "SupermarketDataInPatchRequest": { + "required": [ + "id", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/SupermarketResourceType" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/SupermarketAttributesInPatchRequest" + }, + "relationships": { + "$ref": "#/components/schemas/SupermarketRelationshipsInPatchRequest" + } + }, + "additionalProperties": false + }, + "SupermarketDataInPostRequest": { + "required": [ + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/SupermarketResourceType" + }, + "attributes": { + "$ref": "#/components/schemas/SupermarketAttributesInPostRequest" + }, + "relationships": { + "$ref": "#/components/schemas/SupermarketRelationshipsInPostRequest" + } + }, + "additionalProperties": false + }, + "SupermarketDataInResponse": { + "required": [ + "id", + "links", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/SupermarketResourceType" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/SupermarketAttributesInResponse" + }, + "relationships": { + "$ref": "#/components/schemas/SupermarketRelationshipsInResponse" + }, + "links": { + "$ref": "#/components/schemas/LinksInResourceObject" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "SupermarketPatchRequestDocument": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/SupermarketDataInPatchRequest" + } + }, + "additionalProperties": false + }, + "SupermarketPostRequestDocument": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/SupermarketDataInPostRequest" + } + }, + "additionalProperties": false + }, + "SupermarketPrimaryResponseDocument": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/SupermarketDataInResponse" + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/JsonapiObject" + }, + "links": { + "$ref": "#/components/schemas/LinksInResourceDocument" + } + }, + "additionalProperties": false + }, + "SupermarketRelationshipsInPatchRequest": { + "type": "object", + "properties": { + "StoreManager": { + "$ref": "#/components/schemas/ToOneStaffMemberInRequest" + }, + "BackupStoreManager": { + "$ref": "#/components/schemas/NullableToOneStaffMemberInRequest" + }, + "Cashiers": { + "$ref": "#/components/schemas/ToManyStaffMemberInRequest" + } + }, + "additionalProperties": false + }, + "SupermarketRelationshipsInPostRequest": { + "required": [ + "StoreManager" + ], + "type": "object", + "properties": { + "StoreManager": { + "$ref": "#/components/schemas/ToOneStaffMemberInRequest" + }, + "BackupStoreManager": { + "$ref": "#/components/schemas/NullableToOneStaffMemberInRequest" + }, + "Cashiers": { + "$ref": "#/components/schemas/ToManyStaffMemberInRequest" + } + }, + "additionalProperties": false + }, + "SupermarketRelationshipsInResponse": { + "type": "object", + "properties": { + "StoreManager": { + "$ref": "#/components/schemas/ToOneStaffMemberInResponse" + }, + "BackupStoreManager": { + "$ref": "#/components/schemas/NullableToOneStaffMemberInResponse" + }, + "Cashiers": { + "$ref": "#/components/schemas/ToManyStaffMemberInResponse" + } + }, + "additionalProperties": false + }, + "SupermarketResourceType": { + "enum": [ + "Supermarkets" + ], + "type": "string" + }, + "SupermarketType": { + "enum": [ + "Traditional", + "Budget", + "Warehouse" + ], + "type": "string" + }, + "ToManyStaffMemberInRequest": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StaffMemberIdentifier" + } + } + }, + "additionalProperties": false + }, + "ToManyStaffMemberInResponse": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StaffMemberIdentifier" + } + }, + "links": { + "$ref": "#/components/schemas/LinksInRelationshipObject" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "ToOneStaffMemberInRequest": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/StaffMemberIdentifier" + } + }, + "additionalProperties": false + }, + "ToOneStaffMemberInResponse": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/StaffMemberIdentifier" + }, + "links": { + "$ref": "#/components/schemas/LinksInRelationshipObject" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + } + } + } +} \ No newline at end of file diff --git a/test/OpenApiTests/NamingConvention/SupermarketType.cs b/test/OpenApiTests/NamingConvention/SupermarketType.cs index 551e781b22..428c1ee12c 100644 --- a/test/OpenApiTests/NamingConvention/SupermarketType.cs +++ b/test/OpenApiTests/NamingConvention/SupermarketType.cs @@ -1,5 +1,8 @@ +using JetBrains.Annotations; + namespace OpenApiTests.NamingConvention; +[UsedImplicitly(ImplicitUseTargetFlags.Members)] public enum SupermarketType { Traditional, diff --git a/test/OpenApiTests/OpenApiTestContext.cs b/test/OpenApiTests/OpenApiTestContext.cs new file mode 100644 index 0000000000..37cba8a405 --- /dev/null +++ b/test/OpenApiTests/OpenApiTestContext.cs @@ -0,0 +1,59 @@ +using System.Text.Json; +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore; +using OpenApiTests.Controllers; +using TestBuildingBlocks; +using Xunit; + +namespace OpenApiTests; + +[UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] +public sealed class OpenApiTestContext : IntegrationTestContext, IAsyncLifetime + where TStartup : class + where TDbContext : DbContext +{ + internal JsonElement Document { get; private set; } + + public async Task InitializeAsync() + { + UseController(); + + string content = await GetAsync("swagger/v1/swagger.json"); + + await WriteSwaggerDocumentToFileAsync(content); + + JsonDocument parsedContent = JsonDocument.Parse(content); + + Document = parsedContent.ToJsonElement(); + } + + private async Task GetAsync(string requestUrl) + { + var request = new HttpRequestMessage(HttpMethod.Get, requestUrl); + + using HttpClient client = Factory.CreateClient(); + using HttpResponseMessage responseMessage = await client.SendAsync(request); + + return await responseMessage.Content.ReadAsStringAsync(); + } + + private async Task WriteSwaggerDocumentToFileAsync(string document) + { + string testSuitePath = GetTestSuitePath(); + string documentPath = Path.Join(testSuitePath, "swagger.json"); + await File.WriteAllTextAsync(documentPath, document); + } + + private string GetTestSuitePath() + { + string solutionTestDirectoryPath = Directory.GetParent(Environment.CurrentDirectory)!.Parent!.Parent!.Parent!.FullName; + string currentNamespacePathRelativeToTestDirectory = Path.Join(GetType().Namespace!.Split('.')); + + return Path.Join(solutionTestDirectoryPath, currentNamespacePathRelativeToTestDirectory); + } + + public Task DisposeAsync() + { + return Task.CompletedTask; + } +} diff --git a/test/OpenApiTests/swagger.json b/test/OpenApiTests/swagger.json new file mode 100644 index 0000000000..1013e900a8 --- /dev/null +++ b/test/OpenApiTests/swagger.json @@ -0,0 +1,1466 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenApiTests", + "version": "1.0" + }, + "paths": { + "/supermarkets": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "get-supermarket-collection", + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarket-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "head-supermarket-collection", + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarket-collection-response-document" + } + } + } + } + } + }, + "post": { + "tags": [ + "supermarkets" + ], + "operationId": "post-supermarket", + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarket-post-request-document" + } + } + } + }, + "responses": { + "201": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarket-primary-response-document" + } + } + } + }, + "204": { + "description": "Success" + } + } + } + }, + "/supermarkets/{id}": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "get-supermarket", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarket-primary-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "head-supermarket", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarket-primary-response-document" + } + } + } + } + } + }, + "patch": { + "tags": [ + "supermarkets" + ], + "operationId": "patch-supermarket", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarket-patch-request-document" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/supermarket-primary-response-document" + } + } + } + }, + "204": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "supermarkets" + ], + "operationId": "delete-supermarket", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/supermarkets/{id}/backup-store-manager": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "get-supermarket-backup-store-manager", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullable-staff-member-secondary-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "head-supermarket-backup-store-manager", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullable-staff-member-secondary-response-document" + } + } + } + } + } + } + }, + "/supermarkets/{id}/relationships/backup-store-manager": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "get-supermarket-backup-store-manager-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullable-staff-member-identifier-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "head-supermarket-backup-store-manager-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullable-staff-member-identifier-response-document" + } + } + } + } + } + }, + "patch": { + "tags": [ + "supermarkets" + ], + "operationId": "patch-supermarket-backup-store-manager-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullable-to-one-staff-member-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/supermarkets/{id}/cashiers": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "get-supermarket-cashiers", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staff-member-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "head-supermarket-cashiers", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staff-member-collection-response-document" + } + } + } + } + } + } + }, + "/supermarkets/{id}/relationships/cashiers": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "get-supermarket-cashiers-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staff-member-identifier-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "head-supermarket-cashiers-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staff-member-identifier-collection-response-document" + } + } + } + } + } + }, + "post": { + "tags": [ + "supermarkets" + ], + "operationId": "post-supermarket-cashiers-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-staff-member-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + }, + "patch": { + "tags": [ + "supermarkets" + ], + "operationId": "patch-supermarket-cashiers-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-staff-member-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "supermarkets" + ], + "operationId": "delete-supermarket-cashiers-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-staff-member-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/supermarkets/{id}/store-manager": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "get-supermarket-store-manager", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staff-member-secondary-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "head-supermarket-store-manager", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staff-member-secondary-response-document" + } + } + } + } + } + } + }, + "/supermarkets/{id}/relationships/store-manager": { + "get": { + "tags": [ + "supermarkets" + ], + "operationId": "get-supermarket-store-manager-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staff-member-identifier-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "supermarkets" + ], + "operationId": "head-supermarket-store-manager-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/staff-member-identifier-response-document" + } + } + } + } + } + }, + "patch": { + "tags": [ + "supermarkets" + ], + "operationId": "patch-supermarket-store-manager-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-one-staff-member-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + } + }, + "components": { + "schemas": { + "jsonapi-object": { + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "ext": { + "type": "array", + "items": { + "type": "string" + } + }, + "profile": { + "type": "array", + "items": { + "type": "string" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "links-in-relationship-object": { + "required": [ + "related", + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "related": { + "type": "string" + } + }, + "additionalProperties": false + }, + "links-in-resource-collection-document": { + "required": [ + "first", + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + }, + "first": { + "type": "string" + }, + "last": { + "type": "string" + }, + "prev": { + "type": "string" + }, + "next": { + "type": "string" + } + }, + "additionalProperties": false + }, + "links-in-resource-document": { + "required": [ + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + } + }, + "additionalProperties": false + }, + "links-in-resource-identifier-collection-document": { + "required": [ + "first", + "related", + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + }, + "related": { + "type": "string" + }, + "first": { + "type": "string" + }, + "last": { + "type": "string" + }, + "prev": { + "type": "string" + }, + "next": { + "type": "string" + } + }, + "additionalProperties": false + }, + "links-in-resource-identifier-document": { + "required": [ + "related", + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + }, + "related": { + "type": "string" + } + }, + "additionalProperties": false + }, + "links-in-resource-object": { + "required": [ + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + } + }, + "additionalProperties": false + }, + "null-value": { + "not": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "object" + }, + { + "type": "array" + } + ], + "items": { } + }, + "nullable": true + }, + "nullable-staff-member-identifier-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/staff-member-identifier" + }, + { + "$ref": "#/components/schemas/null-value" + } + ] + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-identifier-document" + } + }, + "additionalProperties": false + }, + "nullable-staff-member-secondary-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/staff-member-data-in-response" + }, + { + "$ref": "#/components/schemas/null-value" + } + ] + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-document" + } + }, + "additionalProperties": false + }, + "nullable-to-one-staff-member-in-request": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/staff-member-identifier" + }, + { + "$ref": "#/components/schemas/null-value" + } + ] + } + }, + "additionalProperties": false + }, + "nullable-to-one-staff-member-in-response": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/staff-member-identifier" + }, + { + "$ref": "#/components/schemas/null-value" + } + ] + }, + "links": { + "$ref": "#/components/schemas/links-in-relationship-object" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "staff-member-attributes-in-response": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "age": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "staff-member-collection-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/staff-member-data-in-response" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-collection-document" + } + }, + "additionalProperties": false + }, + "staff-member-data-in-response": { + "required": [ + "id", + "links", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/staff-member-resource-type" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/staff-member-attributes-in-response" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-object" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "staff-member-identifier": { + "required": [ + "id", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/staff-member-resource-type" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false + }, + "staff-member-identifier-collection-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/staff-member-identifier" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-identifier-collection-document" + } + }, + "additionalProperties": false + }, + "staff-member-identifier-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/staff-member-identifier" + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-identifier-document" + } + }, + "additionalProperties": false + }, + "staff-member-resource-type": { + "enum": [ + "staff-members" + ], + "type": "string" + }, + "staff-member-secondary-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/staff-member-data-in-response" + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-document" + } + }, + "additionalProperties": false + }, + "supermarket-attributes-in-patch-request": { + "type": "object", + "properties": { + "name-of-city": { + "type": "string" + }, + "kind": { + "$ref": "#/components/schemas/supermarket-type" + } + }, + "additionalProperties": false + }, + "supermarket-attributes-in-post-request": { + "required": [ + "name-of-city" + ], + "type": "object", + "properties": { + "name-of-city": { + "type": "string" + }, + "kind": { + "$ref": "#/components/schemas/supermarket-type" + } + }, + "additionalProperties": false + }, + "supermarket-attributes-in-response": { + "type": "object", + "properties": { + "name-of-city": { + "type": "string" + }, + "kind": { + "$ref": "#/components/schemas/supermarket-type" + } + }, + "additionalProperties": false + }, + "supermarket-collection-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/supermarket-data-in-response" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-collection-document" + } + }, + "additionalProperties": false + }, + "supermarket-data-in-patch-request": { + "required": [ + "id", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/supermarket-resource-type" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/supermarket-attributes-in-patch-request" + }, + "relationships": { + "$ref": "#/components/schemas/supermarket-relationships-in-patch-request" + } + }, + "additionalProperties": false + }, + "supermarket-data-in-post-request": { + "required": [ + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/supermarket-resource-type" + }, + "attributes": { + "$ref": "#/components/schemas/supermarket-attributes-in-post-request" + }, + "relationships": { + "$ref": "#/components/schemas/supermarket-relationships-in-post-request" + } + }, + "additionalProperties": false + }, + "supermarket-data-in-response": { + "required": [ + "id", + "links", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/supermarket-resource-type" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/supermarket-attributes-in-response" + }, + "relationships": { + "$ref": "#/components/schemas/supermarket-relationships-in-response" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-object" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "supermarket-patch-request-document": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/supermarket-data-in-patch-request" + } + }, + "additionalProperties": false + }, + "supermarket-post-request-document": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/supermarket-data-in-post-request" + } + }, + "additionalProperties": false + }, + "supermarket-primary-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/supermarket-data-in-response" + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-document" + } + }, + "additionalProperties": false + }, + "supermarket-relationships-in-patch-request": { + "type": "object", + "properties": { + "store-manager": { + "$ref": "#/components/schemas/to-one-staff-member-in-request" + }, + "backup-store-manager": { + "$ref": "#/components/schemas/nullable-to-one-staff-member-in-request" + }, + "cashiers": { + "$ref": "#/components/schemas/to-many-staff-member-in-request" + } + }, + "additionalProperties": false + }, + "supermarket-relationships-in-post-request": { + "required": [ + "store-manager" + ], + "type": "object", + "properties": { + "store-manager": { + "$ref": "#/components/schemas/to-one-staff-member-in-request" + }, + "backup-store-manager": { + "$ref": "#/components/schemas/nullable-to-one-staff-member-in-request" + }, + "cashiers": { + "$ref": "#/components/schemas/to-many-staff-member-in-request" + } + }, + "additionalProperties": false + }, + "supermarket-relationships-in-response": { + "type": "object", + "properties": { + "store-manager": { + "$ref": "#/components/schemas/to-one-staff-member-in-response" + }, + "backup-store-manager": { + "$ref": "#/components/schemas/nullable-to-one-staff-member-in-response" + }, + "cashiers": { + "$ref": "#/components/schemas/to-many-staff-member-in-response" + } + }, + "additionalProperties": false + }, + "supermarket-resource-type": { + "enum": [ + "supermarkets" + ], + "type": "string" + }, + "supermarket-type": { + "enum": [ + "Traditional", + "Budget", + "Warehouse" + ], + "type": "string" + }, + "to-many-staff-member-in-request": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/staff-member-identifier" + } + } + }, + "additionalProperties": false + }, + "to-many-staff-member-in-response": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/staff-member-identifier" + } + }, + "links": { + "$ref": "#/components/schemas/links-in-relationship-object" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "to-one-staff-member-in-request": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/staff-member-identifier" + } + }, + "additionalProperties": false + }, + "to-one-staff-member-in-response": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/staff-member-identifier" + }, + "links": { + "$ref": "#/components/schemas/links-in-relationship-object" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + } + } + } +} \ No newline at end of file diff --git a/test/TestBuildingBlocks/JsonElementAssertions.cs b/test/TestBuildingBlocks/JsonElementAssertions.cs deleted file mode 100644 index b7825358e5..0000000000 --- a/test/TestBuildingBlocks/JsonElementAssertions.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Text.Json; -using FluentAssertions.Execution; - -namespace TestBuildingBlocks -{ - public sealed class JsonElementAssertions : JsonElementAssertions - { - internal JsonElementAssertions(JsonElement subject) - : base(subject) - { - } - } - - public class JsonElementAssertions - where TAssertions : JsonElementAssertions - { - /// - /// - Gets the object which value is being asserted. - /// - private JsonElement Subject { get; } - - protected JsonElementAssertions(JsonElement subject) - { - Subject = subject; - } - - public void HaveProperty(string propertyName, string because = "", params object[] becauseArgs) - { - Execute.Assertion.ForCondition(Subject.TryGetProperty(propertyName, out _)).BecauseOf(because, becauseArgs) - .FailWith($"Expected element to have property with name '{propertyName}, but did not find it."); - } - } -} From f6c01f256bc491d1346f5cd3c980e1234baabe28 Mon Sep 17 00:00:00 2001 From: maurei Date: Wed, 15 Dec 2021 11:16:29 +0100 Subject: [PATCH 05/15] Fix CI - Fixed hanging CI by adding xunit.runner.json - Moved retrieval of swagger document to test context fixture --- test/OpenApiClientTests/xunit.runner.json | 5 + .../CamelCase/CamelCaseTests.cs | 174 +- .../NamingConvention/CamelCase/swagger.json | 32 +- .../NamingConvention/KebabCase/swagger.json | 32 +- .../PascalCase/PascalCaseTests.cs | 174 +- .../NamingConvention/PascalCase/swagger.json | 32 +- .../NamingConvention/Supermarket.cs | 2 +- test/OpenApiTests/OpenApiTestContext.cs | 3 +- test/OpenApiTests/OpenApiTests.csproj | 6 + test/OpenApiTests/swagger.json | 1466 ----------------- test/OpenApiTests/xunit.runner.json | 5 + 11 files changed, 150 insertions(+), 1781 deletions(-) create mode 100644 test/OpenApiClientTests/xunit.runner.json delete mode 100644 test/OpenApiTests/swagger.json create mode 100644 test/OpenApiTests/xunit.runner.json diff --git a/test/OpenApiClientTests/xunit.runner.json b/test/OpenApiClientTests/xunit.runner.json new file mode 100644 index 0000000000..8f5f10571b --- /dev/null +++ b/test/OpenApiClientTests/xunit.runner.json @@ -0,0 +1,5 @@ +{ + "parallelizeAssembly": false, + "parallelizeTestCollections": false, + "maxParallelThreads": 1 +} diff --git a/test/OpenApiTests/NamingConvention/CamelCase/CamelCaseTests.cs b/test/OpenApiTests/NamingConvention/CamelCase/CamelCaseTests.cs index d04e37d187..e03c2aee2d 100644 --- a/test/OpenApiTests/NamingConvention/CamelCase/CamelCaseTests.cs +++ b/test/OpenApiTests/NamingConvention/CamelCase/CamelCaseTests.cs @@ -1,44 +1,24 @@ -using System.Text.Json; -using OpenApiTests.Controllers; using TestBuildingBlocks; using Xunit; namespace OpenApiTests.NamingConvention.CamelCase; -public sealed class CamelCaseTests - : IClassFixture, NamingConventionDbContext>> +public sealed class CamelCaseTests : IClassFixture, NamingConventionDbContext>> { - private static Lazy>? _lazyOpenApiDocument; - private readonly IntegrationTestContext, NamingConventionDbContext> _testContext; + private readonly OpenApiTestContext, NamingConventionDbContext> _testContext; - public CamelCaseTests(IntegrationTestContext, NamingConventionDbContext> testContext) + public CamelCaseTests(OpenApiTestContext, NamingConventionDbContext> testContext) { _testContext = testContext; - - _lazyOpenApiDocument ??= new Lazy>(async () => - { - testContext.UseController(); - - string content = await GetAsync("swagger/v1/swagger.json"); - - await WriteSwaggerDocumentToFileAsync(content); - - JsonDocument document = JsonDocument.Parse(content); - - return document.ToJsonElement(); - }, LazyThreadSafetyMode.ExecutionAndPublication); } [Fact] - public async Task Camel_casing_convention_is_applied_to_GetCollection_endpoint() + public void Camel_casing_convention_is_applied_to_GetCollection_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./supermarkets.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -49,7 +29,7 @@ public async Task Camel_casing_convention_is_applied_to_GetCollection_endpoint() .ShouldBeReferenceSchemaId("supermarketCollectionResponseDocument").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; @@ -132,15 +112,12 @@ public async Task Camel_casing_convention_is_applied_to_GetCollection_endpoint() } [Fact] - public async Task Camel_casing_convention_is_applied_to_GetSingle_endpoint() + public void Camel_casing_convention_is_applied_to_GetSingle_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./supermarkets/{id}.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -151,7 +128,7 @@ public async Task Camel_casing_convention_is_applied_to_GetSingle_endpoint() .ShouldBeReferenceSchemaId("supermarketPrimaryResponseDocument").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { @@ -161,15 +138,12 @@ public async Task Camel_casing_convention_is_applied_to_GetSingle_endpoint() } [Fact] - public async Task Camel_casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() + public void Camel_casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./supermarkets/{id}/storeManager.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/storeManager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -180,7 +154,7 @@ public async Task Camel_casing_convention_is_applied_to_GetSecondary_endpoint_wi .ShouldBeReferenceSchemaId("staffMemberSecondaryResponseDocument").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; @@ -198,13 +172,10 @@ public async Task Camel_casing_convention_is_applied_to_GetSecondary_endpoint_wi } [Fact] - public async Task Camel_casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() + public void Camel_casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./supermarkets/{id}/backupStoreManager.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/backupStoreManager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -217,13 +188,10 @@ public async Task Camel_casing_convention_is_applied_to_GetSecondary_endpoint_wi } [Fact] - public async Task Camel_casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() + public void Camel_casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./supermarkets/{id}/cashiers.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/cashiers.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -236,15 +204,12 @@ public async Task Camel_casing_convention_is_applied_to_GetSecondary_endpoint_wi } [Fact] - public async Task Camel_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() + public void Camel_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./supermarkets/{id}/relationships/storeManager.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/storeManager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -255,7 +220,7 @@ public async Task Camel_casing_convention_is_applied_to_GetRelationship_endpoint .ShouldBeReferenceSchemaId("staffMemberIdentifierResponseDocument").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { @@ -265,13 +230,10 @@ public async Task Camel_casing_convention_is_applied_to_GetRelationship_endpoint } [Fact] - public async Task Camel_casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() + public void Camel_casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./supermarkets/{id}/relationships/backupStoreManager.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/backupStoreManager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -284,15 +246,12 @@ public async Task Camel_casing_convention_is_applied_to_GetRelationship_endpoint } [Fact] - public async Task Camel_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() + public void Camel_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -303,7 +262,7 @@ public async Task Camel_casing_convention_is_applied_to_GetRelationship_endpoint .ShouldBeReferenceSchemaId("staffMemberIdentifierCollectionResponseDocument").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { @@ -313,15 +272,12 @@ public async Task Camel_casing_convention_is_applied_to_GetRelationship_endpoint } [Fact] - public async Task Camel_casing_convention_is_applied_to_Post_endpoint() + public void Camel_casing_convention_is_applied_to_Post_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./supermarkets.post").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets.post").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -332,7 +288,7 @@ public async Task Camel_casing_convention_is_applied_to_Post_endpoint() .ShouldBeReferenceSchemaId("supermarketPostRequestDocument").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; @@ -367,13 +323,10 @@ public async Task Camel_casing_convention_is_applied_to_Post_endpoint() } [Fact] - public async Task Camel_casing_convention_is_applied_to_PostRelationship_endpoint() + public void Camel_casing_convention_is_applied_to_PostRelationship_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.post").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.post").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -383,15 +336,12 @@ public async Task Camel_casing_convention_is_applied_to_PostRelationship_endpoin } [Fact] - public async Task Camel_casing_convention_is_applied_to_Patch_endpoint() + public void Camel_casing_convention_is_applied_to_Patch_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./supermarkets/{id}.patch").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -402,7 +352,7 @@ public async Task Camel_casing_convention_is_applied_to_Patch_endpoint() .ShouldBeReferenceSchemaId("supermarketPatchRequestDocument").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; @@ -421,13 +371,10 @@ public async Task Camel_casing_convention_is_applied_to_Patch_endpoint() } [Fact] - public async Task Camel_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() + public void Camel_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./supermarkets/{id}/relationships/storeManager.patch").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/storeManager.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -437,13 +384,10 @@ public async Task Camel_casing_convention_is_applied_to_PatchRelationship_endpoi } [Fact] - public async Task Camel_casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() + public void Camel_casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./supermarkets/{id}/relationships/backupStoreManager.patch").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/backupStoreManager.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -453,13 +397,10 @@ public async Task Camel_casing_convention_is_applied_to_PatchRelationship_endpoi } [Fact] - public async Task Camel_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() + public void Camel_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.patch").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -469,13 +410,10 @@ public async Task Camel_casing_convention_is_applied_to_PatchRelationship_endpoi } [Fact] - public async Task Camel_casing_convention_is_applied_to_Delete_endpoint() + public void Camel_casing_convention_is_applied_to_Delete_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./supermarkets/{id}.delete").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}.delete").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -485,13 +423,10 @@ public async Task Camel_casing_convention_is_applied_to_Delete_endpoint() } [Fact] - public async Task Camel_casing_convention_is_applied_to_DeleteRelationship_endpoint() + public void Camel_casing_convention_is_applied_to_DeleteRelationship_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.delete").With(getElement => + _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.delete").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -499,29 +434,4 @@ public async Task Camel_casing_convention_is_applied_to_DeleteRelationship_endpo }); }); } - - private async Task GetAsync(string requestUrl) - { - var request = new HttpRequestMessage(HttpMethod.Get, requestUrl); - - using HttpClient client = _testContext.Factory.CreateClient(); - using HttpResponseMessage responseMessage = await client.SendAsync(request); - - return await responseMessage.Content.ReadAsStringAsync(); - } - - private async Task WriteSwaggerDocumentToFileAsync(string document) - { - string testSuitePath = GetTestSuitePath(); - string documentPath = Path.Join(testSuitePath, "swagger.json"); - await File.WriteAllTextAsync(documentPath, document); - } - - private string GetTestSuitePath() - { - string solutionTestDirectoryPath = Directory.GetParent(Environment.CurrentDirectory)!.Parent!.Parent!.Parent!.FullName; - string currentNamespacePathRelativeToTestDirectory = Path.Join(GetType().Namespace!.Split('.')); - - return Path.Join(solutionTestDirectoryPath, currentNamespacePathRelativeToTestDirectory); - } } diff --git a/test/OpenApiTests/NamingConvention/CamelCase/swagger.json b/test/OpenApiTests/NamingConvention/CamelCase/swagger.json index 2eaac9303c..f33421cf38 100644 --- a/test/OpenApiTests/NamingConvention/CamelCase/swagger.json +++ b/test/OpenApiTests/NamingConvention/CamelCase/swagger.json @@ -734,7 +734,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} } }, "additionalProperties": false @@ -880,7 +880,7 @@ "type": "array" } ], - "items": { } + "items": {} }, "nullable": true }, @@ -903,7 +903,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/jsonapiObject" @@ -933,7 +933,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/jsonapiObject" @@ -984,7 +984,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} } }, "additionalProperties": false @@ -1017,7 +1017,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/jsonapiObject" @@ -1050,7 +1050,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} } }, "additionalProperties": false @@ -1086,7 +1086,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/jsonapiObject" @@ -1109,7 +1109,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/jsonapiObject" @@ -1138,7 +1138,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/jsonapiObject" @@ -1203,7 +1203,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/jsonapiObject" @@ -1279,7 +1279,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} } }, "additionalProperties": false @@ -1320,7 +1320,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/jsonapiObject" @@ -1425,7 +1425,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} } }, "additionalProperties": false @@ -1456,11 +1456,11 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} } }, "additionalProperties": false } } } -} \ No newline at end of file +} diff --git a/test/OpenApiTests/NamingConvention/KebabCase/swagger.json b/test/OpenApiTests/NamingConvention/KebabCase/swagger.json index 1013e900a8..91e62448f9 100644 --- a/test/OpenApiTests/NamingConvention/KebabCase/swagger.json +++ b/test/OpenApiTests/NamingConvention/KebabCase/swagger.json @@ -734,7 +734,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} } }, "additionalProperties": false @@ -880,7 +880,7 @@ "type": "array" } ], - "items": { } + "items": {} }, "nullable": true }, @@ -903,7 +903,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -933,7 +933,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -984,7 +984,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} } }, "additionalProperties": false @@ -1017,7 +1017,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -1050,7 +1050,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} } }, "additionalProperties": false @@ -1086,7 +1086,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -1109,7 +1109,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -1138,7 +1138,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -1203,7 +1203,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -1279,7 +1279,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} } }, "additionalProperties": false @@ -1320,7 +1320,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -1425,7 +1425,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} } }, "additionalProperties": false @@ -1456,11 +1456,11 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} } }, "additionalProperties": false } } } -} \ No newline at end of file +} diff --git a/test/OpenApiTests/NamingConvention/PascalCase/PascalCaseTests.cs b/test/OpenApiTests/NamingConvention/PascalCase/PascalCaseTests.cs index b9c26cee3e..ade1727911 100644 --- a/test/OpenApiTests/NamingConvention/PascalCase/PascalCaseTests.cs +++ b/test/OpenApiTests/NamingConvention/PascalCase/PascalCaseTests.cs @@ -1,44 +1,24 @@ -using System.Text.Json; -using OpenApiTests.Controllers; using TestBuildingBlocks; using Xunit; namespace OpenApiTests.NamingConvention.PascalCase; -public sealed class PascalCaseTests - : IClassFixture, NamingConventionDbContext>> +public sealed class PascalCaseTests : IClassFixture, NamingConventionDbContext>> { - private static Lazy>? _lazyOpenApiDocument; - private readonly IntegrationTestContext, NamingConventionDbContext> _testContext; + private readonly OpenApiTestContext, NamingConventionDbContext> _testContext; - public PascalCaseTests(IntegrationTestContext, NamingConventionDbContext> testContext) + public PascalCaseTests(OpenApiTestContext, NamingConventionDbContext> testContext) { _testContext = testContext; - - _lazyOpenApiDocument ??= new Lazy>(async () => - { - testContext.UseController(); - - string content = await GetAsync("swagger/v1/swagger.json"); - - await WriteSwaggerDocumentToFileAsync(content); - - JsonDocument document = JsonDocument.Parse(content); - - return document.ToJsonElement(); - }, LazyThreadSafetyMode.ExecutionAndPublication); } [Fact] - public async Task Pascal_casing_convention_is_applied_to_GetCollection_endpoint() + public void Pascal_casing_convention_is_applied_to_GetCollection_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./Supermarkets.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./Supermarkets.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -49,7 +29,7 @@ public async Task Pascal_casing_convention_is_applied_to_GetCollection_endpoint( .ShouldBeReferenceSchemaId("SupermarketCollectionResponseDocument").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; @@ -132,15 +112,12 @@ public async Task Pascal_casing_convention_is_applied_to_GetCollection_endpoint( } [Fact] - public async Task Pascal_casing_convention_is_applied_to_GetSingle_endpoint() + public void Pascal_casing_convention_is_applied_to_GetSingle_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./Supermarkets/{id}.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -151,7 +128,7 @@ public async Task Pascal_casing_convention_is_applied_to_GetSingle_endpoint() .ShouldBeReferenceSchemaId("SupermarketPrimaryResponseDocument").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { @@ -161,15 +138,12 @@ public async Task Pascal_casing_convention_is_applied_to_GetSingle_endpoint() } [Fact] - public async Task Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() + public void Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./Supermarkets/{id}/StoreManager.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/StoreManager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -180,7 +154,7 @@ public async Task Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_w .ShouldBeReferenceSchemaId("StaffMemberSecondaryResponseDocument").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; @@ -198,13 +172,10 @@ public async Task Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_w } [Fact] - public async Task Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() + public void Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./Supermarkets/{id}/BackupStoreManager.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/BackupStoreManager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -217,13 +188,10 @@ public async Task Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_w } [Fact] - public async Task Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() + public void Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./Supermarkets/{id}/Cashiers.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/Cashiers.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -236,15 +204,12 @@ public async Task Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_w } [Fact] - public async Task Pascal_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() + public void Pascal_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./Supermarkets/{id}/relationships/StoreManager.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/relationships/StoreManager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -255,7 +220,7 @@ public async Task Pascal_casing_convention_is_applied_to_GetRelationship_endpoin .ShouldBeReferenceSchemaId("StaffMemberIdentifierResponseDocument").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { @@ -265,13 +230,10 @@ public async Task Pascal_casing_convention_is_applied_to_GetRelationship_endpoin } [Fact] - public async Task Pascal_casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() + public void Pascal_casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./Supermarkets/{id}/relationships/BackupStoreManager.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/relationships/BackupStoreManager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -284,15 +246,12 @@ public async Task Pascal_casing_convention_is_applied_to_GetRelationship_endpoin } [Fact] - public async Task Pascal_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() + public void Pascal_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.get").With(getElement => + _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -303,7 +262,7 @@ public async Task Pascal_casing_convention_is_applied_to_GetRelationship_endpoin .ShouldBeReferenceSchemaId("StaffMemberIdentifierCollectionResponseDocument").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { @@ -313,15 +272,12 @@ public async Task Pascal_casing_convention_is_applied_to_GetRelationship_endpoin } [Fact] - public async Task Pascal_casing_convention_is_applied_to_Post_endpoint() + public void Pascal_casing_convention_is_applied_to_Post_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./Supermarkets.post").With(getElement => + _testContext.Document.ShouldContainPath("paths./Supermarkets.post").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -332,7 +288,7 @@ public async Task Pascal_casing_convention_is_applied_to_Post_endpoint() .ShouldBeReferenceSchemaId("SupermarketPostRequestDocument").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; @@ -367,13 +323,10 @@ public async Task Pascal_casing_convention_is_applied_to_Post_endpoint() } [Fact] - public async Task Pascal_casing_convention_is_applied_to_PostRelationship_endpoint() + public void Pascal_casing_convention_is_applied_to_PostRelationship_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.post").With(getElement => + _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.post").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -383,15 +336,12 @@ public async Task Pascal_casing_convention_is_applied_to_PostRelationship_endpoi } [Fact] - public async Task Pascal_casing_convention_is_applied_to_Patch_endpoint() + public void Pascal_casing_convention_is_applied_to_Patch_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert string? documentSchemaRefId = null; - document.ShouldContainPath("paths./Supermarkets/{id}.patch").With(getElement => + _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -402,7 +352,7 @@ public async Task Pascal_casing_convention_is_applied_to_Patch_endpoint() .ShouldBeReferenceSchemaId("SupermarketPatchRequestDocument").SchemaReferenceId; }); - document.ShouldContainPath("components.schemas").With(schemasElement => + _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; @@ -421,13 +371,10 @@ public async Task Pascal_casing_convention_is_applied_to_Patch_endpoint() } [Fact] - public async Task Pascal_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() + public void Pascal_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./Supermarkets/{id}/relationships/StoreManager.patch").With(getElement => + _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/relationships/StoreManager.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -437,13 +384,10 @@ public async Task Pascal_casing_convention_is_applied_to_PatchRelationship_endpo } [Fact] - public async Task Pascal_casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() + public void Pascal_casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./Supermarkets/{id}/relationships/BackupStoreManager.patch").With(getElement => + _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/relationships/BackupStoreManager.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -453,13 +397,10 @@ public async Task Pascal_casing_convention_is_applied_to_PatchRelationship_endpo } [Fact] - public async Task Pascal_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() + public void Pascal_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.patch").With(getElement => + _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -469,13 +410,10 @@ public async Task Pascal_casing_convention_is_applied_to_PatchRelationship_endpo } [Fact] - public async Task Pascal_casing_convention_is_applied_to_Delete_endpoint() + public void Pascal_casing_convention_is_applied_to_Delete_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./Supermarkets/{id}.delete").With(getElement => + _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}.delete").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -485,13 +423,10 @@ public async Task Pascal_casing_convention_is_applied_to_Delete_endpoint() } [Fact] - public async Task Pascal_casing_convention_is_applied_to_DeleteRelationship_endpoint() + public void Pascal_casing_convention_is_applied_to_DeleteRelationship_endpoint() { - // Act - JsonElement document = await _lazyOpenApiDocument!.Value; - // Assert - document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.delete").With(getElement => + _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.delete").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -499,29 +434,4 @@ public async Task Pascal_casing_convention_is_applied_to_DeleteRelationship_endp }); }); } - - private async Task GetAsync(string requestUrl) - { - var request = new HttpRequestMessage(HttpMethod.Get, requestUrl); - - using HttpClient client = _testContext.Factory.CreateClient(); - using HttpResponseMessage responseMessage = await client.SendAsync(request); - - return await responseMessage.Content.ReadAsStringAsync(); - } - - private async Task WriteSwaggerDocumentToFileAsync(string document) - { - string testSuitePath = GetTestSuitePath(); - string documentPath = Path.Join(testSuitePath, "swagger.json"); - await File.WriteAllTextAsync(documentPath, document); - } - - private string GetTestSuitePath() - { - string solutionTestDirectoryPath = Directory.GetParent(Environment.CurrentDirectory)!.Parent!.Parent!.Parent!.FullName; - string currentNamespacePathRelativeToTestDirectory = Path.Join(GetType().Namespace!.Split('.')); - - return Path.Join(solutionTestDirectoryPath, currentNamespacePathRelativeToTestDirectory); - } } diff --git a/test/OpenApiTests/NamingConvention/PascalCase/swagger.json b/test/OpenApiTests/NamingConvention/PascalCase/swagger.json index 952cde541a..c29792f530 100644 --- a/test/OpenApiTests/NamingConvention/PascalCase/swagger.json +++ b/test/OpenApiTests/NamingConvention/PascalCase/swagger.json @@ -734,7 +734,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} } }, "additionalProperties": false @@ -880,7 +880,7 @@ "type": "array" } ], - "items": { } + "items": {} }, "nullable": true }, @@ -903,7 +903,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/JsonapiObject" @@ -933,7 +933,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/JsonapiObject" @@ -984,7 +984,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} } }, "additionalProperties": false @@ -1017,7 +1017,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/JsonapiObject" @@ -1050,7 +1050,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} } }, "additionalProperties": false @@ -1086,7 +1086,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/JsonapiObject" @@ -1109,7 +1109,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/JsonapiObject" @@ -1138,7 +1138,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/JsonapiObject" @@ -1203,7 +1203,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/JsonapiObject" @@ -1279,7 +1279,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} } }, "additionalProperties": false @@ -1320,7 +1320,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} }, "jsonapi": { "$ref": "#/components/schemas/JsonapiObject" @@ -1425,7 +1425,7 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} } }, "additionalProperties": false @@ -1456,11 +1456,11 @@ }, "meta": { "type": "object", - "additionalProperties": { } + "additionalProperties": {} } }, "additionalProperties": false } } } -} \ No newline at end of file +} diff --git a/test/OpenApiTests/NamingConvention/Supermarket.cs b/test/OpenApiTests/NamingConvention/Supermarket.cs index 1a22a2a937..af716c1666 100644 --- a/test/OpenApiTests/NamingConvention/Supermarket.cs +++ b/test/OpenApiTests/NamingConvention/Supermarket.cs @@ -5,7 +5,7 @@ namespace OpenApiTests.NamingConvention; [UsedImplicitly(ImplicitUseTargetFlags.Members)] -[Resource] +[Resource(ControllerNamespace = "OpenApiTests")] public sealed class Supermarket : Identifiable { [Attr] diff --git a/test/OpenApiTests/OpenApiTestContext.cs b/test/OpenApiTests/OpenApiTestContext.cs index 37cba8a405..5350173e88 100644 --- a/test/OpenApiTests/OpenApiTestContext.cs +++ b/test/OpenApiTests/OpenApiTestContext.cs @@ -1,7 +1,6 @@ using System.Text.Json; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; -using OpenApiTests.Controllers; using TestBuildingBlocks; using Xunit; @@ -47,7 +46,7 @@ private async Task WriteSwaggerDocumentToFileAsync(string document) private string GetTestSuitePath() { string solutionTestDirectoryPath = Directory.GetParent(Environment.CurrentDirectory)!.Parent!.Parent!.Parent!.FullName; - string currentNamespacePathRelativeToTestDirectory = Path.Join(GetType().Namespace!.Split('.')); + string currentNamespacePathRelativeToTestDirectory = Path.Join(typeof(TStartup).Namespace!.Split('.')); return Path.Join(solutionTestDirectoryPath, currentNamespacePathRelativeToTestDirectory); } diff --git a/test/OpenApiTests/OpenApiTests.csproj b/test/OpenApiTests/OpenApiTests.csproj index 532c372ade..d24a3be47f 100644 --- a/test/OpenApiTests/OpenApiTests.csproj +++ b/test/OpenApiTests/OpenApiTests.csproj @@ -19,4 +19,10 @@ + + + + PreserveNewest + + diff --git a/test/OpenApiTests/swagger.json b/test/OpenApiTests/swagger.json deleted file mode 100644 index 1013e900a8..0000000000 --- a/test/OpenApiTests/swagger.json +++ /dev/null @@ -1,1466 +0,0 @@ -{ - "openapi": "3.0.1", - "info": { - "title": "OpenApiTests", - "version": "1.0" - }, - "paths": { - "/supermarkets": { - "get": { - "tags": [ - "supermarkets" - ], - "operationId": "get-supermarket-collection", - "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/supermarket-collection-response-document" - } - } - } - } - } - }, - "head": { - "tags": [ - "supermarkets" - ], - "operationId": "head-supermarket-collection", - "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/supermarket-collection-response-document" - } - } - } - } - } - }, - "post": { - "tags": [ - "supermarkets" - ], - "operationId": "post-supermarket", - "requestBody": { - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/supermarket-post-request-document" - } - } - } - }, - "responses": { - "201": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/supermarket-primary-response-document" - } - } - } - }, - "204": { - "description": "Success" - } - } - } - }, - "/supermarkets/{id}": { - "get": { - "tags": [ - "supermarkets" - ], - "operationId": "get-supermarket", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/supermarket-primary-response-document" - } - } - } - } - } - }, - "head": { - "tags": [ - "supermarkets" - ], - "operationId": "head-supermarket", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/supermarket-primary-response-document" - } - } - } - } - } - }, - "patch": { - "tags": [ - "supermarkets" - ], - "operationId": "patch-supermarket", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "requestBody": { - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/supermarket-patch-request-document" - } - } - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/supermarket-primary-response-document" - } - } - } - }, - "204": { - "description": "Success" - } - } - }, - "delete": { - "tags": [ - "supermarkets" - ], - "operationId": "delete-supermarket", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "204": { - "description": "Success" - } - } - } - }, - "/supermarkets/{id}/backup-store-manager": { - "get": { - "tags": [ - "supermarkets" - ], - "operationId": "get-supermarket-backup-store-manager", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/nullable-staff-member-secondary-response-document" - } - } - } - } - } - }, - "head": { - "tags": [ - "supermarkets" - ], - "operationId": "head-supermarket-backup-store-manager", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/nullable-staff-member-secondary-response-document" - } - } - } - } - } - } - }, - "/supermarkets/{id}/relationships/backup-store-manager": { - "get": { - "tags": [ - "supermarkets" - ], - "operationId": "get-supermarket-backup-store-manager-relationship", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/nullable-staff-member-identifier-response-document" - } - } - } - } - } - }, - "head": { - "tags": [ - "supermarkets" - ], - "operationId": "head-supermarket-backup-store-manager-relationship", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/nullable-staff-member-identifier-response-document" - } - } - } - } - } - }, - "patch": { - "tags": [ - "supermarkets" - ], - "operationId": "patch-supermarket-backup-store-manager-relationship", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "requestBody": { - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/nullable-to-one-staff-member-in-request" - } - } - } - }, - "responses": { - "204": { - "description": "Success" - } - } - } - }, - "/supermarkets/{id}/cashiers": { - "get": { - "tags": [ - "supermarkets" - ], - "operationId": "get-supermarket-cashiers", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/staff-member-collection-response-document" - } - } - } - } - } - }, - "head": { - "tags": [ - "supermarkets" - ], - "operationId": "head-supermarket-cashiers", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/staff-member-collection-response-document" - } - } - } - } - } - } - }, - "/supermarkets/{id}/relationships/cashiers": { - "get": { - "tags": [ - "supermarkets" - ], - "operationId": "get-supermarket-cashiers-relationship", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/staff-member-identifier-collection-response-document" - } - } - } - } - } - }, - "head": { - "tags": [ - "supermarkets" - ], - "operationId": "head-supermarket-cashiers-relationship", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/staff-member-identifier-collection-response-document" - } - } - } - } - } - }, - "post": { - "tags": [ - "supermarkets" - ], - "operationId": "post-supermarket-cashiers-relationship", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "requestBody": { - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/to-many-staff-member-in-request" - } - } - } - }, - "responses": { - "204": { - "description": "Success" - } - } - }, - "patch": { - "tags": [ - "supermarkets" - ], - "operationId": "patch-supermarket-cashiers-relationship", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "requestBody": { - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/to-many-staff-member-in-request" - } - } - } - }, - "responses": { - "204": { - "description": "Success" - } - } - }, - "delete": { - "tags": [ - "supermarkets" - ], - "operationId": "delete-supermarket-cashiers-relationship", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "requestBody": { - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/to-many-staff-member-in-request" - } - } - } - }, - "responses": { - "204": { - "description": "Success" - } - } - } - }, - "/supermarkets/{id}/store-manager": { - "get": { - "tags": [ - "supermarkets" - ], - "operationId": "get-supermarket-store-manager", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/staff-member-secondary-response-document" - } - } - } - } - } - }, - "head": { - "tags": [ - "supermarkets" - ], - "operationId": "head-supermarket-store-manager", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/staff-member-secondary-response-document" - } - } - } - } - } - } - }, - "/supermarkets/{id}/relationships/store-manager": { - "get": { - "tags": [ - "supermarkets" - ], - "operationId": "get-supermarket-store-manager-relationship", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/staff-member-identifier-response-document" - } - } - } - } - } - }, - "head": { - "tags": [ - "supermarkets" - ], - "operationId": "head-supermarket-store-manager-relationship", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "Success", - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/staff-member-identifier-response-document" - } - } - } - } - } - }, - "patch": { - "tags": [ - "supermarkets" - ], - "operationId": "patch-supermarket-store-manager-relationship", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "requestBody": { - "content": { - "application/vnd.api+json": { - "schema": { - "$ref": "#/components/schemas/to-one-staff-member-in-request" - } - } - } - }, - "responses": { - "204": { - "description": "Success" - } - } - } - } - }, - "components": { - "schemas": { - "jsonapi-object": { - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "ext": { - "type": "array", - "items": { - "type": "string" - } - }, - "profile": { - "type": "array", - "items": { - "type": "string" - } - }, - "meta": { - "type": "object", - "additionalProperties": { } - } - }, - "additionalProperties": false - }, - "links-in-relationship-object": { - "required": [ - "related", - "self" - ], - "type": "object", - "properties": { - "self": { - "type": "string" - }, - "related": { - "type": "string" - } - }, - "additionalProperties": false - }, - "links-in-resource-collection-document": { - "required": [ - "first", - "self" - ], - "type": "object", - "properties": { - "self": { - "type": "string" - }, - "describedby": { - "type": "string" - }, - "first": { - "type": "string" - }, - "last": { - "type": "string" - }, - "prev": { - "type": "string" - }, - "next": { - "type": "string" - } - }, - "additionalProperties": false - }, - "links-in-resource-document": { - "required": [ - "self" - ], - "type": "object", - "properties": { - "self": { - "type": "string" - }, - "describedby": { - "type": "string" - } - }, - "additionalProperties": false - }, - "links-in-resource-identifier-collection-document": { - "required": [ - "first", - "related", - "self" - ], - "type": "object", - "properties": { - "self": { - "type": "string" - }, - "describedby": { - "type": "string" - }, - "related": { - "type": "string" - }, - "first": { - "type": "string" - }, - "last": { - "type": "string" - }, - "prev": { - "type": "string" - }, - "next": { - "type": "string" - } - }, - "additionalProperties": false - }, - "links-in-resource-identifier-document": { - "required": [ - "related", - "self" - ], - "type": "object", - "properties": { - "self": { - "type": "string" - }, - "describedby": { - "type": "string" - }, - "related": { - "type": "string" - } - }, - "additionalProperties": false - }, - "links-in-resource-object": { - "required": [ - "self" - ], - "type": "object", - "properties": { - "self": { - "type": "string" - } - }, - "additionalProperties": false - }, - "null-value": { - "not": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "type": "object" - }, - { - "type": "array" - } - ], - "items": { } - }, - "nullable": true - }, - "nullable-staff-member-identifier-response-document": { - "required": [ - "data", - "links" - ], - "type": "object", - "properties": { - "data": { - "oneOf": [ - { - "$ref": "#/components/schemas/staff-member-identifier" - }, - { - "$ref": "#/components/schemas/null-value" - } - ] - }, - "meta": { - "type": "object", - "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapi-object" - }, - "links": { - "$ref": "#/components/schemas/links-in-resource-identifier-document" - } - }, - "additionalProperties": false - }, - "nullable-staff-member-secondary-response-document": { - "required": [ - "data", - "links" - ], - "type": "object", - "properties": { - "data": { - "oneOf": [ - { - "$ref": "#/components/schemas/staff-member-data-in-response" - }, - { - "$ref": "#/components/schemas/null-value" - } - ] - }, - "meta": { - "type": "object", - "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapi-object" - }, - "links": { - "$ref": "#/components/schemas/links-in-resource-document" - } - }, - "additionalProperties": false - }, - "nullable-to-one-staff-member-in-request": { - "required": [ - "data" - ], - "type": "object", - "properties": { - "data": { - "oneOf": [ - { - "$ref": "#/components/schemas/staff-member-identifier" - }, - { - "$ref": "#/components/schemas/null-value" - } - ] - } - }, - "additionalProperties": false - }, - "nullable-to-one-staff-member-in-response": { - "required": [ - "links" - ], - "type": "object", - "properties": { - "data": { - "oneOf": [ - { - "$ref": "#/components/schemas/staff-member-identifier" - }, - { - "$ref": "#/components/schemas/null-value" - } - ] - }, - "links": { - "$ref": "#/components/schemas/links-in-relationship-object" - }, - "meta": { - "type": "object", - "additionalProperties": { } - } - }, - "additionalProperties": false - }, - "staff-member-attributes-in-response": { - "type": "object", - "properties": { - "name": { - "type": "string" - }, - "age": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "staff-member-collection-response-document": { - "required": [ - "data", - "links" - ], - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/staff-member-data-in-response" - } - }, - "meta": { - "type": "object", - "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapi-object" - }, - "links": { - "$ref": "#/components/schemas/links-in-resource-collection-document" - } - }, - "additionalProperties": false - }, - "staff-member-data-in-response": { - "required": [ - "id", - "links", - "type" - ], - "type": "object", - "properties": { - "type": { - "$ref": "#/components/schemas/staff-member-resource-type" - }, - "id": { - "type": "string" - }, - "attributes": { - "$ref": "#/components/schemas/staff-member-attributes-in-response" - }, - "links": { - "$ref": "#/components/schemas/links-in-resource-object" - }, - "meta": { - "type": "object", - "additionalProperties": { } - } - }, - "additionalProperties": false - }, - "staff-member-identifier": { - "required": [ - "id", - "type" - ], - "type": "object", - "properties": { - "type": { - "$ref": "#/components/schemas/staff-member-resource-type" - }, - "id": { - "type": "string" - } - }, - "additionalProperties": false - }, - "staff-member-identifier-collection-response-document": { - "required": [ - "data", - "links" - ], - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/staff-member-identifier" - } - }, - "meta": { - "type": "object", - "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapi-object" - }, - "links": { - "$ref": "#/components/schemas/links-in-resource-identifier-collection-document" - } - }, - "additionalProperties": false - }, - "staff-member-identifier-response-document": { - "required": [ - "data", - "links" - ], - "type": "object", - "properties": { - "data": { - "$ref": "#/components/schemas/staff-member-identifier" - }, - "meta": { - "type": "object", - "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapi-object" - }, - "links": { - "$ref": "#/components/schemas/links-in-resource-identifier-document" - } - }, - "additionalProperties": false - }, - "staff-member-resource-type": { - "enum": [ - "staff-members" - ], - "type": "string" - }, - "staff-member-secondary-response-document": { - "required": [ - "data", - "links" - ], - "type": "object", - "properties": { - "data": { - "$ref": "#/components/schemas/staff-member-data-in-response" - }, - "meta": { - "type": "object", - "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapi-object" - }, - "links": { - "$ref": "#/components/schemas/links-in-resource-document" - } - }, - "additionalProperties": false - }, - "supermarket-attributes-in-patch-request": { - "type": "object", - "properties": { - "name-of-city": { - "type": "string" - }, - "kind": { - "$ref": "#/components/schemas/supermarket-type" - } - }, - "additionalProperties": false - }, - "supermarket-attributes-in-post-request": { - "required": [ - "name-of-city" - ], - "type": "object", - "properties": { - "name-of-city": { - "type": "string" - }, - "kind": { - "$ref": "#/components/schemas/supermarket-type" - } - }, - "additionalProperties": false - }, - "supermarket-attributes-in-response": { - "type": "object", - "properties": { - "name-of-city": { - "type": "string" - }, - "kind": { - "$ref": "#/components/schemas/supermarket-type" - } - }, - "additionalProperties": false - }, - "supermarket-collection-response-document": { - "required": [ - "data", - "links" - ], - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/supermarket-data-in-response" - } - }, - "meta": { - "type": "object", - "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapi-object" - }, - "links": { - "$ref": "#/components/schemas/links-in-resource-collection-document" - } - }, - "additionalProperties": false - }, - "supermarket-data-in-patch-request": { - "required": [ - "id", - "type" - ], - "type": "object", - "properties": { - "type": { - "$ref": "#/components/schemas/supermarket-resource-type" - }, - "id": { - "type": "string" - }, - "attributes": { - "$ref": "#/components/schemas/supermarket-attributes-in-patch-request" - }, - "relationships": { - "$ref": "#/components/schemas/supermarket-relationships-in-patch-request" - } - }, - "additionalProperties": false - }, - "supermarket-data-in-post-request": { - "required": [ - "type" - ], - "type": "object", - "properties": { - "type": { - "$ref": "#/components/schemas/supermarket-resource-type" - }, - "attributes": { - "$ref": "#/components/schemas/supermarket-attributes-in-post-request" - }, - "relationships": { - "$ref": "#/components/schemas/supermarket-relationships-in-post-request" - } - }, - "additionalProperties": false - }, - "supermarket-data-in-response": { - "required": [ - "id", - "links", - "type" - ], - "type": "object", - "properties": { - "type": { - "$ref": "#/components/schemas/supermarket-resource-type" - }, - "id": { - "type": "string" - }, - "attributes": { - "$ref": "#/components/schemas/supermarket-attributes-in-response" - }, - "relationships": { - "$ref": "#/components/schemas/supermarket-relationships-in-response" - }, - "links": { - "$ref": "#/components/schemas/links-in-resource-object" - }, - "meta": { - "type": "object", - "additionalProperties": { } - } - }, - "additionalProperties": false - }, - "supermarket-patch-request-document": { - "required": [ - "data" - ], - "type": "object", - "properties": { - "data": { - "$ref": "#/components/schemas/supermarket-data-in-patch-request" - } - }, - "additionalProperties": false - }, - "supermarket-post-request-document": { - "required": [ - "data" - ], - "type": "object", - "properties": { - "data": { - "$ref": "#/components/schemas/supermarket-data-in-post-request" - } - }, - "additionalProperties": false - }, - "supermarket-primary-response-document": { - "required": [ - "data", - "links" - ], - "type": "object", - "properties": { - "data": { - "$ref": "#/components/schemas/supermarket-data-in-response" - }, - "meta": { - "type": "object", - "additionalProperties": { } - }, - "jsonapi": { - "$ref": "#/components/schemas/jsonapi-object" - }, - "links": { - "$ref": "#/components/schemas/links-in-resource-document" - } - }, - "additionalProperties": false - }, - "supermarket-relationships-in-patch-request": { - "type": "object", - "properties": { - "store-manager": { - "$ref": "#/components/schemas/to-one-staff-member-in-request" - }, - "backup-store-manager": { - "$ref": "#/components/schemas/nullable-to-one-staff-member-in-request" - }, - "cashiers": { - "$ref": "#/components/schemas/to-many-staff-member-in-request" - } - }, - "additionalProperties": false - }, - "supermarket-relationships-in-post-request": { - "required": [ - "store-manager" - ], - "type": "object", - "properties": { - "store-manager": { - "$ref": "#/components/schemas/to-one-staff-member-in-request" - }, - "backup-store-manager": { - "$ref": "#/components/schemas/nullable-to-one-staff-member-in-request" - }, - "cashiers": { - "$ref": "#/components/schemas/to-many-staff-member-in-request" - } - }, - "additionalProperties": false - }, - "supermarket-relationships-in-response": { - "type": "object", - "properties": { - "store-manager": { - "$ref": "#/components/schemas/to-one-staff-member-in-response" - }, - "backup-store-manager": { - "$ref": "#/components/schemas/nullable-to-one-staff-member-in-response" - }, - "cashiers": { - "$ref": "#/components/schemas/to-many-staff-member-in-response" - } - }, - "additionalProperties": false - }, - "supermarket-resource-type": { - "enum": [ - "supermarkets" - ], - "type": "string" - }, - "supermarket-type": { - "enum": [ - "Traditional", - "Budget", - "Warehouse" - ], - "type": "string" - }, - "to-many-staff-member-in-request": { - "required": [ - "data" - ], - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/staff-member-identifier" - } - } - }, - "additionalProperties": false - }, - "to-many-staff-member-in-response": { - "required": [ - "links" - ], - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/staff-member-identifier" - } - }, - "links": { - "$ref": "#/components/schemas/links-in-relationship-object" - }, - "meta": { - "type": "object", - "additionalProperties": { } - } - }, - "additionalProperties": false - }, - "to-one-staff-member-in-request": { - "required": [ - "data" - ], - "type": "object", - "properties": { - "data": { - "$ref": "#/components/schemas/staff-member-identifier" - } - }, - "additionalProperties": false - }, - "to-one-staff-member-in-response": { - "required": [ - "links" - ], - "type": "object", - "properties": { - "data": { - "$ref": "#/components/schemas/staff-member-identifier" - }, - "links": { - "$ref": "#/components/schemas/links-in-relationship-object" - }, - "meta": { - "type": "object", - "additionalProperties": { } - } - }, - "additionalProperties": false - } - } - } -} \ No newline at end of file diff --git a/test/OpenApiTests/xunit.runner.json b/test/OpenApiTests/xunit.runner.json new file mode 100644 index 0000000000..8f5f10571b --- /dev/null +++ b/test/OpenApiTests/xunit.runner.json @@ -0,0 +1,5 @@ +{ + "parallelizeAssembly": false, + "parallelizeTestCollections": false, + "maxParallelThreads": 1 +} From b43807ad002c9af1be7a062615ef6f5b6b956234 Mon Sep 17 00:00:00 2001 From: maurei Date: Wed, 15 Dec 2021 14:58:18 +0100 Subject: [PATCH 06/15] Process review feedback --- JsonApiDotNetCore.sln.DotSettings | 3 + .../ApiException.cs | 67 +++---- .../Links/LinksInRelationshipObject.cs | 3 + .../LinksInResourceCollectionDocument.cs | 7 + .../Links/LinksInResourceDocument.cs | 3 + ...sInResourceIdentifierCollectionDocument.cs | 8 + .../LinksInResourceIdentifierDocument.cs | 4 + .../Links/LinksInResourceObject.cs | 2 + .../JsonApiOperationIdSelector.cs | 4 +- .../JsonApiSchemaIdSelector.cs | 2 +- .../ServiceCollectionExtensions.cs | 1 - .../StringExtensions.cs | 6 +- .../NullableReferenceSchemaGenerator.cs | 2 +- .../ResourceTypeSchemaGenerator.cs | 2 +- .../CamelCase/GeneratedTypesTests.cs | 78 -------- .../KebabCase/GeneratedTypesTests.cs | 79 -------- .../PascalCase/GeneratedTypesTests.cs | 78 -------- .../CamelCase/GeneratedTypesTests.cs | 77 ++++++++ .../KebabCase/GeneratedTypesTests.cs | 78 ++++++++ .../PascalCase/GeneratedTypesTests.cs | 77 ++++++++ .../OpenApiClientTests.csproj | 122 ++++++------ .../JsonElementExtensions.cs | 34 ++-- .../LegacyOpenApiIntegrationTests.cs | 19 +- .../NamingConventionDbContext.cs | 16 -- .../CamelCaseNamingConventionStartup.cs | 2 +- .../CamelCase/CamelCaseTests.cs | 174 +++++++++++------- .../CamelCase/swagger.json | 2 +- .../KebabCaseNamingConventionStartup.cs | 2 +- .../KebabCase/KebabCaseTests.cs | 174 +++++++++++------- .../KebabCase/swagger.json | 2 +- .../NamingConventionsDbContext.cs | 15 ++ .../PascalCaseNamingConventionStartup.cs | 2 +- .../PascalCase/PascalCaseTests.cs | 174 +++++++++++------- .../PascalCase/swagger.json | 2 +- .../StaffMember.cs | 2 +- .../Supermarket.cs | 4 +- .../SupermarketType.cs | 2 +- test/OpenApiTests/OpenApiTestContext.cs | 42 ++--- test/OpenApiTests/OpenApiTestSuite.cs | 58 ++++++ test/OpenApiTests/OpenApiTests.csproj | 46 ++--- .../JsonDocumentExtensions.cs | 15 -- .../TestBuildingBlocks.csproj | 1 - 42 files changed, 839 insertions(+), 652 deletions(-) delete mode 100644 test/OpenApiClientTests/NamingConvention/CamelCase/GeneratedTypesTests.cs delete mode 100644 test/OpenApiClientTests/NamingConvention/KebabCase/GeneratedTypesTests.cs delete mode 100644 test/OpenApiClientTests/NamingConvention/PascalCase/GeneratedTypesTests.cs create mode 100644 test/OpenApiClientTests/NamingConventions/CamelCase/GeneratedTypesTests.cs create mode 100644 test/OpenApiClientTests/NamingConventions/KebabCase/GeneratedTypesTests.cs create mode 100644 test/OpenApiClientTests/NamingConventions/PascalCase/GeneratedTypesTests.cs rename test/{TestBuildingBlocks => OpenApiTests}/JsonElementExtensions.cs (70%) delete mode 100644 test/OpenApiTests/NamingConvention/NamingConventionDbContext.cs rename test/OpenApiTests/{NamingConvention => NamingConventions}/CamelCase/CamelCaseNamingConventionStartup.cs (93%) rename test/OpenApiTests/{NamingConvention => NamingConventions}/CamelCase/CamelCaseTests.cs (73%) rename test/OpenApiTests/{NamingConvention => NamingConventions}/CamelCase/swagger.json (99%) rename test/OpenApiTests/{NamingConvention => NamingConventions}/KebabCase/KebabCaseNamingConventionStartup.cs (93%) rename test/OpenApiTests/{NamingConvention => NamingConventions}/KebabCase/KebabCaseTests.cs (73%) rename test/OpenApiTests/{NamingConvention => NamingConventions}/KebabCase/swagger.json (99%) create mode 100644 test/OpenApiTests/NamingConventions/NamingConventionsDbContext.cs rename test/OpenApiTests/{NamingConvention => NamingConventions}/PascalCase/PascalCaseNamingConventionStartup.cs (92%) rename test/OpenApiTests/{NamingConvention => NamingConventions}/PascalCase/PascalCaseTests.cs (71%) rename test/OpenApiTests/{NamingConvention => NamingConventions}/PascalCase/swagger.json (99%) rename test/OpenApiTests/{NamingConvention => NamingConventions}/StaffMember.cs (88%) rename test/OpenApiTests/{NamingConvention => NamingConventions}/Supermarket.cs (84%) rename test/OpenApiTests/{NamingConvention => NamingConventions}/SupermarketType.cs (78%) create mode 100644 test/OpenApiTests/OpenApiTestSuite.cs delete mode 100644 test/TestBuildingBlocks/JsonDocumentExtensions.cs diff --git a/JsonApiDotNetCore.sln.DotSettings b/JsonApiDotNetCore.sln.DotSettings index 6ae5a3a918..7982cce175 100644 --- a/JsonApiDotNetCore.sln.DotSettings +++ b/JsonApiDotNetCore.sln.DotSettings @@ -15,6 +15,9 @@ JsonApiDotNetCore.ArgumentGuard.NotNull($EXPR$, $NAME$); 50 False True + ExplicitlyExcluded + ExplicitlyExcluded + ExplicitlyExcluded SOLUTION True True diff --git a/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs b/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs index 05f340fc69..eff00c4230 100644 --- a/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs +++ b/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs @@ -1,44 +1,45 @@ using JetBrains.Annotations; // We cannot rely on generating ApiException as soon as we are generating multiple clients, see https://github.com/RicoSuter/NSwag/issues/2839#issuecomment-776647377. -// Instead, we take the generated code as is and use it for the various clients. -#nullable disable -// @formatter:off -// ReSharper disable All -namespace JsonApiDotNetCore.OpenApi.Client.Exceptions +// Instead, we configure NSwag to point to the exception below in the generated code. + +// ReSharper disable once CheckNamespace +namespace JsonApiDotNetCore.OpenApi.Client.Exceptions; + +[UsedImplicitly(ImplicitUseTargetFlags.Members)] +internal class ApiException : Exception { - [UsedImplicitly(ImplicitUseTargetFlags.Members)] - internal class ApiException : Exception - { - public int StatusCode { get; } + public int StatusCode { get; } + + public string? Response { get; } - public string Response { get; } + public IReadOnlyDictionary> Headers { get; } - public IReadOnlyDictionary> Headers { get; } + public ApiException(string message, int statusCode, string? response, IReadOnlyDictionary> headers, Exception innerException) + : base( + message + "\n\nStatus: " + statusCode + "\nResponse: \n" + + (response == null ? "(null)" : response[..(response.Length >= 512 ? 512 : response.Length)]), innerException) + { + StatusCode = statusCode; + Response = response; + Headers = headers; + } - public ApiException(string message, int statusCode, string response, IReadOnlyDictionary> headers, Exception innerException) - : base( - message + "\n\nStatus: " + statusCode + "\nResponse: \n" + - (response == null ? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)), innerException) - { - StatusCode = statusCode; - Response = response; - Headers = headers; - } + public override string ToString() + { + return $"HTTP Response: \n\n{Response}\n\n{base.ToString()}"; + } +} - public override string ToString() - { - return $"HTTP Response: \n\n{Response}\n\n{base.ToString()}"; - }} +[UsedImplicitly(ImplicitUseTargetFlags.Members)] +internal sealed class ApiException : ApiException +{ + public TResult Result { get; } - internal sealed class ApiException : ApiException + public ApiException(string message, int statusCode, string? response, IReadOnlyDictionary> headers, TResult result, + Exception innerException) + : base(message, statusCode, response, headers, innerException) { - public TResult Result { get; } - - public ApiException(string message, int statusCode, string response, IReadOnlyDictionary> headers, TResult result, - Exception innerException) - : base(message, statusCode, response, headers, innerException) - { - Result = result; - }} + Result = result; + } } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInRelationshipObject.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInRelationshipObject.cs index db689900b3..16b9735dac 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInRelationshipObject.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInRelationshipObject.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; @@ -7,8 +8,10 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; internal sealed class LinksInRelationshipObject { [Required] + [JsonPropertyName("self")] public string Self { get; set; } = null!; [Required] + [JsonPropertyName("related")] public string Related { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceCollectionDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceCollectionDocument.cs index e2a96ef8e4..9ce49f9f58 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceCollectionDocument.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceCollectionDocument.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; @@ -7,16 +8,22 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; internal sealed class LinksInResourceCollectionDocument { [Required] + [JsonPropertyName("self")] public string Self { get; set; } = null!; + [JsonPropertyName("describedby")] public string Describedby { get; set; } = null!; [Required] + [JsonPropertyName("first")] public string First { get; set; } = null!; + [JsonPropertyName("last")] public string Last { get; set; } = null!; + [JsonPropertyName("prev")] public string Prev { get; set; } = null!; + [JsonPropertyName("next")] public string Next { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceDocument.cs index e22ce258bc..b83e59fa4d 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceDocument.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceDocument.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; @@ -7,7 +8,9 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; internal sealed class LinksInResourceDocument { [Required] + [JsonPropertyName("self")] public string Self { get; set; } = null!; + [JsonPropertyName("describedby")] public string Describedby { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierCollectionDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierCollectionDocument.cs index f440b118fd..a13a6175b9 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierCollectionDocument.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierCollectionDocument.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; @@ -7,19 +8,26 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; internal sealed class LinksInResourceIdentifierCollectionDocument { [Required] + [JsonPropertyName("self")] public string Self { get; set; } = null!; + [JsonPropertyName("describedby")] public string Describedby { get; set; } = null!; [Required] + [JsonPropertyName("related")] public string Related { get; set; } = null!; [Required] + [JsonPropertyName("first")] public string First { get; set; } = null!; + [JsonPropertyName("last")] public string Last { get; set; } = null!; + [JsonPropertyName("prev")] public string Prev { get; set; } = null!; + [JsonPropertyName("next")] public string Next { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierDocument.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierDocument.cs index 1fcca155cf..9304162d0f 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierDocument.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceIdentifierDocument.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; @@ -7,10 +8,13 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; internal sealed class LinksInResourceIdentifierDocument { [Required] + [JsonPropertyName("self")] public string Self { get; set; } = null!; + [JsonPropertyName("describedby")] public string Describedby { get; set; } = null!; [Required] + [JsonPropertyName("related")] public string Related { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceObject.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceObject.cs index f8f7de61f2..552cc703e3 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceObject.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiObjects/Links/LinksInResourceObject.cs @@ -1,4 +1,5 @@ using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; using JetBrains.Annotations; namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; @@ -7,5 +8,6 @@ namespace JsonApiDotNetCore.OpenApi.JsonApiObjects.Links; internal sealed class LinksInResourceObject { [Required] + [JsonPropertyName("self")] public string Self { get; set; } = null!; } diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiOperationIdSelector.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiOperationIdSelector.cs index 353433e706..9724effbd5 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiOperationIdSelector.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiOperationIdSelector.cs @@ -112,7 +112,7 @@ private string ApplyTemplate(string operationIdTemplate, ResourceType resourceTy throw new UnreachableCodeException(); } - string method = endpoint.HttpMethod!.ToLowerInvariant(); + string method = endpoint.HttpMethod.ToLowerInvariant(); string relationshipName = operationIdTemplate.Contains("[RelationshipName]") ? endpoint.RelativePath.Split("/").Last() : string.Empty; // @formatter:wrap_chained_method_calls chop_always @@ -122,7 +122,7 @@ private string ApplyTemplate(string operationIdTemplate, ResourceType resourceTy .Replace("[Method]", method) .Replace("[PrimaryResourceName]", resourceType.PublicName.Singularize()) .Replace("[RelationshipName]", relationshipName) - .Pascalize(); + .ToPascalCase(); // @formatter:keep_existing_linebreaks restore // @formatter:wrap_chained_method_calls restore diff --git a/src/JsonApiDotNetCore.OpenApi/JsonApiSchemaIdSelector.cs b/src/JsonApiDotNetCore.OpenApi/JsonApiSchemaIdSelector.cs index 89955b9b64..2eb3f13824 100644 --- a/src/JsonApiDotNetCore.OpenApi/JsonApiSchemaIdSelector.cs +++ b/src/JsonApiDotNetCore.OpenApi/JsonApiSchemaIdSelector.cs @@ -71,7 +71,7 @@ public string GetSchemaId(Type type) throw new UnreachableCodeException(); } - string pascalCaseSchemaId = OpenTypeToSchemaTemplateMap[openType].Replace("[ResourceName]", resourceType.PublicName.Singularize()).Pascalize(); + string pascalCaseSchemaId = OpenTypeToSchemaTemplateMap[openType].Replace("[ResourceName]", resourceType.PublicName.Singularize()).ToPascalCase(); return _namingPolicy != null ? _namingPolicy.ConvertName(pascalCaseSchemaId) : pascalCaseSchemaId; } diff --git a/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs b/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs index 7140d714ca..55695102a2 100644 --- a/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs +++ b/src/JsonApiDotNetCore.OpenApi/ServiceCollectionExtensions.cs @@ -41,7 +41,6 @@ private static void AddCustomApiExplorer(IServiceCollection services, IMvcCoreBu var apiDescriptionProviders = provider.GetRequiredService>(); JsonApiActionDescriptorCollectionProvider descriptorCollectionProviderWrapper = new(controllerResourceMapping, actionDescriptorCollectionProvider); - return new ApiDescriptionGroupCollectionProvider(descriptorCollectionProviderWrapper, apiDescriptionProviders); }); diff --git a/src/JsonApiDotNetCore.OpenApi/StringExtensions.cs b/src/JsonApiDotNetCore.OpenApi/StringExtensions.cs index 14a992c461..d52862844a 100644 --- a/src/JsonApiDotNetCore.OpenApi/StringExtensions.cs +++ b/src/JsonApiDotNetCore.OpenApi/StringExtensions.cs @@ -4,8 +4,10 @@ namespace JsonApiDotNetCore.OpenApi; internal static class StringExtensions { - public static string Pascalize(this string source) + private static readonly Regex Pattern = new("(?:^|-|_| +)(.)", RegexOptions.Compiled); + + public static string ToPascalCase(this string source) { - return Regex.Replace(source, "(?:^|-|_| +)(.)", match => match.Groups[1].Value.ToUpper()); + return Pattern.Replace(source, match => match.Groups[1].Value.ToUpper()); } } diff --git a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/NullableReferenceSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/NullableReferenceSchemaGenerator.cs index 04fabe1807..d9bedc343c 100644 --- a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/NullableReferenceSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/NullableReferenceSchemaGenerator.cs @@ -10,8 +10,8 @@ internal sealed class NullableReferenceSchemaGenerator private readonly NullableReferenceSchemaStrategy _nullableReferenceStrategy = Enum.Parse(NullableReferenceSchemaStrategy.Implicit.ToString()); - private readonly string _nullableSchemaReferenceId; private readonly ISchemaRepositoryAccessor _schemaRepositoryAccessor; + private readonly string _nullableSchemaReferenceId; private OpenApiSchema? _referenceSchemaForExplicitNullValue; diff --git a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceTypeSchemaGenerator.cs b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceTypeSchemaGenerator.cs index 8a7118147e..9113f3b359 100644 --- a/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceTypeSchemaGenerator.cs +++ b/src/JsonApiDotNetCore.OpenApi/SwaggerComponents/ResourceTypeSchemaGenerator.cs @@ -63,7 +63,7 @@ public OpenApiSchema Get(Type resourceClrType) private string GetSchemaId(ResourceType resourceType) { - string pascalCaseSchemaId = ResourceTypeSchemaIdTemplate.Replace("[ResourceName]", resourceType.PublicName.Singularize()).Pascalize(); + string pascalCaseSchemaId = ResourceTypeSchemaIdTemplate.Replace("[ResourceName]", resourceType.PublicName.Singularize()).ToPascalCase(); return _namingPolicy != null ? _namingPolicy.ConvertName(pascalCaseSchemaId) : pascalCaseSchemaId; } diff --git a/test/OpenApiClientTests/NamingConvention/CamelCase/GeneratedTypesTests.cs b/test/OpenApiClientTests/NamingConvention/CamelCase/GeneratedTypesTests.cs deleted file mode 100644 index 37ca4dbe6e..0000000000 --- a/test/OpenApiClientTests/NamingConvention/CamelCase/GeneratedTypesTests.cs +++ /dev/null @@ -1,78 +0,0 @@ -using FluentAssertions; -using OpenApiClientTests.NamingConvention.CamelCase.GeneratedCode; -using Xunit; - -namespace OpenApiClientTests.NamingConvention.CamelCase; - -public sealed class GeneratedTypesTests -{ - [Fact] - public void Generated_code_is_named_as_expected() - { - nameof(CamelCaseClient.GetSupermarketCollectionAsync).Should().NotBeNull(); - nameof(CamelCaseClient.GetSupermarketCollectionAsync).Should().NotBeNull(); - nameof(CamelCaseClient.PostSupermarketAsync).Should().NotBeNull(); - nameof(CamelCaseClient.GetSupermarketAsync).Should().NotBeNull(); - nameof(CamelCaseClient.GetSupermarketAsync).Should().NotBeNull(); - nameof(CamelCaseClient.PatchSupermarketAsync).Should().NotBeNull(); - nameof(CamelCaseClient.DeleteSupermarketAsync).Should().NotBeNull(); - nameof(CamelCaseClient.GetSupermarketBackupStoreManagerAsync).Should().NotBeNull(); - nameof(CamelCaseClient.GetSupermarketBackupStoreManagerAsync).Should().NotBeNull(); - nameof(CamelCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(CamelCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(CamelCaseClient.PatchSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(CamelCaseClient.GetSupermarketCashiersAsync).Should().NotBeNull(); - nameof(CamelCaseClient.GetSupermarketCashiersAsync).Should().NotBeNull(); - nameof(CamelCaseClient.GetSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(CamelCaseClient.GetSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(CamelCaseClient.PostSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(CamelCaseClient.PatchSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(CamelCaseClient.DeleteSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(CamelCaseClient.GetSupermarketStoreManagerAsync).Should().NotBeNull(); - nameof(CamelCaseClient.GetSupermarketStoreManagerAsync).Should().NotBeNull(); - nameof(CamelCaseClient.GetSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(CamelCaseClient.GetSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(CamelCaseClient.PatchSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); - - nameof(SupermarketCollectionResponseDocument).Should().NotBeNull(); - nameof(LinksInResourceCollectionDocument).Should().NotBeNull(); - nameof(JsonapiObject).Should().NotBeNull(); - nameof(SupermarketDataInResponse).Should().NotBeNull(); - nameof(SupermarketResourceType).Should().NotBeNull(); - nameof(SupermarketAttributesInResponse.NameOfCity).Should().NotBeNull(); - nameof(SupermarketRelationshipsInResponse.StoreManager).Should().NotBeNull(); - nameof(SupermarketRelationshipsInResponse.BackupStoreManager).Should().NotBeNull(); - nameof(LinksInResourceObject).Should().NotBeNull(); - nameof(SupermarketType).Should().NotBeNull(); - nameof(CamelCaseClient.GetSupermarketAsync).Should().NotBeNull(); - nameof(ToOneStaffMemberInResponse).Should().NotBeNull(); - nameof(NullableToOneStaffMemberInResponse).Should().NotBeNull(); - nameof(ToManyStaffMemberInResponse).Should().NotBeNull(); - nameof(LinksInRelationshipObject).Should().NotBeNull(); - nameof(StaffMemberIdentifier).Should().NotBeNull(); - nameof(StaffMemberResourceType.StaffMembers).Should().NotBeNull(); - nameof(SupermarketPrimaryResponseDocument).Should().NotBeNull(); - nameof(LinksInResourceDocument).Should().NotBeNull(); - nameof(StaffMemberSecondaryResponseDocument).Should().NotBeNull(); - nameof(StaffMemberDataInResponse).Should().NotBeNull(); - nameof(StaffMemberAttributesInResponse).Should().NotBeNull(); - nameof(NullableStaffMemberSecondaryResponseDocument).Should().NotBeNull(); - nameof(StaffMemberCollectionResponseDocument).Should().NotBeNull(); - nameof(StaffMemberIdentifierResponseDocument).Should().NotBeNull(); - nameof(LinksInResourceIdentifierDocument).Should().NotBeNull(); - nameof(NullableStaffMemberIdentifierResponseDocument).Should().NotBeNull(); - nameof(StaffMemberIdentifierCollectionResponseDocument).Should().NotBeNull(); - nameof(LinksInResourceIdentifierCollectionDocument).Should().NotBeNull(); - nameof(SupermarketPostRequestDocument).Should().NotBeNull(); - nameof(SupermarketDataInPostRequest).Should().NotBeNull(); - nameof(SupermarketAttributesInPostRequest).Should().NotBeNull(); - nameof(SupermarketRelationshipsInPostRequest).Should().NotBeNull(); - nameof(ToOneStaffMemberInRequest).Should().NotBeNull(); - nameof(NullableToOneStaffMemberInRequest).Should().NotBeNull(); - nameof(ToManyStaffMemberInRequest).Should().NotBeNull(); - nameof(SupermarketPatchRequestDocument).Should().NotBeNull(); - nameof(SupermarketDataInPatchRequest).Should().NotBeNull(); - nameof(SupermarketAttributesInPatchRequest).Should().NotBeNull(); - nameof(SupermarketRelationshipsInPatchRequest).Should().NotBeNull(); - } -} diff --git a/test/OpenApiClientTests/NamingConvention/KebabCase/GeneratedTypesTests.cs b/test/OpenApiClientTests/NamingConvention/KebabCase/GeneratedTypesTests.cs deleted file mode 100644 index c601ab0ba4..0000000000 --- a/test/OpenApiClientTests/NamingConvention/KebabCase/GeneratedTypesTests.cs +++ /dev/null @@ -1,79 +0,0 @@ -using FluentAssertions; -using OpenApiClientTests.NamingConvention.KebabCase.GeneratedCode; -using Xunit; - -namespace OpenApiClientTests.NamingConvention.KebabCase; - -public sealed class GeneratedTypesTests -{ - [Fact] - public void Generated_code_is_named_as_expected() - { - nameof(KebabCaseClient.GetSupermarketCollectionAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketCollectionAsync).Should().NotBeNull(); - nameof(KebabCaseClient.PostSupermarketAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketAsync).Should().NotBeNull(); - nameof(KebabCaseClient.PatchSupermarketAsync).Should().NotBeNull(); - nameof(KebabCaseClient.DeleteSupermarketAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketBackupStoreManagerAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketBackupStoreManagerAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.PatchSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketCashiersAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketCashiersAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.PostSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.PatchSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.DeleteSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketStoreManagerAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketStoreManagerAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(KebabCaseClient.PatchSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); - - nameof(SupermarketCollectionResponseDocument).Should().NotBeNull(); - nameof(LinksInResourceCollectionDocument).Should().NotBeNull(); - nameof(JsonapiObject).Should().NotBeNull(); - nameof(SupermarketDataInResponse).Should().NotBeNull(); - nameof(SupermarketResourceType).Should().NotBeNull(); - nameof(SupermarketAttributesInResponse.NameOfCity).Should().NotBeNull(); - nameof(SupermarketRelationshipsInResponse.StoreManager).Should().NotBeNull(); - nameof(SupermarketRelationshipsInResponse.BackupStoreManager).Should().NotBeNull(); - nameof(LinksInResourceObject).Should().NotBeNull(); - nameof(SupermarketType).Should().NotBeNull(); - nameof(KebabCaseClient.GetSupermarketAsync).Should().NotBeNull(); - nameof(ToOneStaffMemberInResponse).Should().NotBeNull(); - nameof(NullableToOneStaffMemberInResponse).Should().NotBeNull(); - nameof(ToManyStaffMemberInResponse).Should().NotBeNull(); - nameof(LinksInRelationshipObject).Should().NotBeNull(); - nameof(StaffMemberIdentifier).Should().NotBeNull(); - nameof(StaffMemberResourceType).Should().NotBeNull(); - nameof(StaffMemberResourceType.StaffMembers).Should().NotBeNull(); - nameof(SupermarketPrimaryResponseDocument).Should().NotBeNull(); - nameof(LinksInResourceDocument).Should().NotBeNull(); - nameof(StaffMemberSecondaryResponseDocument).Should().NotBeNull(); - nameof(StaffMemberDataInResponse).Should().NotBeNull(); - nameof(StaffMemberAttributesInResponse).Should().NotBeNull(); - nameof(NullableStaffMemberSecondaryResponseDocument).Should().NotBeNull(); - nameof(StaffMemberCollectionResponseDocument).Should().NotBeNull(); - nameof(StaffMemberIdentifierResponseDocument).Should().NotBeNull(); - nameof(LinksInResourceIdentifierDocument).Should().NotBeNull(); - nameof(NullableStaffMemberIdentifierResponseDocument).Should().NotBeNull(); - nameof(StaffMemberIdentifierCollectionResponseDocument).Should().NotBeNull(); - nameof(LinksInResourceIdentifierCollectionDocument).Should().NotBeNull(); - nameof(SupermarketPostRequestDocument).Should().NotBeNull(); - nameof(SupermarketDataInPostRequest).Should().NotBeNull(); - nameof(SupermarketAttributesInPostRequest).Should().NotBeNull(); - nameof(SupermarketRelationshipsInPostRequest).Should().NotBeNull(); - nameof(ToOneStaffMemberInRequest).Should().NotBeNull(); - nameof(NullableToOneStaffMemberInRequest).Should().NotBeNull(); - nameof(ToManyStaffMemberInRequest).Should().NotBeNull(); - nameof(SupermarketPatchRequestDocument).Should().NotBeNull(); - nameof(SupermarketDataInPatchRequest).Should().NotBeNull(); - nameof(SupermarketAttributesInPatchRequest).Should().NotBeNull(); - nameof(SupermarketRelationshipsInPatchRequest).Should().NotBeNull(); - } -} diff --git a/test/OpenApiClientTests/NamingConvention/PascalCase/GeneratedTypesTests.cs b/test/OpenApiClientTests/NamingConvention/PascalCase/GeneratedTypesTests.cs deleted file mode 100644 index f1f5e35ea0..0000000000 --- a/test/OpenApiClientTests/NamingConvention/PascalCase/GeneratedTypesTests.cs +++ /dev/null @@ -1,78 +0,0 @@ -using FluentAssertions; -using OpenApiClientTests.NamingConvention.PascalCase.GeneratedCode; -using Xunit; - -namespace OpenApiClientTests.NamingConvention.PascalCase; - -public sealed class GeneratedTypesTests -{ - [Fact] - public void Generated_code_is_named_as_expected() - { - nameof(PascalCaseClient.GetSupermarketCollectionAsync).Should().NotBeNull(); - nameof(PascalCaseClient.GetSupermarketCollectionAsync).Should().NotBeNull(); - nameof(PascalCaseClient.PostSupermarketAsync).Should().NotBeNull(); - nameof(PascalCaseClient.GetSupermarketAsync).Should().NotBeNull(); - nameof(PascalCaseClient.GetSupermarketAsync).Should().NotBeNull(); - nameof(PascalCaseClient.PatchSupermarketAsync).Should().NotBeNull(); - nameof(PascalCaseClient.DeleteSupermarketAsync).Should().NotBeNull(); - nameof(PascalCaseClient.GetSupermarketBackupStoreManagerAsync).Should().NotBeNull(); - nameof(PascalCaseClient.GetSupermarketBackupStoreManagerAsync).Should().NotBeNull(); - nameof(PascalCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(PascalCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(PascalCaseClient.PatchSupermarketBackupStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(PascalCaseClient.GetSupermarketCashiersAsync).Should().NotBeNull(); - nameof(PascalCaseClient.GetSupermarketCashiersAsync).Should().NotBeNull(); - nameof(PascalCaseClient.GetSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(PascalCaseClient.GetSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(PascalCaseClient.PostSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(PascalCaseClient.PatchSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(PascalCaseClient.DeleteSupermarketCashiersRelationshipAsync).Should().NotBeNull(); - nameof(PascalCaseClient.GetSupermarketStoreManagerAsync).Should().NotBeNull(); - nameof(PascalCaseClient.GetSupermarketStoreManagerAsync).Should().NotBeNull(); - nameof(PascalCaseClient.GetSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(PascalCaseClient.GetSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); - nameof(PascalCaseClient.PatchSupermarketStoreManagerRelationshipAsync).Should().NotBeNull(); - - nameof(SupermarketCollectionResponseDocument).Should().NotBeNull(); - nameof(LinksInResourceCollectionDocument).Should().NotBeNull(); - nameof(JsonapiObject).Should().NotBeNull(); - nameof(SupermarketDataInResponse).Should().NotBeNull(); - nameof(SupermarketResourceType).Should().NotBeNull(); - nameof(SupermarketAttributesInResponse.NameOfCity).Should().NotBeNull(); - nameof(SupermarketRelationshipsInResponse.StoreManager).Should().NotBeNull(); - nameof(SupermarketRelationshipsInResponse.BackupStoreManager).Should().NotBeNull(); - nameof(LinksInResourceObject).Should().NotBeNull(); - nameof(SupermarketType).Should().NotBeNull(); - nameof(PascalCaseClient.GetSupermarketAsync).Should().NotBeNull(); - nameof(ToOneStaffMemberInResponse).Should().NotBeNull(); - nameof(NullableToOneStaffMemberInResponse).Should().NotBeNull(); - nameof(ToManyStaffMemberInResponse).Should().NotBeNull(); - nameof(LinksInRelationshipObject).Should().NotBeNull(); - nameof(StaffMemberIdentifier).Should().NotBeNull(); - nameof(StaffMemberResourceType.StaffMembers).Should().NotBeNull(); - nameof(SupermarketPrimaryResponseDocument).Should().NotBeNull(); - nameof(LinksInResourceDocument).Should().NotBeNull(); - nameof(StaffMemberSecondaryResponseDocument).Should().NotBeNull(); - nameof(StaffMemberDataInResponse).Should().NotBeNull(); - nameof(StaffMemberAttributesInResponse).Should().NotBeNull(); - nameof(NullableStaffMemberSecondaryResponseDocument).Should().NotBeNull(); - nameof(StaffMemberCollectionResponseDocument).Should().NotBeNull(); - nameof(StaffMemberIdentifierResponseDocument).Should().NotBeNull(); - nameof(LinksInResourceIdentifierDocument).Should().NotBeNull(); - nameof(NullableStaffMemberIdentifierResponseDocument).Should().NotBeNull(); - nameof(StaffMemberIdentifierCollectionResponseDocument).Should().NotBeNull(); - nameof(LinksInResourceIdentifierCollectionDocument).Should().NotBeNull(); - nameof(SupermarketPostRequestDocument).Should().NotBeNull(); - nameof(SupermarketDataInPostRequest).Should().NotBeNull(); - nameof(SupermarketAttributesInPostRequest).Should().NotBeNull(); - nameof(SupermarketRelationshipsInPostRequest).Should().NotBeNull(); - nameof(ToOneStaffMemberInRequest).Should().NotBeNull(); - nameof(NullableToOneStaffMemberInRequest).Should().NotBeNull(); - nameof(ToManyStaffMemberInRequest).Should().NotBeNull(); - nameof(SupermarketPatchRequestDocument).Should().NotBeNull(); - nameof(SupermarketDataInPatchRequest).Should().NotBeNull(); - nameof(SupermarketAttributesInPatchRequest).Should().NotBeNull(); - nameof(SupermarketRelationshipsInPatchRequest).Should().NotBeNull(); - } -} diff --git a/test/OpenApiClientTests/NamingConventions/CamelCase/GeneratedTypesTests.cs b/test/OpenApiClientTests/NamingConventions/CamelCase/GeneratedTypesTests.cs new file mode 100644 index 0000000000..003c452c98 --- /dev/null +++ b/test/OpenApiClientTests/NamingConventions/CamelCase/GeneratedTypesTests.cs @@ -0,0 +1,77 @@ +using OpenApiClientTests.NamingConventions.CamelCase.GeneratedCode; +using Xunit; + +namespace OpenApiClientTests.NamingConventions.CamelCase; + +public sealed class GeneratedTypesTests +{ + [Fact] + public void Generated_code_is_named_as_expected() + { + _ = nameof(CamelCaseClient.GetSupermarketCollectionAsync); + _ = nameof(CamelCaseClient.GetSupermarketCollectionAsync); + _ = nameof(CamelCaseClient.PostSupermarketAsync); + _ = nameof(CamelCaseClient.GetSupermarketAsync); + _ = nameof(CamelCaseClient.GetSupermarketAsync); + _ = nameof(CamelCaseClient.PatchSupermarketAsync); + _ = nameof(CamelCaseClient.DeleteSupermarketAsync); + _ = nameof(CamelCaseClient.GetSupermarketBackupStoreManagerAsync); + _ = nameof(CamelCaseClient.GetSupermarketBackupStoreManagerAsync); + _ = nameof(CamelCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync); + _ = nameof(CamelCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync); + _ = nameof(CamelCaseClient.PatchSupermarketBackupStoreManagerRelationshipAsync); + _ = nameof(CamelCaseClient.GetSupermarketCashiersAsync); + _ = nameof(CamelCaseClient.GetSupermarketCashiersAsync); + _ = nameof(CamelCaseClient.GetSupermarketCashiersRelationshipAsync); + _ = nameof(CamelCaseClient.GetSupermarketCashiersRelationshipAsync); + _ = nameof(CamelCaseClient.PostSupermarketCashiersRelationshipAsync); + _ = nameof(CamelCaseClient.PatchSupermarketCashiersRelationshipAsync); + _ = nameof(CamelCaseClient.DeleteSupermarketCashiersRelationshipAsync); + _ = nameof(CamelCaseClient.GetSupermarketStoreManagerAsync); + _ = nameof(CamelCaseClient.GetSupermarketStoreManagerAsync); + _ = nameof(CamelCaseClient.GetSupermarketStoreManagerRelationshipAsync); + _ = nameof(CamelCaseClient.GetSupermarketStoreManagerRelationshipAsync); + _ = nameof(CamelCaseClient.PatchSupermarketStoreManagerRelationshipAsync); + + _ = nameof(SupermarketCollectionResponseDocument); + _ = nameof(LinksInResourceCollectionDocument); + _ = nameof(JsonapiObject); + _ = nameof(SupermarketDataInResponse); + _ = nameof(SupermarketResourceType.Supermarkets); + _ = nameof(SupermarketAttributesInResponse.NameOfCity); + _ = nameof(SupermarketRelationshipsInResponse.StoreManager); + _ = nameof(SupermarketRelationshipsInResponse.BackupStoreManager); + _ = nameof(LinksInResourceObject); + _ = nameof(SupermarketType); + _ = nameof(CamelCaseClient.GetSupermarketAsync); + _ = nameof(ToOneStaffMemberInResponse); + _ = nameof(NullableToOneStaffMemberInResponse); + _ = nameof(ToManyStaffMemberInResponse); + _ = nameof(LinksInRelationshipObject); + _ = nameof(StaffMemberIdentifier); + _ = nameof(StaffMemberResourceType.StaffMembers); + _ = nameof(SupermarketPrimaryResponseDocument); + _ = nameof(LinksInResourceDocument); + _ = nameof(StaffMemberSecondaryResponseDocument); + _ = nameof(StaffMemberDataInResponse); + _ = nameof(StaffMemberAttributesInResponse); + _ = nameof(NullableStaffMemberSecondaryResponseDocument); + _ = nameof(StaffMemberCollectionResponseDocument); + _ = nameof(StaffMemberIdentifierResponseDocument); + _ = nameof(LinksInResourceIdentifierDocument); + _ = nameof(NullableStaffMemberIdentifierResponseDocument); + _ = nameof(StaffMemberIdentifierCollectionResponseDocument); + _ = nameof(LinksInResourceIdentifierCollectionDocument); + _ = nameof(SupermarketPostRequestDocument); + _ = nameof(SupermarketDataInPostRequest); + _ = nameof(SupermarketAttributesInPostRequest); + _ = nameof(SupermarketRelationshipsInPostRequest); + _ = nameof(ToOneStaffMemberInRequest); + _ = nameof(NullableToOneStaffMemberInRequest); + _ = nameof(ToManyStaffMemberInRequest); + _ = nameof(SupermarketPatchRequestDocument); + _ = nameof(SupermarketDataInPatchRequest); + _ = nameof(SupermarketAttributesInPatchRequest); + _ = nameof(SupermarketRelationshipsInPatchRequest); + } +} diff --git a/test/OpenApiClientTests/NamingConventions/KebabCase/GeneratedTypesTests.cs b/test/OpenApiClientTests/NamingConventions/KebabCase/GeneratedTypesTests.cs new file mode 100644 index 0000000000..15b3eefcae --- /dev/null +++ b/test/OpenApiClientTests/NamingConventions/KebabCase/GeneratedTypesTests.cs @@ -0,0 +1,78 @@ +using OpenApiClientTests.NamingConventions.KebabCase.GeneratedCode; +using Xunit; + +namespace OpenApiClientTests.NamingConventions.KebabCase; + +public sealed class GeneratedTypesTests +{ + [Fact] + public void Generated_code_is_named_as_expected() + { + _ = nameof(KebabCaseClient.GetSupermarketCollectionAsync); + _ = nameof(KebabCaseClient.GetSupermarketCollectionAsync); + _ = nameof(KebabCaseClient.PostSupermarketAsync); + _ = nameof(KebabCaseClient.GetSupermarketAsync); + _ = nameof(KebabCaseClient.GetSupermarketAsync); + _ = nameof(KebabCaseClient.PatchSupermarketAsync); + _ = nameof(KebabCaseClient.DeleteSupermarketAsync); + _ = nameof(KebabCaseClient.GetSupermarketBackupStoreManagerAsync); + _ = nameof(KebabCaseClient.GetSupermarketBackupStoreManagerAsync); + _ = nameof(KebabCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync); + _ = nameof(KebabCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync); + _ = nameof(KebabCaseClient.PatchSupermarketBackupStoreManagerRelationshipAsync); + _ = nameof(KebabCaseClient.GetSupermarketCashiersAsync); + _ = nameof(KebabCaseClient.GetSupermarketCashiersAsync); + _ = nameof(KebabCaseClient.GetSupermarketCashiersRelationshipAsync); + _ = nameof(KebabCaseClient.GetSupermarketCashiersRelationshipAsync); + _ = nameof(KebabCaseClient.PostSupermarketCashiersRelationshipAsync); + _ = nameof(KebabCaseClient.PatchSupermarketCashiersRelationshipAsync); + _ = nameof(KebabCaseClient.DeleteSupermarketCashiersRelationshipAsync); + _ = nameof(KebabCaseClient.GetSupermarketStoreManagerAsync); + _ = nameof(KebabCaseClient.GetSupermarketStoreManagerAsync); + _ = nameof(KebabCaseClient.GetSupermarketStoreManagerRelationshipAsync); + _ = nameof(KebabCaseClient.GetSupermarketStoreManagerRelationshipAsync); + _ = nameof(KebabCaseClient.PatchSupermarketStoreManagerRelationshipAsync); + + _ = nameof(SupermarketCollectionResponseDocument); + _ = nameof(LinksInResourceCollectionDocument); + _ = nameof(JsonapiObject); + _ = nameof(SupermarketDataInResponse); + _ = nameof(SupermarketResourceType.Supermarkets); + _ = nameof(SupermarketAttributesInResponse.NameOfCity); + _ = nameof(SupermarketRelationshipsInResponse.StoreManager); + _ = nameof(SupermarketRelationshipsInResponse.BackupStoreManager); + _ = nameof(LinksInResourceObject); + _ = nameof(SupermarketType); + _ = nameof(KebabCaseClient.GetSupermarketAsync); + _ = nameof(ToOneStaffMemberInResponse); + _ = nameof(NullableToOneStaffMemberInResponse); + _ = nameof(ToManyStaffMemberInResponse); + _ = nameof(LinksInRelationshipObject); + _ = nameof(StaffMemberIdentifier); + _ = nameof(StaffMemberResourceType); + _ = nameof(StaffMemberResourceType.StaffMembers); + _ = nameof(SupermarketPrimaryResponseDocument); + _ = nameof(LinksInResourceDocument); + _ = nameof(StaffMemberSecondaryResponseDocument); + _ = nameof(StaffMemberDataInResponse); + _ = nameof(StaffMemberAttributesInResponse); + _ = nameof(NullableStaffMemberSecondaryResponseDocument); + _ = nameof(StaffMemberCollectionResponseDocument); + _ = nameof(StaffMemberIdentifierResponseDocument); + _ = nameof(LinksInResourceIdentifierDocument); + _ = nameof(NullableStaffMemberIdentifierResponseDocument); + _ = nameof(StaffMemberIdentifierCollectionResponseDocument); + _ = nameof(LinksInResourceIdentifierCollectionDocument); + _ = nameof(SupermarketPostRequestDocument); + _ = nameof(SupermarketDataInPostRequest); + _ = nameof(SupermarketAttributesInPostRequest); + _ = nameof(SupermarketRelationshipsInPostRequest); + _ = nameof(ToOneStaffMemberInRequest); + _ = nameof(NullableToOneStaffMemberInRequest); + _ = nameof(ToManyStaffMemberInRequest); + _ = nameof(SupermarketPatchRequestDocument); + _ = nameof(SupermarketDataInPatchRequest); + _ = nameof(SupermarketAttributesInPatchRequest); + _ = nameof(SupermarketRelationshipsInPatchRequest); + } +} diff --git a/test/OpenApiClientTests/NamingConventions/PascalCase/GeneratedTypesTests.cs b/test/OpenApiClientTests/NamingConventions/PascalCase/GeneratedTypesTests.cs new file mode 100644 index 0000000000..9ec0325e58 --- /dev/null +++ b/test/OpenApiClientTests/NamingConventions/PascalCase/GeneratedTypesTests.cs @@ -0,0 +1,77 @@ +using OpenApiClientTests.NamingConventions.PascalCase.GeneratedCode; +using Xunit; + +namespace OpenApiClientTests.NamingConventions.PascalCase; + +public sealed class GeneratedTypesTests +{ + [Fact] + public void Generated_code_is_named_as_expected() + { + _ = nameof(PascalCaseClient.GetSupermarketCollectionAsync); + _ = nameof(PascalCaseClient.GetSupermarketCollectionAsync); + _ = nameof(PascalCaseClient.PostSupermarketAsync); + _ = nameof(PascalCaseClient.GetSupermarketAsync); + _ = nameof(PascalCaseClient.GetSupermarketAsync); + _ = nameof(PascalCaseClient.PatchSupermarketAsync); + _ = nameof(PascalCaseClient.DeleteSupermarketAsync); + _ = nameof(PascalCaseClient.GetSupermarketBackupStoreManagerAsync); + _ = nameof(PascalCaseClient.GetSupermarketBackupStoreManagerAsync); + _ = nameof(PascalCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync); + _ = nameof(PascalCaseClient.GetSupermarketBackupStoreManagerRelationshipAsync); + _ = nameof(PascalCaseClient.PatchSupermarketBackupStoreManagerRelationshipAsync); + _ = nameof(PascalCaseClient.GetSupermarketCashiersAsync); + _ = nameof(PascalCaseClient.GetSupermarketCashiersAsync); + _ = nameof(PascalCaseClient.GetSupermarketCashiersRelationshipAsync); + _ = nameof(PascalCaseClient.GetSupermarketCashiersRelationshipAsync); + _ = nameof(PascalCaseClient.PostSupermarketCashiersRelationshipAsync); + _ = nameof(PascalCaseClient.PatchSupermarketCashiersRelationshipAsync); + _ = nameof(PascalCaseClient.DeleteSupermarketCashiersRelationshipAsync); + _ = nameof(PascalCaseClient.GetSupermarketStoreManagerAsync); + _ = nameof(PascalCaseClient.GetSupermarketStoreManagerAsync); + _ = nameof(PascalCaseClient.GetSupermarketStoreManagerRelationshipAsync); + _ = nameof(PascalCaseClient.GetSupermarketStoreManagerRelationshipAsync); + _ = nameof(PascalCaseClient.PatchSupermarketStoreManagerRelationshipAsync); + + _ = nameof(SupermarketCollectionResponseDocument); + _ = nameof(LinksInResourceCollectionDocument); + _ = nameof(JsonapiObject); + _ = nameof(SupermarketDataInResponse); + _ = nameof(SupermarketResourceType.Supermarkets); + _ = nameof(SupermarketAttributesInResponse.NameOfCity); + _ = nameof(SupermarketRelationshipsInResponse.StoreManager); + _ = nameof(SupermarketRelationshipsInResponse.BackupStoreManager); + _ = nameof(LinksInResourceObject); + _ = nameof(SupermarketType); + _ = nameof(PascalCaseClient.GetSupermarketAsync); + _ = nameof(ToOneStaffMemberInResponse); + _ = nameof(NullableToOneStaffMemberInResponse); + _ = nameof(ToManyStaffMemberInResponse); + _ = nameof(LinksInRelationshipObject); + _ = nameof(StaffMemberIdentifier); + _ = nameof(StaffMemberResourceType.StaffMembers); + _ = nameof(SupermarketPrimaryResponseDocument); + _ = nameof(LinksInResourceDocument); + _ = nameof(StaffMemberSecondaryResponseDocument); + _ = nameof(StaffMemberDataInResponse); + _ = nameof(StaffMemberAttributesInResponse); + _ = nameof(NullableStaffMemberSecondaryResponseDocument); + _ = nameof(StaffMemberCollectionResponseDocument); + _ = nameof(StaffMemberIdentifierResponseDocument); + _ = nameof(LinksInResourceIdentifierDocument); + _ = nameof(NullableStaffMemberIdentifierResponseDocument); + _ = nameof(StaffMemberIdentifierCollectionResponseDocument); + _ = nameof(LinksInResourceIdentifierCollectionDocument); + _ = nameof(SupermarketPostRequestDocument); + _ = nameof(SupermarketDataInPostRequest); + _ = nameof(SupermarketAttributesInPostRequest); + _ = nameof(SupermarketRelationshipsInPostRequest); + _ = nameof(ToOneStaffMemberInRequest); + _ = nameof(NullableToOneStaffMemberInRequest); + _ = nameof(ToManyStaffMemberInRequest); + _ = nameof(SupermarketPatchRequestDocument); + _ = nameof(SupermarketDataInPatchRequest); + _ = nameof(SupermarketAttributesInPatchRequest); + _ = nameof(SupermarketRelationshipsInPatchRequest); + } +} diff --git a/test/OpenApiClientTests/OpenApiClientTests.csproj b/test/OpenApiClientTests/OpenApiClientTests.csproj index 958049dad4..5e9ab56e09 100644 --- a/test/OpenApiClientTests/OpenApiClientTests.csproj +++ b/test/OpenApiClientTests/OpenApiClientTests.csproj @@ -1,66 +1,66 @@ - - $(TargetFrameworkName) - + + $(TargetFrameworkName) + - - - - + + + + + + + + PreserveNewest + + - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + - - - OpenApiClientTests.LegacyClient.GeneratedCode - OpenApiClient - OpenApiClient.cs - NSwagCSharp - /UseBaseUrl:false /GenerateClientInterfaces:true /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions - - - OpenApiClientTests.NamingConvention.KebabCase.GeneratedCode - KebabCaseClient - KebabCaseClient.cs - NSwagCSharp - /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions - - - OpenApiClientTests.NamingConvention.CamelCase.GeneratedCode - CamelCaseClient - CamelCaseClient.cs - NSwagCSharp - /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions - - - OpenApiClientTests.NamingConvention.PascalCase.GeneratedCode - PascalCaseClient - PascalCaseClient.cs - NSwagCSharp - /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions - - - - - - PreserveNewest - - + + + OpenApiClientTests.LegacyClient.GeneratedCode + OpenApiClient + OpenApiClient.cs + NSwagCSharp + /UseBaseUrl:false /GenerateClientInterfaces:true /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions + + + OpenApiClientTests.NamingConventions.KebabCase.GeneratedCode + KebabCaseClient + KebabCaseClient.cs + NSwagCSharp + /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions + + + OpenApiClientTests.NamingConventions.CamelCase.GeneratedCode + CamelCaseClient + CamelCaseClient.cs + NSwagCSharp + /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions + + + OpenApiClientTests.NamingConventions.PascalCase.GeneratedCode + PascalCaseClient + PascalCaseClient.cs + NSwagCSharp + /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions + + diff --git a/test/TestBuildingBlocks/JsonElementExtensions.cs b/test/OpenApiTests/JsonElementExtensions.cs similarity index 70% rename from test/TestBuildingBlocks/JsonElementExtensions.cs rename to test/OpenApiTests/JsonElementExtensions.cs index e8f18eff30..768990064d 100644 --- a/test/TestBuildingBlocks/JsonElementExtensions.cs +++ b/test/OpenApiTests/JsonElementExtensions.cs @@ -2,10 +2,11 @@ using BlushingPenguin.JsonPath; using FluentAssertions; using FluentAssertions.Execution; +using TestBuildingBlocks; -namespace TestBuildingBlocks; +namespace OpenApiTests; -public static class JsonElementExtensions +internal static class JsonElementExtensions { public static JsonElementAssertions Should(this JsonElement source) { @@ -14,12 +15,8 @@ public static JsonElementAssertions Should(this JsonElement source) public static JsonElement ShouldContainPath(this JsonElement source, string path) { - JsonElement value = default; - - Action action = () => value = source.SelectToken(path, true)!.Value; - action.Should().NotThrow(); - - return value; + Func elementSelector = () => source.SelectToken(path, true)!.Value; + return elementSelector.Should().NotThrow().Subject; } public static void ShouldBeString(this JsonElement source, string value) @@ -28,7 +25,7 @@ public static void ShouldBeString(this JsonElement source, string value) source.GetString().Should().Be(value); } - public static ReferenceSchemaIdAssertion ShouldBeReferenceSchemaId(this JsonElement source, string value) + public static ReferenceSchemaIdContainer ShouldBeReferenceSchemaId(this JsonElement source, string value) { source.ValueKind.Should().Be(JsonValueKind.String); @@ -38,20 +35,20 @@ public static ReferenceSchemaIdAssertion ShouldBeReferenceSchemaId(this JsonElem string referenceSchemaId = jsonElementValue.Split('/').Last(); referenceSchemaId.Should().Be(value); - return new ReferenceSchemaIdAssertion + return new ReferenceSchemaIdContainer { - SchemaReferenceId = value + ReferenceSchemaId = value }; } - public sealed class ReferenceSchemaIdAssertion + public sealed class ReferenceSchemaIdContainer { - public string SchemaReferenceId { get; internal init; } = null!; + internal string ReferenceSchemaId { get; init; } = null!; } public sealed class JsonElementAssertions : JsonElementAssertions { - internal JsonElementAssertions(JsonElement subject) + public JsonElementAssertions(JsonElement subject) : base(subject) { } @@ -71,12 +68,17 @@ public void ContainProperty(string propertyName) { string json = _subject.ToString(); - json.ShouldNotBeNull(); - string escapedJson = json.Replace("{", "{{").Replace("}", "}}"); Execute.Assertion.ForCondition(_subject.TryGetProperty(propertyName, out _)) .FailWith($"Expected JSON element '{escapedJson}' to contain a property named '{propertyName}'."); } + + public void BeJson(string expectedDocument) + { + string json = _subject.ToString(); + + json.Should().BeJson(expectedDocument); + } } } diff --git a/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs b/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs index 3d253e2dc9..17ec272fee 100644 --- a/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs +++ b/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs @@ -1,12 +1,10 @@ using System.Reflection; -using FluentAssertions; -using TestBuildingBlocks; +using System.Text.Json; using Xunit; namespace OpenApiTests.LegacyOpenApiIntegration; -public sealed class LegacyOpenApiIntegrationTests - : IntegrationTestContext, LegacyIntegrationDbContext> +public sealed class LegacyOpenApiIntegrationTests : OpenApiTestContext, LegacyIntegrationDbContext> { public LegacyOpenApiIntegrationTests() { @@ -21,25 +19,14 @@ public async Task Retrieved_document_matches_expected_document() // Arrange const string embeddedResourceName = $"{nameof(OpenApiTests)}.{nameof(LegacyOpenApiIntegration)}.swagger.json"; string expectedDocument = await LoadEmbeddedResourceAsync(embeddedResourceName); - const string requestUrl = "swagger/v1/swagger.json"; // Act - string actualDocument = await GetAsync(requestUrl); + JsonElement actualDocument = await LazyDocument.Value; // Assert actualDocument.Should().BeJson(expectedDocument); } - private async Task GetAsync(string requestUrl) - { - var request = new HttpRequestMessage(HttpMethod.Get, requestUrl); - - using HttpClient client = Factory.CreateClient(); - HttpResponseMessage responseMessage = await client.SendAsync(request); - - return await responseMessage.Content.ReadAsStringAsync(); - } - private static async Task LoadEmbeddedResourceAsync(string name) { var assembly = Assembly.GetExecutingAssembly(); diff --git a/test/OpenApiTests/NamingConvention/NamingConventionDbContext.cs b/test/OpenApiTests/NamingConvention/NamingConventionDbContext.cs deleted file mode 100644 index 9a48f2bcb0..0000000000 --- a/test/OpenApiTests/NamingConvention/NamingConventionDbContext.cs +++ /dev/null @@ -1,16 +0,0 @@ -using JetBrains.Annotations; -using Microsoft.EntityFrameworkCore; - -namespace OpenApiTests.NamingConvention; - -[UsedImplicitly(ImplicitUseTargetFlags.Members)] -public sealed class NamingConventionDbContext : DbContext -{ - public DbSet Supermarkets => Set(); - public DbSet StaffMembers => Set(); - - public NamingConventionDbContext(DbContextOptions options) - : base(options) - { - } -} diff --git a/test/OpenApiTests/NamingConvention/CamelCase/CamelCaseNamingConventionStartup.cs b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseNamingConventionStartup.cs similarity index 93% rename from test/OpenApiTests/NamingConvention/CamelCase/CamelCaseNamingConventionStartup.cs rename to test/OpenApiTests/NamingConventions/CamelCase/CamelCaseNamingConventionStartup.cs index 54d4b0fc84..242291c4f6 100644 --- a/test/OpenApiTests/NamingConvention/CamelCase/CamelCaseNamingConventionStartup.cs +++ b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseNamingConventionStartup.cs @@ -4,7 +4,7 @@ using JsonApiDotNetCore.Configuration; using Microsoft.EntityFrameworkCore; -namespace OpenApiTests.NamingConvention.CamelCase; +namespace OpenApiTests.NamingConventions.CamelCase; [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] public sealed class CamelCaseNamingConventionStartup : OpenApiStartup diff --git a/test/OpenApiTests/NamingConvention/CamelCase/CamelCaseTests.cs b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs similarity index 73% rename from test/OpenApiTests/NamingConvention/CamelCase/CamelCaseTests.cs rename to test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs index e03c2aee2d..651d1f6e8f 100644 --- a/test/OpenApiTests/NamingConvention/CamelCase/CamelCaseTests.cs +++ b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs @@ -1,24 +1,27 @@ +using System.Text.Json; using TestBuildingBlocks; using Xunit; -namespace OpenApiTests.NamingConvention.CamelCase; +namespace OpenApiTests.NamingConventions.CamelCase; -public sealed class CamelCaseTests : IClassFixture, NamingConventionDbContext>> +public sealed class CamelCaseTests : OpenApiTestSuite, NamingConventionsDbContext> { - private readonly OpenApiTestContext, NamingConventionDbContext> _testContext; - - public CamelCaseTests(OpenApiTestContext, NamingConventionDbContext> testContext) + public CamelCaseTests(OpenApiTestContext, NamingConventionsDbContext> testContext) + : base(testContext) { - _testContext = testContext; + UseController(); } [Fact] - public void Camel_casing_convention_is_applied_to_GetCollection_endpoint() + public async Task Casing_convention_is_applied_to_GetCollection_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./supermarkets.get").With(getElement => + document.ShouldContainPath("paths./supermarkets.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -26,10 +29,10 @@ public void Camel_casing_convention_is_applied_to_GetCollection_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("supermarketCollectionResponseDocument").SchemaReferenceId; + .ShouldBeReferenceSchemaId("supermarketCollectionResponseDocument").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; @@ -39,7 +42,7 @@ public void Camel_casing_convention_is_applied_to_GetCollection_endpoint() propertiesElement.ShouldContainPath("jsonapi.$ref").ShouldBeReferenceSchemaId("jsonapiObject"); resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.items.$ref").ShouldBeReferenceSchemaId("supermarketDataInResponse") - .SchemaReferenceId; + .ReferenceSchemaId; }); string? resourceAttributesInResponseSchemaRefId = null; @@ -49,13 +52,13 @@ public void Camel_casing_convention_is_applied_to_GetCollection_endpoint() schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => { primaryResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("supermarketResourceType") - .SchemaReferenceId; + .ReferenceSchemaId; resourceAttributesInResponseSchemaRefId = propertiesElement.ShouldContainPath("attributes.$ref") - .ShouldBeReferenceSchemaId("supermarketAttributesInResponse").SchemaReferenceId; + .ShouldBeReferenceSchemaId("supermarketAttributesInResponse").ReferenceSchemaId; resourceRelationshipInResponseSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref") - .ShouldBeReferenceSchemaId("supermarketRelationshipsInResponse").SchemaReferenceId; + .ShouldBeReferenceSchemaId("supermarketRelationshipsInResponse").ReferenceSchemaId; propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("linksInResourceObject"); }); @@ -81,7 +84,7 @@ public void Camel_casing_convention_is_applied_to_GetCollection_endpoint() propertiesElement.ShouldContainPath("storeManager.$ref").ShouldBeReferenceSchemaId("toOneStaffMemberInResponse"); nullableToOneResourceResponseDataSchemaRefId = propertiesElement.ShouldContainPath("backupStoreManager.$ref") - .ShouldBeReferenceSchemaId("nullableToOneStaffMemberInResponse").SchemaReferenceId; + .ShouldBeReferenceSchemaId("nullableToOneStaffMemberInResponse").ReferenceSchemaId; propertiesElement.Should().ContainProperty("cashiers"); propertiesElement.ShouldContainPath("cashiers.$ref").ShouldBeReferenceSchemaId("toManyStaffMemberInResponse"); @@ -94,7 +97,7 @@ public void Camel_casing_convention_is_applied_to_GetCollection_endpoint() propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("linksInRelationshipObject"); relatedResourceIdentifierSchemaRefId = propertiesElement.ShouldContainPath("data.oneOf[0].$ref") - .ShouldBeReferenceSchemaId("staffMemberIdentifier").SchemaReferenceId; + .ShouldBeReferenceSchemaId("staffMemberIdentifier").ReferenceSchemaId; propertiesElement.ShouldContainPath("data.oneOf[1].$ref").ShouldBeReferenceSchemaId("nullValue"); }); @@ -104,7 +107,7 @@ public void Camel_casing_convention_is_applied_to_GetCollection_endpoint() schemasElement.ShouldContainPath($"{relatedResourceIdentifierSchemaRefId}.properties").With(propertiesElement => { relatedResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("staffMemberResourceType") - .SchemaReferenceId; + .ReferenceSchemaId; }); schemasElement.ShouldContainPath($"{relatedResourceTypeSchemaRefId}.enum[0]").ShouldBeReferenceSchemaId("staffMembers"); @@ -112,12 +115,15 @@ public void Camel_casing_convention_is_applied_to_GetCollection_endpoint() } [Fact] - public void Camel_casing_convention_is_applied_to_GetSingle_endpoint() + public async Task Casing_convention_is_applied_to_GetSingle_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}.get").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -125,10 +131,10 @@ public void Camel_casing_convention_is_applied_to_GetSingle_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("supermarketPrimaryResponseDocument").SchemaReferenceId; + .ShouldBeReferenceSchemaId("supermarketPrimaryResponseDocument").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { @@ -138,12 +144,15 @@ public void Camel_casing_convention_is_applied_to_GetSingle_endpoint() } [Fact] - public void Camel_casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() + public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/storeManager.get").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/storeManager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -151,17 +160,17 @@ public void Camel_casing_convention_is_applied_to_GetSecondary_endpoint_with_sin }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("staffMemberSecondaryResponseDocument").SchemaReferenceId; + .ShouldBeReferenceSchemaId("staffMemberSecondaryResponseDocument").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("staffMemberDataInResponse") - .SchemaReferenceId; + .ReferenceSchemaId; }); schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => @@ -172,10 +181,13 @@ public void Camel_casing_convention_is_applied_to_GetSecondary_endpoint_with_sin } [Fact] - public void Camel_casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() + public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/backupStoreManager.get").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/backupStoreManager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -188,10 +200,13 @@ public void Camel_casing_convention_is_applied_to_GetSecondary_endpoint_with_nul } [Fact] - public void Camel_casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() + public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/cashiers.get").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/cashiers.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -204,12 +219,15 @@ public void Camel_casing_convention_is_applied_to_GetSecondary_endpoint_with_res } [Fact] - public void Camel_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() + public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/storeManager.get").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/relationships/storeManager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -217,10 +235,10 @@ public void Camel_casing_convention_is_applied_to_GetRelationship_endpoint_with_ }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("staffMemberIdentifierResponseDocument").SchemaReferenceId; + .ShouldBeReferenceSchemaId("staffMemberIdentifierResponseDocument").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { @@ -230,10 +248,13 @@ public void Camel_casing_convention_is_applied_to_GetRelationship_endpoint_with_ } [Fact] - public void Camel_casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() + public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/backupStoreManager.get").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/relationships/backupStoreManager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -246,12 +267,15 @@ public void Camel_casing_convention_is_applied_to_GetRelationship_endpoint_with_ } [Fact] - public void Camel_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() + public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.get").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -259,10 +283,10 @@ public void Camel_casing_convention_is_applied_to_GetRelationship_endpoint_with_ }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("staffMemberIdentifierCollectionResponseDocument").SchemaReferenceId; + .ShouldBeReferenceSchemaId("staffMemberIdentifierCollectionResponseDocument").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { @@ -272,12 +296,15 @@ public void Camel_casing_convention_is_applied_to_GetRelationship_endpoint_with_ } [Fact] - public void Camel_casing_convention_is_applied_to_Post_endpoint() + public async Task Casing_convention_is_applied_to_Post_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./supermarkets.post").With(getElement => + document.ShouldContainPath("paths./supermarkets.post").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -285,17 +312,17 @@ public void Camel_casing_convention_is_applied_to_Post_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("supermarketPostRequestDocument").SchemaReferenceId; + .ShouldBeReferenceSchemaId("supermarketPostRequestDocument").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("supermarketDataInPostRequest") - .SchemaReferenceId; + .ReferenceSchemaId; }); string? resourceRelationshipInPostRequestSchemaRefId = null; @@ -305,7 +332,7 @@ public void Camel_casing_convention_is_applied_to_Post_endpoint() propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("supermarketAttributesInPostRequest"); resourceRelationshipInPostRequestSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref") - .ShouldBeReferenceSchemaId("supermarketRelationshipsInPostRequest").SchemaReferenceId; + .ShouldBeReferenceSchemaId("supermarketRelationshipsInPostRequest").ReferenceSchemaId; }); schemasElement.ShouldContainPath($"{resourceRelationshipInPostRequestSchemaRefId}.properties").With(propertiesElement => @@ -323,10 +350,13 @@ public void Camel_casing_convention_is_applied_to_Post_endpoint() } [Fact] - public void Camel_casing_convention_is_applied_to_PostRelationship_endpoint() + public async Task Casing_convention_is_applied_to_PostRelationship_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.post").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.post").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -336,12 +366,15 @@ public void Camel_casing_convention_is_applied_to_PostRelationship_endpoint() } [Fact] - public void Camel_casing_convention_is_applied_to_Patch_endpoint() + public async Task Casing_convention_is_applied_to_Patch_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}.patch").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -349,17 +382,17 @@ public void Camel_casing_convention_is_applied_to_Patch_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("supermarketPatchRequestDocument").SchemaReferenceId; + .ShouldBeReferenceSchemaId("supermarketPatchRequestDocument").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("supermarketDataInPatchRequest") - .SchemaReferenceId; + .ReferenceSchemaId; }); schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => @@ -371,10 +404,13 @@ public void Camel_casing_convention_is_applied_to_Patch_endpoint() } [Fact] - public void Camel_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() + public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/storeManager.patch").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/relationships/storeManager.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -384,10 +420,13 @@ public void Camel_casing_convention_is_applied_to_PatchRelationship_endpoint_wit } [Fact] - public void Camel_casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() + public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/backupStoreManager.patch").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/relationships/backupStoreManager.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -397,10 +436,13 @@ public void Camel_casing_convention_is_applied_to_PatchRelationship_endpoint_wit } [Fact] - public void Camel_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() + public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.patch").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -410,10 +452,13 @@ public void Camel_casing_convention_is_applied_to_PatchRelationship_endpoint_wit } [Fact] - public void Camel_casing_convention_is_applied_to_Delete_endpoint() + public async Task Casing_convention_is_applied_to_Delete_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}.delete").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}.delete").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -423,10 +468,13 @@ public void Camel_casing_convention_is_applied_to_Delete_endpoint() } [Fact] - public void Camel_casing_convention_is_applied_to_DeleteRelationship_endpoint() + public async Task Casing_convention_is_applied_to_DeleteRelationship_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.delete").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.delete").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { diff --git a/test/OpenApiTests/NamingConvention/CamelCase/swagger.json b/test/OpenApiTests/NamingConventions/CamelCase/swagger.json similarity index 99% rename from test/OpenApiTests/NamingConvention/CamelCase/swagger.json rename to test/OpenApiTests/NamingConventions/CamelCase/swagger.json index f33421cf38..31c65b23e0 100644 --- a/test/OpenApiTests/NamingConvention/CamelCase/swagger.json +++ b/test/OpenApiTests/NamingConventions/CamelCase/swagger.json @@ -1463,4 +1463,4 @@ } } } -} +} \ No newline at end of file diff --git a/test/OpenApiTests/NamingConvention/KebabCase/KebabCaseNamingConventionStartup.cs b/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseNamingConventionStartup.cs similarity index 93% rename from test/OpenApiTests/NamingConvention/KebabCase/KebabCaseNamingConventionStartup.cs rename to test/OpenApiTests/NamingConventions/KebabCase/KebabCaseNamingConventionStartup.cs index 7e08683bb8..ebd532aa65 100644 --- a/test/OpenApiTests/NamingConvention/KebabCase/KebabCaseNamingConventionStartup.cs +++ b/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseNamingConventionStartup.cs @@ -4,7 +4,7 @@ using Microsoft.EntityFrameworkCore; using OpenApiTests.LegacyOpenApiIntegration; -namespace OpenApiTests.NamingConvention.KebabCase; +namespace OpenApiTests.NamingConventions.KebabCase; [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] public sealed class KebabCaseNamingConventionStartup : OpenApiStartup diff --git a/test/OpenApiTests/NamingConvention/KebabCase/KebabCaseTests.cs b/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs similarity index 73% rename from test/OpenApiTests/NamingConvention/KebabCase/KebabCaseTests.cs rename to test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs index 38d8488f2c..9f2ce69d87 100644 --- a/test/OpenApiTests/NamingConvention/KebabCase/KebabCaseTests.cs +++ b/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs @@ -1,24 +1,27 @@ +using System.Text.Json; using TestBuildingBlocks; using Xunit; -namespace OpenApiTests.NamingConvention.KebabCase; +namespace OpenApiTests.NamingConventions.KebabCase; -public sealed class KebabCaseTests : IClassFixture, NamingConventionDbContext>> +public sealed class KebabCaseTests : OpenApiTestSuite, NamingConventionsDbContext> { - private readonly OpenApiTestContext, NamingConventionDbContext> _testContext; - - public KebabCaseTests(OpenApiTestContext, NamingConventionDbContext> testContext) + public KebabCaseTests(OpenApiTestContext, NamingConventionsDbContext> testContext) + : base(testContext) { - _testContext = testContext; + UseController(); } [Fact] - public void Kebab_casing_convention_is_applied_to_GetCollection_endpoint() + public async Task Casing_convention_is_applied_to_GetCollection_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./supermarkets.get").With(getElement => + document.ShouldContainPath("paths./supermarkets.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -26,10 +29,10 @@ public void Kebab_casing_convention_is_applied_to_GetCollection_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("supermarket-collection-response-document").SchemaReferenceId; + .ShouldBeReferenceSchemaId("supermarket-collection-response-document").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; @@ -39,7 +42,7 @@ public void Kebab_casing_convention_is_applied_to_GetCollection_endpoint() propertiesElement.ShouldContainPath("jsonapi.$ref").ShouldBeReferenceSchemaId("jsonapi-object"); resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.items.$ref").ShouldBeReferenceSchemaId("supermarket-data-in-response") - .SchemaReferenceId; + .ReferenceSchemaId; }); string? resourceAttributesInResponseSchemaRefId = null; @@ -49,13 +52,13 @@ public void Kebab_casing_convention_is_applied_to_GetCollection_endpoint() schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => { primaryResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("supermarket-resource-type") - .SchemaReferenceId; + .ReferenceSchemaId; resourceAttributesInResponseSchemaRefId = propertiesElement.ShouldContainPath("attributes.$ref") - .ShouldBeReferenceSchemaId("supermarket-attributes-in-response").SchemaReferenceId; + .ShouldBeReferenceSchemaId("supermarket-attributes-in-response").ReferenceSchemaId; resourceRelationshipInResponseSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref") - .ShouldBeReferenceSchemaId("supermarket-relationships-in-response").SchemaReferenceId; + .ShouldBeReferenceSchemaId("supermarket-relationships-in-response").ReferenceSchemaId; propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("links-in-resource-object"); }); @@ -81,7 +84,7 @@ public void Kebab_casing_convention_is_applied_to_GetCollection_endpoint() propertiesElement.ShouldContainPath("store-manager.$ref").ShouldBeReferenceSchemaId("to-one-staff-member-in-response"); nullableToOneResourceResponseDataSchemaRefId = propertiesElement.ShouldContainPath("backup-store-manager.$ref") - .ShouldBeReferenceSchemaId("nullable-to-one-staff-member-in-response").SchemaReferenceId; + .ShouldBeReferenceSchemaId("nullable-to-one-staff-member-in-response").ReferenceSchemaId; propertiesElement.Should().ContainProperty("cashiers"); propertiesElement.ShouldContainPath("cashiers.$ref").ShouldBeReferenceSchemaId("to-many-staff-member-in-response"); @@ -94,7 +97,7 @@ public void Kebab_casing_convention_is_applied_to_GetCollection_endpoint() propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("links-in-relationship-object"); relatedResourceIdentifierSchemaRefId = propertiesElement.ShouldContainPath("data.oneOf[0].$ref") - .ShouldBeReferenceSchemaId("staff-member-identifier").SchemaReferenceId; + .ShouldBeReferenceSchemaId("staff-member-identifier").ReferenceSchemaId; propertiesElement.ShouldContainPath("data.oneOf[1].$ref").ShouldBeReferenceSchemaId("null-value"); }); @@ -104,7 +107,7 @@ public void Kebab_casing_convention_is_applied_to_GetCollection_endpoint() schemasElement.ShouldContainPath($"{relatedResourceIdentifierSchemaRefId}.properties").With(propertiesElement => { relatedResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("staff-member-resource-type") - .SchemaReferenceId; + .ReferenceSchemaId; }); schemasElement.ShouldContainPath($"{relatedResourceTypeSchemaRefId}.enum[0]").ShouldBeReferenceSchemaId("staff-members"); @@ -112,12 +115,15 @@ public void Kebab_casing_convention_is_applied_to_GetCollection_endpoint() } [Fact] - public void Kebab_casing_convention_is_applied_to_GetSingle_endpoint() + public async Task Casing_convention_is_applied_to_GetSingle_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}.get").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -125,10 +131,10 @@ public void Kebab_casing_convention_is_applied_to_GetSingle_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("supermarket-primary-response-document").SchemaReferenceId; + .ShouldBeReferenceSchemaId("supermarket-primary-response-document").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { @@ -138,12 +144,15 @@ public void Kebab_casing_convention_is_applied_to_GetSingle_endpoint() } [Fact] - public void Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() + public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/store-manager.get").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/store-manager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -151,17 +160,17 @@ public void Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_with_sin }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("staff-member-secondary-response-document").SchemaReferenceId; + .ShouldBeReferenceSchemaId("staff-member-secondary-response-document").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("staff-member-data-in-response") - .SchemaReferenceId; + .ReferenceSchemaId; }); schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => @@ -172,10 +181,13 @@ public void Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_with_sin } [Fact] - public void Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() + public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/backup-store-manager.get").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/backup-store-manager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -188,10 +200,13 @@ public void Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_with_nul } [Fact] - public void Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() + public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/cashiers.get").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/cashiers.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -204,12 +219,15 @@ public void Kebab_casing_convention_is_applied_to_GetSecondary_endpoint_with_res } [Fact] - public void Kebab_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() + public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/store-manager.get").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/relationships/store-manager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -217,10 +235,10 @@ public void Kebab_casing_convention_is_applied_to_GetRelationship_endpoint_with_ }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("staff-member-identifier-response-document").SchemaReferenceId; + .ShouldBeReferenceSchemaId("staff-member-identifier-response-document").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { @@ -230,10 +248,13 @@ public void Kebab_casing_convention_is_applied_to_GetRelationship_endpoint_with_ } [Fact] - public void Kebab_casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() + public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/backup-store-manager.get").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/relationships/backup-store-manager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -246,12 +267,15 @@ public void Kebab_casing_convention_is_applied_to_GetRelationship_endpoint_with_ } [Fact] - public void Kebab_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() + public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.get").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -259,10 +283,10 @@ public void Kebab_casing_convention_is_applied_to_GetRelationship_endpoint_with_ }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("staff-member-identifier-collection-response-document").SchemaReferenceId; + .ShouldBeReferenceSchemaId("staff-member-identifier-collection-response-document").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { @@ -272,12 +296,15 @@ public void Kebab_casing_convention_is_applied_to_GetRelationship_endpoint_with_ } [Fact] - public void Kebab_casing_convention_is_applied_to_Post_endpoint() + public async Task Casing_convention_is_applied_to_Post_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./supermarkets.post").With(getElement => + document.ShouldContainPath("paths./supermarkets.post").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -285,17 +312,17 @@ public void Kebab_casing_convention_is_applied_to_Post_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("supermarket-post-request-document").SchemaReferenceId; + .ShouldBeReferenceSchemaId("supermarket-post-request-document").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("supermarket-data-in-post-request") - .SchemaReferenceId; + .ReferenceSchemaId; }); string? resourceRelationshipInPostRequestSchemaRefId = null; @@ -305,7 +332,7 @@ public void Kebab_casing_convention_is_applied_to_Post_endpoint() propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("supermarket-attributes-in-post-request"); resourceRelationshipInPostRequestSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref") - .ShouldBeReferenceSchemaId("supermarket-relationships-in-post-request").SchemaReferenceId; + .ShouldBeReferenceSchemaId("supermarket-relationships-in-post-request").ReferenceSchemaId; }); schemasElement.ShouldContainPath($"{resourceRelationshipInPostRequestSchemaRefId}.properties").With(propertiesElement => @@ -323,10 +350,13 @@ public void Kebab_casing_convention_is_applied_to_Post_endpoint() } [Fact] - public void Kebab_casing_convention_is_applied_to_PostRelationship_endpoint() + public async Task Casing_convention_is_applied_to_PostRelationship_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.post").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.post").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -336,12 +366,15 @@ public void Kebab_casing_convention_is_applied_to_PostRelationship_endpoint() } [Fact] - public void Kebab_casing_convention_is_applied_to_Patch_endpoint() + public async Task Casing_convention_is_applied_to_Patch_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}.patch").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -349,17 +382,17 @@ public void Kebab_casing_convention_is_applied_to_Patch_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("supermarket-patch-request-document").SchemaReferenceId; + .ShouldBeReferenceSchemaId("supermarket-patch-request-document").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("supermarket-data-in-patch-request") - .SchemaReferenceId; + .ReferenceSchemaId; }); schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => @@ -371,10 +404,13 @@ public void Kebab_casing_convention_is_applied_to_Patch_endpoint() } [Fact] - public void Kebab_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() + public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/store-manager.patch").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/relationships/store-manager.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -384,10 +420,13 @@ public void Kebab_casing_convention_is_applied_to_PatchRelationship_endpoint_wit } [Fact] - public void Kebab_casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() + public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/backup-store-manager.patch").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/relationships/backup-store-manager.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -397,10 +436,13 @@ public void Kebab_casing_convention_is_applied_to_PatchRelationship_endpoint_wit } [Fact] - public void Kebab_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() + public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.patch").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -410,10 +452,13 @@ public void Kebab_casing_convention_is_applied_to_PatchRelationship_endpoint_wit } [Fact] - public void Kebab_casing_convention_is_applied_to_Delete_endpoint() + public async Task Casing_convention_is_applied_to_Delete_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}.delete").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}.delete").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -423,10 +468,13 @@ public void Kebab_casing_convention_is_applied_to_Delete_endpoint() } [Fact] - public void Kebab_casing_convention_is_applied_to_DeleteRelationship_endpoint() + public async Task Casing_convention_is_applied_to_DeleteRelationship_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.delete").With(getElement => + document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.delete").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { diff --git a/test/OpenApiTests/NamingConvention/KebabCase/swagger.json b/test/OpenApiTests/NamingConventions/KebabCase/swagger.json similarity index 99% rename from test/OpenApiTests/NamingConvention/KebabCase/swagger.json rename to test/OpenApiTests/NamingConventions/KebabCase/swagger.json index 91e62448f9..e1de5e7b69 100644 --- a/test/OpenApiTests/NamingConvention/KebabCase/swagger.json +++ b/test/OpenApiTests/NamingConventions/KebabCase/swagger.json @@ -1463,4 +1463,4 @@ } } } -} +} \ No newline at end of file diff --git a/test/OpenApiTests/NamingConventions/NamingConventionsDbContext.cs b/test/OpenApiTests/NamingConventions/NamingConventionsDbContext.cs new file mode 100644 index 0000000000..eb2d0b52d2 --- /dev/null +++ b/test/OpenApiTests/NamingConventions/NamingConventionsDbContext.cs @@ -0,0 +1,15 @@ +using JetBrains.Annotations; +using Microsoft.EntityFrameworkCore; + +namespace OpenApiTests.NamingConventions; + +[UsedImplicitly(ImplicitUseTargetFlags.Members)] +public sealed class NamingConventionsDbContext : DbContext +{ + public DbSet Supermarkets => Set(); + + public NamingConventionsDbContext(DbContextOptions options) + : base(options) + { + } +} diff --git a/test/OpenApiTests/NamingConvention/PascalCase/PascalCaseNamingConventionStartup.cs b/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseNamingConventionStartup.cs similarity index 92% rename from test/OpenApiTests/NamingConvention/PascalCase/PascalCaseNamingConventionStartup.cs rename to test/OpenApiTests/NamingConventions/PascalCase/PascalCaseNamingConventionStartup.cs index 6f38d9fe8d..7c934b94e4 100644 --- a/test/OpenApiTests/NamingConvention/PascalCase/PascalCaseNamingConventionStartup.cs +++ b/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseNamingConventionStartup.cs @@ -3,7 +3,7 @@ using JsonApiDotNetCore.Configuration; using Microsoft.EntityFrameworkCore; -namespace OpenApiTests.NamingConvention.PascalCase; +namespace OpenApiTests.NamingConventions.PascalCase; [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] public sealed class PascalCaseNamingConventionStartup : OpenApiStartup diff --git a/test/OpenApiTests/NamingConvention/PascalCase/PascalCaseTests.cs b/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseTests.cs similarity index 71% rename from test/OpenApiTests/NamingConvention/PascalCase/PascalCaseTests.cs rename to test/OpenApiTests/NamingConventions/PascalCase/PascalCaseTests.cs index ade1727911..d37e9fa3bb 100644 --- a/test/OpenApiTests/NamingConvention/PascalCase/PascalCaseTests.cs +++ b/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseTests.cs @@ -1,24 +1,27 @@ +using System.Text.Json; using TestBuildingBlocks; using Xunit; -namespace OpenApiTests.NamingConvention.PascalCase; +namespace OpenApiTests.NamingConventions.PascalCase; -public sealed class PascalCaseTests : IClassFixture, NamingConventionDbContext>> +public sealed class PascalCaseTests : OpenApiTestSuite, NamingConventionsDbContext> { - private readonly OpenApiTestContext, NamingConventionDbContext> _testContext; - - public PascalCaseTests(OpenApiTestContext, NamingConventionDbContext> testContext) + public PascalCaseTests(OpenApiTestContext, NamingConventionsDbContext> testContext) + : base(testContext) { - _testContext = testContext; + UseController(); } [Fact] - public void Pascal_casing_convention_is_applied_to_GetCollection_endpoint() + public async Task Casing_convention_is_applied_to_GetCollection_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./Supermarkets.get").With(getElement => + document.ShouldContainPath("paths./Supermarkets.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -26,10 +29,10 @@ public void Pascal_casing_convention_is_applied_to_GetCollection_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("SupermarketCollectionResponseDocument").SchemaReferenceId; + .ShouldBeReferenceSchemaId("SupermarketCollectionResponseDocument").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; @@ -39,7 +42,7 @@ public void Pascal_casing_convention_is_applied_to_GetCollection_endpoint() propertiesElement.ShouldContainPath("jsonapi.$ref").ShouldBeReferenceSchemaId("JsonapiObject"); resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.items.$ref").ShouldBeReferenceSchemaId("SupermarketDataInResponse") - .SchemaReferenceId; + .ReferenceSchemaId; }); string? resourceAttributesInResponseSchemaRefId = null; @@ -49,13 +52,13 @@ public void Pascal_casing_convention_is_applied_to_GetCollection_endpoint() schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => { primaryResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("SupermarketResourceType") - .SchemaReferenceId; + .ReferenceSchemaId; resourceAttributesInResponseSchemaRefId = propertiesElement.ShouldContainPath("attributes.$ref") - .ShouldBeReferenceSchemaId("SupermarketAttributesInResponse").SchemaReferenceId; + .ShouldBeReferenceSchemaId("SupermarketAttributesInResponse").ReferenceSchemaId; resourceRelationshipInResponseSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref") - .ShouldBeReferenceSchemaId("SupermarketRelationshipsInResponse").SchemaReferenceId; + .ShouldBeReferenceSchemaId("SupermarketRelationshipsInResponse").ReferenceSchemaId; propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("LinksInResourceObject"); }); @@ -81,7 +84,7 @@ public void Pascal_casing_convention_is_applied_to_GetCollection_endpoint() propertiesElement.ShouldContainPath("StoreManager.$ref").ShouldBeReferenceSchemaId("ToOneStaffMemberInResponse"); nullableToOneResourceResponseDataSchemaRefId = propertiesElement.ShouldContainPath("BackupStoreManager.$ref") - .ShouldBeReferenceSchemaId("NullableToOneStaffMemberInResponse").SchemaReferenceId; + .ShouldBeReferenceSchemaId("NullableToOneStaffMemberInResponse").ReferenceSchemaId; propertiesElement.Should().ContainProperty("Cashiers"); propertiesElement.ShouldContainPath("Cashiers.$ref").ShouldBeReferenceSchemaId("ToManyStaffMemberInResponse"); @@ -94,7 +97,7 @@ public void Pascal_casing_convention_is_applied_to_GetCollection_endpoint() propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("LinksInRelationshipObject"); relatedResourceIdentifierSchemaRefId = propertiesElement.ShouldContainPath("data.oneOf[0].$ref") - .ShouldBeReferenceSchemaId("StaffMemberIdentifier").SchemaReferenceId; + .ShouldBeReferenceSchemaId("StaffMemberIdentifier").ReferenceSchemaId; propertiesElement.ShouldContainPath("data.oneOf[1].$ref").ShouldBeReferenceSchemaId("NullValue"); }); @@ -104,7 +107,7 @@ public void Pascal_casing_convention_is_applied_to_GetCollection_endpoint() schemasElement.ShouldContainPath($"{relatedResourceIdentifierSchemaRefId}.properties").With(propertiesElement => { relatedResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("StaffMemberResourceType") - .SchemaReferenceId; + .ReferenceSchemaId; }); schemasElement.ShouldContainPath($"{relatedResourceTypeSchemaRefId}.enum[0]").ShouldBeReferenceSchemaId("StaffMembers"); @@ -112,12 +115,15 @@ public void Pascal_casing_convention_is_applied_to_GetCollection_endpoint() } [Fact] - public void Pascal_casing_convention_is_applied_to_GetSingle_endpoint() + public async Task Casing_convention_is_applied_to_GetSingle_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}.get").With(getElement => + document.ShouldContainPath("paths./Supermarkets/{id}.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -125,10 +131,10 @@ public void Pascal_casing_convention_is_applied_to_GetSingle_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("SupermarketPrimaryResponseDocument").SchemaReferenceId; + .ShouldBeReferenceSchemaId("SupermarketPrimaryResponseDocument").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { @@ -138,12 +144,15 @@ public void Pascal_casing_convention_is_applied_to_GetSingle_endpoint() } [Fact] - public void Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() + public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/StoreManager.get").With(getElement => + document.ShouldContainPath("paths./Supermarkets/{id}/StoreManager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -151,17 +160,17 @@ public void Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_with_si }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("StaffMemberSecondaryResponseDocument").SchemaReferenceId; + .ShouldBeReferenceSchemaId("StaffMemberSecondaryResponseDocument").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("StaffMemberDataInResponse") - .SchemaReferenceId; + .ReferenceSchemaId; }); schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => @@ -172,10 +181,13 @@ public void Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_with_si } [Fact] - public void Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() + public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/BackupStoreManager.get").With(getElement => + document.ShouldContainPath("paths./Supermarkets/{id}/BackupStoreManager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -188,10 +200,13 @@ public void Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_with_nu } [Fact] - public void Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() + public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/Cashiers.get").With(getElement => + document.ShouldContainPath("paths./Supermarkets/{id}/Cashiers.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -204,12 +219,15 @@ public void Pascal_casing_convention_is_applied_to_GetSecondary_endpoint_with_re } [Fact] - public void Pascal_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() + public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/relationships/StoreManager.get").With(getElement => + document.ShouldContainPath("paths./Supermarkets/{id}/relationships/StoreManager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -217,10 +235,10 @@ public void Pascal_casing_convention_is_applied_to_GetRelationship_endpoint_with }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("StaffMemberIdentifierResponseDocument").SchemaReferenceId; + .ShouldBeReferenceSchemaId("StaffMemberIdentifierResponseDocument").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { @@ -230,10 +248,13 @@ public void Pascal_casing_convention_is_applied_to_GetRelationship_endpoint_with } [Fact] - public void Pascal_casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() + public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/relationships/BackupStoreManager.get").With(getElement => + document.ShouldContainPath("paths./Supermarkets/{id}/relationships/BackupStoreManager.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -246,12 +267,15 @@ public void Pascal_casing_convention_is_applied_to_GetRelationship_endpoint_with } [Fact] - public void Pascal_casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() + public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.get").With(getElement => + document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.get").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -259,10 +283,10 @@ public void Pascal_casing_convention_is_applied_to_GetRelationship_endpoint_with }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("StaffMemberIdentifierCollectionResponseDocument").SchemaReferenceId; + .ShouldBeReferenceSchemaId("StaffMemberIdentifierCollectionResponseDocument").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { @@ -272,12 +296,15 @@ public void Pascal_casing_convention_is_applied_to_GetRelationship_endpoint_with } [Fact] - public void Pascal_casing_convention_is_applied_to_Post_endpoint() + public async Task Casing_convention_is_applied_to_Post_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./Supermarkets.post").With(getElement => + document.ShouldContainPath("paths./Supermarkets.post").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -285,17 +312,17 @@ public void Pascal_casing_convention_is_applied_to_Post_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("SupermarketPostRequestDocument").SchemaReferenceId; + .ShouldBeReferenceSchemaId("SupermarketPostRequestDocument").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("SupermarketDataInPostRequest") - .SchemaReferenceId; + .ReferenceSchemaId; }); string? resourceRelationshipInPostRequestSchemaRefId = null; @@ -305,7 +332,7 @@ public void Pascal_casing_convention_is_applied_to_Post_endpoint() propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("SupermarketAttributesInPostRequest"); resourceRelationshipInPostRequestSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref") - .ShouldBeReferenceSchemaId("SupermarketRelationshipsInPostRequest").SchemaReferenceId; + .ShouldBeReferenceSchemaId("SupermarketRelationshipsInPostRequest").ReferenceSchemaId; }); schemasElement.ShouldContainPath($"{resourceRelationshipInPostRequestSchemaRefId}.properties").With(propertiesElement => @@ -323,10 +350,13 @@ public void Pascal_casing_convention_is_applied_to_Post_endpoint() } [Fact] - public void Pascal_casing_convention_is_applied_to_PostRelationship_endpoint() + public async Task Casing_convention_is_applied_to_PostRelationship_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.post").With(getElement => + document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.post").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -336,12 +366,15 @@ public void Pascal_casing_convention_is_applied_to_PostRelationship_endpoint() } [Fact] - public void Pascal_casing_convention_is_applied_to_Patch_endpoint() + public async Task Casing_convention_is_applied_to_Patch_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert string? documentSchemaRefId = null; - _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}.patch").With(getElement => + document.ShouldContainPath("paths./Supermarkets/{id}.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -349,17 +382,17 @@ public void Pascal_casing_convention_is_applied_to_Patch_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("SupermarketPatchRequestDocument").SchemaReferenceId; + .ShouldBeReferenceSchemaId("SupermarketPatchRequestDocument").ReferenceSchemaId; }); - _testContext.Document.ShouldContainPath("components.schemas").With(schemasElement => + document.ShouldContainPath("components.schemas").With(schemasElement => { string? resourceDataSchemaRefId = null; schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("SupermarketDataInPatchRequest") - .SchemaReferenceId; + .ReferenceSchemaId; }); schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => @@ -371,10 +404,13 @@ public void Pascal_casing_convention_is_applied_to_Patch_endpoint() } [Fact] - public void Pascal_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() + public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/relationships/StoreManager.patch").With(getElement => + document.ShouldContainPath("paths./Supermarkets/{id}/relationships/StoreManager.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -384,10 +420,13 @@ public void Pascal_casing_convention_is_applied_to_PatchRelationship_endpoint_wi } [Fact] - public void Pascal_casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() + public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/relationships/BackupStoreManager.patch").With(getElement => + document.ShouldContainPath("paths./Supermarkets/{id}/relationships/BackupStoreManager.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -397,10 +436,13 @@ public void Pascal_casing_convention_is_applied_to_PatchRelationship_endpoint_wi } [Fact] - public void Pascal_casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() + public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.patch").With(getElement => + document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.patch").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -410,10 +452,13 @@ public void Pascal_casing_convention_is_applied_to_PatchRelationship_endpoint_wi } [Fact] - public void Pascal_casing_convention_is_applied_to_Delete_endpoint() + public async Task Casing_convention_is_applied_to_Delete_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}.delete").With(getElement => + document.ShouldContainPath("paths./Supermarkets/{id}.delete").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { @@ -423,10 +468,13 @@ public void Pascal_casing_convention_is_applied_to_Delete_endpoint() } [Fact] - public void Pascal_casing_convention_is_applied_to_DeleteRelationship_endpoint() + public async Task Casing_convention_is_applied_to_DeleteRelationship_endpoint() { + // Act + JsonElement document = await GetDocumentAsync(); + // Assert - _testContext.Document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.delete").With(getElement => + document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.delete").With(getElement => { getElement.ShouldContainPath("operationId").With(operationElement => { diff --git a/test/OpenApiTests/NamingConvention/PascalCase/swagger.json b/test/OpenApiTests/NamingConventions/PascalCase/swagger.json similarity index 99% rename from test/OpenApiTests/NamingConvention/PascalCase/swagger.json rename to test/OpenApiTests/NamingConventions/PascalCase/swagger.json index c29792f530..91eab90f85 100644 --- a/test/OpenApiTests/NamingConvention/PascalCase/swagger.json +++ b/test/OpenApiTests/NamingConventions/PascalCase/swagger.json @@ -1463,4 +1463,4 @@ } } } -} +} \ No newline at end of file diff --git a/test/OpenApiTests/NamingConvention/StaffMember.cs b/test/OpenApiTests/NamingConventions/StaffMember.cs similarity index 88% rename from test/OpenApiTests/NamingConvention/StaffMember.cs rename to test/OpenApiTests/NamingConventions/StaffMember.cs index 93397b01aa..d14c30a422 100644 --- a/test/OpenApiTests/NamingConvention/StaffMember.cs +++ b/test/OpenApiTests/NamingConventions/StaffMember.cs @@ -2,7 +2,7 @@ using JsonApiDotNetCore.Resources; using JsonApiDotNetCore.Resources.Annotations; -namespace OpenApiTests.NamingConvention; +namespace OpenApiTests.NamingConventions; [UsedImplicitly(ImplicitUseTargetFlags.Members)] public sealed class StaffMember : Identifiable diff --git a/test/OpenApiTests/NamingConvention/Supermarket.cs b/test/OpenApiTests/NamingConventions/Supermarket.cs similarity index 84% rename from test/OpenApiTests/NamingConvention/Supermarket.cs rename to test/OpenApiTests/NamingConventions/Supermarket.cs index af716c1666..4bde8776da 100644 --- a/test/OpenApiTests/NamingConvention/Supermarket.cs +++ b/test/OpenApiTests/NamingConventions/Supermarket.cs @@ -2,10 +2,10 @@ using JsonApiDotNetCore.Resources; using JsonApiDotNetCore.Resources.Annotations; -namespace OpenApiTests.NamingConvention; +namespace OpenApiTests.NamingConventions; [UsedImplicitly(ImplicitUseTargetFlags.Members)] -[Resource(ControllerNamespace = "OpenApiTests")] +[Resource(ControllerNamespace = "OpenApiTests.NamingConventions")] public sealed class Supermarket : Identifiable { [Attr] diff --git a/test/OpenApiTests/NamingConvention/SupermarketType.cs b/test/OpenApiTests/NamingConventions/SupermarketType.cs similarity index 78% rename from test/OpenApiTests/NamingConvention/SupermarketType.cs rename to test/OpenApiTests/NamingConventions/SupermarketType.cs index 428c1ee12c..45570936f5 100644 --- a/test/OpenApiTests/NamingConvention/SupermarketType.cs +++ b/test/OpenApiTests/NamingConventions/SupermarketType.cs @@ -1,6 +1,6 @@ using JetBrains.Annotations; -namespace OpenApiTests.NamingConvention; +namespace OpenApiTests.NamingConventions; [UsedImplicitly(ImplicitUseTargetFlags.Members)] public enum SupermarketType diff --git a/test/OpenApiTests/OpenApiTestContext.cs b/test/OpenApiTests/OpenApiTestContext.cs index 5350173e88..e3d262770e 100644 --- a/test/OpenApiTests/OpenApiTestContext.cs +++ b/test/OpenApiTests/OpenApiTestContext.cs @@ -2,57 +2,41 @@ using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; using TestBuildingBlocks; -using Xunit; namespace OpenApiTests; [UsedImplicitly(ImplicitUseKindFlags.InstantiatedNoFixedConstructorSignature)] -public sealed class OpenApiTestContext : IntegrationTestContext, IAsyncLifetime +public class OpenApiTestContext : IntegrationTestContext where TStartup : class where TDbContext : DbContext { - internal JsonElement Document { get; private set; } + internal readonly Lazy> LazyDocument; - public async Task InitializeAsync() + public OpenApiTestContext() { - UseController(); + LazyDocument = new Lazy>(GetDocumentAsync, LazyThreadSafetyMode.ExecutionAndPublication); + } + private async Task GetDocumentAsync() + { string content = await GetAsync("swagger/v1/swagger.json"); - await WriteSwaggerDocumentToFileAsync(content); - JsonDocument parsedContent = JsonDocument.Parse(content); - Document = parsedContent.ToJsonElement(); + using (parsedContent) + { + JsonElement clonedRoot = parsedContent.RootElement.Clone(); + return clonedRoot; + } } private async Task GetAsync(string requestUrl) { - var request = new HttpRequestMessage(HttpMethod.Get, requestUrl); + using var request = new HttpRequestMessage(HttpMethod.Get, requestUrl); using HttpClient client = Factory.CreateClient(); using HttpResponseMessage responseMessage = await client.SendAsync(request); return await responseMessage.Content.ReadAsStringAsync(); } - - private async Task WriteSwaggerDocumentToFileAsync(string document) - { - string testSuitePath = GetTestSuitePath(); - string documentPath = Path.Join(testSuitePath, "swagger.json"); - await File.WriteAllTextAsync(documentPath, document); - } - - private string GetTestSuitePath() - { - string solutionTestDirectoryPath = Directory.GetParent(Environment.CurrentDirectory)!.Parent!.Parent!.Parent!.FullName; - string currentNamespacePathRelativeToTestDirectory = Path.Join(typeof(TStartup).Namespace!.Split('.')); - - return Path.Join(solutionTestDirectoryPath, currentNamespacePathRelativeToTestDirectory); - } - - public Task DisposeAsync() - { - return Task.CompletedTask; - } } diff --git a/test/OpenApiTests/OpenApiTestSuite.cs b/test/OpenApiTests/OpenApiTestSuite.cs new file mode 100644 index 0000000000..46e779db14 --- /dev/null +++ b/test/OpenApiTests/OpenApiTestSuite.cs @@ -0,0 +1,58 @@ +using System.Text.Json; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using Xunit; + +namespace OpenApiTests; + +public abstract class OpenApiTestSuite : IClassFixture> + where TStartup : class + where TDbContext : DbContext +{ + private readonly OpenApiTestContext _testContext; + private readonly bool _shouldWriteDocumentToDisk; + + protected OpenApiTestSuite(OpenApiTestContext testContext) + { + _testContext = testContext; + _shouldWriteDocumentToDisk = !testContext.LazyDocument.IsValueCreated; + } + + protected void UseController() + where TController : ControllerBase + { + if (!_testContext.LazyDocument.IsValueCreated) + { + _testContext.UseController(); + } + } + + protected async Task GetDocumentAsync() + { + JsonElement document = await _testContext.LazyDocument.Value; + + if (_shouldWriteDocumentToDisk) + { + await WriteSwaggerDocumentToFileAsync(document); + } + + return document; + } + + private async Task WriteSwaggerDocumentToFileAsync(JsonElement document) + { + string pathToTestSuiteDirectory = GetTestSuitePath(); + string pathToDocument = Path.Join(pathToTestSuiteDirectory, "swagger.json"); + string json = document.ToString(); + await File.WriteAllTextAsync(pathToDocument, json); + } + + private static string GetTestSuitePath() + { + string pathToSolutionTestDirectory = Path.Combine(Environment.CurrentDirectory, "../../../../"); + pathToSolutionTestDirectory = Path.GetFullPath(pathToSolutionTestDirectory); + string pathToCurrentNamespaceRelativeToTestDirectory = Path.Combine(typeof(TStartup).Namespace!.Split('.')); + + return Path.Join(pathToSolutionTestDirectory, pathToCurrentNamespaceRelativeToTestDirectory); + } +} diff --git a/test/OpenApiTests/OpenApiTests.csproj b/test/OpenApiTests/OpenApiTests.csproj index d24a3be47f..ceb0298f24 100644 --- a/test/OpenApiTests/OpenApiTests.csproj +++ b/test/OpenApiTests/OpenApiTests.csproj @@ -1,28 +1,28 @@ - - $(TargetFrameworkName) - + + $(TargetFrameworkName) + - - - - - + + + + + + + + + PreserveNewest + + - - - - - - + + + + + + - - - - - - - PreserveNewest - - + + + diff --git a/test/TestBuildingBlocks/JsonDocumentExtensions.cs b/test/TestBuildingBlocks/JsonDocumentExtensions.cs deleted file mode 100644 index d70acbfd78..0000000000 --- a/test/TestBuildingBlocks/JsonDocumentExtensions.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Text.Json; - -namespace TestBuildingBlocks; - -public static class JsonDocumentExtensions -{ - public static JsonElement ToJsonElement(this JsonDocument source) - { - using (source) - { - JsonElement clonedRoot = source.RootElement.Clone(); - return clonedRoot; - } - } -} diff --git a/test/TestBuildingBlocks/TestBuildingBlocks.csproj b/test/TestBuildingBlocks/TestBuildingBlocks.csproj index 0cf2fec525..2c8fdd1cd5 100644 --- a/test/TestBuildingBlocks/TestBuildingBlocks.csproj +++ b/test/TestBuildingBlocks/TestBuildingBlocks.csproj @@ -17,6 +17,5 @@ - From 4a128adf6567414720a5708256fe3e6e3c9defc2 Mon Sep 17 00:00:00 2001 From: maurei Date: Thu, 16 Dec 2021 12:33:14 +0100 Subject: [PATCH 07/15] ignore generated swagger.json files --- JsonApiDotNetCore.sln.DotSettings | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/JsonApiDotNetCore.sln.DotSettings b/JsonApiDotNetCore.sln.DotSettings index 7982cce175..1fae9fbdec 100644 --- a/JsonApiDotNetCore.sln.DotSettings +++ b/JsonApiDotNetCore.sln.DotSettings @@ -15,9 +15,10 @@ JsonApiDotNetCore.ArgumentGuard.NotNull($EXPR$, $NAME$); 50 False True - ExplicitlyExcluded - ExplicitlyExcluded - ExplicitlyExcluded + + + + swagger.json SOLUTION True True From 45dd54975719ebc638270cfda6a7b87f9e2ac4b2 Mon Sep 17 00:00:00 2001 From: maurei Date: Thu, 16 Dec 2021 13:15:37 +0100 Subject: [PATCH 08/15] Restore formatting in csproj files --- .../OpenApiClientTests.csproj | 124 +++++++++--------- test/OpenApiTests/OpenApiTests.csproj | 49 +++---- 2 files changed, 87 insertions(+), 86 deletions(-) diff --git a/test/OpenApiClientTests/OpenApiClientTests.csproj b/test/OpenApiClientTests/OpenApiClientTests.csproj index 5e9ab56e09..62a7368e6e 100644 --- a/test/OpenApiClientTests/OpenApiClientTests.csproj +++ b/test/OpenApiClientTests/OpenApiClientTests.csproj @@ -1,66 +1,66 @@ - - $(TargetFrameworkName) - + + $(TargetFrameworkName) + - - - - - - - - PreserveNewest - - + + + + - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - + + + PreserveNewest + + - - - OpenApiClientTests.LegacyClient.GeneratedCode - OpenApiClient - OpenApiClient.cs - NSwagCSharp - /UseBaseUrl:false /GenerateClientInterfaces:true /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions - - - OpenApiClientTests.NamingConventions.KebabCase.GeneratedCode - KebabCaseClient - KebabCaseClient.cs - NSwagCSharp - /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions - - - OpenApiClientTests.NamingConventions.CamelCase.GeneratedCode - CamelCaseClient - CamelCaseClient.cs - NSwagCSharp - /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions - - - OpenApiClientTests.NamingConventions.PascalCase.GeneratedCode - PascalCaseClient - PascalCaseClient.cs - NSwagCSharp - /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions - - - + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + OpenApiClientTests.LegacyClient.GeneratedCode + OpenApiClient + OpenApiClient.cs + NSwagCSharp + /UseBaseUrl:false /GenerateClientInterfaces:true /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions + + + OpenApiClientTests.NamingConventions.KebabCase.GeneratedCode + KebabCaseClient + KebabCaseClient.cs + NSwagCSharp + /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions + + + OpenApiClientTests.NamingConventions.CamelCase.GeneratedCode + CamelCaseClient + CamelCaseClient.cs + NSwagCSharp + /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions + + + OpenApiClientTests.NamingConventions.PascalCase.GeneratedCode + PascalCaseClient + PascalCaseClient.cs + NSwagCSharp + /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions + + + \ No newline at end of file diff --git a/test/OpenApiTests/OpenApiTests.csproj b/test/OpenApiTests/OpenApiTests.csproj index ceb0298f24..6ba324d30f 100644 --- a/test/OpenApiTests/OpenApiTests.csproj +++ b/test/OpenApiTests/OpenApiTests.csproj @@ -1,28 +1,29 @@ - - $(TargetFrameworkName) - + + $(TargetFrameworkName) + - - - - - - - - - PreserveNewest - - + + + + + - - - - - - + + + PreserveNewest + + - - - - + + + + + + + + + + + + \ No newline at end of file From 531ebd8730f281b3ff67d37267541fcf9222b191 Mon Sep 17 00:00:00 2001 From: maurei Date: Thu, 16 Dec 2021 15:28:08 +0100 Subject: [PATCH 09/15] Additional self-review round --- JsonApiDotNetCore.sln.DotSettings | 3 --- src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs | 4 +--- src/JsonApiDotNetCore.OpenApi/StringExtensions.cs | 4 ++-- test/OpenApiTests/JsonElementExtensions.cs | 12 +++++++----- test/OpenApiTests/OpenApiTestSuite.cs | 9 +++++---- 5 files changed, 15 insertions(+), 17 deletions(-) diff --git a/JsonApiDotNetCore.sln.DotSettings b/JsonApiDotNetCore.sln.DotSettings index 1fae9fbdec..d03207e4fc 100644 --- a/JsonApiDotNetCore.sln.DotSettings +++ b/JsonApiDotNetCore.sln.DotSettings @@ -15,9 +15,6 @@ JsonApiDotNetCore.ArgumentGuard.NotNull($EXPR$, $NAME$); 50 False True - - - swagger.json SOLUTION True diff --git a/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs b/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs index eff00c4230..c33851ebce 100644 --- a/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs +++ b/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs @@ -16,9 +16,7 @@ internal class ApiException : Exception public IReadOnlyDictionary> Headers { get; } public ApiException(string message, int statusCode, string? response, IReadOnlyDictionary> headers, Exception innerException) - : base( - message + "\n\nStatus: " + statusCode + "\nResponse: \n" + - (response == null ? "(null)" : response[..(response.Length >= 512 ? 512 : response.Length)]), innerException) + : base($"{message}\n\nStatus: {statusCode}\nResponse: \n{response ?? "(null)"}", innerException) { StatusCode = statusCode; Response = response; diff --git a/src/JsonApiDotNetCore.OpenApi/StringExtensions.cs b/src/JsonApiDotNetCore.OpenApi/StringExtensions.cs index d52862844a..df1e48099e 100644 --- a/src/JsonApiDotNetCore.OpenApi/StringExtensions.cs +++ b/src/JsonApiDotNetCore.OpenApi/StringExtensions.cs @@ -4,10 +4,10 @@ namespace JsonApiDotNetCore.OpenApi; internal static class StringExtensions { - private static readonly Regex Pattern = new("(?:^|-|_| +)(.)", RegexOptions.Compiled); + private static readonly Regex PatternForPascalCaseConversion = new("(?:^|-|_| +)(.)", RegexOptions.Compiled); public static string ToPascalCase(this string source) { - return Pattern.Replace(source, match => match.Groups[1].Value.ToUpper()); + return PatternForPascalCaseConversion.Replace(source, match => match.Groups[1].Value.ToUpper()); } } diff --git a/test/OpenApiTests/JsonElementExtensions.cs b/test/OpenApiTests/JsonElementExtensions.cs index 768990064d..2f84d13659 100644 --- a/test/OpenApiTests/JsonElementExtensions.cs +++ b/test/OpenApiTests/JsonElementExtensions.cs @@ -35,15 +35,17 @@ public static ReferenceSchemaIdContainer ShouldBeReferenceSchemaId(this JsonElem string referenceSchemaId = jsonElementValue.Split('/').Last(); referenceSchemaId.Should().Be(value); - return new ReferenceSchemaIdContainer - { - ReferenceSchemaId = value - }; + return new ReferenceSchemaIdContainer(value); } public sealed class ReferenceSchemaIdContainer { - internal string ReferenceSchemaId { get; init; } = null!; + public string ReferenceSchemaId { get; } + + public ReferenceSchemaIdContainer(string referenceSchemaId) + { + ReferenceSchemaId = referenceSchemaId; + } } public sealed class JsonElementAssertions : JsonElementAssertions diff --git a/test/OpenApiTests/OpenApiTestSuite.cs b/test/OpenApiTests/OpenApiTestSuite.cs index 46e779db14..eb56572ca2 100644 --- a/test/OpenApiTests/OpenApiTestSuite.cs +++ b/test/OpenApiTests/OpenApiTestSuite.cs @@ -10,18 +10,18 @@ public abstract class OpenApiTestSuite : IClassFixture _testContext; - private readonly bool _shouldWriteDocumentToDisk; + private readonly bool _isFirstTestRunInTestSuite; protected OpenApiTestSuite(OpenApiTestContext testContext) { _testContext = testContext; - _shouldWriteDocumentToDisk = !testContext.LazyDocument.IsValueCreated; + _isFirstTestRunInTestSuite = !testContext.LazyDocument.IsValueCreated; } protected void UseController() where TController : ControllerBase { - if (!_testContext.LazyDocument.IsValueCreated) + if (_isFirstTestRunInTestSuite) { _testContext.UseController(); } @@ -31,7 +31,7 @@ protected async Task GetDocumentAsync() { JsonElement document = await _testContext.LazyDocument.Value; - if (_shouldWriteDocumentToDisk) + if (_isFirstTestRunInTestSuite) { await WriteSwaggerDocumentToFileAsync(document); } @@ -51,6 +51,7 @@ private static string GetTestSuitePath() { string pathToSolutionTestDirectory = Path.Combine(Environment.CurrentDirectory, "../../../../"); pathToSolutionTestDirectory = Path.GetFullPath(pathToSolutionTestDirectory); + string pathToCurrentNamespaceRelativeToTestDirectory = Path.Combine(typeof(TStartup).Namespace!.Split('.')); return Path.Join(pathToSolutionTestDirectory, pathToCurrentNamespaceRelativeToTestDirectory); From 061c357c423adce97655b3bb70fc4e8308d1415d Mon Sep 17 00:00:00 2001 From: maurei Date: Thu, 16 Dec 2021 15:52:55 +0100 Subject: [PATCH 10/15] remove BeJson overload --- test/OpenApiTests/JsonElementExtensions.cs | 7 ------- .../LegacyOpenApiIntegrationTests.cs | 7 +++++-- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/test/OpenApiTests/JsonElementExtensions.cs b/test/OpenApiTests/JsonElementExtensions.cs index 2f84d13659..0fe9a46858 100644 --- a/test/OpenApiTests/JsonElementExtensions.cs +++ b/test/OpenApiTests/JsonElementExtensions.cs @@ -75,12 +75,5 @@ public void ContainProperty(string propertyName) Execute.Assertion.ForCondition(_subject.TryGetProperty(propertyName, out _)) .FailWith($"Expected JSON element '{escapedJson}' to contain a property named '{propertyName}'."); } - - public void BeJson(string expectedDocument) - { - string json = _subject.ToString(); - - json.Should().BeJson(expectedDocument); - } } } diff --git a/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs b/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs index 17ec272fee..3f57a6b837 100644 --- a/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs +++ b/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs @@ -1,5 +1,7 @@ using System.Reflection; using System.Text.Json; +using FluentAssertions; +using TestBuildingBlocks; using Xunit; namespace OpenApiTests.LegacyOpenApiIntegration; @@ -21,10 +23,11 @@ public async Task Retrieved_document_matches_expected_document() string expectedDocument = await LoadEmbeddedResourceAsync(embeddedResourceName); // Act - JsonElement actualDocument = await LazyDocument.Value; + JsonElement jsonElement = await LazyDocument.Value; // Assert - actualDocument.Should().BeJson(expectedDocument); + string jsonText = jsonElement.ToString(); + jsonText.Should().BeJson(expectedDocument); } private static async Task LoadEmbeddedResourceAsync(string name) From c14587cc28faed6e509d32bd1baa7c5d805bd485 Mon Sep 17 00:00:00 2001 From: maurei Date: Fri, 17 Dec 2021 12:17:12 +0100 Subject: [PATCH 11/15] Merge base test suite and text context, move swagger.json to swagger.g.json in client test project --- JsonApiDotNetCore.sln.DotSettings | 1 + .../LegacyClient/swagger.g.json | 3363 +++++++++++++++++ .../CamelCase/swagger.g.json} | 30 +- .../KebabCase/swagger.g.json} | 30 +- .../PascalCase/swagger.g.json} | 94 +- .../OpenApiClientTests.csproj | 8 +- .../LegacyOpenApiIntegrationTests.cs | 8 +- .../LegacyOpenApiIntegration/swagger.json | 2 +- .../CamelCase/CamelCaseTests.cs | 44 +- .../KebabCase/KebabCaseTests.cs | 44 +- .../PascalCase/PascalCaseTests.cs | 42 +- test/OpenApiTests/OpenApiTestContext.cs | 46 +- test/OpenApiTests/OpenApiTestSuite.cs | 59 - .../IntegrationTestContext.cs | 2 +- 14 files changed, 3564 insertions(+), 209 deletions(-) create mode 100644 test/OpenApiClientTests/LegacyClient/swagger.g.json rename test/{OpenApiTests/NamingConventions/CamelCase/swagger.json => OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json} (98%) rename test/{OpenApiTests/NamingConventions/KebabCase/swagger.json => OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json} (98%) rename test/{OpenApiTests/NamingConventions/PascalCase/swagger.json => OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json} (96%) delete mode 100644 test/OpenApiTests/OpenApiTestSuite.cs diff --git a/JsonApiDotNetCore.sln.DotSettings b/JsonApiDotNetCore.sln.DotSettings index d03207e4fc..b5f9e22340 100644 --- a/JsonApiDotNetCore.sln.DotSettings +++ b/JsonApiDotNetCore.sln.DotSettings @@ -15,6 +15,7 @@ JsonApiDotNetCore.ArgumentGuard.NotNull($EXPR$, $NAME$); 50 False True + swagger.g.json swagger.json SOLUTION True diff --git a/test/OpenApiClientTests/LegacyClient/swagger.g.json b/test/OpenApiClientTests/LegacyClient/swagger.g.json new file mode 100644 index 0000000000..03575fe1d2 --- /dev/null +++ b/test/OpenApiClientTests/LegacyClient/swagger.g.json @@ -0,0 +1,3363 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "OpenApiTests", + "version": "1.0" + }, + "paths": { + "/api/v1/airplanes": { + "get": { + "tags": [ + "airplanes" + ], + "operationId": "get-airplane-collection", + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/airplane-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "airplanes" + ], + "operationId": "head-airplane-collection", + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/airplane-collection-response-document" + } + } + } + } + } + }, + "post": { + "tags": [ + "airplanes" + ], + "operationId": "post-airplane", + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/airplane-post-request-document" + } + } + } + }, + "responses": { + "201": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/airplane-primary-response-document" + } + } + } + }, + "204": { + "description": "Success" + } + } + } + }, + "/api/v1/airplanes/{id}": { + "get": { + "tags": [ + "airplanes" + ], + "operationId": "get-airplane", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/airplane-primary-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "airplanes" + ], + "operationId": "head-airplane", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/airplane-primary-response-document" + } + } + } + } + } + }, + "patch": { + "tags": [ + "airplanes" + ], + "operationId": "patch-airplane", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/airplane-patch-request-document" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/airplane-primary-response-document" + } + } + } + }, + "204": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "airplanes" + ], + "operationId": "delete-airplane", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/api/v1/airplanes/{id}/flights": { + "get": { + "tags": [ + "airplanes" + ], + "operationId": "get-airplane-flights", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "airplanes" + ], + "operationId": "head-airplane-flights", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-collection-response-document" + } + } + } + } + } + } + }, + "/api/v1/airplanes/{id}/relationships/flights": { + "get": { + "tags": [ + "airplanes" + ], + "operationId": "get-airplane-flights-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-identifier-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "airplanes" + ], + "operationId": "head-airplane-flights-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-identifier-collection-response-document" + } + } + } + } + } + }, + "post": { + "tags": [ + "airplanes" + ], + "operationId": "post-airplane-flights-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-flight-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + }, + "patch": { + "tags": [ + "airplanes" + ], + "operationId": "patch-airplane-flights-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-flight-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "airplanes" + ], + "operationId": "delete-airplane-flights-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-flight-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/api/v1/flight-attendants": { + "get": { + "tags": [ + "flight-attendants" + ], + "operationId": "get-flight-attendant-collection", + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-attendant-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "flight-attendants" + ], + "operationId": "head-flight-attendant-collection", + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-attendant-collection-response-document" + } + } + } + } + } + }, + "post": { + "tags": [ + "flight-attendants" + ], + "operationId": "post-flight-attendant", + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-attendant-post-request-document" + } + } + } + }, + "responses": { + "201": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-attendant-primary-response-document" + } + } + } + }, + "204": { + "description": "Success" + } + } + } + }, + "/api/v1/flight-attendants/{id}": { + "get": { + "tags": [ + "flight-attendants" + ], + "operationId": "get-flight-attendant", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-attendant-primary-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "flight-attendants" + ], + "operationId": "head-flight-attendant", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-attendant-primary-response-document" + } + } + } + } + } + }, + "patch": { + "tags": [ + "flight-attendants" + ], + "operationId": "patch-flight-attendant", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-attendant-patch-request-document" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-attendant-primary-response-document" + } + } + } + }, + "204": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "flight-attendants" + ], + "operationId": "delete-flight-attendant", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/api/v1/flight-attendants/{id}/purser-on-flights": { + "get": { + "tags": [ + "flight-attendants" + ], + "operationId": "get-flight-attendant-purser-on-flights", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "flight-attendants" + ], + "operationId": "head-flight-attendant-purser-on-flights", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-collection-response-document" + } + } + } + } + } + } + }, + "/api/v1/flight-attendants/{id}/relationships/purser-on-flights": { + "get": { + "tags": [ + "flight-attendants" + ], + "operationId": "get-flight-attendant-purser-on-flights-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-identifier-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "flight-attendants" + ], + "operationId": "head-flight-attendant-purser-on-flights-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-identifier-collection-response-document" + } + } + } + } + } + }, + "post": { + "tags": [ + "flight-attendants" + ], + "operationId": "post-flight-attendant-purser-on-flights-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-flight-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + }, + "patch": { + "tags": [ + "flight-attendants" + ], + "operationId": "patch-flight-attendant-purser-on-flights-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-flight-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "flight-attendants" + ], + "operationId": "delete-flight-attendant-purser-on-flights-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-flight-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/api/v1/flight-attendants/{id}/scheduled-for-flights": { + "get": { + "tags": [ + "flight-attendants" + ], + "operationId": "get-flight-attendant-scheduled-for-flights", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "flight-attendants" + ], + "operationId": "head-flight-attendant-scheduled-for-flights", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-collection-response-document" + } + } + } + } + } + } + }, + "/api/v1/flight-attendants/{id}/relationships/scheduled-for-flights": { + "get": { + "tags": [ + "flight-attendants" + ], + "operationId": "get-flight-attendant-scheduled-for-flights-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-identifier-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "flight-attendants" + ], + "operationId": "head-flight-attendant-scheduled-for-flights-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-identifier-collection-response-document" + } + } + } + } + } + }, + "post": { + "tags": [ + "flight-attendants" + ], + "operationId": "post-flight-attendant-scheduled-for-flights-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-flight-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + }, + "patch": { + "tags": [ + "flight-attendants" + ], + "operationId": "patch-flight-attendant-scheduled-for-flights-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-flight-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "flight-attendants" + ], + "operationId": "delete-flight-attendant-scheduled-for-flights-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-flight-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/api/v1/flights": { + "get": { + "tags": [ + "flights" + ], + "operationId": "get-flight-collection", + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "flights" + ], + "operationId": "head-flight-collection", + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-collection-response-document" + } + } + } + } + } + }, + "post": { + "tags": [ + "flights" + ], + "operationId": "post-flight", + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-post-request-document" + } + } + } + }, + "responses": { + "201": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-primary-response-document" + } + } + } + }, + "204": { + "description": "Success" + } + } + } + }, + "/api/v1/flights/{id}": { + "get": { + "tags": [ + "flights" + ], + "operationId": "get-flight", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-primary-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "flights" + ], + "operationId": "head-flight", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-primary-response-document" + } + } + } + } + } + }, + "patch": { + "tags": [ + "flights" + ], + "operationId": "patch-flight", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-patch-request-document" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-primary-response-document" + } + } + } + }, + "204": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "flights" + ], + "operationId": "delete-flight", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/api/v1/flights/{id}/backup-purser": { + "get": { + "tags": [ + "flights" + ], + "operationId": "get-flight-backup-purser", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullable-flight-attendant-secondary-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "flights" + ], + "operationId": "head-flight-backup-purser", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullable-flight-attendant-secondary-response-document" + } + } + } + } + } + } + }, + "/api/v1/flights/{id}/relationships/backup-purser": { + "get": { + "tags": [ + "flights" + ], + "operationId": "get-flight-backup-purser-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullable-flight-attendant-identifier-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "flights" + ], + "operationId": "head-flight-backup-purser-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullable-flight-attendant-identifier-response-document" + } + } + } + } + } + }, + "patch": { + "tags": [ + "flights" + ], + "operationId": "patch-flight-backup-purser-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/nullable-to-one-flight-attendant-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/api/v1/flights/{id}/cabin-crew-members": { + "get": { + "tags": [ + "flights" + ], + "operationId": "get-flight-cabin-crew-members", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-attendant-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "flights" + ], + "operationId": "head-flight-cabin-crew-members", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-attendant-collection-response-document" + } + } + } + } + } + } + }, + "/api/v1/flights/{id}/relationships/cabin-crew-members": { + "get": { + "tags": [ + "flights" + ], + "operationId": "get-flight-cabin-crew-members-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-attendant-identifier-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "flights" + ], + "operationId": "head-flight-cabin-crew-members-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-attendant-identifier-collection-response-document" + } + } + } + } + } + }, + "post": { + "tags": [ + "flights" + ], + "operationId": "post-flight-cabin-crew-members-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-flight-attendant-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + }, + "patch": { + "tags": [ + "flights" + ], + "operationId": "patch-flight-cabin-crew-members-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-flight-attendant-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "flights" + ], + "operationId": "delete-flight-cabin-crew-members-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-flight-attendant-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/api/v1/flights/{id}/passengers": { + "get": { + "tags": [ + "flights" + ], + "operationId": "get-flight-passengers", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/passenger-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "flights" + ], + "operationId": "head-flight-passengers", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/passenger-collection-response-document" + } + } + } + } + } + } + }, + "/api/v1/flights/{id}/relationships/passengers": { + "get": { + "tags": [ + "flights" + ], + "operationId": "get-flight-passengers-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/passenger-identifier-collection-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "flights" + ], + "operationId": "head-flight-passengers-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/passenger-identifier-collection-response-document" + } + } + } + } + } + }, + "post": { + "tags": [ + "flights" + ], + "operationId": "post-flight-passengers-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-passenger-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + }, + "patch": { + "tags": [ + "flights" + ], + "operationId": "patch-flight-passengers-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-passenger-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + }, + "delete": { + "tags": [ + "flights" + ], + "operationId": "delete-flight-passengers-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-many-passenger-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + }, + "/api/v1/flights/{id}/purser": { + "get": { + "tags": [ + "flights" + ], + "operationId": "get-flight-purser", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-attendant-secondary-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "flights" + ], + "operationId": "head-flight-purser", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-attendant-secondary-response-document" + } + } + } + } + } + } + }, + "/api/v1/flights/{id}/relationships/purser": { + "get": { + "tags": [ + "flights" + ], + "operationId": "get-flight-purser-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-attendant-identifier-response-document" + } + } + } + } + } + }, + "head": { + "tags": [ + "flights" + ], + "operationId": "head-flight-purser-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/flight-attendant-identifier-response-document" + } + } + } + } + } + }, + "patch": { + "tags": [ + "flights" + ], + "operationId": "patch-flight-purser-relationship", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/vnd.api+json": { + "schema": { + "$ref": "#/components/schemas/to-one-flight-attendant-in-request" + } + } + } + }, + "responses": { + "204": { + "description": "Success" + } + } + } + } + }, + "components": { + "schemas": { + "aircraft-kind": { + "enum": [ + "Turboprops", + "LightJet", + "MidSizeJet", + "JumboJet" + ], + "type": "string" + }, + "airline": { + "enum": [ + "DeltaAirLines", + "LufthansaGroup", + "AirFranceKlm" + ], + "type": "string" + }, + "airplane-attributes-in-patch-request": { + "type": "object", + "properties": { + "name": { + "maxLength": 255, + "type": "string" + }, + "serial-number": { + "maxLength": 16, + "type": "string", + "nullable": true + }, + "airtime-in-hours": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "last-serviced-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "is-in-maintenance": { + "type": "boolean" + }, + "manufactured-in-city": { + "maxLength": 85, + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "airplane-attributes-in-post-request": { + "required": [ + "name" + ], + "type": "object", + "properties": { + "name": { + "maxLength": 255, + "type": "string" + }, + "serial-number": { + "maxLength": 16, + "type": "string", + "nullable": true + }, + "airtime-in-hours": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "last-serviced-at": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "additionalProperties": false + }, + "airplane-attributes-in-response": { + "type": "object", + "properties": { + "name": { + "maxLength": 255, + "type": "string" + }, + "serial-number": { + "maxLength": 16, + "type": "string", + "nullable": true + }, + "airtime-in-hours": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "last-serviced-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "manufactured-at": { + "type": "string", + "format": "date-time" + }, + "is-in-maintenance": { + "type": "boolean" + }, + "manufactured-in-city": { + "maxLength": 85, + "type": "string", + "nullable": true + }, + "kind": { + "$ref": "#/components/schemas/aircraft-kind" + } + }, + "additionalProperties": false + }, + "airplane-collection-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/airplane-data-in-response" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-collection-document" + } + }, + "additionalProperties": false + }, + "airplane-data-in-patch-request": { + "required": [ + "id", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/airplane-resource-type" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/airplane-attributes-in-patch-request" + }, + "relationships": { + "$ref": "#/components/schemas/airplane-relationships-in-patch-request" + } + }, + "additionalProperties": false + }, + "airplane-data-in-post-request": { + "required": [ + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/airplane-resource-type" + }, + "attributes": { + "$ref": "#/components/schemas/airplane-attributes-in-post-request" + }, + "relationships": { + "$ref": "#/components/schemas/airplane-relationships-in-post-request" + } + }, + "additionalProperties": false + }, + "airplane-data-in-response": { + "required": [ + "id", + "links", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/airplane-resource-type" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/airplane-attributes-in-response" + }, + "relationships": { + "$ref": "#/components/schemas/airplane-relationships-in-response" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-object" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "airplane-patch-request-document": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/airplane-data-in-patch-request" + } + }, + "additionalProperties": false + }, + "airplane-post-request-document": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/airplane-data-in-post-request" + } + }, + "additionalProperties": false + }, + "airplane-primary-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/airplane-data-in-response" + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-document" + } + }, + "additionalProperties": false + }, + "airplane-relationships-in-patch-request": { + "type": "object", + "properties": { + "flights": { + "$ref": "#/components/schemas/to-many-flight-in-request" + } + }, + "additionalProperties": false + }, + "airplane-relationships-in-post-request": { + "type": "object", + "properties": { + "flights": { + "$ref": "#/components/schemas/to-many-flight-in-request" + } + }, + "additionalProperties": false + }, + "airplane-relationships-in-response": { + "type": "object", + "properties": { + "flights": { + "$ref": "#/components/schemas/to-many-flight-in-response" + } + }, + "additionalProperties": false + }, + "airplane-resource-type": { + "enum": [ + "airplanes" + ], + "type": "string" + }, + "cabin-area": { + "enum": [ + "FirstClass", + "BusinessClass", + "EconomyClass" + ], + "type": "string" + }, + "flight-attendant-attributes-in-patch-request": { + "type": "object", + "properties": { + "email-address": { + "type": "string", + "format": "email" + }, + "age": { + "maximum": 75, + "minimum": 18, + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "flight-attendant-attributes-in-post-request": { + "required": [ + "email-address", + "profile-image-url" + ], + "type": "object", + "properties": { + "email-address": { + "type": "string", + "format": "email" + }, + "age": { + "maximum": 75, + "minimum": 18, + "type": "integer", + "format": "int32" + }, + "profile-image-url": { + "type": "string", + "format": "uri" + } + }, + "additionalProperties": false + }, + "flight-attendant-attributes-in-response": { + "type": "object", + "properties": { + "email-address": { + "type": "string", + "format": "email" + }, + "age": { + "maximum": 75, + "minimum": 18, + "type": "integer", + "format": "int32" + }, + "profile-image-url": { + "type": "string", + "format": "uri" + }, + "distance-traveled-in-kilometers": { + "type": "integer", + "format": "int64" + } + }, + "additionalProperties": false + }, + "flight-attendant-collection-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/flight-attendant-data-in-response" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-collection-document" + } + }, + "additionalProperties": false + }, + "flight-attendant-data-in-patch-request": { + "required": [ + "id", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/flight-attendant-resource-type" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/flight-attendant-attributes-in-patch-request" + }, + "relationships": { + "$ref": "#/components/schemas/flight-attendant-relationships-in-patch-request" + } + }, + "additionalProperties": false + }, + "flight-attendant-data-in-post-request": { + "required": [ + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/flight-attendant-resource-type" + }, + "attributes": { + "$ref": "#/components/schemas/flight-attendant-attributes-in-post-request" + }, + "relationships": { + "$ref": "#/components/schemas/flight-attendant-relationships-in-post-request" + } + }, + "additionalProperties": false + }, + "flight-attendant-data-in-response": { + "required": [ + "id", + "links", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/flight-attendant-resource-type" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/flight-attendant-attributes-in-response" + }, + "relationships": { + "$ref": "#/components/schemas/flight-attendant-relationships-in-response" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-object" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "flight-attendant-identifier": { + "required": [ + "id", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/flight-attendant-resource-type" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false + }, + "flight-attendant-identifier-collection-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/flight-attendant-identifier" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-identifier-collection-document" + } + }, + "additionalProperties": false + }, + "flight-attendant-identifier-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/flight-attendant-identifier" + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-identifier-document" + } + }, + "additionalProperties": false + }, + "flight-attendant-patch-request-document": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/flight-attendant-data-in-patch-request" + } + }, + "additionalProperties": false + }, + "flight-attendant-post-request-document": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/flight-attendant-data-in-post-request" + } + }, + "additionalProperties": false + }, + "flight-attendant-primary-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/flight-attendant-data-in-response" + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-document" + } + }, + "additionalProperties": false + }, + "flight-attendant-relationships-in-patch-request": { + "type": "object", + "properties": { + "scheduled-for-flights": { + "$ref": "#/components/schemas/to-many-flight-in-request" + }, + "purser-on-flights": { + "$ref": "#/components/schemas/to-many-flight-in-request" + } + }, + "additionalProperties": false + }, + "flight-attendant-relationships-in-post-request": { + "type": "object", + "properties": { + "scheduled-for-flights": { + "$ref": "#/components/schemas/to-many-flight-in-request" + }, + "purser-on-flights": { + "$ref": "#/components/schemas/to-many-flight-in-request" + } + }, + "additionalProperties": false + }, + "flight-attendant-relationships-in-response": { + "type": "object", + "properties": { + "scheduled-for-flights": { + "$ref": "#/components/schemas/to-many-flight-in-response" + }, + "purser-on-flights": { + "$ref": "#/components/schemas/to-many-flight-in-response" + } + }, + "additionalProperties": false + }, + "flight-attendant-resource-type": { + "enum": [ + "flight-attendants" + ], + "type": "string" + }, + "flight-attendant-secondary-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/flight-attendant-data-in-response" + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-document" + } + }, + "additionalProperties": false + }, + "flight-attributes-in-patch-request": { + "type": "object", + "properties": { + "final-destination": { + "maxLength": 40, + "type": "string" + }, + "stop-over-destination": { + "maxLength": 2000, + "type": "string", + "nullable": true + }, + "operated-by": { + "$ref": "#/components/schemas/airline" + } + }, + "additionalProperties": false + }, + "flight-attributes-in-response": { + "type": "object", + "properties": { + "final-destination": { + "maxLength": 40, + "type": "string" + }, + "stop-over-destination": { + "maxLength": 2000, + "type": "string", + "nullable": true + }, + "operated-by": { + "$ref": "#/components/schemas/airline" + }, + "departs-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "arrives-at": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "services-on-board": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "flight-collection-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/flight-data-in-response" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-collection-document" + } + }, + "additionalProperties": false + }, + "flight-data-in-patch-request": { + "required": [ + "id", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/flight-resource-type" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/flight-attributes-in-patch-request" + }, + "relationships": { + "$ref": "#/components/schemas/flight-relationships-in-patch-request" + } + }, + "additionalProperties": false + }, + "flight-data-in-post-request": { + "required": [ + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/flight-resource-type" + }, + "relationships": { + "$ref": "#/components/schemas/flight-relationships-in-post-request" + } + }, + "additionalProperties": false + }, + "flight-data-in-response": { + "required": [ + "id", + "links", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/flight-resource-type" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/flight-attributes-in-response" + }, + "relationships": { + "$ref": "#/components/schemas/flight-relationships-in-response" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-object" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "flight-identifier": { + "required": [ + "id", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/flight-resource-type" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false + }, + "flight-identifier-collection-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/flight-identifier" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-identifier-collection-document" + } + }, + "additionalProperties": false + }, + "flight-patch-request-document": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/flight-data-in-patch-request" + } + }, + "additionalProperties": false + }, + "flight-post-request-document": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/flight-data-in-post-request" + } + }, + "additionalProperties": false + }, + "flight-primary-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/flight-data-in-response" + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-document" + } + }, + "additionalProperties": false + }, + "flight-relationships-in-patch-request": { + "type": "object", + "properties": { + "cabin-crew-members": { + "$ref": "#/components/schemas/to-many-flight-attendant-in-request" + }, + "purser": { + "$ref": "#/components/schemas/to-one-flight-attendant-in-request" + }, + "backup-purser": { + "$ref": "#/components/schemas/nullable-to-one-flight-attendant-in-request" + }, + "passengers": { + "$ref": "#/components/schemas/to-many-passenger-in-request" + } + }, + "additionalProperties": false + }, + "flight-relationships-in-post-request": { + "required": [ + "purser" + ], + "type": "object", + "properties": { + "cabin-crew-members": { + "$ref": "#/components/schemas/to-many-flight-attendant-in-request" + }, + "purser": { + "$ref": "#/components/schemas/to-one-flight-attendant-in-request" + }, + "backup-purser": { + "$ref": "#/components/schemas/nullable-to-one-flight-attendant-in-request" + }, + "passengers": { + "$ref": "#/components/schemas/to-many-passenger-in-request" + } + }, + "additionalProperties": false + }, + "flight-relationships-in-response": { + "type": "object", + "properties": { + "cabin-crew-members": { + "$ref": "#/components/schemas/to-many-flight-attendant-in-response" + }, + "purser": { + "$ref": "#/components/schemas/to-one-flight-attendant-in-response" + }, + "backup-purser": { + "$ref": "#/components/schemas/nullable-to-one-flight-attendant-in-response" + }, + "passengers": { + "$ref": "#/components/schemas/to-many-passenger-in-response" + } + }, + "additionalProperties": false + }, + "flight-resource-type": { + "enum": [ + "flights" + ], + "type": "string" + }, + "jsonapi-object": { + "type": "object", + "properties": { + "version": { + "type": "string" + }, + "ext": { + "type": "array", + "items": { + "type": "string" + } + }, + "profile": { + "type": "array", + "items": { + "type": "string" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "links-in-relationship-object": { + "required": [ + "related", + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "related": { + "type": "string" + } + }, + "additionalProperties": false + }, + "links-in-resource-collection-document": { + "required": [ + "first", + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + }, + "first": { + "type": "string" + }, + "last": { + "type": "string" + }, + "prev": { + "type": "string" + }, + "next": { + "type": "string" + } + }, + "additionalProperties": false + }, + "links-in-resource-document": { + "required": [ + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + } + }, + "additionalProperties": false + }, + "links-in-resource-identifier-collection-document": { + "required": [ + "first", + "related", + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + }, + "related": { + "type": "string" + }, + "first": { + "type": "string" + }, + "last": { + "type": "string" + }, + "prev": { + "type": "string" + }, + "next": { + "type": "string" + } + }, + "additionalProperties": false + }, + "links-in-resource-identifier-document": { + "required": [ + "related", + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + }, + "describedby": { + "type": "string" + }, + "related": { + "type": "string" + } + }, + "additionalProperties": false + }, + "links-in-resource-object": { + "required": [ + "self" + ], + "type": "object", + "properties": { + "self": { + "type": "string" + } + }, + "additionalProperties": false + }, + "null-value": { + "not": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "object" + }, + { + "type": "array" + } + ], + "items": { } + }, + "nullable": true + }, + "nullable-flight-attendant-identifier-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/flight-attendant-identifier" + }, + { + "$ref": "#/components/schemas/null-value" + } + ] + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-identifier-document" + } + }, + "additionalProperties": false + }, + "nullable-flight-attendant-secondary-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/flight-attendant-data-in-response" + }, + { + "$ref": "#/components/schemas/null-value" + } + ] + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-document" + } + }, + "additionalProperties": false + }, + "nullable-to-one-flight-attendant-in-request": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/flight-attendant-identifier" + }, + { + "$ref": "#/components/schemas/null-value" + } + ] + } + }, + "additionalProperties": false + }, + "nullable-to-one-flight-attendant-in-response": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "data": { + "oneOf": [ + { + "$ref": "#/components/schemas/flight-attendant-identifier" + }, + { + "$ref": "#/components/schemas/null-value" + } + ] + }, + "links": { + "$ref": "#/components/schemas/links-in-relationship-object" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "passenger-attributes-in-response": { + "type": "object", + "properties": { + "full-name": { + "type": "string", + "nullable": true + }, + "cabin-area": { + "$ref": "#/components/schemas/cabin-area" + } + }, + "additionalProperties": false + }, + "passenger-collection-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/passenger-data-in-response" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-collection-document" + } + }, + "additionalProperties": false + }, + "passenger-data-in-response": { + "required": [ + "id", + "links", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/passenger-resource-type" + }, + "id": { + "type": "string" + }, + "attributes": { + "$ref": "#/components/schemas/passenger-attributes-in-response" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-object" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "passenger-identifier": { + "required": [ + "id", + "type" + ], + "type": "object", + "properties": { + "type": { + "$ref": "#/components/schemas/passenger-resource-type" + }, + "id": { + "type": "string" + } + }, + "additionalProperties": false + }, + "passenger-identifier-collection-response-document": { + "required": [ + "data", + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/passenger-identifier" + } + }, + "meta": { + "type": "object", + "additionalProperties": { } + }, + "jsonapi": { + "$ref": "#/components/schemas/jsonapi-object" + }, + "links": { + "$ref": "#/components/schemas/links-in-resource-identifier-collection-document" + } + }, + "additionalProperties": false + }, + "passenger-resource-type": { + "enum": [ + "passengers" + ], + "type": "string" + }, + "to-many-flight-attendant-in-request": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/flight-attendant-identifier" + } + } + }, + "additionalProperties": false + }, + "to-many-flight-attendant-in-response": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/flight-attendant-identifier" + } + }, + "links": { + "$ref": "#/components/schemas/links-in-relationship-object" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "to-many-flight-in-request": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/flight-identifier" + } + } + }, + "additionalProperties": false + }, + "to-many-flight-in-response": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/flight-identifier" + } + }, + "links": { + "$ref": "#/components/schemas/links-in-relationship-object" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "to-many-passenger-in-request": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/passenger-identifier" + } + } + }, + "additionalProperties": false + }, + "to-many-passenger-in-response": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/passenger-identifier" + } + }, + "links": { + "$ref": "#/components/schemas/links-in-relationship-object" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + }, + "to-one-flight-attendant-in-request": { + "required": [ + "data" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/flight-attendant-identifier" + } + }, + "additionalProperties": false + }, + "to-one-flight-attendant-in-response": { + "required": [ + "links" + ], + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/flight-attendant-identifier" + }, + "links": { + "$ref": "#/components/schemas/links-in-relationship-object" + }, + "meta": { + "type": "object", + "additionalProperties": { } + } + }, + "additionalProperties": false + } + } + } +} \ No newline at end of file diff --git a/test/OpenApiTests/NamingConventions/CamelCase/swagger.json b/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json similarity index 98% rename from test/OpenApiTests/NamingConventions/CamelCase/swagger.json rename to test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json index 31c65b23e0..2eaac9303c 100644 --- a/test/OpenApiTests/NamingConventions/CamelCase/swagger.json +++ b/test/OpenApiClientTests/NamingConventions/CamelCase/swagger.g.json @@ -734,7 +734,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -880,7 +880,7 @@ "type": "array" } ], - "items": {} + "items": { } }, "nullable": true }, @@ -903,7 +903,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapiObject" @@ -933,7 +933,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapiObject" @@ -984,7 +984,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -1017,7 +1017,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapiObject" @@ -1050,7 +1050,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -1086,7 +1086,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapiObject" @@ -1109,7 +1109,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapiObject" @@ -1138,7 +1138,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapiObject" @@ -1203,7 +1203,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapiObject" @@ -1279,7 +1279,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -1320,7 +1320,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapiObject" @@ -1425,7 +1425,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -1456,7 +1456,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false diff --git a/test/OpenApiTests/NamingConventions/KebabCase/swagger.json b/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json similarity index 98% rename from test/OpenApiTests/NamingConventions/KebabCase/swagger.json rename to test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json index e1de5e7b69..1013e900a8 100644 --- a/test/OpenApiTests/NamingConventions/KebabCase/swagger.json +++ b/test/OpenApiClientTests/NamingConventions/KebabCase/swagger.g.json @@ -734,7 +734,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -880,7 +880,7 @@ "type": "array" } ], - "items": {} + "items": { } }, "nullable": true }, @@ -903,7 +903,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -933,7 +933,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -984,7 +984,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -1017,7 +1017,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -1050,7 +1050,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -1086,7 +1086,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -1109,7 +1109,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -1138,7 +1138,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -1203,7 +1203,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -1279,7 +1279,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -1320,7 +1320,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/jsonapi-object" @@ -1425,7 +1425,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -1456,7 +1456,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false diff --git a/test/OpenApiTests/NamingConventions/PascalCase/swagger.json b/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json similarity index 96% rename from test/OpenApiTests/NamingConventions/PascalCase/swagger.json rename to test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json index 91eab90f85..3906897de4 100644 --- a/test/OpenApiTests/NamingConventions/PascalCase/swagger.json +++ b/test/OpenApiClientTests/NamingConventions/PascalCase/swagger.g.json @@ -734,22 +734,22 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false }, "LinksInRelationshipObject": { "required": [ - "Related", - "Self" + "related", + "self" ], "type": "object", "properties": { - "Self": { + "self": { "type": "string" }, - "Related": { + "related": { "type": "string" } }, @@ -757,27 +757,27 @@ }, "LinksInResourceCollectionDocument": { "required": [ - "First", - "Self" + "first", + "self" ], "type": "object", "properties": { - "Self": { + "self": { "type": "string" }, - "Describedby": { + "describedby": { "type": "string" }, - "First": { + "first": { "type": "string" }, - "Last": { + "last": { "type": "string" }, - "Prev": { + "prev": { "type": "string" }, - "Next": { + "next": { "type": "string" } }, @@ -785,14 +785,14 @@ }, "LinksInResourceDocument": { "required": [ - "Self" + "self" ], "type": "object", "properties": { - "Self": { + "self": { "type": "string" }, - "Describedby": { + "describedby": { "type": "string" } }, @@ -800,31 +800,31 @@ }, "LinksInResourceIdentifierCollectionDocument": { "required": [ - "First", - "Related", - "Self" + "first", + "related", + "self" ], "type": "object", "properties": { - "Self": { + "self": { "type": "string" }, - "Describedby": { + "describedby": { "type": "string" }, - "Related": { + "related": { "type": "string" }, - "First": { + "first": { "type": "string" }, - "Last": { + "last": { "type": "string" }, - "Prev": { + "prev": { "type": "string" }, - "Next": { + "next": { "type": "string" } }, @@ -832,18 +832,18 @@ }, "LinksInResourceIdentifierDocument": { "required": [ - "Related", - "Self" + "related", + "self" ], "type": "object", "properties": { - "Self": { + "self": { "type": "string" }, - "Describedby": { + "describedby": { "type": "string" }, - "Related": { + "related": { "type": "string" } }, @@ -851,11 +851,11 @@ }, "LinksInResourceObject": { "required": [ - "Self" + "self" ], "type": "object", "properties": { - "Self": { + "self": { "type": "string" } }, @@ -880,7 +880,7 @@ "type": "array" } ], - "items": {} + "items": { } }, "nullable": true }, @@ -903,7 +903,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/JsonapiObject" @@ -933,7 +933,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/JsonapiObject" @@ -984,7 +984,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -1017,7 +1017,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/JsonapiObject" @@ -1050,7 +1050,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -1086,7 +1086,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/JsonapiObject" @@ -1109,7 +1109,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/JsonapiObject" @@ -1138,7 +1138,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/JsonapiObject" @@ -1203,7 +1203,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/JsonapiObject" @@ -1279,7 +1279,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -1320,7 +1320,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } }, "jsonapi": { "$ref": "#/components/schemas/JsonapiObject" @@ -1425,7 +1425,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false @@ -1456,7 +1456,7 @@ }, "meta": { "type": "object", - "additionalProperties": {} + "additionalProperties": { } } }, "additionalProperties": false diff --git a/test/OpenApiClientTests/OpenApiClientTests.csproj b/test/OpenApiClientTests/OpenApiClientTests.csproj index 62a7368e6e..0263d7a234 100644 --- a/test/OpenApiClientTests/OpenApiClientTests.csproj +++ b/test/OpenApiClientTests/OpenApiClientTests.csproj @@ -34,28 +34,28 @@ - + OpenApiClientTests.LegacyClient.GeneratedCode OpenApiClient OpenApiClient.cs NSwagCSharp /UseBaseUrl:false /GenerateClientInterfaces:true /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions - + OpenApiClientTests.NamingConventions.KebabCase.GeneratedCode KebabCaseClient KebabCaseClient.cs NSwagCSharp /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions - + OpenApiClientTests.NamingConventions.CamelCase.GeneratedCode CamelCaseClient CamelCaseClient.cs NSwagCSharp /UseBaseUrl:false /ClientClassAccessModifier:internal /GenerateExceptionClasses:false /AdditionalNamespaceUsages:JsonApiDotNetCore.OpenApi.Client.Exceptions - + OpenApiClientTests.NamingConventions.PascalCase.GeneratedCode PascalCaseClient PascalCaseClient.cs diff --git a/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs b/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs index 3f57a6b837..daf9f39cb2 100644 --- a/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs +++ b/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs @@ -13,19 +13,19 @@ public LegacyOpenApiIntegrationTests() UseController(); UseController(); UseController(); + GeneratedDocumentNamespace = "OpenApiClientTests.LegacyClient"; } [Fact] public async Task Retrieved_document_matches_expected_document() { - // Arrange - const string embeddedResourceName = $"{nameof(OpenApiTests)}.{nameof(LegacyOpenApiIntegration)}.swagger.json"; - string expectedDocument = await LoadEmbeddedResourceAsync(embeddedResourceName); - // Act JsonElement jsonElement = await LazyDocument.Value; // Assert + const string embeddedResourceName = $"{nameof(OpenApiTests)}.{nameof(LegacyOpenApiIntegration)}.swagger.json"; + string expectedDocument = await LoadEmbeddedResourceAsync(embeddedResourceName); + string jsonText = jsonElement.ToString(); jsonText.Should().BeJson(expectedDocument); } diff --git a/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json b/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json index 805df97adb..3fb80fb856 100644 --- a/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json +++ b/test/OpenApiTests/LegacyOpenApiIntegration/swagger.json @@ -3360,4 +3360,4 @@ } } } -} +} \ No newline at end of file diff --git a/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs index 651d1f6e8f..045d4f6e8b 100644 --- a/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs +++ b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs @@ -4,19 +4,23 @@ namespace OpenApiTests.NamingConventions.CamelCase; -public sealed class CamelCaseTests : OpenApiTestSuite, NamingConventionsDbContext> +public sealed class PascalCaseTests + : IClassFixture, NamingConventionsDbContext>> { - public CamelCaseTests(OpenApiTestContext, NamingConventionsDbContext> testContext) - : base(testContext) + private readonly OpenApiTestContext, NamingConventionsDbContext> _testContext; + + public PascalCaseTests(OpenApiTestContext, NamingConventionsDbContext> testContext) { - UseController(); + _testContext = testContext; + testContext.UseController(); + testContext.GeneratedDocumentNamespace = "OpenApiClientTests.NamingConventions.CamelCase"; } [Fact] public async Task Casing_convention_is_applied_to_GetCollection_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -118,7 +122,7 @@ public async Task Casing_convention_is_applied_to_GetCollection_endpoint() public async Task Casing_convention_is_applied_to_GetSingle_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -147,7 +151,7 @@ public async Task Casing_convention_is_applied_to_GetSingle_endpoint() public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -184,7 +188,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_sin public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./supermarkets/{id}/backupStoreManager.get").With(getElement => @@ -203,7 +207,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nul public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./supermarkets/{id}/cashiers.get").With(getElement => @@ -222,7 +226,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_res public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -251,7 +255,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/backupStoreManager.get").With(getElement => @@ -270,7 +274,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -299,7 +303,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ public async Task Casing_convention_is_applied_to_Post_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -353,7 +357,7 @@ public async Task Casing_convention_is_applied_to_Post_endpoint() public async Task Casing_convention_is_applied_to_PostRelationship_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.post").With(getElement => @@ -369,7 +373,7 @@ public async Task Casing_convention_is_applied_to_PostRelationship_endpoint() public async Task Casing_convention_is_applied_to_Patch_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -407,7 +411,7 @@ public async Task Casing_convention_is_applied_to_Patch_endpoint() public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/storeManager.patch").With(getElement => @@ -423,7 +427,7 @@ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_wit public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/backupStoreManager.patch").With(getElement => @@ -439,7 +443,7 @@ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_wit public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.patch").With(getElement => @@ -455,7 +459,7 @@ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_wit public async Task Casing_convention_is_applied_to_Delete_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./supermarkets/{id}.delete").With(getElement => @@ -471,7 +475,7 @@ public async Task Casing_convention_is_applied_to_Delete_endpoint() public async Task Casing_convention_is_applied_to_DeleteRelationship_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.delete").With(getElement => diff --git a/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs b/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs index 9f2ce69d87..0dfa7421fe 100644 --- a/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs +++ b/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs @@ -4,19 +4,23 @@ namespace OpenApiTests.NamingConventions.KebabCase; -public sealed class KebabCaseTests : OpenApiTestSuite, NamingConventionsDbContext> +public sealed class PascalCaseTests + : IClassFixture, NamingConventionsDbContext>> { - public KebabCaseTests(OpenApiTestContext, NamingConventionsDbContext> testContext) - : base(testContext) + private readonly OpenApiTestContext, NamingConventionsDbContext> _testContext; + + public PascalCaseTests(OpenApiTestContext, NamingConventionsDbContext> testContext) { - UseController(); + _testContext = testContext; + testContext.UseController(); + testContext.GeneratedDocumentNamespace = "OpenApiClientTests.NamingConventions.KebabCase"; } [Fact] public async Task Casing_convention_is_applied_to_GetCollection_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -118,7 +122,7 @@ public async Task Casing_convention_is_applied_to_GetCollection_endpoint() public async Task Casing_convention_is_applied_to_GetSingle_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -147,7 +151,7 @@ public async Task Casing_convention_is_applied_to_GetSingle_endpoint() public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -184,7 +188,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_sin public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./supermarkets/{id}/backup-store-manager.get").With(getElement => @@ -203,7 +207,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nul public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./supermarkets/{id}/cashiers.get").With(getElement => @@ -222,7 +226,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_res public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -251,7 +255,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/backup-store-manager.get").With(getElement => @@ -270,7 +274,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -299,7 +303,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ public async Task Casing_convention_is_applied_to_Post_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -353,7 +357,7 @@ public async Task Casing_convention_is_applied_to_Post_endpoint() public async Task Casing_convention_is_applied_to_PostRelationship_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.post").With(getElement => @@ -369,7 +373,7 @@ public async Task Casing_convention_is_applied_to_PostRelationship_endpoint() public async Task Casing_convention_is_applied_to_Patch_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -407,7 +411,7 @@ public async Task Casing_convention_is_applied_to_Patch_endpoint() public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/store-manager.patch").With(getElement => @@ -423,7 +427,7 @@ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_wit public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/backup-store-manager.patch").With(getElement => @@ -439,7 +443,7 @@ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_wit public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.patch").With(getElement => @@ -455,7 +459,7 @@ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_wit public async Task Casing_convention_is_applied_to_Delete_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./supermarkets/{id}.delete").With(getElement => @@ -471,7 +475,7 @@ public async Task Casing_convention_is_applied_to_Delete_endpoint() public async Task Casing_convention_is_applied_to_DeleteRelationship_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.delete").With(getElement => diff --git a/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseTests.cs b/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseTests.cs index d37e9fa3bb..5d485f0aad 100644 --- a/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseTests.cs +++ b/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseTests.cs @@ -4,19 +4,23 @@ namespace OpenApiTests.NamingConventions.PascalCase; -public sealed class PascalCaseTests : OpenApiTestSuite, NamingConventionsDbContext> +public sealed class PascalCaseTests + : IClassFixture, NamingConventionsDbContext>> { + private readonly OpenApiTestContext, NamingConventionsDbContext> _testContext; + public PascalCaseTests(OpenApiTestContext, NamingConventionsDbContext> testContext) - : base(testContext) { - UseController(); + _testContext = testContext; + testContext.UseController(); + testContext.GeneratedDocumentNamespace = "OpenApiClientTests.NamingConventions.PascalCase"; } [Fact] public async Task Casing_convention_is_applied_to_GetCollection_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -118,7 +122,7 @@ public async Task Casing_convention_is_applied_to_GetCollection_endpoint() public async Task Casing_convention_is_applied_to_GetSingle_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -147,7 +151,7 @@ public async Task Casing_convention_is_applied_to_GetSingle_endpoint() public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -184,7 +188,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_sin public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./Supermarkets/{id}/BackupStoreManager.get").With(getElement => @@ -203,7 +207,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nul public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./Supermarkets/{id}/Cashiers.get").With(getElement => @@ -222,7 +226,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_res public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -251,7 +255,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./Supermarkets/{id}/relationships/BackupStoreManager.get").With(getElement => @@ -270,7 +274,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -299,7 +303,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ public async Task Casing_convention_is_applied_to_Post_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -353,7 +357,7 @@ public async Task Casing_convention_is_applied_to_Post_endpoint() public async Task Casing_convention_is_applied_to_PostRelationship_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.post").With(getElement => @@ -369,7 +373,7 @@ public async Task Casing_convention_is_applied_to_PostRelationship_endpoint() public async Task Casing_convention_is_applied_to_Patch_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert string? documentSchemaRefId = null; @@ -407,7 +411,7 @@ public async Task Casing_convention_is_applied_to_Patch_endpoint() public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./Supermarkets/{id}/relationships/StoreManager.patch").With(getElement => @@ -423,7 +427,7 @@ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_wit public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./Supermarkets/{id}/relationships/BackupStoreManager.patch").With(getElement => @@ -439,7 +443,7 @@ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_wit public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.patch").With(getElement => @@ -455,7 +459,7 @@ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_wit public async Task Casing_convention_is_applied_to_Delete_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./Supermarkets/{id}.delete").With(getElement => @@ -471,7 +475,7 @@ public async Task Casing_convention_is_applied_to_Delete_endpoint() public async Task Casing_convention_is_applied_to_DeleteRelationship_endpoint() { // Act - JsonElement document = await GetDocumentAsync(); + JsonElement document = await _testContext.LazyDocument.Value; // Assert document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.delete").With(getElement => diff --git a/test/OpenApiTests/OpenApiTestContext.cs b/test/OpenApiTests/OpenApiTestContext.cs index e3d262770e..466d422869 100644 --- a/test/OpenApiTests/OpenApiTestContext.cs +++ b/test/OpenApiTests/OpenApiTestContext.cs @@ -10,7 +10,10 @@ public class OpenApiTestContext : IntegrationTestContext> LazyDocument; + internal string? GeneratedDocumentNamespace; public OpenApiTestContext() { @@ -21,12 +24,15 @@ private async Task GetDocumentAsync() { string content = await GetAsync("swagger/v1/swagger.json"); - JsonDocument parsedContent = JsonDocument.Parse(content); + JsonDocument document = JsonDocument.Parse(content); - using (parsedContent) + using (document) { - JsonElement clonedRoot = parsedContent.RootElement.Clone(); - return clonedRoot; + JsonElement clonedDocument = document.RootElement.Clone(); + + await WriteDocumentToFileAsync(clonedDocument); + + return clonedDocument; } } @@ -39,4 +45,36 @@ private async Task GetAsync(string requestUrl) return await responseMessage.Content.ReadAsStringAsync(); } + + public override void UseController() + { + if (!LazyDocument.IsValueCreated) + { + base.UseController(); + } + } + + private async Task WriteDocumentToFileAsync(JsonElement document) + { + string pathToTestSuiteDirectory = GetTestSuitePath(); + string pathToDocument = Path.Join(pathToTestSuiteDirectory, GeneratedDocumentName); + string json = document.ToString(); + await File.WriteAllTextAsync(pathToDocument, json); + } + + private string GetTestSuitePath() + { + string pathToSolutionTestDirectory = Path.Combine(Environment.CurrentDirectory, "../../../../"); + pathToSolutionTestDirectory = Path.GetFullPath(pathToSolutionTestDirectory); + + if (GeneratedDocumentNamespace == null) + { + throw new Exception( + $"Failed to write {GeneratedDocumentName} to disk. Ensure '{nameof(OpenApiTestContext)}.{nameof(GeneratedDocumentNamespace)}' is set."); + } + + string pathToCurrentNamespaceRelativeToTestDirectory = Path.Combine(GeneratedDocumentNamespace.Split('.')); + + return Path.Join(pathToSolutionTestDirectory, pathToCurrentNamespaceRelativeToTestDirectory); + } } diff --git a/test/OpenApiTests/OpenApiTestSuite.cs b/test/OpenApiTests/OpenApiTestSuite.cs deleted file mode 100644 index eb56572ca2..0000000000 --- a/test/OpenApiTests/OpenApiTestSuite.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Text.Json; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using Xunit; - -namespace OpenApiTests; - -public abstract class OpenApiTestSuite : IClassFixture> - where TStartup : class - where TDbContext : DbContext -{ - private readonly OpenApiTestContext _testContext; - private readonly bool _isFirstTestRunInTestSuite; - - protected OpenApiTestSuite(OpenApiTestContext testContext) - { - _testContext = testContext; - _isFirstTestRunInTestSuite = !testContext.LazyDocument.IsValueCreated; - } - - protected void UseController() - where TController : ControllerBase - { - if (_isFirstTestRunInTestSuite) - { - _testContext.UseController(); - } - } - - protected async Task GetDocumentAsync() - { - JsonElement document = await _testContext.LazyDocument.Value; - - if (_isFirstTestRunInTestSuite) - { - await WriteSwaggerDocumentToFileAsync(document); - } - - return document; - } - - private async Task WriteSwaggerDocumentToFileAsync(JsonElement document) - { - string pathToTestSuiteDirectory = GetTestSuitePath(); - string pathToDocument = Path.Join(pathToTestSuiteDirectory, "swagger.json"); - string json = document.ToString(); - await File.WriteAllTextAsync(pathToDocument, json); - } - - private static string GetTestSuitePath() - { - string pathToSolutionTestDirectory = Path.Combine(Environment.CurrentDirectory, "../../../../"); - pathToSolutionTestDirectory = Path.GetFullPath(pathToSolutionTestDirectory); - - string pathToCurrentNamespaceRelativeToTestDirectory = Path.Combine(typeof(TStartup).Namespace!.Split('.')); - - return Path.Join(pathToSolutionTestDirectory, pathToCurrentNamespaceRelativeToTestDirectory); - } -} diff --git a/test/TestBuildingBlocks/IntegrationTestContext.cs b/test/TestBuildingBlocks/IntegrationTestContext.cs index f25eb29070..74eeac0c98 100644 --- a/test/TestBuildingBlocks/IntegrationTestContext.cs +++ b/test/TestBuildingBlocks/IntegrationTestContext.cs @@ -50,7 +50,7 @@ public IntegrationTestContext() _lazyFactory = new Lazy>(CreateFactory); } - public void UseController() + public virtual void UseController() where TController : ControllerBase { _testControllerProvider.AddController(typeof(TController)); From e835b3300352f14e4d25258bcb5620693f8a0143 Mon Sep 17 00:00:00 2001 From: maurei Date: Fri, 17 Dec 2021 15:08:28 +0100 Subject: [PATCH 12/15] Process feedback --- .../ApiException.cs | 15 +- .../StringExtensions.cs | 4 +- .../KebabCase/GeneratedTypesTests.cs | 1 - .../OpenApiClientTests.csproj | 10 +- test/OpenApiTests/JsonElementExtensions.cs | 16 +- .../LegacyOpenApiIntegrationTests.cs | 23 ++- .../CamelCase/CamelCaseTests.cs | 187 +++++++++++------ .../KebabCase/KebabCaseTests.cs | 190 ++++++++++++------ .../PascalCase/PascalCaseTests.cs | 190 ++++++++++++------ test/OpenApiTests/OpenApiTestContext.cs | 74 +++---- test/OpenApiTests/OpenApiTests.csproj | 13 +- .../IntegrationTestContext.cs | 2 +- 12 files changed, 448 insertions(+), 277 deletions(-) diff --git a/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs b/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs index c33851ebce..261521b579 100644 --- a/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs +++ b/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs @@ -7,7 +7,7 @@ namespace JsonApiDotNetCore.OpenApi.Client.Exceptions; [UsedImplicitly(ImplicitUseTargetFlags.Members)] -internal class ApiException : Exception +public sealed class ApiException : Exception { public int StatusCode { get; } @@ -28,16 +28,3 @@ public override string ToString() return $"HTTP Response: \n\n{Response}\n\n{base.ToString()}"; } } - -[UsedImplicitly(ImplicitUseTargetFlags.Members)] -internal sealed class ApiException : ApiException -{ - public TResult Result { get; } - - public ApiException(string message, int statusCode, string? response, IReadOnlyDictionary> headers, TResult result, - Exception innerException) - : base(message, statusCode, response, headers, innerException) - { - Result = result; - } -} diff --git a/src/JsonApiDotNetCore.OpenApi/StringExtensions.cs b/src/JsonApiDotNetCore.OpenApi/StringExtensions.cs index df1e48099e..eff26f712c 100644 --- a/src/JsonApiDotNetCore.OpenApi/StringExtensions.cs +++ b/src/JsonApiDotNetCore.OpenApi/StringExtensions.cs @@ -4,10 +4,10 @@ namespace JsonApiDotNetCore.OpenApi; internal static class StringExtensions { - private static readonly Regex PatternForPascalCaseConversion = new("(?:^|-|_| +)(.)", RegexOptions.Compiled); + private static readonly Regex Regex = new("(?:^|-|_| +)(.)", RegexOptions.Compiled); public static string ToPascalCase(this string source) { - return PatternForPascalCaseConversion.Replace(source, match => match.Groups[1].Value.ToUpper()); + return Regex.Replace(source, match => match.Groups[1].Value.ToUpper()); } } diff --git a/test/OpenApiClientTests/NamingConventions/KebabCase/GeneratedTypesTests.cs b/test/OpenApiClientTests/NamingConventions/KebabCase/GeneratedTypesTests.cs index 15b3eefcae..f4884561fd 100644 --- a/test/OpenApiClientTests/NamingConventions/KebabCase/GeneratedTypesTests.cs +++ b/test/OpenApiClientTests/NamingConventions/KebabCase/GeneratedTypesTests.cs @@ -49,7 +49,6 @@ public void Generated_code_is_named_as_expected() _ = nameof(ToManyStaffMemberInResponse); _ = nameof(LinksInRelationshipObject); _ = nameof(StaffMemberIdentifier); - _ = nameof(StaffMemberResourceType); _ = nameof(StaffMemberResourceType.StaffMembers); _ = nameof(SupermarketPrimaryResponseDocument); _ = nameof(LinksInResourceDocument); diff --git a/test/OpenApiClientTests/OpenApiClientTests.csproj b/test/OpenApiClientTests/OpenApiClientTests.csproj index 0263d7a234..3f54c161b8 100644 --- a/test/OpenApiClientTests/OpenApiClientTests.csproj +++ b/test/OpenApiClientTests/OpenApiClientTests.csproj @@ -3,17 +3,17 @@ $(TargetFrameworkName) - - - - - PreserveNewest + + + + + diff --git a/test/OpenApiTests/JsonElementExtensions.cs b/test/OpenApiTests/JsonElementExtensions.cs index 0fe9a46858..d8dc7d4e20 100644 --- a/test/OpenApiTests/JsonElementExtensions.cs +++ b/test/OpenApiTests/JsonElementExtensions.cs @@ -25,26 +25,26 @@ public static void ShouldBeString(this JsonElement source, string value) source.GetString().Should().Be(value); } - public static ReferenceSchemaIdContainer ShouldBeReferenceSchemaId(this JsonElement source, string value) + public static SchemaReferenceIdContainer ShouldBeSchemaReferenceId(this JsonElement source, string value) { source.ValueKind.Should().Be(JsonValueKind.String); string? jsonElementValue = source.GetString(); jsonElementValue.ShouldNotBeNull(); - string referenceSchemaId = jsonElementValue.Split('/').Last(); - referenceSchemaId.Should().Be(value); + string schemaReferenceId = jsonElementValue.Split('/').Last(); + schemaReferenceId.Should().Be(value); - return new ReferenceSchemaIdContainer(value); + return new SchemaReferenceIdContainer(value); } - public sealed class ReferenceSchemaIdContainer + public sealed class SchemaReferenceIdContainer { - public string ReferenceSchemaId { get; } + public string SchemaReferenceId { get; } - public ReferenceSchemaIdContainer(string referenceSchemaId) + public SchemaReferenceIdContainer(string schemaReferenceId) { - ReferenceSchemaId = referenceSchemaId; + SchemaReferenceId = schemaReferenceId; } } diff --git a/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs b/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs index daf9f39cb2..a6da96f37b 100644 --- a/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs +++ b/test/OpenApiTests/LegacyOpenApiIntegration/LegacyOpenApiIntegrationTests.cs @@ -13,31 +13,32 @@ public LegacyOpenApiIntegrationTests() UseController(); UseController(); UseController(); - GeneratedDocumentNamespace = "OpenApiClientTests.LegacyClient"; + + SwaggerDocumentOutputPath = "test/OpenApiClientTests/LegacyClient"; } [Fact] - public async Task Retrieved_document_matches_expected_document() + public async Task Retrieved_swagger_document_matches_expected_document() { // Act - JsonElement jsonElement = await LazyDocument.Value; + JsonElement jsonElement = await GetSwaggerDocumentAsync(); // Assert - const string embeddedResourceName = $"{nameof(OpenApiTests)}.{nameof(LegacyOpenApiIntegration)}.swagger.json"; - string expectedDocument = await LoadEmbeddedResourceAsync(embeddedResourceName); - - string jsonText = jsonElement.ToString(); - jsonText.Should().BeJson(expectedDocument); + string expectedJsonText = await GetExpectedSwaggerDocumentAsync(); + string actualJsonText = jsonElement.ToString(); + actualJsonText.Should().BeJson(expectedJsonText); } - private static async Task LoadEmbeddedResourceAsync(string name) + private static async Task GetExpectedSwaggerDocumentAsync() { + const string embeddedResourceName = $"{nameof(OpenApiTests)}.{nameof(LegacyOpenApiIntegration)}.swagger.json"; var assembly = Assembly.GetExecutingAssembly(); - await using Stream? stream = assembly.GetManifestResourceStream(name); + + await using Stream? stream = assembly.GetManifestResourceStream(embeddedResourceName); if (stream == null) { - throw new Exception($"Failed to load embedded resource '{name}'. Set Build Action to Embedded Resource in properties."); + throw new Exception($"Failed to load embedded resource '{embeddedResourceName}'. Set Build Action to Embedded Resource in properties."); } using var reader = new StreamReader(stream); diff --git a/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs index 045d4f6e8b..0f2a974b58 100644 --- a/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs +++ b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs @@ -12,15 +12,16 @@ public sealed class PascalCaseTests public PascalCaseTests(OpenApiTestContext, NamingConventionsDbContext> testContext) { _testContext = testContext; + testContext.UseController(); - testContext.GeneratedDocumentNamespace = "OpenApiClientTests.NamingConventions.CamelCase"; + testContext.SwaggerDocumentOutputPath = "test/OpenApiClientTests/NamingConventions/CamelCase"; } [Fact] public async Task Casing_convention_is_applied_to_GetCollection_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -33,38 +34,57 @@ public async Task Casing_convention_is_applied_to_GetCollection_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("supermarketCollectionResponseDocument").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("supermarketCollectionResponseDocument").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => { + string? linksInResourceCollectionDocumentSchemaRefId = null; string? resourceDataSchemaRefId = null; schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("linksInResourceCollectionDocument"); - propertiesElement.ShouldContainPath("jsonapi.$ref").ShouldBeReferenceSchemaId("jsonapiObject"); + propertiesElement.ShouldContainPath("jsonapi.$ref").ShouldBeSchemaReferenceId("jsonapiObject"); + + linksInResourceCollectionDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref") + .ShouldBeSchemaReferenceId("linksInResourceCollectionDocument").SchemaReferenceId; + + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.items.$ref").ShouldBeSchemaReferenceId("supermarketDataInResponse") + .SchemaReferenceId; + }); - resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.items.$ref").ShouldBeReferenceSchemaId("supermarketDataInResponse") - .ReferenceSchemaId; + schemasElement.ShouldContainPath($"{linksInResourceCollectionDocumentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("self"); + propertiesElement.Should().ContainProperty("describedby"); + propertiesElement.Should().ContainProperty("first"); + propertiesElement.Should().ContainProperty("last"); + propertiesElement.Should().ContainProperty("prev"); + propertiesElement.Should().ContainProperty("next"); }); + string? linksInResourceObject = null; string? resourceAttributesInResponseSchemaRefId = null; string? resourceRelationshipInResponseSchemaRefId = null; string? primaryResourceTypeSchemaRefId = null; schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => { - primaryResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("supermarketResourceType") - .ReferenceSchemaId; + linksInResourceObject = propertiesElement.ShouldContainPath("links.$ref").ShouldBeSchemaReferenceId("linksInResourceObject").SchemaReferenceId; + + primaryResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeSchemaReferenceId("supermarketResourceType") + .SchemaReferenceId; resourceAttributesInResponseSchemaRefId = propertiesElement.ShouldContainPath("attributes.$ref") - .ShouldBeReferenceSchemaId("supermarketAttributesInResponse").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("supermarketAttributesInResponse").SchemaReferenceId; resourceRelationshipInResponseSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref") - .ShouldBeReferenceSchemaId("supermarketRelationshipsInResponse").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("supermarketRelationshipsInResponse").SchemaReferenceId; + }); - propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("linksInResourceObject"); + schemasElement.ShouldContainPath($"{linksInResourceObject}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("self"); }); schemasElement.ShouldContainPath($"{primaryResourceTypeSchemaRefId}.enum[0]").With(enumValueElement => @@ -76,7 +96,7 @@ public async Task Casing_convention_is_applied_to_GetCollection_endpoint() { propertiesElement.Should().ContainProperty("nameOfCity"); propertiesElement.Should().ContainProperty("kind"); - propertiesElement.ShouldContainPath("kind.$ref").ShouldBeReferenceSchemaId("supermarketType"); + propertiesElement.ShouldContainPath("kind.$ref").ShouldBeSchemaReferenceId("supermarketType"); }); string? nullableToOneResourceResponseDataSchemaRefId = null; @@ -85,36 +105,44 @@ public async Task Casing_convention_is_applied_to_GetCollection_endpoint() { propertiesElement.Should().ContainProperty("storeManager"); - propertiesElement.ShouldContainPath("storeManager.$ref").ShouldBeReferenceSchemaId("toOneStaffMemberInResponse"); + propertiesElement.ShouldContainPath("storeManager.$ref").ShouldBeSchemaReferenceId("toOneStaffMemberInResponse"); nullableToOneResourceResponseDataSchemaRefId = propertiesElement.ShouldContainPath("backupStoreManager.$ref") - .ShouldBeReferenceSchemaId("nullableToOneStaffMemberInResponse").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("nullableToOneStaffMemberInResponse").SchemaReferenceId; propertiesElement.Should().ContainProperty("cashiers"); - propertiesElement.ShouldContainPath("cashiers.$ref").ShouldBeReferenceSchemaId("toManyStaffMemberInResponse"); + propertiesElement.ShouldContainPath("cashiers.$ref").ShouldBeSchemaReferenceId("toManyStaffMemberInResponse"); }); + string? linksInRelationshipObjectSchemaRefId = null; string? relatedResourceIdentifierSchemaRefId = null; schemasElement.ShouldContainPath($"{nullableToOneResourceResponseDataSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("linksInRelationshipObject"); + linksInRelationshipObjectSchemaRefId = propertiesElement.ShouldContainPath("links.$ref").ShouldBeSchemaReferenceId("linksInRelationshipObject") + .SchemaReferenceId; relatedResourceIdentifierSchemaRefId = propertiesElement.ShouldContainPath("data.oneOf[0].$ref") - .ShouldBeReferenceSchemaId("staffMemberIdentifier").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("staffMemberIdentifier").SchemaReferenceId; + + propertiesElement.ShouldContainPath("data.oneOf[1].$ref").ShouldBeSchemaReferenceId("nullValue"); + }); - propertiesElement.ShouldContainPath("data.oneOf[1].$ref").ShouldBeReferenceSchemaId("nullValue"); + schemasElement.ShouldContainPath($"{linksInRelationshipObjectSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("self"); + propertiesElement.Should().ContainProperty("related"); }); string? relatedResourceTypeSchemaRefId = null; schemasElement.ShouldContainPath($"{relatedResourceIdentifierSchemaRefId}.properties").With(propertiesElement => { - relatedResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("staffMemberResourceType") - .ReferenceSchemaId; + relatedResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeSchemaReferenceId("staffMemberResourceType") + .SchemaReferenceId; }); - schemasElement.ShouldContainPath($"{relatedResourceTypeSchemaRefId}.enum[0]").ShouldBeReferenceSchemaId("staffMembers"); + schemasElement.ShouldContainPath($"{relatedResourceTypeSchemaRefId}.enum[0]").ShouldBeSchemaReferenceId("staffMembers"); }); } @@ -122,7 +150,7 @@ public async Task Casing_convention_is_applied_to_GetCollection_endpoint() public async Task Casing_convention_is_applied_to_GetSingle_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -135,14 +163,23 @@ public async Task Casing_convention_is_applied_to_GetSingle_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("supermarketPrimaryResponseDocument").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("supermarketPrimaryResponseDocument").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => { + string? linksInResourceDocumentSchemaRefId = null; + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("linksInResourceDocument"); + linksInResourceDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref").ShouldBeSchemaReferenceId("linksInResourceDocument") + .SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{linksInResourceDocumentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("self"); + propertiesElement.Should().ContainProperty("describedby"); }); }); } @@ -151,7 +188,7 @@ public async Task Casing_convention_is_applied_to_GetSingle_endpoint() public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -164,7 +201,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_sin }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("staffMemberSecondaryResponseDocument").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("staffMemberSecondaryResponseDocument").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => @@ -173,13 +210,13 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_sin schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("staffMemberDataInResponse") - .ReferenceSchemaId; + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeSchemaReferenceId("staffMemberDataInResponse") + .SchemaReferenceId; }); schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("staffMemberAttributesInResponse"); + propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeSchemaReferenceId("staffMemberAttributesInResponse"); }); }); } @@ -188,7 +225,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_sin public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./supermarkets/{id}/backupStoreManager.get").With(getElement => @@ -199,7 +236,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nul }); getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("nullableStaffMemberSecondaryResponseDocument"); + .ShouldBeSchemaReferenceId("nullableStaffMemberSecondaryResponseDocument"); }); } @@ -207,7 +244,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nul public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./supermarkets/{id}/cashiers.get").With(getElement => @@ -218,7 +255,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_res }); getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("staffMemberCollectionResponseDocument"); + .ShouldBeSchemaReferenceId("staffMemberCollectionResponseDocument"); }); } @@ -226,7 +263,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_res public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -239,14 +276,24 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("staffMemberIdentifierResponseDocument").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("staffMemberIdentifierResponseDocument").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => { + string? linksInResourceIdentifierDocumentSchemaRefId = null; + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("linksInResourceIdentifierDocument"); + linksInResourceIdentifierDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref") + .ShouldBeSchemaReferenceId("linksInResourceIdentifierDocument").SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{linksInResourceIdentifierDocumentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("self"); + propertiesElement.Should().ContainProperty("describedby"); + propertiesElement.Should().ContainProperty("related"); }); }); } @@ -255,7 +302,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/backupStoreManager.get").With(getElement => @@ -266,7 +313,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ }); getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("nullableStaffMemberIdentifierResponseDocument"); + .ShouldBeSchemaReferenceId("nullableStaffMemberIdentifierResponseDocument"); }); } @@ -274,7 +321,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -287,14 +334,28 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("staffMemberIdentifierCollectionResponseDocument").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("staffMemberIdentifierCollectionResponseDocument").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => { + string? linksInResourceIdentifierCollectionDocumentSchemaRefId = null; + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("linksInResourceIdentifierCollectionDocument"); + linksInResourceIdentifierCollectionDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref") + .ShouldBeSchemaReferenceId("linksInResourceIdentifierCollectionDocument").SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{linksInResourceIdentifierCollectionDocumentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("self"); + propertiesElement.Should().ContainProperty("describedby"); + propertiesElement.Should().ContainProperty("related"); + propertiesElement.Should().ContainProperty("first"); + propertiesElement.Should().ContainProperty("last"); + propertiesElement.Should().ContainProperty("prev"); + propertiesElement.Should().ContainProperty("next"); }); }); } @@ -303,7 +364,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ public async Task Casing_convention_is_applied_to_Post_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -316,7 +377,7 @@ public async Task Casing_convention_is_applied_to_Post_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("supermarketPostRequestDocument").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("supermarketPostRequestDocument").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => @@ -325,30 +386,30 @@ public async Task Casing_convention_is_applied_to_Post_endpoint() schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("supermarketDataInPostRequest") - .ReferenceSchemaId; + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeSchemaReferenceId("supermarketDataInPostRequest") + .SchemaReferenceId; }); string? resourceRelationshipInPostRequestSchemaRefId = null; schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("supermarketAttributesInPostRequest"); + propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeSchemaReferenceId("supermarketAttributesInPostRequest"); resourceRelationshipInPostRequestSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref") - .ShouldBeReferenceSchemaId("supermarketRelationshipsInPostRequest").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("supermarketRelationshipsInPostRequest").SchemaReferenceId; }); schemasElement.ShouldContainPath($"{resourceRelationshipInPostRequestSchemaRefId}.properties").With(propertiesElement => { propertiesElement.Should().ContainProperty("storeManager"); - propertiesElement.ShouldContainPath("storeManager.$ref").ShouldBeReferenceSchemaId("toOneStaffMemberInRequest"); + propertiesElement.ShouldContainPath("storeManager.$ref").ShouldBeSchemaReferenceId("toOneStaffMemberInRequest"); propertiesElement.Should().ContainProperty("backupStoreManager"); - propertiesElement.ShouldContainPath("backupStoreManager.$ref").ShouldBeReferenceSchemaId("nullableToOneStaffMemberInRequest"); + propertiesElement.ShouldContainPath("backupStoreManager.$ref").ShouldBeSchemaReferenceId("nullableToOneStaffMemberInRequest"); propertiesElement.Should().ContainProperty("cashiers"); - propertiesElement.ShouldContainPath("cashiers.$ref").ShouldBeReferenceSchemaId("toManyStaffMemberInRequest"); + propertiesElement.ShouldContainPath("cashiers.$ref").ShouldBeSchemaReferenceId("toManyStaffMemberInRequest"); }); }); } @@ -357,7 +418,7 @@ public async Task Casing_convention_is_applied_to_Post_endpoint() public async Task Casing_convention_is_applied_to_PostRelationship_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.post").With(getElement => @@ -373,7 +434,7 @@ public async Task Casing_convention_is_applied_to_PostRelationship_endpoint() public async Task Casing_convention_is_applied_to_Patch_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -386,7 +447,7 @@ public async Task Casing_convention_is_applied_to_Patch_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("supermarketPatchRequestDocument").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("supermarketPatchRequestDocument").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => @@ -395,14 +456,14 @@ public async Task Casing_convention_is_applied_to_Patch_endpoint() schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("supermarketDataInPatchRequest") - .ReferenceSchemaId; + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeSchemaReferenceId("supermarketDataInPatchRequest") + .SchemaReferenceId; }); schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("supermarketAttributesInPatchRequest"); - propertiesElement.ShouldContainPath("relationships.$ref").ShouldBeReferenceSchemaId("supermarketRelationshipsInPatchRequest"); + propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeSchemaReferenceId("supermarketAttributesInPatchRequest"); + propertiesElement.ShouldContainPath("relationships.$ref").ShouldBeSchemaReferenceId("supermarketRelationshipsInPatchRequest"); }); }); } @@ -411,7 +472,7 @@ public async Task Casing_convention_is_applied_to_Patch_endpoint() public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/storeManager.patch").With(getElement => @@ -427,7 +488,7 @@ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_wit public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/backupStoreManager.patch").With(getElement => @@ -443,7 +504,7 @@ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_wit public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.patch").With(getElement => @@ -459,7 +520,7 @@ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_wit public async Task Casing_convention_is_applied_to_Delete_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./supermarkets/{id}.delete").With(getElement => @@ -475,7 +536,7 @@ public async Task Casing_convention_is_applied_to_Delete_endpoint() public async Task Casing_convention_is_applied_to_DeleteRelationship_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.delete").With(getElement => diff --git a/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs b/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs index 0dfa7421fe..061bd873e8 100644 --- a/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs +++ b/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs @@ -12,15 +12,16 @@ public sealed class PascalCaseTests public PascalCaseTests(OpenApiTestContext, NamingConventionsDbContext> testContext) { _testContext = testContext; + testContext.UseController(); - testContext.GeneratedDocumentNamespace = "OpenApiClientTests.NamingConventions.KebabCase"; + testContext.SwaggerDocumentOutputPath = "test/OpenApiClientTests/NamingConventions/KebabCase"; } [Fact] public async Task Casing_convention_is_applied_to_GetCollection_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -33,38 +34,58 @@ public async Task Casing_convention_is_applied_to_GetCollection_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("supermarket-collection-response-document").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("supermarket-collection-response-document").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => { + string? linksInResourceCollectionDocumentSchemaRefId = null; string? resourceDataSchemaRefId = null; schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("links-in-resource-collection-document"); - propertiesElement.ShouldContainPath("jsonapi.$ref").ShouldBeReferenceSchemaId("jsonapi-object"); + propertiesElement.ShouldContainPath("jsonapi.$ref").ShouldBeSchemaReferenceId("jsonapi-object"); + + linksInResourceCollectionDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref") + .ShouldBeSchemaReferenceId("links-in-resource-collection-document").SchemaReferenceId; - resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.items.$ref").ShouldBeReferenceSchemaId("supermarket-data-in-response") - .ReferenceSchemaId; + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.items.$ref").ShouldBeSchemaReferenceId("supermarket-data-in-response") + .SchemaReferenceId; }); + schemasElement.ShouldContainPath($"{linksInResourceCollectionDocumentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("self"); + propertiesElement.Should().ContainProperty("describedby"); + propertiesElement.Should().ContainProperty("first"); + propertiesElement.Should().ContainProperty("last"); + propertiesElement.Should().ContainProperty("prev"); + propertiesElement.Should().ContainProperty("next"); + }); + + string? linksInResourceObjectSchemaRefId = null; + string? primaryResourceTypeSchemaRefId = null; string? resourceAttributesInResponseSchemaRefId = null; string? resourceRelationshipInResponseSchemaRefId = null; - string? primaryResourceTypeSchemaRefId = null; schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => { - primaryResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("supermarket-resource-type") - .ReferenceSchemaId; + linksInResourceObjectSchemaRefId = propertiesElement.ShouldContainPath("links.$ref").ShouldBeSchemaReferenceId("links-in-resource-object") + .SchemaReferenceId; + + primaryResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeSchemaReferenceId("supermarket-resource-type") + .SchemaReferenceId; resourceAttributesInResponseSchemaRefId = propertiesElement.ShouldContainPath("attributes.$ref") - .ShouldBeReferenceSchemaId("supermarket-attributes-in-response").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("supermarket-attributes-in-response").SchemaReferenceId; resourceRelationshipInResponseSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref") - .ShouldBeReferenceSchemaId("supermarket-relationships-in-response").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("supermarket-relationships-in-response").SchemaReferenceId; + }); - propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("links-in-resource-object"); + schemasElement.ShouldContainPath($"{linksInResourceObjectSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("self"); }); schemasElement.ShouldContainPath($"{primaryResourceTypeSchemaRefId}.enum[0]").With(enumValueElement => @@ -76,7 +97,7 @@ public async Task Casing_convention_is_applied_to_GetCollection_endpoint() { propertiesElement.Should().ContainProperty("name-of-city"); propertiesElement.Should().ContainProperty("kind"); - propertiesElement.ShouldContainPath("kind.$ref").ShouldBeReferenceSchemaId("supermarket-type"); + propertiesElement.ShouldContainPath("kind.$ref").ShouldBeSchemaReferenceId("supermarket-type"); }); string? nullableToOneResourceResponseDataSchemaRefId = null; @@ -85,36 +106,44 @@ public async Task Casing_convention_is_applied_to_GetCollection_endpoint() { propertiesElement.Should().ContainProperty("store-manager"); - propertiesElement.ShouldContainPath("store-manager.$ref").ShouldBeReferenceSchemaId("to-one-staff-member-in-response"); + propertiesElement.ShouldContainPath("store-manager.$ref").ShouldBeSchemaReferenceId("to-one-staff-member-in-response"); nullableToOneResourceResponseDataSchemaRefId = propertiesElement.ShouldContainPath("backup-store-manager.$ref") - .ShouldBeReferenceSchemaId("nullable-to-one-staff-member-in-response").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("nullable-to-one-staff-member-in-response").SchemaReferenceId; propertiesElement.Should().ContainProperty("cashiers"); - propertiesElement.ShouldContainPath("cashiers.$ref").ShouldBeReferenceSchemaId("to-many-staff-member-in-response"); + propertiesElement.ShouldContainPath("cashiers.$ref").ShouldBeSchemaReferenceId("to-many-staff-member-in-response"); }); + string? linksInRelationshipObjectSchemaRefId = null; string? relatedResourceIdentifierSchemaRefId = null; schemasElement.ShouldContainPath($"{nullableToOneResourceResponseDataSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("links-in-relationship-object"); + linksInRelationshipObjectSchemaRefId = propertiesElement.ShouldContainPath("links.$ref") + .ShouldBeSchemaReferenceId("links-in-relationship-object").SchemaReferenceId; relatedResourceIdentifierSchemaRefId = propertiesElement.ShouldContainPath("data.oneOf[0].$ref") - .ShouldBeReferenceSchemaId("staff-member-identifier").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("staff-member-identifier").SchemaReferenceId; - propertiesElement.ShouldContainPath("data.oneOf[1].$ref").ShouldBeReferenceSchemaId("null-value"); + propertiesElement.ShouldContainPath("data.oneOf[1].$ref").ShouldBeSchemaReferenceId("null-value"); + }); + + schemasElement.ShouldContainPath($"{linksInRelationshipObjectSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("self"); + propertiesElement.Should().ContainProperty("related"); }); string? relatedResourceTypeSchemaRefId = null; schemasElement.ShouldContainPath($"{relatedResourceIdentifierSchemaRefId}.properties").With(propertiesElement => { - relatedResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("staff-member-resource-type") - .ReferenceSchemaId; + relatedResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeSchemaReferenceId("staff-member-resource-type") + .SchemaReferenceId; }); - schemasElement.ShouldContainPath($"{relatedResourceTypeSchemaRefId}.enum[0]").ShouldBeReferenceSchemaId("staff-members"); + schemasElement.ShouldContainPath($"{relatedResourceTypeSchemaRefId}.enum[0]").ShouldBeSchemaReferenceId("staff-members"); }); } @@ -122,7 +151,7 @@ public async Task Casing_convention_is_applied_to_GetCollection_endpoint() public async Task Casing_convention_is_applied_to_GetSingle_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -135,14 +164,23 @@ public async Task Casing_convention_is_applied_to_GetSingle_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("supermarket-primary-response-document").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("supermarket-primary-response-document").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => { + string? linksInResourceDocumentSchemaRefId = null; + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("links-in-resource-document"); + linksInResourceDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref").ShouldBeSchemaReferenceId("links-in-resource-document") + .SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{linksInResourceDocumentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("self"); + propertiesElement.Should().ContainProperty("describedby"); }); }); } @@ -151,7 +189,7 @@ public async Task Casing_convention_is_applied_to_GetSingle_endpoint() public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -164,7 +202,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_sin }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("staff-member-secondary-response-document").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("staff-member-secondary-response-document").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => @@ -173,13 +211,13 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_sin schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("staff-member-data-in-response") - .ReferenceSchemaId; + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeSchemaReferenceId("staff-member-data-in-response") + .SchemaReferenceId; }); schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("staff-member-attributes-in-response"); + propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeSchemaReferenceId("staff-member-attributes-in-response"); }); }); } @@ -188,7 +226,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_sin public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./supermarkets/{id}/backup-store-manager.get").With(getElement => @@ -199,7 +237,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nul }); getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("nullable-staff-member-secondary-response-document"); + .ShouldBeSchemaReferenceId("nullable-staff-member-secondary-response-document"); }); } @@ -207,7 +245,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nul public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./supermarkets/{id}/cashiers.get").With(getElement => @@ -218,7 +256,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_res }); getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("staff-member-collection-response-document"); + .ShouldBeSchemaReferenceId("staff-member-collection-response-document"); }); } @@ -226,7 +264,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_res public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -239,14 +277,24 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("staff-member-identifier-response-document").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("staff-member-identifier-response-document").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => { + string? linksInResourceIdentifierDocumentSchemaRefId = null; + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("links-in-resource-identifier-document"); + linksInResourceIdentifierDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref") + .ShouldBeSchemaReferenceId("links-in-resource-identifier-document").SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{linksInResourceIdentifierDocumentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("self"); + propertiesElement.Should().ContainProperty("describedby"); + propertiesElement.Should().ContainProperty("related"); }); }); } @@ -255,7 +303,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/backup-store-manager.get").With(getElement => @@ -266,7 +314,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ }); getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("nullable-staff-member-identifier-response-document"); + .ShouldBeSchemaReferenceId("nullable-staff-member-identifier-response-document"); }); } @@ -274,7 +322,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -287,14 +335,28 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("staff-member-identifier-collection-response-document").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("staff-member-identifier-collection-response-document").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => { + string? linksInResourceIdentifierCollectionDocumentSchemaRefId = null; + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("links-in-resource-identifier-collection-document"); + linksInResourceIdentifierCollectionDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref") + .ShouldBeSchemaReferenceId("links-in-resource-identifier-collection-document").SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{linksInResourceIdentifierCollectionDocumentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("self"); + propertiesElement.Should().ContainProperty("describedby"); + propertiesElement.Should().ContainProperty("related"); + propertiesElement.Should().ContainProperty("first"); + propertiesElement.Should().ContainProperty("last"); + propertiesElement.Should().ContainProperty("prev"); + propertiesElement.Should().ContainProperty("next"); }); }); } @@ -303,7 +365,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ public async Task Casing_convention_is_applied_to_Post_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -316,7 +378,7 @@ public async Task Casing_convention_is_applied_to_Post_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("supermarket-post-request-document").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("supermarket-post-request-document").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => @@ -325,30 +387,30 @@ public async Task Casing_convention_is_applied_to_Post_endpoint() schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("supermarket-data-in-post-request") - .ReferenceSchemaId; + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeSchemaReferenceId("supermarket-data-in-post-request") + .SchemaReferenceId; }); string? resourceRelationshipInPostRequestSchemaRefId = null; schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("supermarket-attributes-in-post-request"); + propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeSchemaReferenceId("supermarket-attributes-in-post-request"); resourceRelationshipInPostRequestSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref") - .ShouldBeReferenceSchemaId("supermarket-relationships-in-post-request").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("supermarket-relationships-in-post-request").SchemaReferenceId; }); schemasElement.ShouldContainPath($"{resourceRelationshipInPostRequestSchemaRefId}.properties").With(propertiesElement => { propertiesElement.Should().ContainProperty("store-manager"); - propertiesElement.ShouldContainPath("store-manager.$ref").ShouldBeReferenceSchemaId("to-one-staff-member-in-request"); + propertiesElement.ShouldContainPath("store-manager.$ref").ShouldBeSchemaReferenceId("to-one-staff-member-in-request"); propertiesElement.Should().ContainProperty("backup-store-manager"); - propertiesElement.ShouldContainPath("backup-store-manager.$ref").ShouldBeReferenceSchemaId("nullable-to-one-staff-member-in-request"); + propertiesElement.ShouldContainPath("backup-store-manager.$ref").ShouldBeSchemaReferenceId("nullable-to-one-staff-member-in-request"); propertiesElement.Should().ContainProperty("cashiers"); - propertiesElement.ShouldContainPath("cashiers.$ref").ShouldBeReferenceSchemaId("to-many-staff-member-in-request"); + propertiesElement.ShouldContainPath("cashiers.$ref").ShouldBeSchemaReferenceId("to-many-staff-member-in-request"); }); }); } @@ -357,7 +419,7 @@ public async Task Casing_convention_is_applied_to_Post_endpoint() public async Task Casing_convention_is_applied_to_PostRelationship_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.post").With(getElement => @@ -373,7 +435,7 @@ public async Task Casing_convention_is_applied_to_PostRelationship_endpoint() public async Task Casing_convention_is_applied_to_Patch_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -386,7 +448,7 @@ public async Task Casing_convention_is_applied_to_Patch_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("supermarket-patch-request-document").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("supermarket-patch-request-document").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => @@ -395,14 +457,14 @@ public async Task Casing_convention_is_applied_to_Patch_endpoint() schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("supermarket-data-in-patch-request") - .ReferenceSchemaId; + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeSchemaReferenceId("supermarket-data-in-patch-request") + .SchemaReferenceId; }); schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("supermarket-attributes-in-patch-request"); - propertiesElement.ShouldContainPath("relationships.$ref").ShouldBeReferenceSchemaId("supermarket-relationships-in-patch-request"); + propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeSchemaReferenceId("supermarket-attributes-in-patch-request"); + propertiesElement.ShouldContainPath("relationships.$ref").ShouldBeSchemaReferenceId("supermarket-relationships-in-patch-request"); }); }); } @@ -411,7 +473,7 @@ public async Task Casing_convention_is_applied_to_Patch_endpoint() public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/store-manager.patch").With(getElement => @@ -427,7 +489,7 @@ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_wit public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/backup-store-manager.patch").With(getElement => @@ -443,7 +505,7 @@ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_wit public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.patch").With(getElement => @@ -459,7 +521,7 @@ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_wit public async Task Casing_convention_is_applied_to_Delete_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./supermarkets/{id}.delete").With(getElement => @@ -475,7 +537,7 @@ public async Task Casing_convention_is_applied_to_Delete_endpoint() public async Task Casing_convention_is_applied_to_DeleteRelationship_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./supermarkets/{id}/relationships/cashiers.delete").With(getElement => diff --git a/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseTests.cs b/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseTests.cs index 5d485f0aad..73868dcdad 100644 --- a/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseTests.cs +++ b/test/OpenApiTests/NamingConventions/PascalCase/PascalCaseTests.cs @@ -12,15 +12,16 @@ public sealed class PascalCaseTests public PascalCaseTests(OpenApiTestContext, NamingConventionsDbContext> testContext) { _testContext = testContext; + testContext.UseController(); - testContext.GeneratedDocumentNamespace = "OpenApiClientTests.NamingConventions.PascalCase"; + testContext.SwaggerDocumentOutputPath = "test/OpenApiClientTests/NamingConventions/PascalCase"; } [Fact] public async Task Casing_convention_is_applied_to_GetCollection_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -33,38 +34,58 @@ public async Task Casing_convention_is_applied_to_GetCollection_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("SupermarketCollectionResponseDocument").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("SupermarketCollectionResponseDocument").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => { + string? linksInResourceCollectionDocumentSchemaRefId = null; string? resourceDataSchemaRefId = null; schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("LinksInResourceCollectionDocument"); - propertiesElement.ShouldContainPath("jsonapi.$ref").ShouldBeReferenceSchemaId("JsonapiObject"); + propertiesElement.ShouldContainPath("jsonapi.$ref").ShouldBeSchemaReferenceId("JsonapiObject"); + + linksInResourceCollectionDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref") + .ShouldBeSchemaReferenceId("LinksInResourceCollectionDocument").SchemaReferenceId; - resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.items.$ref").ShouldBeReferenceSchemaId("SupermarketDataInResponse") - .ReferenceSchemaId; + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.items.$ref").ShouldBeSchemaReferenceId("SupermarketDataInResponse") + .SchemaReferenceId; }); + schemasElement.ShouldContainPath($"{linksInResourceCollectionDocumentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("self"); + propertiesElement.Should().ContainProperty("describedby"); + propertiesElement.Should().ContainProperty("first"); + propertiesElement.Should().ContainProperty("last"); + propertiesElement.Should().ContainProperty("prev"); + propertiesElement.Should().ContainProperty("next"); + }); + + string? linksInResourceObjectSchemaRefId = null; + string? primaryResourceTypeSchemaRefId = null; string? resourceAttributesInResponseSchemaRefId = null; string? resourceRelationshipInResponseSchemaRefId = null; - string? primaryResourceTypeSchemaRefId = null; schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => { - primaryResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("SupermarketResourceType") - .ReferenceSchemaId; + linksInResourceObjectSchemaRefId = propertiesElement.ShouldContainPath("links.$ref").ShouldBeSchemaReferenceId("LinksInResourceObject") + .SchemaReferenceId; + + primaryResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeSchemaReferenceId("SupermarketResourceType") + .SchemaReferenceId; resourceAttributesInResponseSchemaRefId = propertiesElement.ShouldContainPath("attributes.$ref") - .ShouldBeReferenceSchemaId("SupermarketAttributesInResponse").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("SupermarketAttributesInResponse").SchemaReferenceId; resourceRelationshipInResponseSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref") - .ShouldBeReferenceSchemaId("SupermarketRelationshipsInResponse").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("SupermarketRelationshipsInResponse").SchemaReferenceId; + }); - propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("LinksInResourceObject"); + schemasElement.ShouldContainPath($"{linksInResourceObjectSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("self"); }); schemasElement.ShouldContainPath($"{primaryResourceTypeSchemaRefId}.enum[0]").With(enumValueElement => @@ -76,7 +97,7 @@ public async Task Casing_convention_is_applied_to_GetCollection_endpoint() { propertiesElement.Should().ContainProperty("NameOfCity"); propertiesElement.Should().ContainProperty("Kind"); - propertiesElement.ShouldContainPath("Kind.$ref").ShouldBeReferenceSchemaId("SupermarketType"); + propertiesElement.ShouldContainPath("Kind.$ref").ShouldBeSchemaReferenceId("SupermarketType"); }); string? nullableToOneResourceResponseDataSchemaRefId = null; @@ -85,36 +106,44 @@ public async Task Casing_convention_is_applied_to_GetCollection_endpoint() { propertiesElement.Should().ContainProperty("StoreManager"); - propertiesElement.ShouldContainPath("StoreManager.$ref").ShouldBeReferenceSchemaId("ToOneStaffMemberInResponse"); + propertiesElement.ShouldContainPath("StoreManager.$ref").ShouldBeSchemaReferenceId("ToOneStaffMemberInResponse"); nullableToOneResourceResponseDataSchemaRefId = propertiesElement.ShouldContainPath("BackupStoreManager.$ref") - .ShouldBeReferenceSchemaId("NullableToOneStaffMemberInResponse").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("NullableToOneStaffMemberInResponse").SchemaReferenceId; propertiesElement.Should().ContainProperty("Cashiers"); - propertiesElement.ShouldContainPath("Cashiers.$ref").ShouldBeReferenceSchemaId("ToManyStaffMemberInResponse"); + propertiesElement.ShouldContainPath("Cashiers.$ref").ShouldBeSchemaReferenceId("ToManyStaffMemberInResponse"); }); + string? linksInRelationshipObjectSchemaRefId = null; string? relatedResourceIdentifierSchemaRefId = null; schemasElement.ShouldContainPath($"{nullableToOneResourceResponseDataSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("LinksInRelationshipObject"); + linksInRelationshipObjectSchemaRefId = propertiesElement.ShouldContainPath("links.$ref").ShouldBeSchemaReferenceId("LinksInRelationshipObject") + .SchemaReferenceId; relatedResourceIdentifierSchemaRefId = propertiesElement.ShouldContainPath("data.oneOf[0].$ref") - .ShouldBeReferenceSchemaId("StaffMemberIdentifier").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("StaffMemberIdentifier").SchemaReferenceId; - propertiesElement.ShouldContainPath("data.oneOf[1].$ref").ShouldBeReferenceSchemaId("NullValue"); + propertiesElement.ShouldContainPath("data.oneOf[1].$ref").ShouldBeSchemaReferenceId("NullValue"); + }); + + schemasElement.ShouldContainPath($"{linksInRelationshipObjectSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("self"); + propertiesElement.Should().ContainProperty("related"); }); string? relatedResourceTypeSchemaRefId = null; schemasElement.ShouldContainPath($"{relatedResourceIdentifierSchemaRefId}.properties").With(propertiesElement => { - relatedResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeReferenceSchemaId("StaffMemberResourceType") - .ReferenceSchemaId; + relatedResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeSchemaReferenceId("StaffMemberResourceType") + .SchemaReferenceId; }); - schemasElement.ShouldContainPath($"{relatedResourceTypeSchemaRefId}.enum[0]").ShouldBeReferenceSchemaId("StaffMembers"); + schemasElement.ShouldContainPath($"{relatedResourceTypeSchemaRefId}.enum[0]").ShouldBeSchemaReferenceId("StaffMembers"); }); } @@ -122,7 +151,7 @@ public async Task Casing_convention_is_applied_to_GetCollection_endpoint() public async Task Casing_convention_is_applied_to_GetSingle_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -135,14 +164,23 @@ public async Task Casing_convention_is_applied_to_GetSingle_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("SupermarketPrimaryResponseDocument").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("SupermarketPrimaryResponseDocument").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => { + string? linksInResourceDocumentSchemaRefId = null; + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("LinksInResourceDocument"); + linksInResourceDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref").ShouldBeSchemaReferenceId("LinksInResourceDocument") + .SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{linksInResourceDocumentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("self"); + propertiesElement.Should().ContainProperty("describedby"); }); }); } @@ -151,7 +189,7 @@ public async Task Casing_convention_is_applied_to_GetSingle_endpoint() public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_single_resource() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -164,7 +202,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_sin }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("StaffMemberSecondaryResponseDocument").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("StaffMemberSecondaryResponseDocument").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => @@ -173,13 +211,13 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_sin schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("StaffMemberDataInResponse") - .ReferenceSchemaId; + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeSchemaReferenceId("StaffMemberDataInResponse") + .SchemaReferenceId; }); schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("StaffMemberAttributesInResponse"); + propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeSchemaReferenceId("StaffMemberAttributesInResponse"); }); }); } @@ -188,7 +226,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_sin public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nullable_resource() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./Supermarkets/{id}/BackupStoreManager.get").With(getElement => @@ -199,7 +237,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nul }); getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("NullableStaffMemberSecondaryResponseDocument"); + .ShouldBeSchemaReferenceId("NullableStaffMemberSecondaryResponseDocument"); }); } @@ -207,7 +245,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_nul public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_resources() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./Supermarkets/{id}/Cashiers.get").With(getElement => @@ -218,7 +256,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_res }); getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("StaffMemberCollectionResponseDocument"); + .ShouldBeSchemaReferenceId("StaffMemberCollectionResponseDocument"); }); } @@ -226,7 +264,7 @@ public async Task Casing_convention_is_applied_to_GetSecondary_endpoint_with_res public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToOne_relationship() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -239,14 +277,24 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("StaffMemberIdentifierResponseDocument").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("StaffMemberIdentifierResponseDocument").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => { + string? linksInResourceIdentifierDocumentSchemaRefId = null; + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("LinksInResourceIdentifierDocument"); + linksInResourceIdentifierDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref") + .ShouldBeSchemaReferenceId("LinksInResourceIdentifierDocument").SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{linksInResourceIdentifierDocumentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("self"); + propertiesElement.Should().ContainProperty("describedby"); + propertiesElement.Should().ContainProperty("related"); }); }); } @@ -255,7 +303,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_nullable_ToOne_relationship() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./Supermarkets/{id}/relationships/BackupStoreManager.get").With(getElement => @@ -266,7 +314,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ }); getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("NullableStaffMemberIdentifierResponseDocument"); + .ShouldBeSchemaReferenceId("NullableStaffMemberIdentifierResponseDocument"); }); } @@ -274,7 +322,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ToMany_relationship() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -287,14 +335,28 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ }); documentSchemaRefId = getElement.ShouldContainPath("responses.200.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("StaffMemberIdentifierCollectionResponseDocument").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("StaffMemberIdentifierCollectionResponseDocument").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => { + string? linksInResourceIdentifierCollectionDocumentSchemaRefId = null; + schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("links.$ref").ShouldBeReferenceSchemaId("LinksInResourceIdentifierCollectionDocument"); + linksInResourceIdentifierCollectionDocumentSchemaRefId = propertiesElement.ShouldContainPath("links.$ref") + .ShouldBeSchemaReferenceId("LinksInResourceIdentifierCollectionDocument").SchemaReferenceId; + }); + + schemasElement.ShouldContainPath($"{linksInResourceIdentifierCollectionDocumentSchemaRefId}.properties").With(propertiesElement => + { + propertiesElement.Should().ContainProperty("self"); + propertiesElement.Should().ContainProperty("describedby"); + propertiesElement.Should().ContainProperty("related"); + propertiesElement.Should().ContainProperty("first"); + propertiesElement.Should().ContainProperty("last"); + propertiesElement.Should().ContainProperty("prev"); + propertiesElement.Should().ContainProperty("next"); }); }); } @@ -303,7 +365,7 @@ public async Task Casing_convention_is_applied_to_GetRelationship_endpoint_with_ public async Task Casing_convention_is_applied_to_Post_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -316,7 +378,7 @@ public async Task Casing_convention_is_applied_to_Post_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("SupermarketPostRequestDocument").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("SupermarketPostRequestDocument").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => @@ -325,30 +387,30 @@ public async Task Casing_convention_is_applied_to_Post_endpoint() schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("SupermarketDataInPostRequest") - .ReferenceSchemaId; + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeSchemaReferenceId("SupermarketDataInPostRequest") + .SchemaReferenceId; }); string? resourceRelationshipInPostRequestSchemaRefId = null; schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("SupermarketAttributesInPostRequest"); + propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeSchemaReferenceId("SupermarketAttributesInPostRequest"); resourceRelationshipInPostRequestSchemaRefId = propertiesElement.ShouldContainPath("relationships.$ref") - .ShouldBeReferenceSchemaId("SupermarketRelationshipsInPostRequest").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("SupermarketRelationshipsInPostRequest").SchemaReferenceId; }); schemasElement.ShouldContainPath($"{resourceRelationshipInPostRequestSchemaRefId}.properties").With(propertiesElement => { propertiesElement.Should().ContainProperty("StoreManager"); - propertiesElement.ShouldContainPath("StoreManager.$ref").ShouldBeReferenceSchemaId("ToOneStaffMemberInRequest"); + propertiesElement.ShouldContainPath("StoreManager.$ref").ShouldBeSchemaReferenceId("ToOneStaffMemberInRequest"); propertiesElement.Should().ContainProperty("BackupStoreManager"); - propertiesElement.ShouldContainPath("BackupStoreManager.$ref").ShouldBeReferenceSchemaId("NullableToOneStaffMemberInRequest"); + propertiesElement.ShouldContainPath("BackupStoreManager.$ref").ShouldBeSchemaReferenceId("NullableToOneStaffMemberInRequest"); propertiesElement.Should().ContainProperty("Cashiers"); - propertiesElement.ShouldContainPath("Cashiers.$ref").ShouldBeReferenceSchemaId("ToManyStaffMemberInRequest"); + propertiesElement.ShouldContainPath("Cashiers.$ref").ShouldBeSchemaReferenceId("ToManyStaffMemberInRequest"); }); }); } @@ -357,7 +419,7 @@ public async Task Casing_convention_is_applied_to_Post_endpoint() public async Task Casing_convention_is_applied_to_PostRelationship_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.post").With(getElement => @@ -373,7 +435,7 @@ public async Task Casing_convention_is_applied_to_PostRelationship_endpoint() public async Task Casing_convention_is_applied_to_Patch_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert string? documentSchemaRefId = null; @@ -386,7 +448,7 @@ public async Task Casing_convention_is_applied_to_Patch_endpoint() }); documentSchemaRefId = getElement.ShouldContainPath("requestBody.content['application/vnd.api+json'].schema.$ref") - .ShouldBeReferenceSchemaId("SupermarketPatchRequestDocument").ReferenceSchemaId; + .ShouldBeSchemaReferenceId("SupermarketPatchRequestDocument").SchemaReferenceId; }); document.ShouldContainPath("components.schemas").With(schemasElement => @@ -395,14 +457,14 @@ public async Task Casing_convention_is_applied_to_Patch_endpoint() schemasElement.ShouldContainPath($"{documentSchemaRefId}.properties").With(propertiesElement => { - resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeReferenceSchemaId("SupermarketDataInPatchRequest") - .ReferenceSchemaId; + resourceDataSchemaRefId = propertiesElement.ShouldContainPath("data.$ref").ShouldBeSchemaReferenceId("SupermarketDataInPatchRequest") + .SchemaReferenceId; }); schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => { - propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeReferenceSchemaId("SupermarketAttributesInPatchRequest"); - propertiesElement.ShouldContainPath("relationships.$ref").ShouldBeReferenceSchemaId("SupermarketRelationshipsInPatchRequest"); + propertiesElement.ShouldContainPath("attributes.$ref").ShouldBeSchemaReferenceId("SupermarketAttributesInPatchRequest"); + propertiesElement.ShouldContainPath("relationships.$ref").ShouldBeSchemaReferenceId("SupermarketRelationshipsInPatchRequest"); }); }); } @@ -411,7 +473,7 @@ public async Task Casing_convention_is_applied_to_Patch_endpoint() public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToOne_relationship() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./Supermarkets/{id}/relationships/StoreManager.patch").With(getElement => @@ -427,7 +489,7 @@ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_wit public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_nullable_ToOne_relationship() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./Supermarkets/{id}/relationships/BackupStoreManager.patch").With(getElement => @@ -443,7 +505,7 @@ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_wit public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_with_ToMany_relationship() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.patch").With(getElement => @@ -459,7 +521,7 @@ public async Task Casing_convention_is_applied_to_PatchRelationship_endpoint_wit public async Task Casing_convention_is_applied_to_Delete_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./Supermarkets/{id}.delete").With(getElement => @@ -475,7 +537,7 @@ public async Task Casing_convention_is_applied_to_Delete_endpoint() public async Task Casing_convention_is_applied_to_DeleteRelationship_endpoint() { // Act - JsonElement document = await _testContext.LazyDocument.Value; + JsonElement document = await _testContext.GetSwaggerDocumentAsync(); // Assert document.ShouldContainPath("paths./Supermarkets/{id}/relationships/Cashiers.delete").With(getElement => diff --git a/test/OpenApiTests/OpenApiTestContext.cs b/test/OpenApiTests/OpenApiTestContext.cs index 466d422869..dda000ff9d 100644 --- a/test/OpenApiTests/OpenApiTestContext.cs +++ b/test/OpenApiTests/OpenApiTestContext.cs @@ -1,7 +1,9 @@ +using System.Reflection; using System.Text.Json; using JetBrains.Annotations; using Microsoft.EntityFrameworkCore; using TestBuildingBlocks; +using SysNotNull = System.Diagnostics.CodeAnalysis.NotNullAttribute; namespace OpenApiTests; @@ -10,29 +12,47 @@ public class OpenApiTestContext : IntegrationTestContext> _lazySwaggerDocument; - internal readonly Lazy> LazyDocument; - internal string? GeneratedDocumentNamespace; + internal string? SwaggerDocumentOutputPath { private get; set; } public OpenApiTestContext() { - LazyDocument = new Lazy>(GetDocumentAsync, LazyThreadSafetyMode.ExecutionAndPublication); + _lazySwaggerDocument = new Lazy>(CreateSwaggerDocumentAsync, LazyThreadSafetyMode.ExecutionAndPublication); } - private async Task GetDocumentAsync() + internal async Task GetSwaggerDocumentAsync() { + return await _lazySwaggerDocument.Value; + } + + private async Task CreateSwaggerDocumentAsync() + { + string swaggerDocumentOutputPath = GetSwaggerDocumentAbsoluteOutputPath(SwaggerDocumentOutputPath); + string content = await GetAsync("swagger/v1/swagger.json"); - JsonDocument document = JsonDocument.Parse(content); + JsonElement swaggerDocument = ParseSwaggerDocument(content); + await WriteToDiskAsync(swaggerDocumentOutputPath, swaggerDocument); - using (document) - { - JsonElement clonedDocument = document.RootElement.Clone(); + return swaggerDocument; + } - await WriteDocumentToFileAsync(clonedDocument); + private static string GetSwaggerDocumentAbsoluteOutputPath(string? relativePath) + { + AssertHasSwaggerDocumentOutputPath(relativePath); + + string solutionRoot = Path.Combine(Assembly.GetExecutingAssembly().Location, "../../../../../../"); + string outputPath = Path.Join(solutionRoot, relativePath, "swagger.g.json"); - return clonedDocument; + return Path.GetFullPath(outputPath); + } + + private static void AssertHasSwaggerDocumentOutputPath([SysNotNull] string? relativePath) + { + if (relativePath is null) + { + throw new Exception($"Property '{nameof(OpenApiTestContext)}.{nameof(SwaggerDocumentOutputPath)}' must be set."); } } @@ -46,35 +66,15 @@ private async Task GetAsync(string requestUrl) return await responseMessage.Content.ReadAsStringAsync(); } - public override void UseController() - { - if (!LazyDocument.IsValueCreated) - { - base.UseController(); - } - } - - private async Task WriteDocumentToFileAsync(JsonElement document) + private static JsonElement ParseSwaggerDocument(string content) { - string pathToTestSuiteDirectory = GetTestSuitePath(); - string pathToDocument = Path.Join(pathToTestSuiteDirectory, GeneratedDocumentName); - string json = document.ToString(); - await File.WriteAllTextAsync(pathToDocument, json); + using JsonDocument jsonDocument = JsonDocument.Parse(content); + return jsonDocument.RootElement.Clone(); } - private string GetTestSuitePath() + private static async Task WriteToDiskAsync(string path, JsonElement jsonElement) { - string pathToSolutionTestDirectory = Path.Combine(Environment.CurrentDirectory, "../../../../"); - pathToSolutionTestDirectory = Path.GetFullPath(pathToSolutionTestDirectory); - - if (GeneratedDocumentNamespace == null) - { - throw new Exception( - $"Failed to write {GeneratedDocumentName} to disk. Ensure '{nameof(OpenApiTestContext)}.{nameof(GeneratedDocumentNamespace)}' is set."); - } - - string pathToCurrentNamespaceRelativeToTestDirectory = Path.Combine(GeneratedDocumentNamespace.Split('.')); - - return Path.Join(pathToSolutionTestDirectory, pathToCurrentNamespaceRelativeToTestDirectory); + string contents = jsonElement.ToString(); + await File.WriteAllTextAsync(path, contents); } } diff --git a/test/OpenApiTests/OpenApiTests.csproj b/test/OpenApiTests/OpenApiTests.csproj index 6ba324d30f..975777963b 100644 --- a/test/OpenApiTests/OpenApiTests.csproj +++ b/test/OpenApiTests/OpenApiTests.csproj @@ -3,18 +3,18 @@ $(TargetFrameworkName) - - - - - - PreserveNewest + + + + + + @@ -25,5 +25,4 @@ - \ No newline at end of file diff --git a/test/TestBuildingBlocks/IntegrationTestContext.cs b/test/TestBuildingBlocks/IntegrationTestContext.cs index 74eeac0c98..f25eb29070 100644 --- a/test/TestBuildingBlocks/IntegrationTestContext.cs +++ b/test/TestBuildingBlocks/IntegrationTestContext.cs @@ -50,7 +50,7 @@ public IntegrationTestContext() _lazyFactory = new Lazy>(CreateFactory); } - public virtual void UseController() + public void UseController() where TController : ControllerBase { _testControllerProvider.AddController(typeof(TController)); From c7eff0a6ec4241dd10d2fbdb30b0eba31a861013 Mon Sep 17 00:00:00 2001 From: maurei Date: Mon, 20 Dec 2021 15:05:02 +0100 Subject: [PATCH 13/15] Process feedback --- src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs | 5 ----- .../NamingConventions/CamelCase/CamelCaseTests.cs | 4 ++-- .../NamingConventions/KebabCase/KebabCaseTests.cs | 4 ++-- test/OpenApiTests/OpenApiTestContext.cs | 10 +++++----- test/OpenApiTests/OpenApiTests.csproj | 12 ++++++------ 5 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs b/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs index 261521b579..1224308af9 100644 --- a/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs +++ b/src/JsonApiDotNetCore.OpenApi.Client/ApiException.cs @@ -22,9 +22,4 @@ public ApiException(string message, int statusCode, string? response, IReadOnlyD Response = response; Headers = headers; } - - public override string ToString() - { - return $"HTTP Response: \n\n{Response}\n\n{base.ToString()}"; - } } diff --git a/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs index 0f2a974b58..1edc803f3d 100644 --- a/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs +++ b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs @@ -4,12 +4,12 @@ namespace OpenApiTests.NamingConventions.CamelCase; -public sealed class PascalCaseTests +public sealed class CamelCaseTests : IClassFixture, NamingConventionsDbContext>> { private readonly OpenApiTestContext, NamingConventionsDbContext> _testContext; - public PascalCaseTests(OpenApiTestContext, NamingConventionsDbContext> testContext) + public CamelCaseTests(OpenApiTestContext, NamingConventionsDbContext> testContext) { _testContext = testContext; diff --git a/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs b/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs index 061bd873e8..9e2fd73db9 100644 --- a/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs +++ b/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs @@ -4,12 +4,12 @@ namespace OpenApiTests.NamingConventions.KebabCase; -public sealed class PascalCaseTests +public sealed class KebabCaseTests : IClassFixture, NamingConventionsDbContext>> { private readonly OpenApiTestContext, NamingConventionsDbContext> _testContext; - public PascalCaseTests(OpenApiTestContext, NamingConventionsDbContext> testContext) + public KebabCaseTests(OpenApiTestContext, NamingConventionsDbContext> testContext) { _testContext = testContext; diff --git a/test/OpenApiTests/OpenApiTestContext.cs b/test/OpenApiTests/OpenApiTestContext.cs index dda000ff9d..a750929827 100644 --- a/test/OpenApiTests/OpenApiTestContext.cs +++ b/test/OpenApiTests/OpenApiTestContext.cs @@ -28,14 +28,14 @@ internal async Task GetSwaggerDocumentAsync() private async Task CreateSwaggerDocumentAsync() { - string swaggerDocumentOutputPath = GetSwaggerDocumentAbsoluteOutputPath(SwaggerDocumentOutputPath); + string absoluteOutputPath = GetSwaggerDocumentAbsoluteOutputPath(SwaggerDocumentOutputPath); string content = await GetAsync("swagger/v1/swagger.json"); - JsonElement swaggerDocument = ParseSwaggerDocument(content); - await WriteToDiskAsync(swaggerDocumentOutputPath, swaggerDocument); + JsonElement rootElement = ParseSwaggerDocument(content); + await WriteToDiskAsync(absoluteOutputPath, rootElement); - return swaggerDocument; + return rootElement; } private static string GetSwaggerDocumentAbsoluteOutputPath(string? relativePath) @@ -43,7 +43,7 @@ private static string GetSwaggerDocumentAbsoluteOutputPath(string? relativePath) AssertHasSwaggerDocumentOutputPath(relativePath); string solutionRoot = Path.Combine(Assembly.GetExecutingAssembly().Location, "../../../../../../"); - string outputPath = Path.Join(solutionRoot, relativePath, "swagger.g.json"); + string outputPath = Path.Combine(solutionRoot, relativePath, "swagger.g.json"); return Path.GetFullPath(outputPath); } diff --git a/test/OpenApiTests/OpenApiTests.csproj b/test/OpenApiTests/OpenApiTests.csproj index 975777963b..f5a24feec9 100644 --- a/test/OpenApiTests/OpenApiTests.csproj +++ b/test/OpenApiTests/OpenApiTests.csproj @@ -9,6 +9,10 @@ + + + + @@ -19,10 +23,6 @@ - - - - - + - \ No newline at end of file + From c6d264187eab7f514f8c46d0ab133a5a16616701 Mon Sep 17 00:00:00 2001 From: maurei Date: Mon, 20 Dec 2021 17:56:45 +0100 Subject: [PATCH 14/15] cleanup code --- .../OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs | 3 +-- .../OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs index 1edc803f3d..f2c373f377 100644 --- a/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs +++ b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs @@ -4,8 +4,7 @@ namespace OpenApiTests.NamingConventions.CamelCase; -public sealed class CamelCaseTests - : IClassFixture, NamingConventionsDbContext>> +public sealed class CamelCaseTests : IClassFixture, NamingConventionsDbContext>> { private readonly OpenApiTestContext, NamingConventionsDbContext> _testContext; diff --git a/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs b/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs index 9e2fd73db9..0a532a6e3f 100644 --- a/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs +++ b/test/OpenApiTests/NamingConventions/KebabCase/KebabCaseTests.cs @@ -4,8 +4,7 @@ namespace OpenApiTests.NamingConventions.KebabCase; -public sealed class KebabCaseTests - : IClassFixture, NamingConventionsDbContext>> +public sealed class KebabCaseTests : IClassFixture, NamingConventionsDbContext>> { private readonly OpenApiTestContext, NamingConventionsDbContext> _testContext; From 9f3f665138dc3302f7dafa22b1c660d966213050 Mon Sep 17 00:00:00 2001 From: maurei Date: Tue, 21 Dec 2021 11:12:02 +0100 Subject: [PATCH 15/15] Fix irregularities in test file --- .../NamingConventions/CamelCase/CamelCaseTests.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs index f2c373f377..e0bbd5bad3 100644 --- a/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs +++ b/test/OpenApiTests/NamingConventions/CamelCase/CamelCaseTests.cs @@ -62,14 +62,15 @@ public async Task Casing_convention_is_applied_to_GetCollection_endpoint() propertiesElement.Should().ContainProperty("next"); }); - string? linksInResourceObject = null; + string? linksInResourceObjectSchemaRefId = null; + string? primaryResourceTypeSchemaRefId = null; string? resourceAttributesInResponseSchemaRefId = null; string? resourceRelationshipInResponseSchemaRefId = null; - string? primaryResourceTypeSchemaRefId = null; schemasElement.ShouldContainPath($"{resourceDataSchemaRefId}.properties").With(propertiesElement => { - linksInResourceObject = propertiesElement.ShouldContainPath("links.$ref").ShouldBeSchemaReferenceId("linksInResourceObject").SchemaReferenceId; + linksInResourceObjectSchemaRefId = propertiesElement.ShouldContainPath("links.$ref").ShouldBeSchemaReferenceId("linksInResourceObject") + .SchemaReferenceId; primaryResourceTypeSchemaRefId = propertiesElement.ShouldContainPath("type.$ref").ShouldBeSchemaReferenceId("supermarketResourceType") .SchemaReferenceId; @@ -81,7 +82,7 @@ public async Task Casing_convention_is_applied_to_GetCollection_endpoint() .ShouldBeSchemaReferenceId("supermarketRelationshipsInResponse").SchemaReferenceId; }); - schemasElement.ShouldContainPath($"{linksInResourceObject}.properties").With(propertiesElement => + schemasElement.ShouldContainPath($"{linksInResourceObjectSchemaRefId}.properties").With(propertiesElement => { propertiesElement.Should().ContainProperty("self"); });