Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using Microsoft.AspNetCore.Mvc;
using NJsonSchema.NewtonsoftJson.Generation;
using NSwag.CodeGeneration.OperationNameGenerators;
using NSwag.CodeGeneration.Tests;
using NSwag.Generation.WebApi;
using System.ComponentModel.DataAnnotations;
using NSwag.CodeGeneration.Tests;
using System.Reflection;

namespace NSwag.CodeGeneration.CSharp.Tests
{
Expand Down Expand Up @@ -46,7 +47,11 @@ public async Task TestNoGuardForOptionalBodyParameter()
{
UseBaseUrl = false,
GenerateClientInterfaces = true,
OperationNameGenerator = new SingleClientFromOperationIdOperationNameGenerator()
OperationNameGenerator = new SingleClientFromOperationIdOperationNameGenerator(),
CSharpGeneratorSettings =
{
Namespace = VerifyHelper.GetNameSpace(),
},
});

var code = codeGen.GenerateFile();
Expand All @@ -61,25 +66,47 @@ public async Task TestNullableBodyWithAllowNullableBodyParameters()
{
// Arrange
var generator = await GenerateCode(true);
generator.Settings.CSharpGeneratorSettings.Namespace = VerifyHelper.GetNameSpace();

// Act
var code = generator.GenerateFile();

// Assert
await VerifyHelper.Verify(code);
CSharpCompiler.AssertCompile(code + @"
namespace AllowNullableBodyParametersTests.TestNullableBodyWithAllowNullableBodyParameters
{
public class MyBaseClass
{
public MyBaseClass(MyConfig configuration) {}
}
public class MyConfig {}
}
");
}

[Fact]
public async Task TestNullableBodyWithoutAllowNullableBodyParameters()
{
// Arrange
var generator = await GenerateCode(false);
generator.Settings.CSharpGeneratorSettings.Namespace = VerifyHelper.GetNameSpace();

// Act
var code = generator.GenerateFile();

// Assert
await VerifyHelper.Verify(code);
CSharpCompiler.AssertCompile(code + @"
namespace AllowNullableBodyParametersTests.TestNullableBodyWithoutAllowNullableBodyParameters
{
public class MyBaseClass
{
public MyBaseClass(MyConfig configuration) {}
}
public class MyConfig {}
}
");
}

private static async Task<CSharpClientGenerator> GenerateCode(bool allowNullableBodyParameters)
Expand Down
54 changes: 48 additions & 6 deletions src/NSwag.CodeGeneration.CSharp.Tests/ArrayParameterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,14 @@ public async Task When_parameter_is_array_then_CSharp_is_correct()
var document = await OpenApiDocument.FromJsonAsync(swagger);

// Act
var settings = new CSharpClientGeneratorSettings { ClassName = "MyClass" };
var settings = new CSharpClientGeneratorSettings
{
ClassName = "MyClass",
CSharpGeneratorSettings =
{
Namespace = VerifyHelper.GetNameSpace(),
},
};
var generator = new CSharpClientGenerator(document, settings);
var code = generator.GenerateFile();

Expand Down Expand Up @@ -136,7 +143,14 @@ public async Task When_explode_is_false_then_do_not_explode(string explode)
var document = await OpenApiDocument.FromJsonAsync(json);

// Act
var settings = new CSharpClientGeneratorSettings { ClassName = "MyClass" };
var settings = new CSharpClientGeneratorSettings
{
ClassName = "MyClass",
CSharpGeneratorSettings =
{
Namespace = VerifyHelper.GetNameSpace(),
},
};
var generator = new CSharpClientGenerator(document, settings);
var code = generator.GenerateFile();

Expand Down Expand Up @@ -214,7 +228,14 @@ public async Task When_explode_is_explicitly_or_implicitly_true_then_explode(str
var document = await OpenApiDocument.FromJsonAsync(json);

// Act
var settings = new CSharpClientGeneratorSettings { ClassName = "MyClass" };
var settings = new CSharpClientGeneratorSettings
{
ClassName = "MyClass",
CSharpGeneratorSettings =
{
Namespace = VerifyHelper.GetNameSpace(),
},
};
var generator = new CSharpClientGenerator(document, settings);
var code = generator.GenerateFile();

Expand Down Expand Up @@ -280,7 +301,14 @@ public async Task When_CollectionFormat_is_csv_then_do_not_explode()
var document = await OpenApiDocument.FromJsonAsync(swagger);

// Act
var settings = new CSharpClientGeneratorSettings { ClassName = "MyClass" };
var settings = new CSharpClientGeneratorSettings
{
ClassName = "MyClass",
CSharpGeneratorSettings =
{
Namespace = VerifyHelper.GetNameSpace(),
},
};
var generator = new CSharpClientGenerator(document, settings);
var code = generator.GenerateFile();

Expand Down Expand Up @@ -346,7 +374,14 @@ public async Task When_CollectionFormat_is_multi_then_explode()
var document = await OpenApiDocument.FromJsonAsync(swagger);

// Act
var settings = new CSharpClientGeneratorSettings { ClassName = "MyClass" };
var settings = new CSharpClientGeneratorSettings
{
ClassName = "MyClass",
CSharpGeneratorSettings =
{
Namespace = VerifyHelper.GetNameSpace(),
},
};
var generator = new CSharpClientGenerator(document, settings);
var code = generator.GenerateFile();

Expand Down Expand Up @@ -421,7 +456,14 @@ public async Task when_content_is_formdata_with_property_array_then_content_shou
var document = await OpenApiDocument.FromJsonAsync(json);

// Act
var settings = new CSharpClientGeneratorSettings { ClassName = "MyClass" };
var settings = new CSharpClientGeneratorSettings
{
ClassName = "MyClass",
CSharpGeneratorSettings =
{
Namespace = VerifyHelper.GetNameSpace(),
},
};
var generator = new CSharpClientGenerator(document, settings);
var code = generator.GenerateFile();

Expand Down
45 changes: 45 additions & 0 deletions src/NSwag.CodeGeneration.CSharp.Tests/CSharpClientSettingsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ public async Task When_ConfigurationClass_is_set_then_correct_ctor_is_generated(

// Assert
await VerifyHelper.Verify(code);
CSharpCompiler.AssertCompile(code + @"
namespace MyNamespace
{
public class MyBaseClass
{
public MyBaseClass(MyConfig configuration) {}
}
public class MyConfig {}
}
");
}

[Fact]
Expand All @@ -72,6 +82,17 @@ public async Task When_UseHttpRequestMessageCreationMethod_is_set_then_CreateReq

// Assert
await VerifyHelper.Verify(code);
CSharpCompiler.AssertCompile(code + @"
namespace MyNamespace
{
public class MyBaseClass
{
public MyBaseClass(MyConfig configuration) {}
protected global::System.Threading.Tasks.Task<global::System.Net.Http.HttpRequestMessage> CreateHttpRequestMessageAsync(global::System.Threading.CancellationToken ct) { return default; }
}
public class MyConfig {}
}
");
}

[Fact]
Expand Down Expand Up @@ -162,6 +183,12 @@ public async Task When_custom_http_client_type_is_specified_then_an_instance_of_

// Assert
await VerifyHelper.Verify(code);
CSharpCompiler.AssertCompile(code + @"
namespace CustomNamespace
{
public class CustomHttpClient : global::System.Net.Http.HttpClient { }
}
");
}

[Fact]
Expand Down Expand Up @@ -232,6 +259,12 @@ public async Task When_client_base_interface_is_specified_then_client_interface_

// Assert
await VerifyHelper.Verify(code);
CSharpCompiler.AssertCompile(code + @"
namespace MyNamespace
{
public interface IClientBase { }
}
");
}

[Fact]
Expand All @@ -256,6 +289,12 @@ public async Task When_client_base_interface_is_specified_with_access_modifier_t

// Assert
await VerifyHelper.Verify(code);
CSharpCompiler.AssertCompile(code + @"
namespace MyNamespace
{
public interface IClientBase { }
}
");
}

[Fact]
Expand Down Expand Up @@ -307,6 +346,12 @@ public async Task When_client_interface_generation_is_enabled_and_suppressed_the

// Assert
await VerifyHelper.Verify(code);
CSharpCompiler.AssertCompile(code + @"
namespace MyNamespace
{
public interface IFooClient { }
}
");
}

public class OperationSelectionTestData : IEnumerable<object[]>
Expand Down
47 changes: 47 additions & 0 deletions src/NSwag.CodeGeneration.CSharp.Tests/CSharpCompiler.TypeStubs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
namespace System.Web.Http
{
public class ApiController { }
public abstract class ParameterBindingAttribute : global::System.Attribute
{
public abstract System.Web.Http.Controllers.HttpParameterBinding GetBinding(global::System.Web.Http.Controllers.HttpParameterDescriptor parameter);
}
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class HttpGetAttribute : global::System.Attribute { }
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class HttpPostAttribute : global::System.Attribute { }
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class FromUriAttribute : global::System.Attribute { }
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class FromBodyAttribute : global::System.Attribute { }
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
public class RouteAttribute : global::System.Attribute
{
public RouteAttribute(string template) { }
}
}

namespace System.Web.Http.Controllers
{
public abstract class HttpParameterBinding
{
protected HttpParameterBinding(global::System.Web.Http.Controllers.HttpParameterDescriptor parameter) { }
public dynamic ActionArguments { get; }
public dynamic Descriptor { get; }
public abstract System.Threading.Tasks.Task ExecuteBindingAsync(global::System.Web.Http.Metadata.ModelMetadataProvider metadataProvider, global::System.Web.Http.Controllers.HttpActionContext actionContext, global::System.Threading.CancellationToken cancellationToken);
}
public abstract class HttpParameterDescriptor
{
public string ParameterName { get; }
public dynamic ActionArguments { get; }
}
public abstract class HttpActionContext
{
public dynamic ActionArguments { get; }
public dynamic Request { get; }
}
}

namespace System.Web.Http.Metadata
{
public abstract class ModelMetadataProvider { }
}
15 changes: 15 additions & 0 deletions src/NSwag.CodeGeneration.CSharp.Tests/CSharpCompiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,27 @@ static CSharpCompiler()
.Append(MetadataReference.CreateFromFile(typeof(HttpClient).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(Microsoft.AspNetCore.Mvc.FileResult).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(Microsoft.AspNetCore.Http.IFormFile).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(Microsoft.AspNetCore.Http.HttpRequest).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(Microsoft.Extensions.Primitives.StringValues).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(Newtonsoft.Json.JsonSerializer).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(System.Net.HttpStatusCode).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(System.ComponentModel.DataAnnotations.RangeAttribute).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(System.Collections.ObjectModel.ObservableCollection<>).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(System.Runtime.Serialization.EnumMemberAttribute).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(System.Text.Json.Serialization.JsonConverter).Assembly.Location))
// stubs
.Append(MetadataReference.CreateFromFile(typeof(System.Web.Http.ApiController).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(System.Web.Http.FromBodyAttribute).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(System.Web.Http.FromUriAttribute).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(System.Web.Http.HttpGetAttribute).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(System.Web.Http.HttpPostAttribute).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(System.Web.Http.ParameterBindingAttribute).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(System.Web.Http.RouteAttribute).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(System.Web.Http.Controllers.HttpActionContext).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(System.Web.Http.Controllers.HttpParameterBinding).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(System.Web.Http.Controllers.HttpParameterDescriptor).Assembly.Location))
.Append(MetadataReference.CreateFromFile(typeof(System.Web.Http.Metadata.ModelMetadataProvider).Assembly.Location))
.ToList();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,21 @@ public class ClientGenerationTests
[Fact]
public async Task CanGenerateFromJiraOpenApiSpecification()
{
// Jira's OpenAPI spec generates code like this:
//// public bool ShowDaysInColumn { get; set; } = MyNamespace.bool.False;
await VerifyOutput("JIRA_OpenAPI", "jira-open-api.json", compile: false);
}

[Fact]
public async Task CanGenerateFromShipBobOpenApiSpecification()
{
await VerifyOutput("ShipBob_OpenAPI", "shipbob-2025-07.json");
await VerifyOutput("ShipBob_OpenAPI", "shipbob-2025-07.json", compile: true);
}

[Fact]
public async Task CanGenerateFromNhsSpineServicesOpenApiSpecification()
{
await VerifyOutput("NHS_SpineServices_OpenAPI", "nhs-spineservices.json");
await VerifyOutput("NHS_SpineServices_OpenAPI", "nhs-spineservices.json", compile: true);
}

private static async Task VerifyOutput(string name, string fileName, bool compile = true)
Expand Down
Loading
Loading