From 91ff9da73058f3b60644abfb8cd3b796f8a7f9c6 Mon Sep 17 00:00:00 2001 From: Colin Eberhardt Date: Sun, 5 Mar 2023 21:06:43 +0000 Subject: [PATCH 1/4] feat: added HttpResponse object --- helpers/createReturnStatement.js | 2 +- template/ApiClient.cs.handlebars | 10 +++++--- template/HttpResponse.cs.handlebars | 5 ++++ template/IApiClient.cs.handlebars | 2 +- tests/FeaturesTests/Components.cs | 6 ++--- tests/FeaturesTests/Deserialisation.cs | 20 ++++++++-------- tests/FeaturesTests/FeatureBase.cs | 4 ++-- tests/FeaturesTests/Objects.cs | 6 ++--- tests/FeaturesTests/Response.cs | 33 ++++++++++++++++---------- 9 files changed, 53 insertions(+), 35 deletions(-) create mode 100644 template/HttpResponse.cs.handlebars diff --git a/helpers/createReturnStatement.js b/helpers/createReturnStatement.js index 9bcff26..93a8b6f 100644 --- a/helpers/createReturnStatement.js +++ b/helpers/createReturnStatement.js @@ -20,7 +20,7 @@ const createReturnStatement = (responseSchema) => { returnStatement = `JsonSerializer.Deserialize<${responseType}>(responseBody)`; } - return new Handlebars.SafeString(`return ${returnStatement};`); + return new Handlebars.SafeString(returnStatement); }; module.exports = createReturnStatement; diff --git a/template/ApiClient.cs.handlebars b/template/ApiClient.cs.handlebars index eea61a1..f77e53d 100644 --- a/template/ApiClient.cs.handlebars +++ b/template/ApiClient.cs.handlebars @@ -49,7 +49,7 @@ using System.Web; {{#each _sortedParameters}} /// {{description}} {{/each}} - public async Task{{#if _response.schema}}<{{safeTypeConvert _response.schema}}>{{/if}} {{operationId}}( + public async Task> {{operationId}}( {{~#each _sortedParameters ~}} {{~nullableTypeConvert schema _optional}} {{toParamName name ~}} {{~#if (hasDefault schema.default)}} = {{{quoteIfString schema.default}}}{{/if ~}} @@ -72,11 +72,15 @@ using System.Web; response.EnsureSuccessStatusCode(); {{#if _response.schema}} var responseBody = await response.Content.ReadAsStringAsync(); - {{createReturnStatement _response.schema}} + return new HttpResponse<{{safeTypeConvert _response.schema}}>() { + Data = {{createReturnStatement _response.schema}} + }; + {{else}} + return new HttpResponse() { }; {{/if}} } {{else}} - public Task{{#if _response.schema}}<{{safeTypeConvert _response.schema}}>{{/if}} {{operationId}}({{#each _sortedParameters}}{{nullableTypeConvert schema _optional}} {{name}}{{#if schema.default}} = {{{quoteIfString schema.default}}}{{/if}}{{#unless @last}}, {{/unless}}{{/each}}) + public Task{{#if _response.schema}}>{{/if}} {{operationId}}({{#each _sortedParameters}}{{nullableTypeConvert schema _optional}} {{name}}{{#if schema.default}} = {{{quoteIfString schema.default}}}{{/if}}{{#unless @last}}, {{/unless}}{{/each}}) { throw new NotImplementedException("Operation '{{operationId}}' most likely does not support json encoded requests which are not supported by openapi forge."); } diff --git a/template/HttpResponse.cs.handlebars b/template/HttpResponse.cs.handlebars new file mode 100644 index 0000000..5b617b9 --- /dev/null +++ b/template/HttpResponse.cs.handlebars @@ -0,0 +1,5 @@ +{{>namespace}} { + public class HttpResponse { + public T Data { get; set; } + } +} \ No newline at end of file diff --git a/template/IApiClient.cs.handlebars b/template/IApiClient.cs.handlebars index f250144..7159f97 100644 --- a/template/IApiClient.cs.handlebars +++ b/template/IApiClient.cs.handlebars @@ -29,7 +29,7 @@ using System.Threading.Tasks; {{#each _sortedParameters}} /// {{description}} {{/each}} - public Task{{#if _response.schema}}<{{safeTypeConvert _response.schema}}>{{/if}} {{operationId}}( + public Task> {{operationId}}( {{~#each _sortedParameters ~}} {{~nullableTypeConvert schema _optional}} {{toParamName name ~}} {{~#if (hasDefault schema.default)}} = {{{quoteIfString schema.default}}}{{/if ~}} diff --git a/tests/FeaturesTests/Components.cs b/tests/FeaturesTests/Components.cs index b889a23..c4e92c1 100644 --- a/tests/FeaturesTests/Components.cs +++ b/tests/FeaturesTests/Components.cs @@ -22,15 +22,15 @@ public async Task CallWithResponse(string methodName, DocString response) [Then(@"the response should be of type (\w+)")] public void CheckResponseType(string type) { - Assert.EndsWith(type, _actual.GetType().Name); + Assert.EndsWith(type, _actual.Data.GetType().Name); } [And(@"the response should have a property (id|value) with value (.+)")] public void CheckResponseIdProperty(string propName, string propValue) { - var propInfo = _actual.GetType().GetProperty(propName); + var propInfo = _actual.Data.GetType().GetProperty(propName); Assert.NotNull(propInfo); - Assert.Equal(propValue, propInfo.GetValue(_actual).ToString()); + Assert.Equal(propValue, propInfo.GetValue(_actual.Data).ToString()); } [When(@"calling the method (\w+) with (?:object|array|parameters) ""(.+)""")] diff --git a/tests/FeaturesTests/Deserialisation.cs b/tests/FeaturesTests/Deserialisation.cs index 6af9846..61d32a0 100644 --- a/tests/FeaturesTests/Deserialisation.cs +++ b/tests/FeaturesTests/Deserialisation.cs @@ -44,48 +44,48 @@ public async Task CallWithResponse(string methodName, DocString response) [Then(@"the response should be of type (\w+)")] public void CheckResponseType(string expectedType) { - Assert.EndsWith(expectedType, _actual.GetType().Name); + Assert.EndsWith(expectedType, _actual.Data.GetType().Name); } [And(@"the response should have a property (id|value) with value (.+)")] public void CheckResponseIdProperty(string propName, string propValue) { - var propInfo = _actual.GetType().GetProperty(propName); + var propInfo = _actual.Data.GetType().GetProperty(propName); Assert.NotNull(propInfo); - Assert.Equal(propValue, propInfo.GetValue(_actual).ToString()); + Assert.Equal(propValue, propInfo.GetValue(_actual.Data).ToString()); } [And(@"the response should be equal to (""[\w\s]+"")")] public void CheckStringResponseValue(string expectedResponse) { - Assert.Equal(expectedResponse, _actual); + Assert.Equal(expectedResponse, _actual.Data); } [Then(@"the response should be an array")] public void CheckArrayResponseType() { - Assert.True(_actual.GetType().IsArray); + Assert.True(_actual.Data.GetType().IsArray); } [When(@"extracting the object at index (\d)")] public void CheckArrayResponseType(string index) { - _actual = ((object[])_actual)[int.Parse(index)]; + _actual.Data = ((object[])_actual.Data)[int.Parse(index)]; } [And(@"the response should have a property (date|dateTime) with value ([\d-:.TZ]+)")] public void CheckDateValueProperty(string propertyName, string expectedPropValue) { - var propInfo = _actual.GetType().GetProperty(propertyName); + var propInfo = _actual.Data.GetType().GetProperty(propertyName); Assert.NotNull(propInfo); - Assert.Equal(DateTime.Parse(expectedPropValue).ToUniversalTime(), propInfo.GetValue(_actual)); + Assert.Equal(DateTime.Parse(expectedPropValue).ToUniversalTime(), propInfo.GetValue(_actual.Data)); } [Then(@"the response should have a property (cats) with value (\d+)")] [And(@"the response should have a property (dogs) with value (\d+)")] public void CheckResponseIntDictionaryProperties(string propertyName, string expectedPropValue) { - var actual = _actual as Dictionary; + var actual = _actual.Data as Dictionary; Assert.NotNull(actual); Assert.Equal(int.Parse(expectedPropValue), actual[propertyName]); } @@ -94,7 +94,7 @@ public void CheckResponseIntDictionaryProperties(string propertyName, string exp [And(@"the response should have a property (dateTwo) with value ([\d-:.TZ]+)")] public void CheckResponseDateDictionaryProperties(string propertyName, string expectedPropValue) { - var actual = _actual as Dictionary; + var actual = _actual.Data as Dictionary; Assert.NotNull(actual); Assert.Equal(DateTime.Parse(expectedPropValue).ToUniversalTime(), actual[propertyName]); } diff --git a/tests/FeaturesTests/FeatureBase.cs b/tests/FeaturesTests/FeatureBase.cs index dcbefcb..2c4ac61 100644 --- a/tests/FeaturesTests/FeatureBase.cs +++ b/tests/FeaturesTests/FeatureBase.cs @@ -19,7 +19,7 @@ public abstract class FeatureBase : Xunit.Gherkin.Quick.Feature protected readonly string _testId; - protected object _actual; + protected dynamic _actual; protected string _docStringContent; @@ -46,7 +46,7 @@ public virtual void Generate(DocString schema) public void CheckRequestUri(string url) { var expected = new Uri(url); - var actual = new Uri(_actual.ToString()); + var actual = new Uri(_actual.Data.ToString()); Assert.Equal(expected.Host, actual.Host); Assert.Equal(expected.AbsolutePath, actual.AbsolutePath); var separators = new[] { '?', '&' }; diff --git a/tests/FeaturesTests/Objects.cs b/tests/FeaturesTests/Objects.cs index afe39c8..95bfc3b 100644 --- a/tests/FeaturesTests/Objects.cs +++ b/tests/FeaturesTests/Objects.cs @@ -23,15 +23,15 @@ public async Task CallWithResponse(string methodName, DocString response) [Then(@"the response should be of type (\w+)")] public void CheckResponseType(string type) { - Assert.EndsWith(type, _actual.GetType().Name); + Assert.EndsWith(type, _actual.Data.GetType().Name); } [And(@"the response should have a property (id|value) with value (.+)")] public void CheckResponseIdProperty(string propName, string propValue) { - var propInfo = _actual.GetType().GetProperty(propName); + var propInfo = _actual.Data.GetType().GetProperty(propName); Assert.NotNull(propInfo); - Assert.Equal(propValue, propInfo.GetValue(_actual).ToString()); + Assert.Equal(propValue, propInfo.GetValue(_actual.Data).ToString()); } [When(@"calling the method (\w+) with (?:object|array|parameters) (.+)")] diff --git a/tests/FeaturesTests/Response.cs b/tests/FeaturesTests/Response.cs index a41d99d..b9e67c4 100644 --- a/tests/FeaturesTests/Response.cs +++ b/tests/FeaturesTests/Response.cs @@ -12,10 +12,17 @@ public sealed class Response : FeatureBase { private readonly Dictionary _responses = new Dictionary(); + protected dynamic _extractedResponse; + public Response(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } + public void Dispose() + { + _extractedResponse = null; + } + [When(@"calling the method (\w+) and the server responds with")] public async Task CallWithResponse(string methodName, DocString response) { @@ -42,17 +49,19 @@ public async Task CallWithResponse(string methodName, DocString response) } [Then(@"the response should be of type (\w+)")] - public void CheckResponseType(string type) + public void CheckResponseType(string expected) { - Assert.EndsWith(type, _actual.GetType().Name); + var type = _extractedResponse != null ? _extractedResponse.GetType() : _actual.Data.GetType(); + Assert.EndsWith(expected, type.Name); } [And(@"the response should have a property (id|value) with value (.+)")] public void CheckResponseIdProperty(string propName, string propValue) { - var propInfo = _actual.GetType().GetProperty(propName); + var property = _extractedResponse != null ? _extractedResponse : _actual.Data; + var propInfo = property.GetType().GetProperty(propName); Assert.NotNull(propInfo); - Assert.Equal(propValue, propInfo.GetValue(_actual).ToString()); + Assert.Equal(propValue, propInfo.GetValue(property).ToString()); } [When(@"calling the method (\w+) with parameters (.+)")] @@ -72,21 +81,21 @@ public async Task CallMethodWithParameters(string methodName, string rawParamete [And(@"the response should have a property (date|dateTime) with value ([\d-:.TZ]+)")] public void CheckDateValueProperty(string propertyName, string expectedPropValue) { - var propInfo = _actual.GetType().GetProperty(propertyName); + var propInfo = _actual.Data.GetType().GetProperty(propertyName); Assert.NotNull(propInfo); - Assert.Equal(DateTime.Parse(expectedPropValue).ToUniversalTime(), propInfo.GetValue(_actual)); + Assert.Equal(DateTime.Parse(expectedPropValue).ToUniversalTime(), propInfo.GetValue(_actual.Data)); } [And(@"the response should be equal to (""[\w\s]+"")")] public void CheckStringResponseValue(string expectedResponse) { - Assert.Equal(expectedResponse, _actual); + Assert.Equal(expectedResponse, _actual.Data); } [Then(@"the response should be an array")] public void CheckArrayResponseType() { - Assert.True(_actual.GetType().IsArray); + Assert.True(_actual.Data.GetType().IsArray); } [When(@"calling the method (\w+) and the server provides an empty response")] @@ -98,20 +107,20 @@ public async Task WhenEmptyResponse(string methodName) [Then(@"the response should be null")] public void ThenResponseTypeIsTask() { - Assert.Null(_actual); + Assert.Null(_actual.Data); } [When(@"extracting the object at index (\d)")] public void CheckArrayResponseType(string index) { - _actual = ((object[])_actual)[int.Parse(index)]; + _extractedResponse = ((object[])_actual.Data)[int.Parse(index)]; } [Then(@"the response should have a property (cats) with value (\d+)")] [And(@"the response should have a property (dogs) with value (\d+)")] public void CheckResponseIntDictionaryProperties(string propertyName, string expectedPropValue) { - var actual = _actual as Dictionary; + var actual = _actual.Data as Dictionary; Assert.NotNull(actual); Assert.Equal(int.Parse(expectedPropValue), actual[propertyName]); } @@ -120,7 +129,7 @@ public void CheckResponseIntDictionaryProperties(string propertyName, string exp [And(@"the response should have a property (dateTwo) with value ([\d-:.TZ]+)")] public void CheckResponseDateDictionaryProperties(string propertyName, string expectedPropValue) { - var actual = _actual as Dictionary; + var actual = _actual.Data as Dictionary; Assert.NotNull(actual); Assert.Equal(DateTime.Parse(expectedPropValue).ToUniversalTime(), actual[propertyName]); } From ffd5fab177e734796358d83bcd37ffffc18f41cc Mon Sep 17 00:00:00 2001 From: Colin Eberhardt Date: Mon, 6 Mar 2023 10:05:47 +0000 Subject: [PATCH 2/4] feat: expanded the response object with additional properties --- template/ApiClient.cs.handlebars | 14 ++++++++++---- template/HttpResponse.cs.handlebars | 27 ++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/template/ApiClient.cs.handlebars b/template/ApiClient.cs.handlebars index f77e53d..b47955d 100644 --- a/template/ApiClient.cs.handlebars +++ b/template/ApiClient.cs.handlebars @@ -72,11 +72,17 @@ using System.Web; response.EnsureSuccessStatusCode(); {{#if _response.schema}} var responseBody = await response.Content.ReadAsStringAsync(); - return new HttpResponse<{{safeTypeConvert _response.schema}}>() { - Data = {{createReturnStatement _response.schema}} - }; + return new HttpResponse<{{safeTypeConvert _response.schema}}>( + {{createReturnStatement _response.schema}}, + response.StatusCode, + response.Headers + ); {{else}} - return new HttpResponse() { }; + return new HttpResponse( + null, + response.StatusCode, + response.Headers + ); {{/if}} } {{else}} diff --git a/template/HttpResponse.cs.handlebars b/template/HttpResponse.cs.handlebars index 5b617b9..c2d56f5 100644 --- a/template/HttpResponse.cs.handlebars +++ b/template/HttpResponse.cs.handlebars @@ -1,5 +1,30 @@ +using System.Net; +using System.Net.Http.Headers; + {{>namespace}} { + /// + /// Represents an HTTP response. + /// public class HttpResponse { - public T Data { get; set; } + public HttpResponse(T data, HttpStatusCode statusCode, HttpResponseHeaders headers) { + Data = data; + StatusCode = statusCode; + Headers = headers; + } + + /// + /// Gets the typed response. + /// + public T Data { get; private set; } + + /// + /// Gets the HTTP status code. + /// + public HttpStatusCode StatusCode { get; private set; } + + /// + /// Gets the returned HTTP headers. + /// + public HttpResponseHeaders Headers { get; private set; } } } \ No newline at end of file From 8d96191a2772b96ba56007e996402108ff713337 Mon Sep 17 00:00:00 2001 From: Colin Eberhardt Date: Mon, 6 Mar 2023 14:58:19 +0000 Subject: [PATCH 3/4] test: added new test for returning headers --- README.md | 2 +- tests/FeaturesTests/Response.cs | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ad0da2f..d122e4e 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ await api.addPet(new Pet() { // fetch the pet var result = await api.getPetById(1); -Console.WriteLine(result.name); +Console.WriteLine(result.Data.name); ``` Run from the terminal as follows: diff --git a/tests/FeaturesTests/Response.cs b/tests/FeaturesTests/Response.cs index b9e67c4..efb0a04 100644 --- a/tests/FeaturesTests/Response.cs +++ b/tests/FeaturesTests/Response.cs @@ -1,4 +1,5 @@ using System; +using System.Text.RegularExpressions; using Gherkin.Ast; using RichardSzalay.MockHttp; using Xunit; @@ -104,6 +105,37 @@ public async Task WhenEmptyResponse(string methodName) await CallMethod(methodName); } + [When(@"calling the method (\w+) and the server responds with headers")] + public async Task WhenEmptyResponse(string methodName, DocString headers) + { + _responses[methodName.Replace("Response", string.Empty)] = ""; + + // we'll assume a single header for now + var header = headers.Content.Split(":"); + var headerName = Regex.Match(header[0], "\"(.*)\"").Groups[1].Value; + var headerValue = Regex.Match(header[1], "\"(.*)\"").Groups[1].Value; + + _mockHttp.When("*").Respond((HttpRequestMessage request) => + { + var message = new HttpResponseMessage + { + StatusCode = System.Net.HttpStatusCode.OK, + Content = new StringContent(_responses[request.RequestUri.LocalPath.Split("/").Last()]), + }; + message.Headers.Add(headerName, headerValue); + return Task.FromResult(message); + }); + + var request = _mockHttp.When("*").Respond("application/json", ""); + var apiClient = _testHelper.CreateApiClient(_mockHttp.ToHttpClient()); + + var methodInfo = apiClient.GetType().GetMethod(methodName); + + dynamic awaitable = methodInfo.Invoke(apiClient, null); + await awaitable; + _actual = awaitable.GetAwaiter().GetResult(); + } + [Then(@"the response should be null")] public void ThenResponseTypeIsTask() { @@ -125,6 +157,13 @@ public void CheckResponseIntDictionaryProperties(string propertyName, string exp Assert.Equal(int.Parse(expectedPropValue), actual[propertyName]); } + [Then(@"the response should have a header (.+) with value (.+)")] + [And(@"the response should have a header (.+) with value (.+)")] + public void CheckResponseHeaderProperty(string propertyName, string expectedPropValue) + { + Assert.Equal(expectedPropValue, _actual.Headers.GetValues(propertyName)[0]); + } + [Then(@"the response should have a property (dateOne) with value ([\d-:.TZ]+)")] [And(@"the response should have a property (dateTwo) with value ([\d-:.TZ]+)")] public void CheckResponseDateDictionaryProperties(string propertyName, string expectedPropValue) From 783c99533237541d95b455b5042944ff5d0b60c3 Mon Sep 17 00:00:00 2001 From: Colin Eberhardt Date: Tue, 7 Mar 2023 14:53:52 +0000 Subject: [PATCH 4/4] chore: consolidating test logic --- tests/FeaturesTests/Components.cs | 20 ----- tests/FeaturesTests/Configuration.cs | 13 ---- tests/FeaturesTests/CookieParams.cs | 13 ---- tests/FeaturesTests/Deserialisation.cs | 102 ------------------------- tests/FeaturesTests/FeatureBase.cs | 78 +++++++++++++++++++ tests/FeaturesTests/HeaderParams.cs | 13 ---- tests/FeaturesTests/Objects.cs | 28 ------- tests/FeaturesTests/PathParams.cs | 20 ----- tests/FeaturesTests/QueryString.cs | 26 ------- tests/FeaturesTests/RequestBody.cs | 1 - tests/FeaturesTests/Response.cs | 25 ------ 11 files changed, 78 insertions(+), 261 deletions(-) delete mode 100644 tests/FeaturesTests/Deserialisation.cs diff --git a/tests/FeaturesTests/Components.cs b/tests/FeaturesTests/Components.cs index c4e92c1..9fb1acb 100644 --- a/tests/FeaturesTests/Components.cs +++ b/tests/FeaturesTests/Components.cs @@ -13,26 +13,6 @@ public Components(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } - [When(@"calling the method (\w+) and the server responds with")] - public async Task CallWithResponse(string methodName, DocString response) - { - await CallMethod(methodName, null, response.Content); - } - - [Then(@"the response should be of type (\w+)")] - public void CheckResponseType(string type) - { - Assert.EndsWith(type, _actual.Data.GetType().Name); - } - - [And(@"the response should have a property (id|value) with value (.+)")] - public void CheckResponseIdProperty(string propName, string propValue) - { - var propInfo = _actual.Data.GetType().GetProperty(propName); - Assert.NotNull(propInfo); - Assert.Equal(propValue, propInfo.GetValue(_actual.Data).ToString()); - } - [When(@"calling the method (\w+) with (?:object|array|parameters) ""(.+)""")] public async Task CallMethodWithParameters(string methodName, string rawParameters) { diff --git a/tests/FeaturesTests/Configuration.cs b/tests/FeaturesTests/Configuration.cs index f4ed005..863d502 100644 --- a/tests/FeaturesTests/Configuration.cs +++ b/tests/FeaturesTests/Configuration.cs @@ -9,22 +9,9 @@ namespace Features [FeatureFile(nameof(Configuration) + Constants.FeatureFileExtension)] public sealed class Configuration : FeatureBase { - private int? _serverIndex; public Configuration(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } - - [When(@"calling the method (\w+) without params")] - public async Task CallWithoutParameters(string methodName) - { - await CallMethod(methodName, null, null, _serverIndex); - } - - [When(@"selecting the server at index (\d)")] - public void SelectedServerIndexIsOne(string serverIndex) - { - _serverIndex = new Nullable(int.Parse(serverIndex)); - } } } \ No newline at end of file diff --git a/tests/FeaturesTests/CookieParams.cs b/tests/FeaturesTests/CookieParams.cs index 638b523..a172b7a 100644 --- a/tests/FeaturesTests/CookieParams.cs +++ b/tests/FeaturesTests/CookieParams.cs @@ -11,19 +11,6 @@ public CookieParams(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } - [When(@"calling the method (\w+) with (object|array|parameters) ""(.+)""")] - public async Task CallMethodWithStringParameters(string methodName, string paramType, string parametersString) - { - var parameters = paramType switch - { - "object" => new object[] { _testHelper.JsonToTypeInstance("InlineObject1", parametersString) }, - "array" => new object[] { parametersString.Split(",") }, - _ => parametersString.Split(",") - }; - - await CallMethod(methodName, parameters); - } - [Then(@"the request header should have a cookie property with value (.+)")] public void CheckCookiePropertyAsync(string headerProperty) { diff --git a/tests/FeaturesTests/Deserialisation.cs b/tests/FeaturesTests/Deserialisation.cs deleted file mode 100644 index 61d32a0..0000000 --- a/tests/FeaturesTests/Deserialisation.cs +++ /dev/null @@ -1,102 +0,0 @@ -using Gherkin.Ast; -using RichardSzalay.MockHttp; -using Xunit; -using Xunit.Abstractions; -using Xunit.Gherkin.Quick; - -namespace Features -{ - [FeatureFile(nameof(Deserialization) + Constants.FeatureFileExtension)] - public sealed class Deserialization : FeatureBase - { - private readonly Dictionary _responses; - - public Deserialization(ITestOutputHelper testOutputHelper) : base(testOutputHelper) - { - _responses = new Dictionary(); - } - - [When(@"calling the method (\w+) and the server responds with")] - public async Task CallWithResponse(string methodName, DocString response) - { - _responses[methodName.Replace("Response", string.Empty)] = response.Content; - - _mockHttp.When("*").Respond((HttpRequestMessage request) => - { - return Task.FromResult( - new HttpResponseMessage - { - StatusCode = System.Net.HttpStatusCode.OK, - Content = new StringContent(_responses[request.RequestUri.LocalPath.Split("/").Last()]) - }); - }); - - var request = _mockHttp.When("*").Respond("application/json", response.Content); - var apiClient = _testHelper.CreateApiClient(_mockHttp.ToHttpClient()); - - var methodInfo = apiClient.GetType().GetMethod(methodName); - - dynamic awaitable = methodInfo.Invoke(apiClient, null); - await awaitable; - _actual = awaitable.GetAwaiter().GetResult(); - } - - [Then(@"the response should be of type (\w+)")] - public void CheckResponseType(string expectedType) - { - Assert.EndsWith(expectedType, _actual.Data.GetType().Name); - } - - [And(@"the response should have a property (id|value) with value (.+)")] - public void CheckResponseIdProperty(string propName, string propValue) - { - var propInfo = _actual.Data.GetType().GetProperty(propName); - Assert.NotNull(propInfo); - Assert.Equal(propValue, propInfo.GetValue(_actual.Data).ToString()); - } - - [And(@"the response should be equal to (""[\w\s]+"")")] - public void CheckStringResponseValue(string expectedResponse) - { - Assert.Equal(expectedResponse, _actual.Data); - } - - [Then(@"the response should be an array")] - public void CheckArrayResponseType() - { - Assert.True(_actual.Data.GetType().IsArray); - } - - [When(@"extracting the object at index (\d)")] - public void CheckArrayResponseType(string index) - { - _actual.Data = ((object[])_actual.Data)[int.Parse(index)]; - } - - [And(@"the response should have a property (date|dateTime) with value ([\d-:.TZ]+)")] - public void CheckDateValueProperty(string propertyName, string expectedPropValue) - { - var propInfo = _actual.Data.GetType().GetProperty(propertyName); - Assert.NotNull(propInfo); - Assert.Equal(DateTime.Parse(expectedPropValue).ToUniversalTime(), propInfo.GetValue(_actual.Data)); - } - - [Then(@"the response should have a property (cats) with value (\d+)")] - [And(@"the response should have a property (dogs) with value (\d+)")] - public void CheckResponseIntDictionaryProperties(string propertyName, string expectedPropValue) - { - var actual = _actual.Data as Dictionary; - Assert.NotNull(actual); - Assert.Equal(int.Parse(expectedPropValue), actual[propertyName]); - } - - [Then(@"the response should have a property (dateOne) with value ([\d-:.TZ]+)")] - [And(@"the response should have a property (dateTwo) with value ([\d-:.TZ]+)")] - public void CheckResponseDateDictionaryProperties(string propertyName, string expectedPropValue) - { - var actual = _actual.Data as Dictionary; - Assert.NotNull(actual); - Assert.Equal(DateTime.Parse(expectedPropValue).ToUniversalTime(), actual[propertyName]); - } - } -} \ No newline at end of file diff --git a/tests/FeaturesTests/FeatureBase.cs b/tests/FeaturesTests/FeatureBase.cs index 2c4ac61..7a09292 100644 --- a/tests/FeaturesTests/FeatureBase.cs +++ b/tests/FeaturesTests/FeatureBase.cs @@ -13,6 +13,10 @@ public abstract class FeatureBase : Xunit.Gherkin.Quick.Feature { protected readonly ITestOutputHelper _testOutputHelper; + private int? _serverIndex; + + private readonly Dictionary _responses = new Dictionary(); + protected readonly TestHelper _testHelper; protected readonly MockHttpMessageHandler _mockHttp; @@ -33,6 +37,80 @@ public FeatureBase(ITestOutputHelper testOutputHelper) _mockHttp = new MockHttpMessageHandler(); } + [When(@"calling the method (\w+) and the server responds with")] + public async Task CallWithResponse(string methodName, DocString response) + { + _responses[methodName.Replace("Response", string.Empty)] = response.Content; + + _mockHttp.When("*").Respond((HttpRequestMessage request) => + { + return Task.FromResult( + new HttpResponseMessage + { + StatusCode = System.Net.HttpStatusCode.OK, + Content = new StringContent(_responses[request.RequestUri.LocalPath.Split("/").Last()]) + }); + }); + + var request = _mockHttp.When("*").Respond("application/json", response.Content); + var apiClient = _testHelper.CreateApiClient(_mockHttp.ToHttpClient()); + + var methodInfo = apiClient.GetType().GetMethod(methodName); + + dynamic awaitable = methodInfo.Invoke(apiClient, null); + await awaitable; + _actual = awaitable.GetAwaiter().GetResult(); + } + + [Then(@"the response should be of type (\w+)")] + public void CheckResponseType(string type) + { + Assert.EndsWith(type, _actual.Data.GetType().Name); + } + + [When(@"calling the method (\w+) without params")] + public async Task CallWithoutParameters(string methodName) + { + await CallMethod(methodName, null, null, _serverIndex); + } + + [When(@"calling the method (\w+) with object (.+)")] + public async Task CallMethodWithStringObject(string methodName, string parametersString) + { + var parameters = new object[] { _testHelper.JsonToTypeInstance("InlineObject1", parametersString) }; + + await CallMethod(methodName, parameters); + } + + [When(@"calling the method (\w+) with (object|array|parameters) ""(.+)""")] + public async Task CallMethodWithStringParameters(string methodName, string paramType, string parametersString) + { + var parameters = paramType switch + { + "object" => new object[] { _testHelper.JsonToTypeInstance("InlineObject1", parametersString) }, + "array" => new object[] { parametersString.Split(",") }, + _ => parametersString.Split(",") + }; + + await CallMethod(methodName, parameters); + } + + [When(@"selecting the server at index (\d)")] + public void SelectedServerIndexIsOne(string serverIndex) + { + _serverIndex = new Nullable(int.Parse(serverIndex)); + } + + + [Then(@"the response should have a property (.+) with value (.+)")] + [And(@"the response should have a property (.+) with value (.+)")] + public void CheckResponseIdProperty(string propName, string propValue) + { + var propInfo = _actual.Data.GetType().GetProperty(propName); + Assert.NotNull(propInfo); + Assert.Equal(propValue, propInfo.GetValue(_actual.Data).ToString()); + } + [Given(@"an API with the following specification")] public virtual void Generate(DocString schema) { diff --git a/tests/FeaturesTests/HeaderParams.cs b/tests/FeaturesTests/HeaderParams.cs index c093a2b..4cbd9b2 100644 --- a/tests/FeaturesTests/HeaderParams.cs +++ b/tests/FeaturesTests/HeaderParams.cs @@ -11,19 +11,6 @@ public HeaderParams(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } - [When(@"calling the method (\w+) with (object|array|parameters) ""(.+)""")] - public async Task CallMethodWithStringParameters(string methodName, string paramType, string parametersString) - { - var parameters = paramType switch - { - "object" => new object[] { _testHelper.JsonToTypeInstance("InlineObject1", parametersString) }, - "array" => new object[] { parametersString.Split(",") }, - _ => parametersString.Split(",") - }; - - await CallMethod(methodName, parameters); - } - [Then(@"the request should have a header property with value (.+)")] public void CheckHeaderPropertyAsync(string headerProperty) { diff --git a/tests/FeaturesTests/Objects.cs b/tests/FeaturesTests/Objects.cs index 95bfc3b..e4d9072 100644 --- a/tests/FeaturesTests/Objects.cs +++ b/tests/FeaturesTests/Objects.cs @@ -14,34 +14,6 @@ public Objects(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } - [When(@"calling the method (\w+) and the server responds with")] - public async Task CallWithResponse(string methodName, DocString response) - { - await CallMethod(methodName, null, response.Content); - } - - [Then(@"the response should be of type (\w+)")] - public void CheckResponseType(string type) - { - Assert.EndsWith(type, _actual.Data.GetType().Name); - } - - [And(@"the response should have a property (id|value) with value (.+)")] - public void CheckResponseIdProperty(string propName, string propValue) - { - var propInfo = _actual.Data.GetType().GetProperty(propName); - Assert.NotNull(propInfo); - Assert.Equal(propValue, propInfo.GetValue(_actual.Data).ToString()); - } - - [When(@"calling the method (\w+) with (?:object|array|parameters) (.+)")] - public async Task CallMethodWithParameters(string methodName, string jsonTextObject) - { - var inlineObj = _testHelper.JsonToTypeInstance("InlineObject1", jsonTextObject); - - await CallMethod(methodName, new object[] { inlineObj }); - } - [And("the request should have a body with value (.+)")] public async Task CheckRequestBody(string propValue) { diff --git a/tests/FeaturesTests/PathParams.cs b/tests/FeaturesTests/PathParams.cs index e462dd3..810f3be 100644 --- a/tests/FeaturesTests/PathParams.cs +++ b/tests/FeaturesTests/PathParams.cs @@ -13,25 +13,5 @@ public sealed class PathParams : FeatureBase public PathParams(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } - - [When(@"calling the method (\w+) with (parameters|array) ""(.+)""")] - public async Task CallMethodWithStringParameters(string methodName, string paramType, string parametersString) - { - var parameters = paramType switch - { - "array" => new object[] { parametersString.Split(",") }, - _ => parametersString.Split(",") - }; - - await CallMethod(methodName, parameters); - } - - [When(@"calling the method (\w+) with object (.+)")] - public async Task CallMethodWithStringObject(string methodName, string parametersString) - { - var parameters = new object[] { _testHelper.JsonToTypeInstance("InlineObject1", parametersString) }; - - await CallMethod(methodName, parameters); - } } } diff --git a/tests/FeaturesTests/QueryString.cs b/tests/FeaturesTests/QueryString.cs index 19c080a..529ba5e 100644 --- a/tests/FeaturesTests/QueryString.cs +++ b/tests/FeaturesTests/QueryString.cs @@ -11,31 +11,5 @@ public sealed class QueryString : FeatureBase public QueryString(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } - - [When(@"calling the method (\w+) with (array|parameters) ""(.+)""")] - public async Task CallMethodWithStringParameters(string methodName, string paramType, string parametersString) - { - var parameters = paramType switch - { - "array" => new object[] { parametersString.Split(",") }, - _ => parametersString.Split(",") - }; - - await CallMethod(methodName, parameters); - } - - [When(@"calling the method (\w+) with object (.+)")] - public async Task CallMethodWithStringObject(string methodName, string parametersString) - { - var parameters = new object[] { _testHelper.JsonToTypeInstance("InlineObject1", parametersString) }; - - await CallMethod(methodName, parameters); - } - - [When(@"calling the method (\w+) without params")] - public async Task CallMethodWithStringParameters(string methodName) - { - await CallMethod(methodName); - } } } diff --git a/tests/FeaturesTests/RequestBody.cs b/tests/FeaturesTests/RequestBody.cs index d3d2598..aa077ee 100644 --- a/tests/FeaturesTests/RequestBody.cs +++ b/tests/FeaturesTests/RequestBody.cs @@ -14,7 +14,6 @@ public RequestBody(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { } - [When(@"calling the method (\w+) with (?:object|array|parameters) (.+)")] public async Task CallMethodWithStringParameters(string methodName, string parametersString) { diff --git a/tests/FeaturesTests/Response.cs b/tests/FeaturesTests/Response.cs index efb0a04..13aa0a0 100644 --- a/tests/FeaturesTests/Response.cs +++ b/tests/FeaturesTests/Response.cs @@ -24,31 +24,6 @@ public void Dispose() _extractedResponse = null; } - [When(@"calling the method (\w+) and the server responds with")] - public async Task CallWithResponse(string methodName, DocString response) - { - _responses[methodName.Replace("Response", string.Empty)] = response.Content; - - _mockHttp.When("*").Respond((HttpRequestMessage request) => - { - return Task.FromResult( - new HttpResponseMessage - { - StatusCode = System.Net.HttpStatusCode.OK, - Content = new StringContent(_responses[request.RequestUri.LocalPath.Split("/").Last()]) - }); - }); - - var request = _mockHttp.When("*").Respond("application/json", response.Content); - var apiClient = _testHelper.CreateApiClient(_mockHttp.ToHttpClient()); - - var methodInfo = apiClient.GetType().GetMethod(methodName); - - dynamic awaitable = methodInfo.Invoke(apiClient, null); - await awaitable; - _actual = awaitable.GetAwaiter().GetResult(); - } - [Then(@"the response should be of type (\w+)")] public void CheckResponseType(string expected) {