diff --git a/src/Refitter.Core/ParameterExtractor.cs b/src/Refitter.Core/ParameterExtractor.cs index 003d0ef9..2e2310db 100644 --- a/src/Refitter.Core/ParameterExtractor.cs +++ b/src/Refitter.Core/ParameterExtractor.cs @@ -145,9 +145,11 @@ private static string GetDefaultValueForParameter(string parameterString, IColle var variableName = parts[parts.Length - 1].TrimEnd(';', ','); var parameterModel = parameterModels.FirstOrDefault(p => p.VariableName == variableName); - return parameterModel?.Schema?.Default != null - ? FormatDefaultValue(parameterModel.Schema.Default, parameterModel.Type) - : "default"; + if (parameterModel?.Schema?.Default != null && !string.IsNullOrEmpty(parameterModel.Type)) + { + return FormatDefaultValue(parameterModel.Schema.Default, parameterModel.Type); + } + return "default"; } private static string FormatDefaultValue(object? defaultValue, string parameterType) @@ -160,12 +162,82 @@ private static string FormatDefaultValue(object? defaultValue, string parameterT return type switch { "bool" => defaultValue.ToString()?.ToLowerInvariant() ?? "default", - "string" => $"\"{defaultValue}\"", - _ when IsNumericType(type) => defaultValue.ToString() ?? "default", + "string" => $"\"{EscapeString(defaultValue.ToString() ?? string.Empty)}\"", + _ when IsNumericType(type) => FormatNumericValue(defaultValue, type), _ => "default" }; } + private static string EscapeString(string value) + { + var sb = new StringBuilder(value.Length + 10); + foreach (var c in value) + { + switch (c) + { + case '\\': + sb.Append("\\\\"); + break; + case '"': + sb.Append("\\\""); + break; + case '\n': + sb.Append("\\n"); + break; + case '\r': + sb.Append("\\r"); + break; + case '\t': + sb.Append("\\t"); + break; + case '\f': + sb.Append("\\f"); + break; + case '\v': + sb.Append("\\v"); + break; + case '\b': + sb.Append("\\b"); + break; + case '\0': + sb.Append("\\0"); + break; + default: + sb.Append(c); + break; + } + } + return sb.ToString(); + } + + private static string FormatNumericValue(object defaultValue, string type) + { + var numericString = defaultValue is IFormattable formattable + ? formattable.ToString(null, CultureInfo.InvariantCulture) + : (defaultValue.ToString() ?? "default"); + + return type switch + { + "float" or "Single" => $"{numericString}f", + "decimal" or "Decimal" => $"{numericString}m", + "double" or "Double" => FormatDoubleLiteral(numericString), + "long" or "Int64" => $"{numericString}L", + "ulong" or "UInt64" => $"{numericString}UL", + "uint" or "UInt32" => $"{numericString}U", + _ => numericString + }; + } + + private static string FormatDoubleLiteral(string numericString) + { + // If the string already contains a decimal point or exponent, return as-is + if (numericString.Contains('.') || numericString.Contains('e') || numericString.Contains('E')) + return numericString; + + // Otherwise, append .0 to make it a double literal + return numericString + ".0"; + } + private static bool IsNumericType(string type) { return type is "int" or "Int32" or "long" or "Int64" or "short" or "Int16" diff --git a/src/Refitter.Tests/Examples/DynamicQueryStringParametersEdgeCasesTests.cs b/src/Refitter.Tests/Examples/DynamicQueryStringParametersEdgeCasesTests.cs new file mode 100644 index 00000000..7cb2133b --- /dev/null +++ b/src/Refitter.Tests/Examples/DynamicQueryStringParametersEdgeCasesTests.cs @@ -0,0 +1,590 @@ +using FluentAssertions; +using Refitter.Core; +using Refitter.Tests.Build; +using Refitter.Tests.TestUtilities; +using Xunit; + +namespace Refitter.Tests.Examples; + +public class DynamicQueryStringParametersEdgeCasesTests +{ + [Fact] + public async Task Dynamic_QueryString_With_Escaped_String_Defaults() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestEscaping", + "parameters": [ + { + "name": "requiredParam", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "quotedString", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "value with \"quotes\"" + } + }, + { + "name": "backslashString", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "path\\to\\file" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + + // Verify strings are properly escaped in dynamic query string class + generatedCode.Should().Contain("string? QuotedString { get; set; } = \"value with \\\"quotes\\\"\""); + generatedCode.Should().Contain("string? BackslashString { get; set; } = \"path\\\\to\\\\file\""); + } + + [Fact] + public async Task Dynamic_QueryString_With_All_Escape_Characters() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestAllEscapes", + "parameters": [ + { + "name": "requiredParam", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "newlineString", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "line1\nline2" + } + }, + { + "name": "carriageReturnString", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "line1\rline2" + } + }, + { + "name": "tabString", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "col1\tcol2" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + + // Verify all special characters are properly escaped + generatedCode.Should().Contain("string? NewlineString { get; set; } = \"line1\\nline2\""); + generatedCode.Should().Contain("string? CarriageReturnString { get; set; } = \"line1\\rline2\""); + generatedCode.Should().Contain("string? TabString { get; set; } = \"col1\\tcol2\""); + } + + [Fact] + public async Task Dynamic_QueryString_With_Float_And_Decimal_Defaults() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestNumeric", + "parameters": [ + { + "name": "requiredParam", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "floatValue", + "in": "query", + "required": false, + "schema": { + "type": "number", + "format": "float", + "default": 1.5 + } + }, + { + "name": "decimalValue", + "in": "query", + "required": false, + "schema": { + "type": "number", + "format": "decimal", + "default": 99.99 + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + + // Verify numeric types have proper suffixes + generatedCode.Should().Contain("float? FloatValue { get; set; } = 1.5f"); + generatedCode.Should().Contain("decimal? DecimalValue { get; set; } = 99.99m"); + } + + [Fact] + public async Task Dynamic_QueryString_With_Boolean_Defaults() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestBool", + "parameters": [ + { + "name": "requiredParam", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "isEnabled", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "isDisabled", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + + // Verify booleans are lowercase + generatedCode.Should().Contain("bool? IsEnabled { get; set; } = true"); + generatedCode.Should().Contain("bool? IsDisabled { get; set; } = false"); + } + + [Fact] + public async Task Dynamic_QueryString_With_Integer_Defaults() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestInt", + "parameters": [ + { + "name": "requiredParam", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "intValue", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 42 + } + }, + { + "name": "longValue", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "default": 9999 + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + + // Verify integers don't have suffixes + generatedCode.Should().Contain("int? IntValue { get; set; } = 42"); + generatedCode.Should().Contain("long? LongValue { get; set; } = 9999"); + } + + [Fact] + public async Task Dynamic_QueryString_Generated_Code_Should_Build() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestBuild", + "parameters": [ + { + "name": "requiredParam", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "escapedString", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "value with \"quotes\" and \\backslashes\\" + } + }, + { + "name": "floatValue", + "in": "query", + "required": false, + "schema": { + "type": "number", + "format": "float", + "default": 1.5 + } + }, + { + "name": "decimalValue", + "in": "query", + "required": false, + "schema": { + "type": "number", + "format": "decimal", + "default": 99.99 + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + BuildHelper.BuildCSharp(generatedCode).Should().BeTrue(); + } + + [Fact] + public async Task Dynamic_QueryString_With_Mixed_Escape_Characters() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestMixedEscapes", + "parameters": [ + { + "name": "requiredParam", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "complexString", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "path\\to\\file with \"quotes\"\nand newlines" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + + // Verify mixed escape sequences + generatedCode.Should().Contain("string? ComplexString { get; set; } = \"path\\\\to\\\\file with \\\"quotes\\\"\\nand newlines\""); + } + + [Fact] + public async Task Dynamic_QueryString_With_Long_And_ULong_Defaults() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestLongTypes", + "parameters": [ + { + "name": "requiredParam", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "longValue", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "default": 3000000000 + } + }, + { + "name": "ulongValue", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "uint64", + "default": 5000000000 + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + + // Verify numeric type suffixes + generatedCode.Should().Contain("long? LongValue { get; set; } = 3000000000L"); + generatedCode.Should().Contain("ulong? UlongValue { get; set; } = 5000000000UL"); + } + + [Fact] + public async Task Dynamic_QueryString_With_Double_Integer_Value() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestDouble", + "parameters": [ + { + "name": "requiredParam", + "in": "query", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "doubleFloatValue", + "in": "query", + "required": false, + "schema": { + "type": "number", + "format": "double", + "default": 3.14 + } + }, + { + "name": "doubleIntValue", + "in": "query", + "required": false, + "schema": { + "type": "number", + "format": "double", + "default": 10 + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + + // Verify double formatting + generatedCode.Should().Contain("double? DoubleFloatValue { get; set; } = 3.14"); + generatedCode.Should().Contain("double? DoubleIntValue { get; set; } = 10.0"); + } + + private static async Task GenerateCode(string openApiSpec) + { + var swaggerFile = await SwaggerFileHelper.CreateSwaggerFile(openApiSpec); + var settings = new RefitGeneratorSettings + { + OpenApiPath = swaggerFile, + OptionalParameters = true, + UseDynamicQuerystringParameters = true + }; + + var sut = await RefitGenerator.CreateAsync(settings); + var code = sut.Generate(); + return code; + } +} diff --git a/src/Refitter.Tests/Examples/OptionalParametersWithDefaultValuesEdgeCasesTests.cs b/src/Refitter.Tests/Examples/OptionalParametersWithDefaultValuesEdgeCasesTests.cs new file mode 100644 index 00000000..2dfd2577 --- /dev/null +++ b/src/Refitter.Tests/Examples/OptionalParametersWithDefaultValuesEdgeCasesTests.cs @@ -0,0 +1,638 @@ +using FluentAssertions; +using Refitter.Core; +using Refitter.Tests.Build; +using Refitter.Tests.TestUtilities; +using Xunit; + +namespace Refitter.Tests.Examples; + +public class OptionalParametersWithDefaultValuesEdgeCasesTests +{ + [Fact] + public async Task String_Default_Values_Should_Be_Escaped() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestEscaping", + "parameters": [ + { + "name": "quotedString", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "value with \"quotes\"" + } + }, + { + "name": "backslashString", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "path\\to\\file" + } + }, + { + "name": "newlineString", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "line1\nline2" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + + // Verify strings are properly escaped + generatedCode.Should().Contain("string? quotedString = \"value with \\\"quotes\\\"\""); + generatedCode.Should().Contain("string? backslashString = \"path\\\\to\\\\file\""); + generatedCode.Should().Contain("string? newlineString = \"line1\\nline2\""); + } + + [Fact] + public async Task String_Default_Values_With_All_Escape_Characters_Should_Be_Escaped() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestAllEscapes", + "parameters": [ + { + "name": "carriageReturnString", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "line1\rline2" + } + }, + { + "name": "tabString", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "col1\tcol2" + } + }, + { + "name": "allSpecialChars", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "test\n\r\t\\\"" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + + // Verify all special characters are properly escaped + generatedCode.Should().Contain("string? carriageReturnString = \"line1\\rline2\""); + generatedCode.Should().Contain("string? tabString = \"col1\\tcol2\""); + generatedCode.Should().Contain("string? allSpecialChars = \"test\\n\\r\\t\\\\\\\"\""); + } + + [Fact] + public async Task Float_Default_Values_Should_Have_Type_Suffix() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestFloat", + "parameters": [ + { + "name": "floatValue", + "in": "query", + "required": false, + "schema": { + "type": "number", + "format": "float", + "default": 1.5 + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + + // Verify float has 'f' suffix + generatedCode.Should().Contain("float? floatValue = 1.5f"); + } + + [Fact] + public async Task Decimal_Default_Values_Should_Have_Type_Suffix() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestDecimal", + "parameters": [ + { + "name": "decimalValue", + "in": "query", + "required": false, + "schema": { + "type": "number", + "format": "decimal", + "default": 99.99 + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + + // Verify decimal has 'm' suffix + generatedCode.Should().Contain("decimal? decimalValue = 99.99m"); + } + + [Fact] + public async Task Generated_Code_With_Escaped_Strings_Should_Build() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestBuild", + "parameters": [ + { + "name": "escapedString", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "value with \"quotes\" and \\backslashes\\" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + BuildHelper.BuildCSharp(generatedCode).Should().BeTrue(); + } + + [Fact] + public async Task Generated_Code_With_Float_Decimal_Should_Build() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestBuild", + "parameters": [ + { + "name": "floatValue", + "in": "query", + "required": false, + "schema": { + "type": "number", + "format": "float", + "default": 1.5 + } + }, + { + "name": "decimalValue", + "in": "query", + "required": false, + "schema": { + "type": "number", + "format": "decimal", + "default": 99.99 + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + BuildHelper.BuildCSharp(generatedCode).Should().BeTrue(); + } + + [Fact] + public async Task Integer_Default_Values_Should_Not_Have_Suffix() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestInt", + "parameters": [ + { + "name": "intValue", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int32", + "default": 42 + } + }, + { + "name": "longValue", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "default": 9999 + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + + // Verify integers don't have suffixes + generatedCode.Should().Contain("int? intValue = 42"); + generatedCode.Should().Contain("long? longValue = 9999"); + } + + [Fact] + public async Task Double_Default_Values_Should_Have_Decimal_Point() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestDouble", + "parameters": [ + { + "name": "doubleValue", + "in": "query", + "required": false, + "schema": { + "type": "number", + "format": "double", + "default": 3.14159 + } + }, + { + "name": "doubleIntValue", + "in": "query", + "required": false, + "schema": { + "type": "number", + "format": "double", + "default": 10 + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + + // Verify double with decimal point stays as-is + generatedCode.Should().Contain("double? doubleValue = 3.14159"); + // Verify double with integer value gets .0 appended + generatedCode.Should().Contain("double? doubleIntValue = 10.0"); + } + + [Fact] + public async Task Boolean_Default_Values_Should_Be_Lowercase() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestBool", + "parameters": [ + { + "name": "isEnabled", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "default": true + } + }, + { + "name": "isDisabled", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + + // Verify booleans are lowercase + generatedCode.Should().Contain("bool? isEnabled = true"); + generatedCode.Should().Contain("bool? isDisabled = false"); + } + + [Fact] + public async Task Empty_String_Default_Value_Should_Be_Handled() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestEmpty", + "parameters": [ + { + "name": "emptyString", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + + // Verify empty string is properly quoted + generatedCode.Should().Contain("string? emptyString = \"\""); + } + + [Fact] + public async Task Mixed_Escape_Sequences_Should_Be_Handled() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestMixedEscapes", + "parameters": [ + { + "name": "complexString", + "in": "query", + "required": false, + "schema": { + "type": "string", + "default": "path\\to\\file with \"quotes\" and\nnewlines\tand tabs" + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + + // Verify all escape sequences are properly handled in combination + generatedCode.Should().Contain("string? complexString = \"path\\\\to\\\\file with \\\"quotes\\\" and\\nnewlines\\tand tabs\""); + } + + [Fact] + public async Task Long_And_ULong_Default_Values_Should_Have_Suffixes() + { + const string openApiSpec = + """ + { + "openapi": "3.0.1", + "info": { + "title": "Test API", + "version": "v1" + }, + "paths": { + "/api/test": { + "get": { + "operationId": "TestLong", + "parameters": [ + { + "name": "longValue", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "default": 3000000000 + } + }, + { + "name": "ulongValue", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "uint64", + "default": 5000000000 + } + } + ], + "responses": { + "200": { + "description": "Success" + } + } + } + } + } + } + """; + + string generatedCode = await GenerateCode(openApiSpec); + + // Verify long and ulong have proper suffixes + generatedCode.Should().Contain("long? longValue = 3000000000L"); + generatedCode.Should().Contain("ulong? ulongValue = 5000000000UL"); + } + + + + private static async Task GenerateCode(string openApiSpec) + { + var swaggerFile = await SwaggerFileHelper.CreateSwaggerFile(openApiSpec); + var settings = new RefitGeneratorSettings + { + OpenApiPath = swaggerFile, + OptionalParameters = true + }; + + var sut = await RefitGenerator.CreateAsync(settings); + var code = sut.Generate(); + return code; + } +}