From 3cbd7ad6380efd04f0c35e274d4cbb2b95e3ce84 Mon Sep 17 00:00:00 2001 From: charlie green Date: Wed, 18 Sep 2024 13:01:34 +0100 Subject: [PATCH 1/2] Allow leaving encoded slash in UrlSegmentParameter value --- .../Parameters/UrlSegmentParameter.cs | 5 ++-- test/RestSharp.Tests/ParametersTests.cs | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/RestSharp/Parameters/UrlSegmentParameter.cs b/src/RestSharp/Parameters/UrlSegmentParameter.cs index b9da7752a..c3c4ff98a 100644 --- a/src/RestSharp/Parameters/UrlSegmentParameter.cs +++ b/src/RestSharp/Parameters/UrlSegmentParameter.cs @@ -26,10 +26,11 @@ public partial record UrlSegmentParameter : NamedParameter { /// Parameter name /// Parameter value /// Optional: encode the value, default is true - public UrlSegmentParameter(string name, string value, bool encode = true) + /// Optional: whether to replace all %2f and %2F in the parameter value with '/', default is true + public UrlSegmentParameter(string name, string value, bool encode = true, bool replaceEncodedSlash = true) : base( name, - RegexPattern.Replace(Ensure.NotEmptyString(value, nameof(value)), "/"), + replaceEncodedSlash ? RegexPattern.Replace(Ensure.NotEmptyString(value, nameof(value)), "/") : value, ParameterType.UrlSegment, encode ) { } diff --git a/test/RestSharp.Tests/ParametersTests.cs b/test/RestSharp.Tests/ParametersTests.cs index e9c702fbc..b8807ed20 100644 --- a/test/RestSharp.Tests/ParametersTests.cs +++ b/test/RestSharp.Tests/ParametersTests.cs @@ -63,4 +63,28 @@ public void AddUrlSegmentModifiesUrlSegmentWithString() { expected.Should().BeEquivalentTo(actual); } + + [Theory] + [InlineData("bar%2fBAR")] + [InlineData("bar%2FBAR")] + public void UrlSegmentParameter_WithValueWithEncodedSlash_WillReplaceEncodedSlashByDefault(string inputValue) { + var urlSegmentParameter = new UrlSegmentParameter("foo", inputValue); + urlSegmentParameter.Value.Should().BeEquivalentTo("bar/BAR"); + } + + [Theory] + [InlineData("bar%2fBAR")] + [InlineData("bar%2FBAR")] + public void UrlSegmentParameter_WithValueWithEncodedSlash_CanReplaceEncodedSlash(string inputValue) { + var urlSegmentParameter = new UrlSegmentParameter("foo", inputValue, replaceEncodedSlash: true); + urlSegmentParameter.Value.Should().BeEquivalentTo("bar/BAR"); + } + + [Theory] + [InlineData("bar%2fBAR")] + [InlineData("bar%2FBAR")] + public void UrlSegmentParameter_WithValueWithEncodedSlash_CanLeaveEncodedSlash(string inputValue) { + var urlSegmentParameter = new UrlSegmentParameter("foo", inputValue, replaceEncodedSlash: false); + urlSegmentParameter.Value.Should().BeEquivalentTo(inputValue); + } } \ No newline at end of file From 40b9416d2ce43af007fb75e91d034263feaa1974 Mon Sep 17 00:00:00 2001 From: Alexey Zimarev Date: Tue, 17 Dec 2024 11:14:07 +0100 Subject: [PATCH 2/2] Allow adding empty value for URL segments --- .../Parameters/UrlSegmentParameter.cs | 3 +- .../Headers/DefaultHeaderTests.cs | 23 ++ .../HeaderRangeTests.cs} | 4 +- .../{ => Headers}/HostHeaderTests.cs | 0 .../{ => Headers}/RequestHeaderTests.cs | 0 .../ObjectParameterTests.ArrayData.cs | 2 +- .../ObjectParameterTests.CsvData.cs | 2 +- .../ObjectParameterTests.FormattedData.cs | 2 +- .../ObjectParameterTests.NamedData.cs | 2 +- .../{ => Parameters}/ObjectParameterTests.cs | 2 +- .../ParameterValidationTests.cs | 2 +- .../UrlSegmentTests.cs} | 21 +- test/RestSharp.Tests/RestClientTests.cs | 32 -- test/RestSharp.Tests/RestSharp.Tests.csproj | 14 +- test/RestSharp.Tests/UrlBuilderTests.Get.cs | 197 ++++++++++++ test/RestSharp.Tests/UrlBuilderTests.Post.cs | 60 ++++ test/RestSharp.Tests/UrlBuilderTests.cs | 286 +++--------------- 17 files changed, 330 insertions(+), 322 deletions(-) create mode 100644 test/RestSharp.Tests/Headers/DefaultHeaderTests.cs rename test/RestSharp.Tests/{AddRangeTests.cs => Headers/HeaderRangeTests.cs} (89%) rename test/RestSharp.Tests/{ => Headers}/HostHeaderTests.cs (100%) rename test/RestSharp.Tests/{ => Headers}/RequestHeaderTests.cs (100%) rename test/RestSharp.Tests/{ => Parameters}/ObjectParameterTests.ArrayData.cs (84%) rename test/RestSharp.Tests/{ => Parameters}/ObjectParameterTests.CsvData.cs (83%) rename test/RestSharp.Tests/{ => Parameters}/ObjectParameterTests.FormattedData.cs (82%) rename test/RestSharp.Tests/{ => Parameters}/ObjectParameterTests.NamedData.cs (78%) rename test/RestSharp.Tests/{ => Parameters}/ObjectParameterTests.cs (99%) rename test/RestSharp.Tests/{ => Parameters}/ParameterValidationTests.cs (97%) rename test/RestSharp.Tests/{ParametersTests.cs => Parameters/UrlSegmentTests.cs} (79%) create mode 100644 test/RestSharp.Tests/UrlBuilderTests.Get.cs create mode 100644 test/RestSharp.Tests/UrlBuilderTests.Post.cs diff --git a/src/RestSharp/Parameters/UrlSegmentParameter.cs b/src/RestSharp/Parameters/UrlSegmentParameter.cs index c3c4ff98a..7e24678cd 100644 --- a/src/RestSharp/Parameters/UrlSegmentParameter.cs +++ b/src/RestSharp/Parameters/UrlSegmentParameter.cs @@ -13,6 +13,7 @@ // limitations under the License. using System.Text.RegularExpressions; +using RestSharp.Extensions; namespace RestSharp; @@ -30,7 +31,7 @@ public partial record UrlSegmentParameter : NamedParameter { public UrlSegmentParameter(string name, string value, bool encode = true, bool replaceEncodedSlash = true) : base( name, - replaceEncodedSlash ? RegexPattern.Replace(Ensure.NotEmptyString(value, nameof(value)), "/") : value, + value.IsEmpty() ? value : replaceEncodedSlash ? RegexPattern.Replace(value, "/") : value, ParameterType.UrlSegment, encode ) { } diff --git a/test/RestSharp.Tests/Headers/DefaultHeaderTests.cs b/test/RestSharp.Tests/Headers/DefaultHeaderTests.cs new file mode 100644 index 000000000..dd1e69c42 --- /dev/null +++ b/test/RestSharp.Tests/Headers/DefaultHeaderTests.cs @@ -0,0 +1,23 @@ +namespace RestSharp.Tests.Headers; + +public class DefaultHeaderTests { + const string BaseUrl = "http://localhost:8888/"; + + [Fact] + public void AddDefaultHeadersUsingDictionary() { + var headers = new Dictionary { + { KnownHeaders.ContentType, ContentType.Json }, + { KnownHeaders.Accept, ContentType.Json }, + { KnownHeaders.ContentEncoding, "gzip, deflate" } + }; + + var expected = headers.Select(x => new HeaderParameter(x.Key, x.Value)); + + using var client = new RestClient(BaseUrl); + client.AddDefaultHeaders(headers); + + var actual = client.DefaultParameters.Select(x => x as HeaderParameter); + expected.Should().BeSubsetOf(actual); + } + +} \ No newline at end of file diff --git a/test/RestSharp.Tests/AddRangeTests.cs b/test/RestSharp.Tests/Headers/HeaderRangeTests.cs similarity index 89% rename from test/RestSharp.Tests/AddRangeTests.cs rename to test/RestSharp.Tests/Headers/HeaderRangeTests.cs index 1f2dbbd19..ccedaa280 100644 --- a/test/RestSharp.Tests/AddRangeTests.cs +++ b/test/RestSharp.Tests/Headers/HeaderRangeTests.cs @@ -1,6 +1,6 @@ -namespace RestSharp.Tests; +namespace RestSharp.Tests.Parameters; -public class AddRangeTests { +public class HeaderRangeTests { [Fact] public async Task ShouldParseOutLongRangeSpecifier() { using var restClient = new RestClient("http://localhost"); diff --git a/test/RestSharp.Tests/HostHeaderTests.cs b/test/RestSharp.Tests/Headers/HostHeaderTests.cs similarity index 100% rename from test/RestSharp.Tests/HostHeaderTests.cs rename to test/RestSharp.Tests/Headers/HostHeaderTests.cs diff --git a/test/RestSharp.Tests/RequestHeaderTests.cs b/test/RestSharp.Tests/Headers/RequestHeaderTests.cs similarity index 100% rename from test/RestSharp.Tests/RequestHeaderTests.cs rename to test/RestSharp.Tests/Headers/RequestHeaderTests.cs diff --git a/test/RestSharp.Tests/ObjectParameterTests.ArrayData.cs b/test/RestSharp.Tests/Parameters/ObjectParameterTests.ArrayData.cs similarity index 84% rename from test/RestSharp.Tests/ObjectParameterTests.ArrayData.cs rename to test/RestSharp.Tests/Parameters/ObjectParameterTests.ArrayData.cs index be6b10782..367395d9f 100644 --- a/test/RestSharp.Tests/ObjectParameterTests.ArrayData.cs +++ b/test/RestSharp.Tests/Parameters/ObjectParameterTests.ArrayData.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests; +namespace RestSharp.Tests.Parameters; public partial class ObjectParameterTests { sealed record ArrayData([property: RequestProperty(ArrayQueryType = RequestArrayQueryType.ArrayParameters)] TEnumerable Array) where TEnumerable : notnull; diff --git a/test/RestSharp.Tests/ObjectParameterTests.CsvData.cs b/test/RestSharp.Tests/Parameters/ObjectParameterTests.CsvData.cs similarity index 83% rename from test/RestSharp.Tests/ObjectParameterTests.CsvData.cs rename to test/RestSharp.Tests/Parameters/ObjectParameterTests.CsvData.cs index 7ae47f78a..07cb78dc1 100644 --- a/test/RestSharp.Tests/ObjectParameterTests.CsvData.cs +++ b/test/RestSharp.Tests/Parameters/ObjectParameterTests.CsvData.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests; +namespace RestSharp.Tests.Parameters; public partial class ObjectParameterTests { sealed record CsvData([property: RequestProperty(ArrayQueryType = RequestArrayQueryType.CommaSeparated)] TEnumerable Csv) where TEnumerable : notnull; diff --git a/test/RestSharp.Tests/ObjectParameterTests.FormattedData.cs b/test/RestSharp.Tests/Parameters/ObjectParameterTests.FormattedData.cs similarity index 82% rename from test/RestSharp.Tests/ObjectParameterTests.FormattedData.cs rename to test/RestSharp.Tests/Parameters/ObjectParameterTests.FormattedData.cs index c11c1d6b3..fb76f8405 100644 --- a/test/RestSharp.Tests/ObjectParameterTests.FormattedData.cs +++ b/test/RestSharp.Tests/Parameters/ObjectParameterTests.FormattedData.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests; +namespace RestSharp.Tests.Parameters; public partial class ObjectParameterTests { sealed record FormattedData([property: RequestProperty(Format = "hh:mm tt")] TDateTime FormattedParameter) where TDateTime : notnull; diff --git a/test/RestSharp.Tests/ObjectParameterTests.NamedData.cs b/test/RestSharp.Tests/Parameters/ObjectParameterTests.NamedData.cs similarity index 78% rename from test/RestSharp.Tests/ObjectParameterTests.NamedData.cs rename to test/RestSharp.Tests/Parameters/ObjectParameterTests.NamedData.cs index 908127dee..2a6c0f574 100644 --- a/test/RestSharp.Tests/ObjectParameterTests.NamedData.cs +++ b/test/RestSharp.Tests/Parameters/ObjectParameterTests.NamedData.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests; +namespace RestSharp.Tests.Parameters; public partial class ObjectParameterTests { sealed record NamedData([property: RequestProperty(Name = "CustomName")] object NamedParameter); diff --git a/test/RestSharp.Tests/ObjectParameterTests.cs b/test/RestSharp.Tests/Parameters/ObjectParameterTests.cs similarity index 99% rename from test/RestSharp.Tests/ObjectParameterTests.cs rename to test/RestSharp.Tests/Parameters/ObjectParameterTests.cs index 65de48aa2..305427f90 100644 --- a/test/RestSharp.Tests/ObjectParameterTests.cs +++ b/test/RestSharp.Tests/Parameters/ObjectParameterTests.cs @@ -1,7 +1,7 @@ using System.Collections; using System.Globalization; -namespace RestSharp.Tests; +namespace RestSharp.Tests.Parameters; public partial class ObjectParameterTests { public ObjectParameterTests() => Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; diff --git a/test/RestSharp.Tests/ParameterValidationTests.cs b/test/RestSharp.Tests/Parameters/ParameterValidationTests.cs similarity index 97% rename from test/RestSharp.Tests/ParameterValidationTests.cs rename to test/RestSharp.Tests/Parameters/ParameterValidationTests.cs index 365da204d..81b6f39a7 100644 --- a/test/RestSharp.Tests/ParameterValidationTests.cs +++ b/test/RestSharp.Tests/Parameters/ParameterValidationTests.cs @@ -1,4 +1,4 @@ -namespace RestSharp.Tests; +namespace RestSharp.Tests.Parameters; public class ParameterValidationTests { [Fact] diff --git a/test/RestSharp.Tests/ParametersTests.cs b/test/RestSharp.Tests/Parameters/UrlSegmentTests.cs similarity index 79% rename from test/RestSharp.Tests/ParametersTests.cs rename to test/RestSharp.Tests/Parameters/UrlSegmentTests.cs index b8807ed20..063a1f92a 100644 --- a/test/RestSharp.Tests/ParametersTests.cs +++ b/test/RestSharp.Tests/Parameters/UrlSegmentTests.cs @@ -1,25 +1,8 @@ -namespace RestSharp.Tests; +namespace RestSharp.Tests.Parameters; -public class ParametersTests { +public class UrlSegmentTests { const string BaseUrl = "http://localhost:8888/"; - [Fact] - public void AddDefaultHeadersUsingDictionary() { - var headers = new Dictionary { - { KnownHeaders.ContentType, ContentType.Json }, - { KnownHeaders.Accept, ContentType.Json }, - { KnownHeaders.ContentEncoding, "gzip, deflate" } - }; - - var expected = headers.Select(x => new HeaderParameter(x.Key, x.Value)); - - using var client = new RestClient(BaseUrl); - client.AddDefaultHeaders(headers); - - var actual = client.DefaultParameters.Select(x => x as HeaderParameter); - expected.Should().BeSubsetOf(actual); - } - [Fact] public void AddUrlSegmentWithInt() { const string name = "foo"; diff --git a/test/RestSharp.Tests/RestClientTests.cs b/test/RestSharp.Tests/RestClientTests.cs index 9d575db4c..0bb54b328 100644 --- a/test/RestSharp.Tests/RestClientTests.cs +++ b/test/RestSharp.Tests/RestClientTests.cs @@ -32,38 +32,6 @@ public async Task ConfigureHttp_will_set_proxy_to_null_with_no_exceptions_When_n await client.ExecuteAsync(req); } - [Fact] - public void BuildUri_should_build_with_passing_link_as_Uri() { - // arrange - var relative = new Uri("/foo/bar/baz", UriKind.Relative); - var absoluteUri = new Uri(new Uri(BaseUrl), relative); - var req = new RestRequest(absoluteUri); - - // act - using var client = new RestClient(); - - var builtUri = client.BuildUri(req); - - // assert - absoluteUri.Should().Be(builtUri); - } - - [Fact] - public void BuildUri_should_build_with_passing_link_as_Uri_with_set_BaseUrl() { - // arrange - var baseUrl = new Uri(BaseUrl); - var relative = new Uri("/foo/bar/baz", UriKind.Relative); - var req = new RestRequest(relative); - - // act - using var client = new RestClient(baseUrl); - - var builtUri = client.BuildUri(req); - - // assert - new Uri(baseUrl, relative).Should().Be(builtUri); - } - [Fact] public void UseJson_leaves_only_json_serializer() { // arrange diff --git a/test/RestSharp.Tests/RestSharp.Tests.csproj b/test/RestSharp.Tests/RestSharp.Tests.csproj index 5806b6700..af5fb6fa9 100644 --- a/test/RestSharp.Tests/RestSharp.Tests.csproj +++ b/test/RestSharp.Tests/RestSharp.Tests.csproj @@ -29,17 +29,11 @@ - - ObjectParameterTests.cs + + UrlBuilderTests.cs - - ObjectParameterTests.cs - - - ObjectParameterTests.cs - - - ObjectParameterTests.cs + + UrlBuilderTests.cs \ No newline at end of file diff --git a/test/RestSharp.Tests/UrlBuilderTests.Get.cs b/test/RestSharp.Tests/UrlBuilderTests.Get.cs new file mode 100644 index 000000000..2dcb35577 --- /dev/null +++ b/test/RestSharp.Tests/UrlBuilderTests.Get.cs @@ -0,0 +1,197 @@ +namespace RestSharp.Tests; + +public partial class UrlBuilderTests { + [Fact] + public void GET_with_empty_base_and_query_parameters_without_encoding() { + var request = new RestRequest($"{Base}/{Resource}?param1=value1") + .AddQueryParameter("foo", "bar,baz", false); + var expected = new Uri($"{Base}/{Resource}?param1=value1&foo=bar,baz"); + + using var client = new RestClient(); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } + + [Fact] + public void GET_with_empty_base_and_resource_containing_tokens() { + var request = new RestRequest($"{Base}/{Resource}/{{foo}}"); + request.AddUrlSegment("foo", "bar"); + + using var client = new RestClient(); + + var expected = new Uri($"{Base}/{Resource}/bar"); + var output = client.BuildUri(request); + + Assert.Equal(expected, output); + } + + [Fact] + public void GET_with_empty_request() { + var request = new RestRequest(); + var expected = new Uri(Base); + + using var client = new RestClient(new Uri(Base)); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } + + [Fact] + public void GET_with_empty_request_and_bare_hostname() { + var request = new RestRequest(); + var expected = new Uri(Base); + + using var client = new RestClient(new Uri(Base)); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } + + [Fact] + public void GET_with_empty_request_and_query_parameters_without_encoding() { + var request = new RestRequest(); + request.AddQueryParameter("foo", "bar,baz", false); + var expected = new Uri($"{Base}/{Resource}?param1=value1&foo=bar,baz"); + + using var client = new RestClient($"{Base}/{Resource}?param1=value1"); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } + + [Fact] + public void GET_with_Invalid_Url_string_throws_exception() + => Assert.Throws( + () => { _ = new RestClient("invalid url"); } + ); + + [Fact] + public void GET_with_leading_slash() { + var request = new RestRequest($"/{Resource}"); + var expected = new Uri($"{Base}/{Resource}"); + + using var client = new RestClient(new Uri(Base)); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } + + [Fact] + public void GET_with_leading_slash_and_baseurl_trailing_slash() { + var request = new RestRequest($"/{Resource}"); + request.AddParameter("foo", "bar"); + var expected = new Uri($"{Base}/{Resource}?foo=bar"); + + using var client = new RestClient(new Uri(Base)); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } + + [Fact] + public void GET_with_multiple_instances_of_same_key() { + var request = new RestRequest("v1/people/~/network/updates"); + request.AddParameter("type", "STAT"); + request.AddParameter("type", "PICT"); + request.AddParameter("count", "50"); + request.AddParameter("start", "50"); + var expected = new Uri("https://api.linkedin.com/v1/people/~/network/updates?type=STAT&type=PICT&count=50&start=50"); + + using var client = new RestClient("https://api.linkedin.com"); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } + + [Fact] + public void GET_with_resource_containing_null_token() { + var request = new RestRequest($"/{Resource}/{{foo}}"); + Assert.Throws(() => request.AddUrlSegment("foo", null!)); + } + + [Fact] + public void GET_with_resource_containing_slashes() { + var request = new RestRequest($"{Resource}/foo"); + var expected = new Uri($"{Base}/{Resource}/foo"); + + using var client = new RestClient(new Uri(Base)); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } + + [Fact] + public void GET_with_resource_containing_tokens() { + var request = new RestRequest($"{Resource}/{{foo}}"); + request.AddUrlSegment("foo", "bar"); + var expected = new Uri($"{Base}/{Resource}/bar"); + + using var client = new RestClient(new Uri(Base)); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } + + [Fact] + public void GET_with_Uri_and_resource_containing_tokens() { + var request = new RestRequest($"/{{foo}}/{Resource}/{{baz}}"); + request.AddUrlSegment("foo", "bar"); + request.AddUrlSegment("baz", "bat"); + var expected = new Uri($"{Base}/bar/{Resource}/bat"); + + using var client = new RestClient(Base); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } + + [Fact] + public void GET_with_Uri_containing_tokens() { + var request = new RestRequest(); + request.AddUrlSegment("foo", "bar"); + var expected = new Uri(Base); + + using var client = new RestClient(Base); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } + + [Fact] + public void GET_with_Url_string_and_resource_containing_tokens() { + var request = new RestRequest($"{Resource}/{{baz}}"); + request.AddUrlSegment("foo", "bar"); + request.AddUrlSegment("baz", "bat"); + var expected = new Uri($"{Base}/bar/{Resource}/bat"); + + using var client = new RestClient($"{Base}/{{foo}}"); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } + + [Fact] + public void GET_with_Url_string_containing_tokens() { + var request = new RestRequest(); + request.AddUrlSegment("foo", "bar"); + var expected = new Uri($"{Base}/bar"); + + using var client = new RestClient($"{Base}/{{foo}}"); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } + + [Fact] + public void GET_wth_trailing_slash_and_query_parameters() { + var request = new RestRequest($"/{Resource}/"); + request.AddParameter("foo", "bar"); + var expected = new Uri($"{Base}/{Resource}/?foo=bar"); + + using var client = new RestClient(Base); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } +} \ No newline at end of file diff --git a/test/RestSharp.Tests/UrlBuilderTests.Post.cs b/test/RestSharp.Tests/UrlBuilderTests.Post.cs new file mode 100644 index 000000000..129b1079f --- /dev/null +++ b/test/RestSharp.Tests/UrlBuilderTests.Post.cs @@ -0,0 +1,60 @@ +namespace RestSharp.Tests; + +public partial class UrlBuilderTests { + [Fact] + public void POST_with_leading_slash() { + var request = new RestRequest($"/{Resource}", Method.Post); + var expected = new Uri($"{Base}/{Resource}"); + + using var client = new RestClient(new Uri(Base)); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } + + [Fact] + public void POST_with_leading_slash_and_baseurl_trailing_slash() { + var request = new RestRequest($"/{Resource}", Method.Post); + var expected = new Uri($"{Base}/{Resource}"); + + using var client = new RestClient(Base); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } + + [Fact] + public void POST_with_querystring_containing_tokens() { + var request = new RestRequest(Resource, Method.Post); + request.AddParameter("foo", "bar", ParameterType.QueryString); + var expected = new Uri($"{Base}/{Resource}?foo=bar"); + + using var client = new RestClient(Base); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } + + [Fact] + public void POST_with_resource_containing_slashes() { + var request = new RestRequest($"{Resource}/foo", Method.Post); + var expected = new Uri($"{Base}/{Resource}/foo"); + + using var client = new RestClient(Base); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } + + [Fact] + public void POST_with_resource_containing_tokens() { + var request = new RestRequest($"{Resource}/{{foo}}", Method.Post); + request.AddUrlSegment("foo", "bar"); + var expected = new Uri($"{Base}/{Resource}/bar"); + + using var client = new RestClient(Base); + + var output = client.BuildUri(request); + Assert.Equal(expected, output); + } +} \ No newline at end of file diff --git a/test/RestSharp.Tests/UrlBuilderTests.cs b/test/RestSharp.Tests/UrlBuilderTests.cs index 2d66f1e05..9a80a20f6 100644 --- a/test/RestSharp.Tests/UrlBuilderTests.cs +++ b/test/RestSharp.Tests/UrlBuilderTests.cs @@ -5,261 +5,10 @@ namespace RestSharp.Tests; /// /// Note: These tests do not handle QueryString building, which is handled in Http, not RestClient /// -public class UrlBuilderTests { +public partial class UrlBuilderTests { const string Base = "https://some.path"; const string Resource = "resource"; - [Fact] - public void GET_with_empty_base_and_query_parameters_without_encoding() { - var request = new RestRequest($"{Base}/{Resource}?param1=value1") - .AddQueryParameter("foo", "bar,baz", false); - var expected = new Uri($"{Base}/{Resource}?param1=value1&foo=bar,baz"); - - using var client = new RestClient(); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - - [Fact] - public void GET_with_empty_base_and_resource_containing_tokens() { - var request = new RestRequest($"{Base}/{Resource}/{{foo}}"); - request.AddUrlSegment("foo", "bar"); - - using var client = new RestClient(); - - var expected = new Uri($"{Base}/{Resource}/bar"); - var output = client.BuildUri(request); - - Assert.Equal(expected, output); - } - - [Fact] - public void GET_with_empty_request() { - var request = new RestRequest(); - var expected = new Uri(Base); - - using var client = new RestClient(new Uri(Base)); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - - [Fact] - public void GET_with_empty_request_and_bare_hostname() { - var request = new RestRequest(); - var expected = new Uri(Base); - - using var client = new RestClient(new Uri(Base)); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - - [Fact] - public void GET_with_empty_request_and_query_parameters_without_encoding() { - var request = new RestRequest(); - request.AddQueryParameter("foo", "bar,baz", false); - var expected = new Uri($"{Base}/{Resource}?param1=value1&foo=bar,baz"); - - using var client = new RestClient($"{Base}/{Resource}?param1=value1"); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - - [Fact] - public void GET_with_Invalid_Url_string_throws_exception() - => Assert.Throws( - () => { _ = new RestClient("invalid url"); } - ); - - [Fact] - public void GET_with_leading_slash() { - var request = new RestRequest($"/{Resource}"); - var expected = new Uri($"{Base}/{Resource}"); - - using var client = new RestClient(new Uri(Base)); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - - [Fact] - public void GET_with_leading_slash_and_baseurl_trailing_slash() { - var request = new RestRequest($"/{Resource}"); - request.AddParameter("foo", "bar"); - var expected = new Uri($"{Base}/{Resource}?foo=bar"); - - using var client = new RestClient(new Uri(Base)); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - - [Fact] - public void GET_with_multiple_instances_of_same_key() { - var request = new RestRequest("v1/people/~/network/updates"); - request.AddParameter("type", "STAT"); - request.AddParameter("type", "PICT"); - request.AddParameter("count", "50"); - request.AddParameter("start", "50"); - var expected = new Uri("https://api.linkedin.com/v1/people/~/network/updates?type=STAT&type=PICT&count=50&start=50"); - - using var client = new RestClient("https://api.linkedin.com"); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - - [Fact] - public void GET_with_resource_containing_null_token() { - var request = new RestRequest($"/{Resource}/{{foo}}"); - Assert.Throws(() => request.AddUrlSegment("foo", null!)); - } - - [Fact] - public void GET_with_resource_containing_slashes() { - var request = new RestRequest($"{Resource}/foo"); - var expected = new Uri($"{Base}/{Resource}/foo"); - - using var client = new RestClient(new Uri(Base)); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - - [Fact] - public void GET_with_resource_containing_tokens() { - var request = new RestRequest($"{Resource}/{{foo}}"); - request.AddUrlSegment("foo", "bar"); - var expected = new Uri($"{Base}/{Resource}/bar"); - - using var client = new RestClient(new Uri(Base)); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - - [Fact] - public void GET_with_Uri_and_resource_containing_tokens() { - var request = new RestRequest($"/{{foo}}/{Resource}/{{baz}}"); - request.AddUrlSegment("foo", "bar"); - request.AddUrlSegment("baz", "bat"); - var expected = new Uri($"{Base}/bar/{Resource}/bat"); - - using var client = new RestClient(Base); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - - [Fact] - public void GET_with_Uri_containing_tokens() { - var request = new RestRequest(); - request.AddUrlSegment("foo", "bar"); - var expected = new Uri(Base); - - using var client = new RestClient(Base); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - - [Fact] - public void GET_with_Url_string_and_resource_containing_tokens() { - var request = new RestRequest($"{Resource}/{{baz}}"); - request.AddUrlSegment("foo", "bar"); - request.AddUrlSegment("baz", "bat"); - var expected = new Uri($"{Base}/bar/{Resource}/bat"); - - using var client = new RestClient($"{Base}/{{foo}}"); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - - [Fact] - public void GET_with_Url_string_containing_tokens() { - var request = new RestRequest(); - request.AddUrlSegment("foo", "bar"); - var expected = new Uri($"{Base}/bar"); - - using var client = new RestClient($"{Base}/{{foo}}"); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - - [Fact] - public void GET_wth_trailing_slash_and_query_parameters() { - var request = new RestRequest($"/{Resource}/"); - request.AddParameter("foo", "bar"); - var expected = new Uri($"{Base}/{Resource}/?foo=bar"); - - using var client = new RestClient(Base); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - - [Fact] - public void POST_with_leading_slash() { - var request = new RestRequest($"/{Resource}", Method.Post); - var expected = new Uri($"{Base}/{Resource}"); - - using var client = new RestClient(new Uri(Base)); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - - [Fact] - public void POST_with_leading_slash_and_baseurl_trailing_slash() { - var request = new RestRequest($"/{Resource}", Method.Post); - var expected = new Uri($"{Base}/{Resource}"); - - using var client = new RestClient(Base); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - - [Fact] - public void POST_with_querystring_containing_tokens() { - var request = new RestRequest(Resource, Method.Post); - request.AddParameter("foo", "bar", ParameterType.QueryString); - var expected = new Uri($"{Base}/{Resource}?foo=bar"); - - using var client = new RestClient(Base); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - - [Fact] - public void POST_with_resource_containing_slashes() { - var request = new RestRequest($"{Resource}/foo", Method.Post); - var expected = new Uri($"{Base}/{Resource}/foo"); - - using var client = new RestClient(Base); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - - [Fact] - public void POST_with_resource_containing_tokens() { - var request = new RestRequest($"{Resource}/{{foo}}", Method.Post); - request.AddUrlSegment("foo", "bar"); - var expected = new Uri($"{Base}/{Resource}/bar"); - - using var client = new RestClient(Base); - - var output = client.BuildUri(request); - Assert.Equal(expected, output); - } - [Fact] public void Should_add_parameter_if_it_is_new() { var request = new RestRequest(); @@ -362,4 +111,37 @@ public void Should_use_ipv6_address() { actual.HostNameType.Should().Be(UriHostNameType.IPv6); actual.AbsoluteUri.Should().Be("https://[fe80::290:e8ff:fe8b:2537]:8443/api/v1/auth"); } + + + [Fact] + public void BuildUri_should_build_with_passing_link_as_Uri() { + // arrange + var relative = new Uri("/foo/bar/baz", UriKind.Relative); + var absoluteUri = new Uri(new(Base), relative); + var req = new RestRequest(absoluteUri); + + // act + using var client = new RestClient(); + + var builtUri = client.BuildUri(req); + + // assert + absoluteUri.Should().Be(builtUri); + } + + [Fact] + public void BuildUri_should_build_with_passing_link_as_Uri_with_set_BaseUrl() { + // arrange + var baseUrl = new Uri(Base); + var relative = new Uri("/foo/bar/baz", UriKind.Relative); + var req = new RestRequest(relative); + + // act + using var client = new RestClient(baseUrl); + + var builtUri = client.BuildUri(req); + + // assert + new Uri(baseUrl, relative).Should().Be(builtUri); + } } \ No newline at end of file