diff --git a/src/Refitter.Tests/CustomCSharpTypeResolverTests.cs b/src/Refitter.Tests/CustomCSharpTypeResolverTests.cs index c359fc74..b0980ff4 100644 --- a/src/Refitter.Tests/CustomCSharpTypeResolverTests.cs +++ b/src/Refitter.Tests/CustomCSharpTypeResolverTests.cs @@ -1,4 +1,3 @@ -using System.Reflection; using FluentAssertions; using NJsonSchema; using NJsonSchema.CodeGeneration.CSharp; @@ -267,121 +266,4 @@ public void Resolve_Nullable_With_Multiple_Mappings_Returns_Correct_Nullable_Typ resolver.Resolve(new JsonSchema { Format = "uuid" }, true, null).Should().Be("Guid?"); } - [Test] - [Arguments("System.Guid")] - [Arguments("System.DateTime")] - [Arguments("System.DateTimeOffset")] - [Arguments("System.TimeSpan")] - [Arguments("System.Decimal")] - [Arguments("System.Int32")] - [Arguments("System.Int64")] - [Arguments("System.Double")] - [Arguments("System.Single")] - [Arguments("System.Boolean")] - [Arguments("System.Byte")] - [Arguments("System.SByte")] - [Arguments("System.Int16")] - [Arguments("System.UInt16")] - [Arguments("System.UInt32")] - [Arguments("System.UInt64")] - [Arguments("System.Char")] - [Arguments("Guid")] - [Arguments("DateTime")] - [Arguments("DateTimeOffset")] - [Arguments("TimeSpan")] - [Arguments("Decimal")] - [Arguments("Int32")] - [Arguments("Int64")] - [Arguments("Double")] - [Arguments("Single")] - [Arguments("Boolean")] - [Arguments("Byte")] - [Arguments("SByte")] - [Arguments("Int16")] - [Arguments("UInt16")] - [Arguments("UInt32")] - [Arguments("UInt64")] - [Arguments("Char")] - [Arguments("bool")] - [Arguments("byte")] - [Arguments("sbyte")] - [Arguments("char")] - [Arguments("decimal")] - [Arguments("double")] - [Arguments("float")] - [Arguments("int")] - [Arguments("uint")] - [Arguments("long")] - [Arguments("ulong")] - [Arguments("short")] - [Arguments("ushort")] - public void IsValueType_Returns_True_For_All_Known_Mappings(string mappedType) - { - var method = typeof(CustomCSharpTypeResolver).GetMethod( - "IsValueType", - BindingFlags.NonPublic | BindingFlags.Static); - - var result = (bool?)method?.Invoke(null, [mappedType]); - - result.Should().BeTrue(); - } - - [Test] - [Arguments("string")] - [Arguments("List")] - [Arguments("System.String")] - [Arguments("System.GuidValue")] - [Arguments("System.DateTimer")] - [Arguments("System.DateTimeOffsets")] - [Arguments("System.TimeSpans")] - [Arguments("System.Decimals")] - [Arguments("System.Int33")] - [Arguments("System.Int128")] - [Arguments("System.DoubleValue")] - [Arguments("System.SingleValue")] - [Arguments("System.BooleanValue")] - [Arguments("System.Bytes")] - [Arguments("System.SBytes")] - [Arguments("System.Int24")] - [Arguments("System.UInt24")] - [Arguments("System.UInt128")] - [Arguments("System.Chars")] - [Arguments("GuidValue")] - [Arguments("DateTimer")] - [Arguments("DateTimeOffsets")] - [Arguments("TimeSpans")] - [Arguments("Decimals")] - [Arguments("Int33")] - [Arguments("Int128")] - [Arguments("DoubleValue")] - [Arguments("SingleValue")] - [Arguments("BooleanValue")] - [Arguments("Bytes")] - [Arguments("SBytes")] - [Arguments("Int24")] - [Arguments("UInt24")] - [Arguments("UInt128")] - [Arguments("Chars")] - [Arguments("boolean")] - [Arguments("bytes")] - [Arguments("sbytes")] - [Arguments("character")] - [Arguments("decimals")] - [Arguments("doubleValue")] - [Arguments("floating")] - [Arguments("integer")] - [Arguments("unsigned")] - [Arguments("longValue")] - [Arguments("ulongValue")] - [Arguments("shortValue")] - public void IsValueType_Returns_False_For_Reference_Types(string mappedType) - { - var method = typeof(CustomCSharpTypeResolver).GetMethod( - "IsValueType", - BindingFlags.NonPublic | BindingFlags.Static); - - var result = (bool?)method?.Invoke(null, [mappedType]); - - result.Should().BeFalse(); - } } diff --git a/src/Refitter.Tests/FormParameterExtractorTests.cs b/src/Refitter.Tests/FormParameterExtractorTests.cs deleted file mode 100644 index 6e047eba..00000000 --- a/src/Refitter.Tests/FormParameterExtractorTests.cs +++ /dev/null @@ -1,251 +0,0 @@ -using System.Runtime.CompilerServices; -using FluentAssertions; -using NJsonSchema; -using NSwag; -using NSwag.CodeGeneration.CSharp.Models; -using Refitter.Core; -using TUnit.Core; - -namespace Refitter.Tests; - -public class FormParameterExtractorTests -{ - [Test] - public void Extract_Returns_Empty_When_No_FormData_Parameters() - { - var extractor = new FormParameterExtractor(); - var operationModel = CreateEmptyOperationModel(); - var operation = new OpenApiOperation(); - - var result = extractor.Extract(operationModel, operation, new RefitGeneratorSettings()); - result.Should().BeEmpty(); - } - - [Test] - public void Extract_Returns_FormData_Parameters_With_Correct_Format() - { - var extractor = new FormParameterExtractor(); - var parameter = CreateFormDataParameterModel("field1", "field1", "string"); - var operationModel = CreateOperationModel(parameter); - var operation = new OpenApiOperation(); - - var result = extractor.Extract(operationModel, operation, new RefitGeneratorSettings()).ToList(); - result.Should().ContainSingle().Which.Should().Be("string field1"); - } - - [Test] - public void Extract_Handles_Alias_For_Different_Variable_Name() - { - var extractor = new FormParameterExtractor(); - var parameter = CreateFormDataParameterModel("field-name", "field_name", "string"); - var operationModel = CreateOperationModel(parameter); - var operation = new OpenApiOperation(); - - var result = extractor.Extract(operationModel, operation, new RefitGeneratorSettings()).ToList(); - result.Should().ContainSingle().Which.Should().Be("[AliasAs(\"field-name\")] string field_name"); - } - - [Test] - public void Extract_Deduplicates_FormData_Parameters_By_Variable_Name() - { - var extractor = new FormParameterExtractor(); - var parameter1 = CreateFormDataParameterModel("field1", "field1", "string"); - var parameter2 = CreateFormDataParameterModel("field1", "field1", "int"); - var operationModel = CreateOperationModel(parameter1, parameter2); - var operation = new OpenApiOperation(); - - var result = extractor.Extract(operationModel, operation, new RefitGeneratorSettings()).ToList(); - result.Should().ContainSingle(); - } - - [Test] - public void Extract_Extracts_Multipart_Text_Fields_From_RequestBody() - { - var extractor = new FormParameterExtractor(); - var operationModel = CreateEmptyOperationModel(); - var operation = new OpenApiOperation - { - RequestBody = new OpenApiRequestBody() - }; - var schema = new JsonSchema(); - schema.Properties["title"] = new JsonSchemaProperty - { - Type = JsonObjectType.String - }; - schema.Properties["description"] = new JsonSchemaProperty - { - Type = JsonObjectType.String - }; - operation.RequestBody.Content["multipart/form-data"] = new OpenApiMediaType - { - Schema = schema - }; - - var result = extractor.Extract(operationModel, operation, new RefitGeneratorSettings()).ToList(); - - result.Should().HaveCount(2); - result.Should().Contain("string title"); - result.Should().Contain("string description"); - } - - [Test] - public void Extract_Skips_Binary_Fields_From_Multipart_RequestBody() - { - var extractor = new FormParameterExtractor(); - var operationModel = CreateEmptyOperationModel(); - var operation = new OpenApiOperation - { - RequestBody = new OpenApiRequestBody() - }; - var schema = new JsonSchema(); - schema.Properties["avatar"] = new JsonSchemaProperty - { - Type = JsonObjectType.String, - Format = "binary" - }; - schema.Properties["title"] = new JsonSchemaProperty - { - Type = JsonObjectType.String - }; - operation.RequestBody.Content["multipart/form-data"] = new OpenApiMediaType - { - Schema = schema - }; - - var result = extractor.Extract(operationModel, operation, new RefitGeneratorSettings()).ToList(); - - result.Should().ContainSingle().Which.Should().Be("string title"); - } - - [Test] - public void Extract_Skips_Array_Of_Binary_From_Multipart_RequestBody() - { - var extractor = new FormParameterExtractor(); - var operationModel = CreateEmptyOperationModel(); - var operation = new OpenApiOperation - { - RequestBody = new OpenApiRequestBody() - }; - var schema = new JsonSchema(); - schema.Properties["files"] = new JsonSchemaProperty - { - Type = JsonObjectType.Array, - Item = new JsonSchema - { - Type = JsonObjectType.String, - Format = "binary" - } - }; - operation.RequestBody.Content["multipart/form-data"] = new OpenApiMediaType - { - Schema = schema - }; - - var result = extractor.Extract(operationModel, operation, new RefitGeneratorSettings()).ToList(); - result.Should().BeEmpty(); - } - - [Test] - public void Extract_Handles_Missing_RequestBody_Schema() - { - var extractor = new FormParameterExtractor(); - var operationModel = CreateEmptyOperationModel(); - var operation = new OpenApiOperation - { - RequestBody = new OpenApiRequestBody() - }; - operation.RequestBody.Content["multipart/form-data"] = new OpenApiMediaType(); - - var result = extractor.Extract(operationModel, operation, new RefitGeneratorSettings()).ToList(); - result.Should().BeEmpty(); - } - - [Test] - public void Extract_Handles_Null_RequestBody_Properties() - { - var extractor = new FormParameterExtractor(); - var operationModel = CreateEmptyOperationModel(); - var operation = new OpenApiOperation - { - RequestBody = new OpenApiRequestBody() - }; - var schema = new JsonSchema(); - operation.RequestBody.Content["multipart/form-data"] = new OpenApiMediaType - { - Schema = schema - }; - - var result = extractor.Extract(operationModel, operation, new RefitGeneratorSettings()).ToList(); - result.Should().BeEmpty(); - } - - [Test] - public void Extract_Skips_When_No_Multipart_Content() - { - var extractor = new FormParameterExtractor(); - var operationModel = CreateEmptyOperationModel(); - var operation = new OpenApiOperation - { - RequestBody = new OpenApiRequestBody() - }; - operation.RequestBody.Content["application/json"] = new OpenApiMediaType(); - - var result = extractor.Extract(operationModel, operation, new RefitGeneratorSettings()).ToList(); - result.Should().BeEmpty(); - } - - private static CSharpOperationModel CreateEmptyOperationModel() - { - var operationModel = (CSharpOperationModel)RuntimeHelpers.GetUninitializedObject(typeof(CSharpOperationModel)); - var baseType = typeof(CSharpOperationModel).BaseType!; - - baseType - .GetField("k__BackingField", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)! - .SetValue(operationModel, new List()); - - return operationModel; - } - - private static CSharpOperationModel CreateOperationModel(params CSharpParameterModel[] parameters) - { - var operationModel = (CSharpOperationModel)RuntimeHelpers.GetUninitializedObject(typeof(CSharpOperationModel)); - var baseType = typeof(CSharpOperationModel).BaseType!; - - baseType - .GetField("k__BackingField", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)! - .SetValue(operationModel, parameters.ToList()); - - return operationModel; - } - - private static CSharpParameterModel CreateFormDataParameterModel( - string name, - string variableName, - string type = "string") - { - var parameterModel = (CSharpParameterModel)RuntimeHelpers.GetUninitializedObject(typeof(CSharpParameterModel)); - var baseType = typeof(CSharpParameterModel).BaseType!; - - baseType - .GetField("k__BackingField", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)! - .SetValue(parameterModel, type); - baseType - .GetField("k__BackingField", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)! - .SetValue(parameterModel, name); - baseType - .GetField("k__BackingField", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)! - .SetValue(parameterModel, variableName); - baseType - .GetField("_parameter", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)! - .SetValue( - parameterModel, - new OpenApiParameter - { - Name = name, - Kind = OpenApiParameterKind.FormData, - Schema = new JsonSchema() - }); - - return parameterModel; - } -} diff --git a/src/Refitter.Tests/OpenApi/OpenApiDocumentFactoryMergeTests.cs b/src/Refitter.Tests/OpenApi/OpenApiDocumentFactoryMergeTests.cs index 83aca3d5..6e0cdf3f 100644 --- a/src/Refitter.Tests/OpenApi/OpenApiDocumentFactoryMergeTests.cs +++ b/src/Refitter.Tests/OpenApi/OpenApiDocumentFactoryMergeTests.cs @@ -1,4 +1,3 @@ -using System.Reflection; using FluentAssertions; using Newtonsoft.Json.Linq; using NJsonSchema; @@ -634,49 +633,6 @@ public async Task Merge_With_Equivalent_Recursive_Schema_Duplicate_Ignores_Dupli secondDocument.Paths.Should().ContainSingle().Which.Key.Should().Be("/linked-list"); } - [Test] - public async Task Merge_With_Equivalent_Swagger2_Definition_Duplicate_Ignores_Duplicate() - { - var target = new Dictionary - { - ["ProblemDetails"] = await JsonSchema.FromJsonAsync(""" - { - "type": "object", - "required": [ "title" ], - "properties": { - "title": { - "type": "string" - }, - "status": { - "type": "integer", - "format": "int32" - } - } - } - """) - }; - var incoming = await JsonSchema.FromJsonAsync(""" - { - "properties": { - "status": { - "format": "int32", - "type": "integer" - }, - "title": { - "type": "string" - } - }, - "required": [ "title" ], - "type": "object" - } - """); - - InvokeMergeIfMissingOrThrowOnConflict(target, "ProblemDetails", incoming, "definition"); - - target.Should().ContainSingle().Which.Key.Should().Be("ProblemDetails"); - target["ProblemDetails"].Properties.Should().ContainKeys("title", "status"); - } - [Test] public async Task Merge_With_Collisions_Throws_And_Does_Not_Mutate_Inputs() { @@ -848,45 +804,6 @@ public async Task Merge_With_Schema_Collision_Throws_And_Does_Not_Mutate_Inputs( secondDocument.Components.Schemas["Shared"].Properties.Should().ContainKey("email"); } - [Test] - public void Merge_With_Swagger2_Definition_Collision_Throws_And_Does_Not_Mutate_Dictionaries() - { - var target = new Dictionary - { - ["Shared"] = new() - { - Type = JsonObjectType.Object, - Properties = - { - ["id"] = new JsonSchemaProperty - { - Type = JsonObjectType.String - } - } - } - }; - var incoming = new JsonSchema - { - Type = JsonObjectType.Object, - Properties = - { - ["total"] = new JsonSchemaProperty - { - Type = JsonObjectType.Integer - } - } - }; - - var act = () => InvokeMergeIfMissingOrThrowOnConflict(target, "Shared", incoming, "definition"); - - act.Should().Throw() - .WithMessage("*duplicate definition 'Shared'*"); - - target.Should().ContainSingle().Which.Key.Should().Be("Shared"); - target["Shared"].Properties.Should().ContainKey("id"); - incoming.Properties.Should().ContainKey("total"); - } - [Test] public async Task Merge_With_Security_Scheme_Collision_Throws_And_Does_Not_Mutate_Inputs() { @@ -964,83 +881,6 @@ public async Task Merge_With_Security_Scheme_Collision_Throws_And_Does_Not_Mutat secondDocument.SecurityDefinitions["ApiKey"].Name.Should().Be("X-Second-Key"); } - [Test] - public async Task Merge_With_Equivalent_Composed_Schema_Duplicate_Ignores_Duplicate() - { - const string schemaJson = """ - { - "type": "object", - "required": [ "child", "kind" ], - "properties": { - "kind": { - "type": "string", - "enum": [ "basic", "advanced" ] - }, - "child": { - "$ref": "#/definitions/NamedChild" - } - }, - "allOf": [ - { - "$ref": "#/definitions/BasePart" - } - ], - "oneOf": [ - { - "$ref": "#/definitions/NamedChild" - }, - { - "type": "string" - } - ], - "anyOf": [ - { - "type": "integer" - }, - { - "$ref": "#/definitions/BasePart" - } - ], - "x-meta": { - "alpha": 1, - "zeta": null - }, - "x-null": null, - "definitions": { - "NamedChild": { - "type": "object", - "required": [ "id" ], - "properties": { - "id": { - "type": "string" - } - } - }, - "BasePart": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean" - } - } - } - } - } - """; - var target = new Dictionary - { - ["Shared"] = await JsonSchema.FromJsonAsync(schemaJson) - }; - var incoming = await JsonSchema.FromJsonAsync(schemaJson); - - InvokeMergeIfMissingOrThrowOnConflict(target, "Shared", incoming, "schema"); - - target.Should().ContainSingle().Which.Key.Should().Be("Shared"); - target["Shared"].RequiredProperties.Should().BeEquivalentTo(["kind", "child"]); - target["Shared"].Properties.Should().ContainKeys("kind", "child"); - target["Shared"].Properties["kind"].Enumeration.Should().BeEquivalentTo(["basic", "advanced"]); - } - [Test] public async Task Merge_With_Base_Tags_Null_And_Swagger2_Only_Incoming_Document_Merges_Without_Creating_Tags() { @@ -1621,26 +1461,6 @@ private static Task ParseJsonDocument(string json) private static OpenApiDocument InvokeMerge(params OpenApiDocument[] documents) => Merger.Merge(documents); - private static void InvokeMergeIfMissingOrThrowOnConflict( - IDictionary target, - string key, - TValue value, - string itemType) - { - var mergeMethod = typeof(DocumentMerger) - .GetMethod("MergeIfMissingOrThrowOnConflict", BindingFlags.NonPublic | BindingFlags.Instance)! - .MakeGenericMethod(typeof(TValue)); - - try - { - mergeMethod.Invoke(Merger, [target, key, value!, itemType]); - } - catch (TargetInvocationException exception) when (exception.InnerException != null) - { - throw exception.InnerException; - } - } - private static bool InvokeAreEquivalent(TValue existingValue, TValue incomingValue) => Comparer.AreEquivalent(existingValue, incomingValue); diff --git a/src/Refitter.Tests/Parameters/ParameterExtractorPrivateCoverageTests.cs b/src/Refitter.Tests/Parameters/ParameterExtractorPrivateCoverageTests.cs index 384ad90c..c11d3c0a 100644 --- a/src/Refitter.Tests/Parameters/ParameterExtractorPrivateCoverageTests.cs +++ b/src/Refitter.Tests/Parameters/ParameterExtractorPrivateCoverageTests.cs @@ -1,11 +1,7 @@ -using System.Reflection; -using System.Runtime.CompilerServices; using System.Text; using FluentAssertions; using NJsonSchema; -using NSwag; using NSwag.CodeGeneration.CSharp.Models; -using NSwag.CodeGeneration.Models; using Refitter.Core; namespace Refitter.Tests.Parameters; @@ -92,32 +88,6 @@ public void IsNumericType_Returns_False_For_Non_Numeric_Types(string numericType result.Should().BeFalse(); } - [Test] - public void GetAliasAsAttribute_CSharpParameterModel_Returns_Expected_Value() - { - var unchangedName = CreateParameterModel("id", "id"); - var aliasedName = CreateParameterModel("user-id", "userId"); - - var unchangedResult = ParameterShared.GetAliasAsAttribute(unchangedName); - var aliasedResult = ParameterShared.GetAliasAsAttribute(aliasedName); - - unchangedResult.Should().BeEmpty(); - aliasedResult.Should().Be("AliasAs(\"user-id\")"); - } - - [Test] - public void GetAliasAsAttribute_CSharpParameterModel_Escapes_Special_Characters() - { - var withQuote = CreateParameterModel("user\"id", "userQuoteid"); - var withBackslash = CreateParameterModel("user\\id", "userBackslashid"); - - var quoteResult = ParameterShared.GetAliasAsAttribute(withQuote); - var backslashResult = ParameterShared.GetAliasAsAttribute(withBackslash); - - quoteResult.Should().Be("AliasAs(\"user\\\"id\")"); - backslashResult.Should().Be("AliasAs(\"user\\\\id\")"); - } - [Test] public void GetAliasAsAttribute_StringOverload_Escapes_Special_Characters() { @@ -184,77 +154,6 @@ public void GetArrayType_Returns_Object_Array_When_Item_Is_Missing() result.Should().Be("object[]"); } - [Test] - public void ParameterAggregator_ExtractParameters_Adds_Multipart_Text_Fields_When_NSwag_Parameters_Are_Empty() - { - var operationModel = CreateOperationModel(); - var operation = new OpenApiOperation - { - RequestBody = new OpenApiRequestBody() - }; - var schema = new JsonSchema(); - schema.Properties["title"] = new JsonSchemaProperty - { - Type = JsonObjectType.String - }; - operation.RequestBody.Content["multipart/form-data"] = new OpenApiMediaType - { - Schema = schema - }; - - var aggregator = new ParameterAggregator(); - var result = aggregator.ExtractParameters( - operationModel, - operation, - new RefitGeneratorSettings(), - "QueryParams", - out var dynamicQuerystringParameters); - - result.Should().ContainSingle().Which.Should().Be("string title"); - dynamicQuerystringParameters.Should().Be(string.Empty); - } - - [Test] - public void ParameterAggregator_Does_Not_Mutate_Query_Parameter_Collection_When_Generating_Dynamic_Querystring_Wrapper() - { - var firstParameter = CreateParameterModel( - "query", - "query", - parameter: new OpenApiParameter - { - Name = "query", - Kind = OpenApiParameterKind.Query, - IsRequired = true, - Schema = new JsonSchema { Type = JsonObjectType.String } - }); - var secondParameter = CreateParameterModel( - "page", - "page", - type: "int?", - parameter: new OpenApiParameter - { - Name = "page", - Kind = OpenApiParameterKind.Query, - Schema = new JsonSchema { Type = JsonObjectType.Integer } - }); - var operationModel = CreateOperationModel(firstParameter, secondParameter); - var operation = new OpenApiOperation(); - - var aggregator = new ParameterAggregator(); - var parameters = aggregator.ExtractParameters( - operationModel, - operation, - new RefitGeneratorSettings { UseDynamicQuerystringParameters = true }, - "SearchQueryParams", - out var dynamicQuerystringParameters) - .ToList(); - - parameters.Should().ContainSingle().Which.Should().Be("[Query] SearchQueryParams queryParams"); - dynamicQuerystringParameters.Should().Contain("class SearchQueryParams"); - operationModel.Parameters.Should().HaveCount(2); - operationModel.Parameters.Should().ContainInOrder(firstParameter, secondParameter); - } - [Test] public void ReplaceUnsafeCharacters_Delegates_To_ParameterShared() { @@ -281,30 +180,6 @@ public void FormatDefaultValue_Adds_PointZero_For_Double_Integer_Values() result.Should().Be("42.0"); } - [Test] - public void GetBodyAttribute_Returns_Body_For_String_Parameter() - { - var param = CreateParameterModel("body", "body", "string"); - var result = ParameterShared.GetBodyAttribute(param, new RefitGeneratorSettings()); - result.Should().Be("Body"); - } - - [Test] - public void GetBodyAttribute_Returns_Serialized_For_Object_Parameter() - { - var param = CreateParameterModel("body", "body", "object"); - var result = ParameterShared.GetBodyAttribute(param, new RefitGeneratorSettings()); - result.Should().Be("Body(BodySerializationMethod.Serialized)"); - } - - [Test] - public void GetQueryAttribute_Returns_Query_Attribute() - { - var param = CreateParameterModel("q", "q"); - var result = ParameterShared.GetQueryAttribute(param, new RefitGeneratorSettings()); - result.Should().NotBeNull(); - } - [Test] public void JoinAttributes_Returns_Empty_For_Empty_Input() { @@ -326,22 +201,6 @@ public void JoinAttributes_Returns_Single_Attribute() result.Should().Be("[AliasAs(\"name\")] "); } - [Test] - public void GetParameterType_Uses_CSharpProvider_Model_Type() - { - var param = CreateParameterModel("param1", "param1", "int"); - var result = ParameterShared.GetParameterType(param, new RefitGeneratorSettings()); - result.Should().Be("int"); - } - - [Test] - public void GetQueryParameterType_Returns_Query_Parameter_Type() - { - var param = CreateParameterModel("q", "q", "string"); - var result = ParameterShared.GetQueryParameterType(param, new RefitGeneratorSettings()); - result.Should().NotBeNull(); - } - [Test] public void FindSupportedType_Passes_Through_Type_Name() { @@ -363,14 +222,6 @@ public void ConvertToVariableName_Returns_Value_For_Empty_String() result.Should().Be("value"); } - [Test] - public void GetVariableName_Returns_VariableName_From_Model() - { - var param = CreateParameterModel("param-name", "paramName"); - var result = ParameterShared.GetVariableName(param); - result.Should().Be("paramName"); - } - [Test] public void AppendXmlDocComment_Extends_CodeBuilder() { @@ -378,178 +229,4 @@ public void AppendXmlDocComment_Extends_CodeBuilder() ParameterShared.AppendXmlDocComment("Some description", codeBuilder); codeBuilder.ToString().Should().Contain("Some description"); } - - [Test] - public void QueryParameterExtractor_Returns_Empty_When_No_Query_Parameters() - { - var operationModel = CreateOperationModel(); - var extractor = new QueryParameterExtractor(); - var result = extractor.Extract(operationModel, new OpenApiOperation(), new RefitGeneratorSettings()).ToList(); - - result.Should().BeEmpty(); - extractor.DynamicQuerystringCode.Should().Be(string.Empty); - } - - [Test] - public void QueryParameterExtractor_With_Dynamic_Enabled_But_Single_Query_Param_Falls_Back_To_Simple() - { - var param = CreateParameterModel("query", "query", "string", - parameter: new OpenApiParameter - { - Name = "query", - Kind = OpenApiParameterKind.Query, - Schema = new JsonSchema { Type = JsonObjectType.String } - }); - var operationModel = CreateOperationModel(param); - var settings = new RefitGeneratorSettings { UseDynamicQuerystringParameters = true }; - - var extractor = new QueryParameterExtractor - { - DynamicQuerystringParameterType = "QueryParams" - }; - var result = extractor.Extract(operationModel, new OpenApiOperation(), settings).ToList(); - - result.Should().ContainSingle().Which.Should().Contain("query"); - extractor.DynamicQuerystringCode.Should().Be(string.Empty); - } - - [Test] - public void QueryParameterExtractor_With_No_Dynamic_Returns_Simple_Extraction() - { - var param = CreateParameterModel("query", "query", "string", - parameter: new OpenApiParameter - { - Name = "query", - Kind = OpenApiParameterKind.Query, - Schema = new JsonSchema { Type = JsonObjectType.String } - }); - var operationModel = CreateOperationModel(param); - var settings = new RefitGeneratorSettings(); - - var extractor = new QueryParameterExtractor(); - var result = extractor.Extract(operationModel, new OpenApiOperation(), settings).ToList(); - - result.Should().ContainSingle().Which.Should().Contain("query"); - extractor.DynamicQuerystringCode.Should().Be(string.Empty); - } - - [Test] - public void QueryParameterExtractor_With_Dynamic_And_All_Nullable() - { - var firstParameter = CreateParameterModel( - "query", - "query", - type: "string?", - parameter: new OpenApiParameter - { - Name = "query", - Kind = OpenApiParameterKind.Query, - Schema = new JsonSchema { Type = JsonObjectType.String } - }); - var secondParameter = CreateParameterModel( - "page", - "page", - type: "int?", - parameter: new OpenApiParameter - { - Name = "page", - Kind = OpenApiParameterKind.Query, - Schema = new JsonSchema { Type = JsonObjectType.Integer } - }); - var operationModel = CreateOperationModel(firstParameter, secondParameter); - - var extractor = new QueryParameterExtractor - { - DynamicQuerystringParameterType = "SearchQueryParams" - }; - var result = extractor.Extract( - operationModel, - new OpenApiOperation(), - new RefitGeneratorSettings { UseDynamicQuerystringParameters = true }).ToList(); - - result.Should().ContainSingle().Which.Should().Be("[Query] SearchQueryParams? queryParams"); - extractor.DynamicQuerystringCode.Should().Contain("class SearchQueryParams"); - } - - [Test] - public void QueryParameterExtractor_With_Dynamic_And_Not_All_Nullable() - { - var firstParameter = CreateParameterModel( - "query", - "query", - type: "string", - parameter: new OpenApiParameter - { - Name = "query", - Kind = OpenApiParameterKind.Query, - Schema = new JsonSchema { Type = JsonObjectType.String } - }); - var secondParameter = CreateParameterModel( - "page", - "page", - type: "int", - parameter: new OpenApiParameter - { - Name = "page", - Kind = OpenApiParameterKind.Query, - Schema = new JsonSchema { Type = JsonObjectType.Integer } - }); - var operationModel = CreateOperationModel(firstParameter, secondParameter); - - var extractor = new QueryParameterExtractor - { - DynamicQuerystringParameterType = "SearchQueryParams" - }; - var result = extractor.Extract( - operationModel, - new OpenApiOperation(), - new RefitGeneratorSettings { UseDynamicQuerystringParameters = true }).ToList(); - - result.Should().ContainSingle().Which.Should().Be("[Query] SearchQueryParams queryParams"); - extractor.DynamicQuerystringCode.Should().Contain("class SearchQueryParams"); - } - - private static CSharpParameterModel CreateParameterModel( - string name, - string variableName, - string type = "string", - OpenApiParameter? parameter = null) - { - var parameterModel = (CSharpParameterModel)RuntimeHelpers.GetUninitializedObject(typeof(CSharpParameterModel)); - var baseType = typeof(CSharpParameterModel).BaseType!; - - baseType - .GetField("k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic)! - .SetValue(parameterModel, type); - baseType - .GetField("k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic)! - .SetValue(parameterModel, name); - baseType - .GetField("k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic)! - .SetValue(parameterModel, variableName); - baseType - .GetField("_parameter", BindingFlags.Instance | BindingFlags.NonPublic)! - .SetValue( - parameterModel, - parameter ?? new OpenApiParameter - { - Name = name, - Kind = OpenApiParameterKind.Query, - Schema = new JsonSchema() - }); - - return parameterModel; - } - - private static CSharpOperationModel CreateOperationModel(params CSharpParameterModel[] parameters) - { - var operationModel = (CSharpOperationModel)RuntimeHelpers.GetUninitializedObject(typeof(CSharpOperationModel)); - var baseType = typeof(CSharpOperationModel).BaseType!; - - baseType - .GetField("k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic)! - .SetValue(operationModel, parameters.ToList()); - - return operationModel; - } } diff --git a/src/Refitter.Tests/Scenarios/IdentifierCorrectnessTests.cs b/src/Refitter.Tests/Scenarios/IdentifierCorrectnessTests.cs index d4e8f478..05f5749c 100644 --- a/src/Refitter.Tests/Scenarios/IdentifierCorrectnessTests.cs +++ b/src/Refitter.Tests/Scenarios/IdentifierCorrectnessTests.cs @@ -1,9 +1,4 @@ -using System.Reflection; -using System.Runtime.CompilerServices; using FluentAssertions; -using NJsonSchema; -using NSwag; -using NSwag.CodeGeneration.CSharp.Models; using Refitter.Core; using Refitter.Tests.Build; using Refitter.Tests.TestUtilities; @@ -645,42 +640,116 @@ public async Task Generated_Code_With_Generic_Parameters_Compiles_Swagger2() #region Optional Parameter Identifier Reordering + private const string SpecWithUnsanitizedParameterName = """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "1.0.0" + }, + "paths": { + "/test": { + "get": { + "operationId": "TestMethod", + "parameters": [ + { + "name": "filter#tag", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "abc" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + [Test] + public async Task Optional_Parameter_With_Unsanitized_Name_Falls_Back_To_Sanitized_Variable_Name() + { + var generatedCode = await GenerateCode( + SpecWithUnsanitizedParameterName, + optionalParameters: true); + + generatedCode.Should().Contain("filter_tag"); + generatedCode.Should().Contain("\"abc\""); + } + [Test] - public void GetDefaultValueForParameter_Uses_Sanitized_Variable_Name_Fallback() + public async Task Generated_Code_With_Unsanitized_Parameter_Name_Compiles() { - var openApiParameter = new OpenApiParameter + var generatedCode = await GenerateCode( + SpecWithUnsanitizedParameterName, + optionalParameters: true); + + BuildHelper.BuildCSharp(generatedCode).Should().BeTrue(); + } + + #endregion + + #region Optional Parameter Identifier Reordering (Swagger 2.0) + + private const string SpecWithUnsanitizedParameterName_Swagger2 = """ { - Name = "class", - Kind = OpenApiParameterKind.Query, - IsRequired = false, - Schema = new JsonSchema - { - Type = JsonObjectType.String, - Default = "abc" + "swagger": "2.0", + "info": { + "title": "Test API", + "version": "1.0.0" + }, + "host": "localhost", + "basePath": "/", + "paths": { + "/test": { + "get": { + "operationId": "TestMethod", + "parameters": [ + { + "name": "filter#tag", + "in": "query", + "required": false, + "type": "string", + "default": "abc" + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } } - }; - - var parameterModel = (CSharpParameterModel)RuntimeHelpers.GetUninitializedObject(typeof(CSharpParameterModel)); - var baseType = typeof(CSharpParameterModel).BaseType!; - - baseType - .GetField("k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic)! - .SetValue(parameterModel, "string"); - baseType - .GetField("k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic)! - .SetValue(parameterModel, "class"); - baseType - .GetField("k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic)! - .SetValue(parameterModel, "class"); - baseType - .GetField("_parameter", BindingFlags.Instance | BindingFlags.NonPublic)! - .SetValue(parameterModel, openApiParameter); - - var result = ParameterShared.GetDefaultValueForParameter( - "string? @class", - new List { parameterModel }); - - result.Should().Be("\"abc\""); + } + } + """; + + [Test] + public async Task Optional_Parameter_With_Unsanitized_Name_Falls_Back_To_Sanitized_Variable_Name_Swagger2() + { + var generatedCode = await GenerateCode( + SpecWithUnsanitizedParameterName_Swagger2, + optionalParameters: true); + + generatedCode.Should().Contain("filter_tag"); + generatedCode.Should().Contain("\"abc\""); + } + + [Test] + public async Task Generated_Code_With_Unsanitized_Parameter_Name_Compiles_Swagger2() + { + var generatedCode = await GenerateCode( + SpecWithUnsanitizedParameterName_Swagger2, + optionalParameters: true); + + BuildHelper.BuildCSharp(generatedCode).Should().BeTrue(); } #endregion