From 812c3443cfef57787325329f93ef65bf047877ed Mon Sep 17 00:00:00 2001 From: Alexey Zimarev Date: Sun, 9 Apr 2023 16:17:47 +0200 Subject: [PATCH] Move the instantiation of RequestContent after calling the Authenticator (#2062) * Move the instantiation of RequestContent after calling the Authenticator * Add auth tests * Fix null content issues with .NET Framework --- RestSharp.sln | 33 ---- RestSharp.sln.DotSettings | 1 + .../AddObjectToRequestParametersBenchmarks.cs | 43 +++-- .../RestSharp.Benchmarks/Requests/Data.cs | 18 +- .../Serializers/JsonNetSerializeBenchmarks.cs | 27 ++- .../Serializers/TestClass.cs | 1 + .../XmlExtensions.cs | 2 +- .../XmlSerializer.cs | 28 +-- .../OAuth/Extensions/StringExtensions.cs | 2 +- .../OAuth/OAuth1Authenticator.cs | 3 + .../Authenticators/OAuth/OAuthTools.cs | 17 +- .../Authenticators/OAuth/OAuthWorkflow.cs | 30 ++- ...AuthorizationRequestHeaderAuthenticator.cs | 1 + .../OAuth2UriQueryParameterAuthenticator.cs | 1 + src/RestSharp/ContentType.cs | 6 +- .../Extensions/HttpResponseExtensions.cs | 8 +- .../Extensions/ImmutableGenerator.cs | 48 ----- .../Extensions/ReflectionExtensions.cs | 2 - src/RestSharp/Options/RestRequestOptions.cs | 30 --- .../Request/PropertyCache.Populator.cs | 6 +- src/RestSharp/Request/PropertyCache.cs | 4 +- src/RestSharp/Request/RequestContent.cs | 4 +- src/RestSharp/Request/RestRequest.cs | 3 + .../Request/RestRequestExtensions.cs | 2 +- src/RestSharp/Request/UriExtensions.cs | 10 +- src/RestSharp/Response/RestResponse.cs | 8 +- src/RestSharp/Response/RestResponseBase.cs | 2 +- src/RestSharp/RestClient.Async.cs | 5 +- src/RestSharp/RestClient.Extensions.Config.cs | 3 +- src/RestSharp/RestClient.Extensions.Json.cs | 1 - src/RestSharp/RestClient.Extensions.Params.cs | 3 - src/RestSharp/RestClient.Extensions.cs | 1 - src/RestSharp/RestClient.Serialization.cs | 26 --- .../Serializers/Xml/DotNetXmlDeserializer.cs | 2 + .../Serializers/Xml/DotNetXmlSerializer.cs | 2 - src/RestSharp/Sync/AsyncHelpers.cs | 174 +++++++++--------- .../TwitterClient.cs | 2 +- .../RestSharp.Tests.Integrated/CookieTests.cs | 6 +- .../Fixtures/CaptureFixture.cs | 15 +- .../HttpHeadersTests.cs | 2 - .../MultipartFormDataTests.cs | 16 -- .../NonProtocolExceptionHandlingTests.cs | 1 + .../RestSharp.Tests.Integrated/OAuth1Tests.cs | 4 +- test/RestSharp.Tests.Integrated/PostTests.cs | 2 +- test/RestSharp.Tests.Integrated/ProxyTests.cs | 2 +- test/RestSharp.Tests.Integrated/PutTests.cs | 3 +- .../RedirectTests.cs | 2 +- .../RequestFailureTests.cs | 2 + .../RequestHeadTests.cs | 18 +- .../Server/Handlers/FileHandlers.cs | 26 +-- .../Server/Handlers/RequestHandlers.cs | 4 - .../Server/Models.cs | 10 +- .../StatusCodeTests.cs | 2 +- .../StructuredSyntaxSuffixTests.cs | 2 +- .../RequestBodyTests.cs | 16 -- .../RestSharp.Tests.Legacy.csproj | 15 -- .../SampleData.cs | 3 +- .../NamespacedXmlTests.cs | 8 +- .../SampleClasses/twitter.cs | 7 +- .../XmlAttributeDeserializerTests.cs | 16 +- .../XmlDeserializerTests.cs | 56 +++--- .../XmlSerializerTests.cs | 2 +- .../Fixtures/Handlers.cs | 17 -- .../Fixtures/RequestBodyCapturer.cs | 1 + .../Fixtures/TestHttpServer.cs | 15 +- .../Fixtures/TestHttpServerExtensions.cs | 5 +- test/RestSharp.Tests/AddRangeTests.cs | 4 +- test/RestSharp.Tests/AuthenticatorTests.cs | 66 +++++++ test/RestSharp.Tests/MultipartFormTests.cs | 44 +++++ test/RestSharp.Tests/ObjectParameterTests.cs | 15 +- test/RestSharp.Tests/OptionsTests.cs | 2 +- test/RestSharp.Tests/ParametersTests.cs | 31 ++-- test/RestSharp.Tests/RestClientTests.cs | 11 +- test/RestSharp.Tests/RestSharp.Tests.csproj | 2 + test/RestSharp.Tests/UrlBuilderTests.cs | 2 +- 75 files changed, 441 insertions(+), 573 deletions(-) delete mode 100644 src/RestSharp/Extensions/ImmutableGenerator.cs delete mode 100644 src/RestSharp/Options/RestRequestOptions.cs delete mode 100644 src/RestSharp/RestClient.Serialization.cs delete mode 100644 test/RestSharp.Tests.Legacy/RequestBodyTests.cs delete mode 100644 test/RestSharp.Tests.Legacy/RestSharp.Tests.Legacy.csproj create mode 100644 test/RestSharp.Tests/AuthenticatorTests.cs create mode 100644 test/RestSharp.Tests/MultipartFormTests.cs diff --git a/RestSharp.sln b/RestSharp.sln index 25439c208..b3efff12e 100644 --- a/RestSharp.sln +++ b/RestSharp.sln @@ -29,8 +29,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.Tests.Serializers EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.Serializers.Xml", "src\RestSharp.Serializers.Xml\RestSharp.Serializers.Xml.csproj", "{4A35B1C5-520D-4267-BA70-2DCEAC0A5662}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.Tests.Legacy", "test\RestSharp.Tests.Legacy\RestSharp.Tests.Legacy.csproj", "{5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.Serializers.CsvHelper", "src\RestSharp.Serializers.CsvHelper\RestSharp.Serializers.CsvHelper.csproj", "{2150E333-8FDC-42A3-9474-1A3956D46DE8}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.Tests.Serializers.Csv", "test\RestSharp.Tests.Serializers.Csv\RestSharp.Tests.Serializers.Csv.csproj", "{E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}" @@ -358,36 +356,6 @@ Global {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Release|x64.Build.0 = Release|Any CPU {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Release|x86.ActiveCfg = Release|Any CPU {4A35B1C5-520D-4267-BA70-2DCEAC0A5662}.Release|x86.Build.0 = Release|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug.Appveyor|Any CPU.ActiveCfg = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug.Appveyor|Any CPU.Build.0 = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug.Appveyor|ARM.ActiveCfg = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug.Appveyor|ARM.Build.0 = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug.Appveyor|Mixed Platforms.ActiveCfg = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug.Appveyor|Mixed Platforms.Build.0 = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug.Appveyor|x64.ActiveCfg = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug.Appveyor|x64.Build.0 = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug.Appveyor|x86.ActiveCfg = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug.Appveyor|x86.Build.0 = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug|ARM.ActiveCfg = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug|ARM.Build.0 = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug|x64.ActiveCfg = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug|x64.Build.0 = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug|x86.ActiveCfg = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Debug|x86.Build.0 = Debug|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Release|Any CPU.Build.0 = Release|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Release|ARM.ActiveCfg = Release|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Release|ARM.Build.0 = Release|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Release|x64.ActiveCfg = Release|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Release|x64.Build.0 = Release|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Release|x86.ActiveCfg = Release|Any CPU - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Release|x86.Build.0 = Release|Any CPU {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug.Appveyor|Any CPU.ActiveCfg = Debug|Any CPU {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug.Appveyor|Any CPU.Build.0 = Debug|Any CPU {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug.Appveyor|ARM.ActiveCfg = Debug|Any CPU @@ -492,7 +460,6 @@ Global {6D7D1D60-4473-4C52-800C-9B892C6640A5} = {9051DDA0-E563-45D5-9504-085EBAACF469} {E6D94C12-9AD7-46E6-AB62-3676F25FDE51} = {9051DDA0-E563-45D5-9504-085EBAACF469} {4A35B1C5-520D-4267-BA70-2DCEAC0A5662} = {8C7B43EB-2F93-483C-B433-E28F9386AD67} - {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0} = {9051DDA0-E563-45D5-9504-085EBAACF469} {2150E333-8FDC-42A3-9474-1A3956D46DE8} = {8C7B43EB-2F93-483C-B433-E28F9386AD67} {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060} = {9051DDA0-E563-45D5-9504-085EBAACF469} {FE778406-ADCF-45A1-B775-A054B55BFC50} = {55B8F371-B2BA-4DEE-AB98-5BAB8A21B1C2} diff --git a/RestSharp.sln.DotSettings b/RestSharp.sln.DotSettings index 764b7bbf2..ed2cafe7c 100644 --- a/RestSharp.sln.DotSettings +++ b/RestSharp.sln.DotSettings @@ -103,5 +103,6 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + True True \ No newline at end of file diff --git a/benchmarks/RestSharp.Benchmarks/Requests/AddObjectToRequestParametersBenchmarks.cs b/benchmarks/RestSharp.Benchmarks/Requests/AddObjectToRequestParametersBenchmarks.cs index e5174e8df..072877d4b 100644 --- a/benchmarks/RestSharp.Benchmarks/Requests/AddObjectToRequestParametersBenchmarks.cs +++ b/benchmarks/RestSharp.Benchmarks/Requests/AddObjectToRequestParametersBenchmarks.cs @@ -2,31 +2,30 @@ using BenchmarkDotNet.Order; using System.Globalization; -namespace RestSharp.Benchmarks.Requests { - [MemoryDiagnoser, RankColumn, Orderer(SummaryOrderPolicy.FastestToSlowest)] - public partial class AddObjectToRequestParametersBenchmarks { - Data _data; +namespace RestSharp.Benchmarks.Requests; - [GlobalSetup] - public void GlobalSetup() { - const string @string = "random string"; - const int arraySize = 10_000; - var strings = new string[arraySize]; - Array.Fill(strings, @string); - var ints = new int[arraySize]; - Array.Fill(ints, int.MaxValue); +[MemoryDiagnoser, RankColumn, Orderer(SummaryOrderPolicy.FastestToSlowest)] +public class AddObjectToRequestParametersBenchmarks { + Data _data; - Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; - var dateTime = DateTime.Parse("01/01/2013 03:03:12"); + [GlobalSetup] + public void GlobalSetup() { + const string @string = "random string"; + const int arraySize = 10_000; + var strings = new string[arraySize]; + Array.Fill(strings, @string); + var ints = new int[arraySize]; + Array.Fill(ints, int.MaxValue); - _data = new Data(@string, int.MaxValue, strings, ints, dateTime, strings); - } + Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; + var dateTime = DateTime.Parse("01/01/2013 03:03:12"); - [Benchmark(Baseline = true)] - public void AddObject() => new RestRequest().AddObject(_data); + _data = new Data(@string, int.MaxValue, strings, ints, dateTime, strings); + } - [Benchmark] - public void AddObjectStatic() => new RestRequest().AddObjectStatic(_data); + [Benchmark(Baseline = true)] + public void AddObject() => new RestRequest().AddObject(_data); - } -} + [Benchmark] + public void AddObjectStatic() => new RestRequest().AddObjectStatic(_data); +} \ No newline at end of file diff --git a/benchmarks/RestSharp.Benchmarks/Requests/Data.cs b/benchmarks/RestSharp.Benchmarks/Requests/Data.cs index 350d5376b..48be615a7 100644 --- a/benchmarks/RestSharp.Benchmarks/Requests/Data.cs +++ b/benchmarks/RestSharp.Benchmarks/Requests/Data.cs @@ -1,9 +1,9 @@ -namespace RestSharp.Benchmarks.Requests { - sealed record Data( - string String, - [property: RequestProperty(Name = "PropertyName")] int Int32, - string[] Strings, - [property: RequestProperty(Format = "00000", ArrayQueryType = RequestArrayQueryType.ArrayParameters)] int[] Ints, - [property: RequestProperty(Name = "DateTime", Format = "hh:mm tt")] object DateTime, - object StringArray); -} +namespace RestSharp.Benchmarks.Requests; + +sealed record Data( + string String, + [property: RequestProperty(Name = "PropertyName")] int Int32, + string[] Strings, + [property: RequestProperty(Format = "00000", ArrayQueryType = RequestArrayQueryType.ArrayParameters)] int[] Ints, + [property: RequestProperty(Name = "DateTime", Format = "hh:mm tt")] object DateTime, + object StringArray); \ No newline at end of file diff --git a/benchmarks/RestSharp.Benchmarks/Serializers/JsonNetSerializeBenchmarks.cs b/benchmarks/RestSharp.Benchmarks/Serializers/JsonNetSerializeBenchmarks.cs index f97d590f3..7a8e40cdc 100644 --- a/benchmarks/RestSharp.Benchmarks/Serializers/JsonNetSerializeBenchmarks.cs +++ b/benchmarks/RestSharp.Benchmarks/Serializers/JsonNetSerializeBenchmarks.cs @@ -2,22 +2,21 @@ using BenchmarkDotNet.Attributes; using RestSharp.Serializers.NewtonsoftJson; -namespace RestSharp.Benchmarks.Serializers +namespace RestSharp.Benchmarks.Serializers; + +[MemoryDiagnoser] +public class JsonNetSerializeBenchmarks { - [MemoryDiagnoser] - public class JsonNetSerializeBenchmarks - { - readonly JsonNetSerializer _serializer = new(); + readonly JsonNetSerializer _serializer = new(); - List _fakeData; + List _fakeData; - [Params(1, 10, 20)] - public int N { get; set; } + [Params(1, 10, 20)] + public int N { get; set; } - [GlobalSetup] - public void GlobalSetup() => _fakeData = new Fixture().CreateMany(N).ToList(); + [GlobalSetup] + public void GlobalSetup() => _fakeData = new Fixture().CreateMany(N).ToList(); - [Benchmark(Baseline = true)] - public string Serialize() => _serializer.Serialize(_fakeData); - } -} + [Benchmark(Baseline = true)] + public string Serialize() => _serializer.Serialize(_fakeData); +} \ No newline at end of file diff --git a/benchmarks/RestSharp.Benchmarks/Serializers/TestClass.cs b/benchmarks/RestSharp.Benchmarks/Serializers/TestClass.cs index ff41a84f6..7345517ab 100644 --- a/benchmarks/RestSharp.Benchmarks/Serializers/TestClass.cs +++ b/benchmarks/RestSharp.Benchmarks/Serializers/TestClass.cs @@ -1,3 +1,4 @@ +// ReSharper disable UnusedMember.Global namespace RestSharp.Benchmarks.Serializers; public class TestClass { diff --git a/src/RestSharp.Serializers.Xml/XmlExtensions.cs b/src/RestSharp.Serializers.Xml/XmlExtensions.cs index fba9da379..b988f7abb 100644 --- a/src/RestSharp.Serializers.Xml/XmlExtensions.cs +++ b/src/RestSharp.Serializers.Xml/XmlExtensions.cs @@ -30,7 +30,7 @@ public static class XmlExtensions { public static XName? AsNamespaced(this string? name, string? @namespace) { XName? xName = name; - if (name != null && @namespace.IsNotEmpty()) xName = XName.Get(name, @namespace!); + if (name != null && @namespace.IsNotEmpty()) xName = XName.Get(name, @namespace); return xName; } diff --git a/src/RestSharp.Serializers.Xml/XmlSerializer.cs b/src/RestSharp.Serializers.Xml/XmlSerializer.cs index e31e9f067..d5c235f1e 100644 --- a/src/RestSharp.Serializers.Xml/XmlSerializer.cs +++ b/src/RestSharp.Serializers.Xml/XmlSerializer.cs @@ -110,7 +110,7 @@ public class XmlSerializer : IXmlSerializer, IWithRootElement, IWithDateFormat { var props = objType.GetProperties() .Select(p => new { p, indexAttribute = p.GetAttribute() }) - .Where(t => t.p.CanRead && t.p.CanWrite) + .Where(t => t.p is { CanRead: true, CanWrite: true }) .OrderBy(t => t.indexAttribute?.Index ?? int.MaxValue) .Select(t => t.p); var globalOptions = objType.GetAttribute(); @@ -177,7 +177,7 @@ public class XmlSerializer : IXmlSerializer, IWithRootElement, IWithDateFormat { ? setting.Name : type.Name; - var instance = new XElement(itemTypeName!.AsNamespaced(Namespace)!); + var instance = new XElement(itemTypeName.AsNamespaced(Namespace)!); Map(instance, item); @@ -228,17 +228,17 @@ static string SerializeNumber(object number) /// static bool IsNumeric(object value) => value switch { - sbyte _ => true, - byte _ => true, - short _ => true, - ushort _ => true, - int _ => true, - uint _ => true, - long _ => true, - ulong _ => true, - float _ => true, - double _ => true, - decimal _ => true, - _ => false + sbyte => true, + byte => true, + short => true, + ushort => true, + int => true, + uint => true, + long => true, + ulong => true, + float => true, + double => true, + decimal => true, + _ => false }; } \ No newline at end of file diff --git a/src/RestSharp/Authenticators/OAuth/Extensions/StringExtensions.cs b/src/RestSharp/Authenticators/OAuth/Extensions/StringExtensions.cs index 532ec9969..aef613233 100644 --- a/src/RestSharp/Authenticators/OAuth/Extensions/StringExtensions.cs +++ b/src/RestSharp/Authenticators/OAuth/Extensions/StringExtensions.cs @@ -21,7 +21,7 @@ static class StringExtensions { public static string Then(this string input, string value) => string.Concat(input, value); - public static Uri AsUri(this string value) => new Uri(value); + public static Uri AsUri(this string value) => new(value); public static byte[] GetBytes(this string input) => Encoding.UTF8.GetBytes(input); diff --git a/src/RestSharp/Authenticators/OAuth/OAuth1Authenticator.cs b/src/RestSharp/Authenticators/OAuth/OAuth1Authenticator.cs index 93e0c6bff..b3637db42 100644 --- a/src/RestSharp/Authenticators/OAuth/OAuth1Authenticator.cs +++ b/src/RestSharp/Authenticators/OAuth/OAuth1Authenticator.cs @@ -75,6 +75,7 @@ public class OAuth1Authenticator : IAuthenticator { Type = OAuthType.RequestToken }; + [PublicAPI] public static OAuth1Authenticator ForRequestToken(string consumerKey, string? consumerSecret, string callbackUrl) { var authenticator = ForRequestToken(consumerKey, consumerSecret); @@ -102,6 +103,7 @@ public class OAuth1Authenticator : IAuthenticator { Type = OAuthType.AccessToken }; + [PublicAPI] public static OAuth1Authenticator ForAccessToken( string consumerKey, string? consumerSecret, @@ -167,6 +169,7 @@ string sessionHandle Type = OAuthType.ClientAuthentication }; + [PublicAPI] public static OAuth1Authenticator ForProtectedResource( string consumerKey, string? consumerSecret, diff --git a/src/RestSharp/Authenticators/OAuth/OAuthTools.cs b/src/RestSharp/Authenticators/OAuth/OAuthTools.cs index 3badb1692..f48400fbc 100644 --- a/src/RestSharp/Authenticators/OAuth/OAuthTools.cs +++ b/src/RestSharp/Authenticators/OAuth/OAuthTools.cs @@ -139,7 +139,7 @@ static class OAuthTools { /// /// A collection of parameters to sort /// A sorted parameter collection - public static IEnumerable SortParametersExcludingSignature(WebPairCollection parameters) + internal static IEnumerable SortParametersExcludingSignature(WebPairCollection parameters) => parameters .Where(x => !x.Name.EqualsIgnoreCase("oauth_signature")) .Select(x => new WebPair(UrlEncodeStrict(x.Name), UrlEncodeStrict(x.Value))) @@ -231,9 +231,9 @@ public static IEnumerable SortParametersExcludingSignature(WebPairCollec if (tokenSecret.IsEmpty()) tokenSecret = string.Empty; if (consumerSecret.IsEmpty()) consumerSecret = string.Empty; - var unencodedConsumerSecret = consumerSecret!; - consumerSecret = Uri.EscapeDataString(consumerSecret!); - tokenSecret = Uri.EscapeDataString(tokenSecret!); + var unencodedConsumerSecret = consumerSecret; + consumerSecret = Uri.EscapeDataString(consumerSecret); + tokenSecret = Uri.EscapeDataString(tokenSecret); var signature = signatureMethod switch { HmacSha1 => GetHmacSignature(new HMACSHA1(), consumerSecret, tokenSecret, signatureBase), @@ -254,9 +254,12 @@ public static IEnumerable SortParametersExcludingSignature(WebPairCollec provider.FromXmlString(unencodedConsumerSecret); +#if NET + var hash = SHA1.HashData(Encoding.GetBytes(signatureBase)); +#else var hasher = SHA1.Create(); - var hash = hasher.ComputeHash(Encoding.GetBytes(signatureBase)); - + var hash = hasher.ComputeHash(Encoding.GetBytes(signatureBase)); +#endif return Convert.ToBase64String(provider.SignHash(hash, CryptoConfig.MapNameToOID("SHA1"))); } } @@ -266,4 +269,4 @@ public static IEnumerable SortParametersExcludingSignature(WebPairCollec crypto.Key = Encoding.GetBytes(key); return signatureBase.HashWith(crypto); } -} \ No newline at end of file +} diff --git a/src/RestSharp/Authenticators/OAuth/OAuthWorkflow.cs b/src/RestSharp/Authenticators/OAuth/OAuthWorkflow.cs index 5221da829..2039fb069 100644 --- a/src/RestSharp/Authenticators/OAuth/OAuthWorkflow.cs +++ b/src/RestSharp/Authenticators/OAuth/OAuthWorkflow.cs @@ -21,19 +21,19 @@ namespace RestSharp.Authenticators.OAuth; /// A class to encapsulate OAuth authentication flow. /// sealed class OAuthWorkflow { - public string? Version { get; set; } - public string? ConsumerKey { get; set; } - public string? ConsumerSecret { get; set; } - public string? Token { get; set; } - public string? TokenSecret { get; set; } - public string? CallbackUrl { get; set; } - public string? Verifier { get; set; } - public string? SessionHandle { get; set; } - public OAuthSignatureMethod SignatureMethod { get; set; } - public OAuthSignatureTreatment SignatureTreatment { get; set; } + public string? Version { get; init; } + public string? ConsumerKey { get; init; } + public string? ConsumerSecret { get; init; } + public string? Token { get; init; } + public string? TokenSecret { get; init; } + public string? CallbackUrl { get; init; } + public string? Verifier { get; init; } + public string? SessionHandle { get; init; } + public OAuthSignatureMethod SignatureMethod { get; init; } + public OAuthSignatureTreatment SignatureTreatment { get; init; } public OAuthParameterHandling ParameterHandling { get; set; } - public string? ClientUsername { get; set; } - public string? ClientPassword { get; set; } + public string? ClientUsername { get; init; } + public string? ClientPassword { get; init; } public string? RequestTokenUrl { get; set; } public string? AccessTokenUrl { get; set; } @@ -164,9 +164,7 @@ sealed class OAuthWorkflow { Ensure.NotEmpty(ClientUsername, nameof(ClientUsername)); } - void ValidateProtectedResourceState() { - Ensure.NotEmpty(ConsumerKey, nameof(ConsumerKey)); - } + void ValidateProtectedResourceState() => Ensure.NotEmpty(ConsumerKey, nameof(ConsumerKey)); WebPairCollection GenerateAuthParameters(string timestamp, string nonce) => new WebPairCollection { @@ -181,7 +179,7 @@ WebPairCollection GenerateAuthParameters(string timestamp, string nonce) .AddNotEmpty("oauth_session_handle", SessionHandle!); WebPairCollection GenerateXAuthParameters(string timestamp, string nonce) - => new WebPairCollection { + => new() { new("x_auth_username", Ensure.NotNull(ClientUsername, nameof(ClientUsername))), new("x_auth_password", Ensure.NotNull(ClientPassword, nameof(ClientPassword))), new("x_auth_mode", "client_auth"), diff --git a/src/RestSharp/Authenticators/OAuth2/OAuth2AuthorizationRequestHeaderAuthenticator.cs b/src/RestSharp/Authenticators/OAuth2/OAuth2AuthorizationRequestHeaderAuthenticator.cs index e05d4751a..59f9a71a0 100644 --- a/src/RestSharp/Authenticators/OAuth2/OAuth2AuthorizationRequestHeaderAuthenticator.cs +++ b/src/RestSharp/Authenticators/OAuth2/OAuth2AuthorizationRequestHeaderAuthenticator.cs @@ -20,6 +20,7 @@ namespace RestSharp.Authenticators.OAuth2; /// /// Based on http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-5.1.1 /// +[PublicAPI] public class OAuth2AuthorizationRequestHeaderAuthenticator : AuthenticatorBase { readonly string _tokenType; diff --git a/src/RestSharp/Authenticators/OAuth2/OAuth2UriQueryParameterAuthenticator.cs b/src/RestSharp/Authenticators/OAuth2/OAuth2UriQueryParameterAuthenticator.cs index 2b040a85a..9ea1b593f 100644 --- a/src/RestSharp/Authenticators/OAuth2/OAuth2UriQueryParameterAuthenticator.cs +++ b/src/RestSharp/Authenticators/OAuth2/OAuth2UriQueryParameterAuthenticator.cs @@ -20,6 +20,7 @@ namespace RestSharp.Authenticators.OAuth2; /// /// Based on http://tools.ietf.org/html/draft-ietf-oauth-v2-10#section-5.1.2 /// +[PublicAPI] public class OAuth2UriQueryParameterAuthenticator : AuthenticatorBase { /// /// Initializes a new instance of the class. diff --git a/src/RestSharp/ContentType.cs b/src/RestSharp/ContentType.cs index 1a2d3d36d..54bec16e8 100644 --- a/src/RestSharp/ContentType.cs +++ b/src/RestSharp/ContentType.cs @@ -44,9 +44,9 @@ public class ContentType : IEquatable { public static implicit operator string(ContentType contentType) => contentType.Value; - public ContentType Or(ContentType? contentType) => Equals(Undefined) ? (contentType ?? Plain) : this; + public ContentType Or(ContentType? contentType) => Equals(Undefined) ? contentType ?? Plain : this; - public string OrValue(string? contentType) => Equals(Undefined) ? (contentType ?? Plain.Value) : Value; + public string OrValue(string? contentType) => Equals(Undefined) ? contentType ?? Plain.Value : Value; public MediaTypeHeaderValue AsMediaTypeHeaderValue => MediaTypeHeaderValue.Parse(Value); @@ -78,7 +78,7 @@ public class ContentType : IEquatable { public override bool Equals(object? obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj.GetType() != GetType()) return false; return Equals((ContentType)obj); } diff --git a/src/RestSharp/Extensions/HttpResponseExtensions.cs b/src/RestSharp/Extensions/HttpResponseExtensions.cs index 734ff0cd2..d501f5c5a 100644 --- a/src/RestSharp/Extensions/HttpResponseExtensions.cs +++ b/src/RestSharp/Extensions/HttpResponseExtensions.cs @@ -49,24 +49,24 @@ static class HttpResponseExtensions { Func? writer, CancellationToken cancellationToken = default ) { - var readTask = writer == null ? ReadResponse() : ReadAndConvertResponse(); + var readTask = writer == null ? ReadResponse() : ReadAndConvertResponse(writer); return readTask; Task ReadResponse() { #if NET return httpResponse.Content.ReadAsStreamAsync(cancellationToken)!; # else - return httpResponse.Content.ReadAsStreamAsync(); + return httpResponse.Content == null ? Task.FromResult((Stream?)null) : httpResponse.Content.ReadAsStreamAsync(); #endif } - async Task ReadAndConvertResponse() { + async Task ReadAndConvertResponse(Func streamWriter) { #if NET await using var original = await ReadResponse().ConfigureAwait(false); #else using var original = await ReadResponse().ConfigureAwait(false); #endif - return writer!(original!); + return original == null ? null : streamWriter(original); } } } diff --git a/src/RestSharp/Extensions/ImmutableGenerator.cs b/src/RestSharp/Extensions/ImmutableGenerator.cs deleted file mode 100644 index e25e19183..000000000 --- a/src/RestSharp/Extensions/ImmutableGenerator.cs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) .NET Foundation and Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -using System.Linq.Expressions; -using System.Reflection; - -namespace RestSharp.Extensions; - -static class ImmutableGenerator { - static readonly MethodInfo SetPropertyMethod = - typeof(ImmutableGenerator).GetMethod(nameof(SetProperty), BindingFlags.Static | BindingFlags.NonPublic)!; - - static void SetProperty(T obj, PropertyInfo property, object value) => property.SetValue(obj, (T)value); - - public static Func CreateImmutableFunc() - where TMutable : class - where TImmutable : class, new() - { - var mutableType = typeof(TMutable); - var immutableType = typeof(TImmutable); - - var parameter = Expression.Parameter(mutableType, "mutable"); - - var bindings = mutableType.GetProperties(BindingFlags.Public | BindingFlags.Instance) - .Select(property => - Expression.Bind( - immutableType.GetProperty(property.Name)!, - Expression.Property(parameter, property))); - - var body = Expression.MemberInit(Expression.New(immutableType), bindings); - - var lambda = Expression.Lambda>(body, parameter); - - return lambda.Compile(); - } -} diff --git a/src/RestSharp/Extensions/ReflectionExtensions.cs b/src/RestSharp/Extensions/ReflectionExtensions.cs index a16513535..01a7e2b96 100644 --- a/src/RestSharp/Extensions/ReflectionExtensions.cs +++ b/src/RestSharp/Extensions/ReflectionExtensions.cs @@ -57,8 +57,6 @@ public static class ReflectionExtensions { return false; } - internal static object ChangeType(this object source, Type newType, IFormatProvider provider) => Convert.ChangeType(source, newType, provider); - internal static object? ChangeType(this object? source, Type newType) => Convert.ChangeType(source, newType); /// diff --git a/src/RestSharp/Options/RestRequestOptions.cs b/src/RestSharp/Options/RestRequestOptions.cs deleted file mode 100644 index 7dfdadc44..000000000 --- a/src/RestSharp/Options/RestRequestOptions.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) .NET Foundation and Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -using System.Net.Http.Headers; -using RestSharp.Authenticators; - -namespace RestSharp; - -public class RestRequestOptions { - /// - /// Authenticator that will be used to populate request with necessary authentication data - /// - public IAuthenticator? Authenticator { get; set; } - - public CacheControlHeaderValue? CachePolicy { get; set; } - - public string? BaseHost { get; set; } -} diff --git a/src/RestSharp/Request/PropertyCache.Populator.cs b/src/RestSharp/Request/PropertyCache.Populator.cs index 278dfdf51..4118b6747 100644 --- a/src/RestSharp/Request/PropertyCache.Populator.cs +++ b/src/RestSharp/Request/PropertyCache.Populator.cs @@ -133,7 +133,7 @@ sealed partial class Populator { // and use its type converter. Even though the property itself returns an object, // the object returned itself may need to be treated in a special way, so we check // it as we go. - var otherType => GetPopulate(getObject, requestProperty) + _ => GetPopulate(getObject, requestProperty) }; } @@ -146,8 +146,8 @@ sealed partial class Populator { } return enumeratedType switch { - var formattableEnumeratedType when typeof(IFormattable).IsAssignableFrom(formattableEnumeratedType) => GetPopulate( - GetEnumerableOf(getEnumerable, formattableEnumeratedType), + _ when typeof(IFormattable).IsAssignableFrom(enumeratedType) => GetPopulate( + GetEnumerableOf(getEnumerable, enumeratedType), requestProperty ), _ when typeof(IConvertible).IsAssignableFrom(enumeratedType) => GetPopulate( diff --git a/src/RestSharp/Request/PropertyCache.cs b/src/RestSharp/Request/PropertyCache.cs index a967362bd..5427323b5 100644 --- a/src/RestSharp/Request/PropertyCache.cs +++ b/src/RestSharp/Request/PropertyCache.cs @@ -23,13 +23,13 @@ static partial class PropertyCache where T : class { // We need to ensure the property does not return a ref struct // since reflection and LINQ expressions do not play well with // them. All bets are off, so let's just ignore them. -#if NETCOREAPP2_1_OR_GREATER +#if NET .Where(property => !property.PropertyType.IsByRefLike) #else // Since `IsByRefLikeAttribute` is generated at compile time, each assembly // may have its own definition of the attribute, so we must compare by full name // instead of type. - .Where(property => !property.PropertyType.GetCustomAttributes().Select(attribute => attribute.GetType().FullName).Any(attributeName => attributeName == "System.Runtime.CompilerServices.IsByRefLikeAttribute")) + .Where(property => property.PropertyType.GetCustomAttributes().Select(attribute => attribute.GetType().FullName).All(attributeName => attributeName != "System.Runtime.CompilerServices.IsByRefLikeAttribute")) #endif .Select(Populator.From) .ToArray(); diff --git a/src/RestSharp/Request/RequestContent.cs b/src/RestSharp/Request/RequestContent.cs index 3ba769012..4df106cb1 100644 --- a/src/RestSharp/Request/RequestContent.cs +++ b/src/RestSharp/Request/RequestContent.cs @@ -123,7 +123,7 @@ class RequestContent : IDisposable { var bodyContent = Serialize(bodyParameter); // we need to send the body - if (hasPostParameters || _request.HasFiles() || BodyShouldBeMultipartForm(bodyParameter!) || _request.AlwaysMultipartFormData) { + if (hasPostParameters || _request.HasFiles() || BodyShouldBeMultipartForm(bodyParameter) || _request.AlwaysMultipartFormData) { // here we must use multipart form data var mpContent = Content as MultipartFormDataContent ?? CreateMultipartFormDataContent(); var ct = bodyContent.Headers.ContentType?.MediaType; @@ -160,7 +160,7 @@ class RequestContent : IDisposable { } } else { - var encodedItems = postParameters.Select(x => $"{x.Name!.UrlEncode()}={x.Value?.ToString()?.UrlEncode() ?? string.Empty}"); + var encodedItems = postParameters.Select(x => $"{x.Name!.UrlEncode()}={x.Value?.ToString()!.UrlEncode() ?? string.Empty}"); var encodedContent = new StringContent(encodedItems.JoinToString("&"), _client.Options.Encoding, ContentType.FormUrlEncoded.Value); if (_client.Options.DisableCharset) { diff --git a/src/RestSharp/Request/RestRequest.cs b/src/RestSharp/Request/RestRequest.cs index 6e5290595..bc3b68382 100644 --- a/src/RestSharp/Request/RestRequest.cs +++ b/src/RestSharp/Request/RestRequest.cs @@ -93,6 +93,7 @@ public RestRequest(Uri resource, Method method = Method.Get) /// When set to true, the form boundary part of the content type will be enclosed in /// quotation marks. Default is true. /// + [PublicAPI] public bool MultipartFormQuoteBoundary { get; set; } = true; /// @@ -144,6 +145,7 @@ public RestRequest(Uri resource, Method method = Method.Get) /// request.Resource = "Products/{ProductId}"; /// request.AddParameter("ProductId", 123, ParameterType.UrlSegment); /// + [PublicAPI] public string Resource { get; set; } = ""; /// @@ -180,6 +182,7 @@ public RestRequest(Uri resource, Method method = Method.Get) /// /// This number is incremented each time the RestClient sends the request. /// + [PublicAPI] public int Attempts { get; private set; } /// diff --git a/src/RestSharp/Request/RestRequestExtensions.cs b/src/RestSharp/Request/RestRequestExtensions.cs index 2e429d91d..ce33b2611 100644 --- a/src/RestSharp/Request/RestRequestExtensions.cs +++ b/src/RestSharp/Request/RestRequestExtensions.cs @@ -338,7 +338,7 @@ public static RestRequest AddOrUpdateParameter(this RestRequest request, Paramet DataFormat.Json => request.AddJsonBody(obj, contentType), DataFormat.Xml => request.AddXmlBody(obj, contentType), DataFormat.Binary => request.AddParameter(new BodyParameter("", obj, ContentType.Binary)), - _ => request.AddParameter(new BodyParameter("", obj.ToString(), ContentType.Plain)) + _ => request.AddParameter(new BodyParameter("", obj.ToString()!, ContentType.Plain)) }; } diff --git a/src/RestSharp/Request/UriExtensions.cs b/src/RestSharp/Request/UriExtensions.cs index 887e9ed7d..95ad66611 100644 --- a/src/RestSharp/Request/UriExtensions.cs +++ b/src/RestSharp/Request/UriExtensions.cs @@ -13,7 +13,6 @@ // limitations under the License. // -using System.Text; using RestSharp.Extensions; namespace RestSharp; @@ -22,11 +21,11 @@ static class UriExtensions { public static Uri MergeBaseUrlAndResource(this Uri? baseUrl, string? resource) { var assembled = resource; - if (assembled.IsNotEmpty() && assembled!.StartsWith("/")) assembled = assembled.Substring(1); + if (assembled.IsNotEmpty() && assembled.StartsWith("/")) assembled = assembled.Substring(1); if (baseUrl == null || baseUrl.AbsoluteUri.IsEmpty()) { return assembled.IsNotEmpty() - ? new Uri(assembled!) + ? new Uri(assembled) : throw new ArgumentException("Both BaseUrl and Resource are empty", nameof(resource)); } @@ -55,13 +54,14 @@ static class UriExtensions { var hasResource = !assembled.IsEmpty(); - var parameters = parametersCollections.SelectMany(x => x.GetParameters(ParameterType.UrlSegment)); + var parameters = parametersCollections.SelectMany(x => x.GetParameters()); var builder = new UriBuilder(baseUrl); foreach (var parameter in parameters) { var paramPlaceHolder = $"{{{parameter.Name}}}"; - var paramValue = parameter.Encode ? encode(parameter.Value!.ToString()!) : parameter.Value!.ToString(); + var value = Ensure.NotNull(parameter.Value!.ToString(), $"URL segment parameter {parameter.Name} value"); + var paramValue = parameter.Encode ? encode(value) : value; if (hasResource) assembled = assembled.Replace(paramPlaceHolder, paramValue); diff --git a/src/RestSharp/Response/RestResponse.cs b/src/RestSharp/Response/RestResponse.cs index 00b704a13..0240946e0 100644 --- a/src/RestSharp/Response/RestResponse.cs +++ b/src/RestSharp/Response/RestResponse.cs @@ -84,10 +84,10 @@ CancellationToken cancellationToken return new RestResponse(request) { Content = content, RawBytes = bytes, - ContentEncoding = httpResponse.Content.Headers.ContentEncoding, + ContentEncoding = httpResponse.Content?.Headers.ContentEncoding ?? Array.Empty(), Version = httpResponse.RequestMessage?.Version, - ContentLength = httpResponse.Content.Headers.ContentLength, - ContentType = httpResponse.Content.Headers.ContentType?.MediaType, + ContentLength = httpResponse.Content?.Headers.ContentLength, + ContentType = httpResponse.Content?.Headers.ContentType?.MediaType, ResponseStatus = calculateResponseStatus(httpResponse), ErrorException = httpResponse.MaybeException(), ResponseUri = httpResponse.RequestMessage?.RequestUri, @@ -96,7 +96,7 @@ CancellationToken cancellationToken StatusDescription = httpResponse.ReasonPhrase, IsSuccessStatusCode = httpResponse.IsSuccessStatusCode, Headers = httpResponse.Headers.GetHeaderParameters(), - ContentHeaders = httpResponse.Content.Headers.GetHeaderParameters(), + ContentHeaders = httpResponse.Content?.Headers.GetHeaderParameters(), Cookies = cookieCollection, RootElement = request.RootElement }; diff --git a/src/RestSharp/Response/RestResponseBase.cs b/src/RestSharp/Response/RestResponseBase.cs index 0e5077950..6bbe710b0 100644 --- a/src/RestSharp/Response/RestResponseBase.cs +++ b/src/RestSharp/Response/RestResponseBase.cs @@ -52,7 +52,7 @@ public abstract class RestResponseBase { /// /// Encoding of the response content /// - public ICollection ContentEncoding { get; set; } = new List(); + public ICollection ContentEncoding { get; set; } = Array.Empty(); /// /// String representation of response content diff --git a/src/RestSharp/RestClient.Async.cs b/src/RestSharp/RestClient.Async.cs index 0bc010bb6..c5da81007 100644 --- a/src/RestSharp/RestClient.Async.cs +++ b/src/RestSharp/RestClient.Async.cs @@ -13,7 +13,6 @@ // limitations under the License. using System.Net; -using System.Net.Http.Headers; using RestSharp.Extensions; namespace RestSharp; @@ -78,11 +77,11 @@ public partial class RestClient { throw new ObjectDisposedException(nameof(RestClient)); } - using var requestContent = new RequestContent(this, request); - var authenticator = request.Authenticator ?? Options.Authenticator; if (authenticator != null) await authenticator.Authenticate(this, request).ConfigureAwait(false); + using var requestContent = new RequestContent(this, request); + var httpMethod = AsHttpMethod(request.Method); var url = this.BuildUri(request); diff --git a/src/RestSharp/RestClient.Extensions.Config.cs b/src/RestSharp/RestClient.Extensions.Config.cs index 006bdc571..3b4eda0a2 100644 --- a/src/RestSharp/RestClient.Extensions.Config.cs +++ b/src/RestSharp/RestClient.Extensions.Config.cs @@ -15,14 +15,13 @@ using System.Text; using RestSharp.Authenticators; -using RestSharp.Extensions; namespace RestSharp; public static partial class RestClientExtensions { [PublicAPI] public static RestResponse Deserialize(this IRestClient client, RestResponse response) - => client.Serializers.Deserialize(response.Request!, response, client.Options); + => client.Serializers.Deserialize(response.Request, response, client.Options); [Obsolete("Set the RestClientOptions.Encode property instead")] public static RestClient UseUrlEncoder(this RestClient client, Func encoder) diff --git a/src/RestSharp/RestClient.Extensions.Json.cs b/src/RestSharp/RestClient.Extensions.Json.cs index 3f5a3cbbd..5a98a6821 100644 --- a/src/RestSharp/RestClient.Extensions.Json.cs +++ b/src/RestSharp/RestClient.Extensions.Json.cs @@ -14,7 +14,6 @@ // using System.Net; -using RestSharp.Extensions; namespace RestSharp; diff --git a/src/RestSharp/RestClient.Extensions.Params.cs b/src/RestSharp/RestClient.Extensions.Params.cs index 840ef74b3..a919fa8b4 100644 --- a/src/RestSharp/RestClient.Extensions.Params.cs +++ b/src/RestSharp/RestClient.Extensions.Params.cs @@ -13,9 +13,6 @@ // limitations under the License. // -using System.Net; -using System.Text; - namespace RestSharp; public static partial class RestClientExtensions { diff --git a/src/RestSharp/RestClient.Extensions.cs b/src/RestSharp/RestClient.Extensions.cs index d1ebbd11e..01593c268 100644 --- a/src/RestSharp/RestClient.Extensions.cs +++ b/src/RestSharp/RestClient.Extensions.cs @@ -14,7 +14,6 @@ using System.Runtime.CompilerServices; using RestSharp.Extensions; -using RestSharp.Serializers; namespace RestSharp; diff --git a/src/RestSharp/RestClient.Serialization.cs b/src/RestSharp/RestClient.Serialization.cs deleted file mode 100644 index d36954966..000000000 --- a/src/RestSharp/RestClient.Serialization.cs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) .NET Foundation and Contributors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -using RestSharp.Extensions; -using RestSharp.Serializers; -using RestSharp.Serializers.Json; -using RestSharp.Serializers.Xml; - -// ReSharper disable VirtualMemberCallInConstructor -#pragma warning disable 618 - -namespace RestSharp; - -public partial class RestClient { -} \ No newline at end of file diff --git a/src/RestSharp/Serializers/Xml/DotNetXmlDeserializer.cs b/src/RestSharp/Serializers/Xml/DotNetXmlDeserializer.cs index f05a8f22f..11ce197e4 100644 --- a/src/RestSharp/Serializers/Xml/DotNetXmlDeserializer.cs +++ b/src/RestSharp/Serializers/Xml/DotNetXmlDeserializer.cs @@ -28,6 +28,7 @@ public class DotNetXmlDeserializer : IXmlDeserializer { /// /// Name of the root element to use when serializing /// + [Obsolete("DotnetXmlDeserializer does not support RootElement.")] public string? RootElement { get; set; } /// @@ -35,6 +36,7 @@ public class DotNetXmlDeserializer : IXmlDeserializer { /// public string? Namespace { get; set; } + [Obsolete("DotnetXmlDeserializer does not support DateFormat.")] public string? DateFormat { get; set; } public T? Deserialize(RestResponse response) { diff --git a/src/RestSharp/Serializers/Xml/DotNetXmlSerializer.cs b/src/RestSharp/Serializers/Xml/DotNetXmlSerializer.cs index 20eda856e..021b32633 100644 --- a/src/RestSharp/Serializers/Xml/DotNetXmlSerializer.cs +++ b/src/RestSharp/Serializers/Xml/DotNetXmlSerializer.cs @@ -52,8 +52,6 @@ public class DotNetXmlSerializer : IXmlSerializer { ns.Add(string.Empty, Namespace); - var root = RootElement == null ? null : new XmlRootAttribute(RootElement); - var serializer = GetXmlSerializer(obj.GetType(), RootElement); var writer = new EncodingStringWriter(Encoding); diff --git a/src/RestSharp/Sync/AsyncHelpers.cs b/src/RestSharp/Sync/AsyncHelpers.cs index fb73c02fd..d65bac248 100644 --- a/src/RestSharp/Sync/AsyncHelpers.cs +++ b/src/RestSharp/Sync/AsyncHelpers.cs @@ -17,109 +17,109 @@ using System.Collections.Concurrent; using System.Runtime.ExceptionServices; -namespace RestSharp { - static class AsyncHelpers { - /// - /// Executes a task synchronously on the calling thread by installing a temporary synchronization context that queues continuations - /// - /// Callback for asynchronous task to run - public static void RunSync(Func task) { - var currentContext = SynchronizationContext.Current; - var customContext = new CustomSynchronizationContext(task); +namespace RestSharp; - try { - SynchronizationContext.SetSynchronizationContext(customContext); - customContext.Run(); - } - finally { - SynchronizationContext.SetSynchronizationContext(currentContext); - } +static class AsyncHelpers { + /// + /// Executes a task synchronously on the calling thread by installing a temporary synchronization context that queues continuations + /// + /// Callback for asynchronous task to run + public static void RunSync(Func task) { + var currentContext = SynchronizationContext.Current; + var customContext = new CustomSynchronizationContext(task); + + try { + SynchronizationContext.SetSynchronizationContext(customContext); + customContext.Run(); + } + finally { + SynchronizationContext.SetSynchronizationContext(currentContext); } + } + + /// + /// Executes a task synchronously on the calling thread by installing a temporary synchronization context that queues continuations + /// + /// Callback for asynchronous task to run + /// Return type for the task + /// Return value from the task + public static T RunSync(Func> task) { + T result = default!; + RunSync(async () => { result = await task(); }); + return result; + } + + /// + /// Synchronization context that can be "pumped" in order to have it execute continuations posted back to it + /// + class CustomSynchronizationContext : SynchronizationContext { + readonly ConcurrentQueue> _items = new(); + readonly AutoResetEvent _workItemsWaiting = new(false); + readonly Func _task; + ExceptionDispatchInfo? _caughtException; + bool _done; /// - /// Executes a task synchronously on the calling thread by installing a temporary synchronization context that queues continuations + /// Constructor for the custom context /// - /// Callback for asynchronous task to run - /// Return type for the task - /// Return value from the task - public static T RunSync(Func> task) { - T result = default!; - RunSync(async () => { result = await task(); }); - return result; - } + /// Task to execute + public CustomSynchronizationContext(Func task) => + _task = task ?? throw new ArgumentNullException(nameof(task), "Please remember to pass a Task to be executed"); /// - /// Synchronization context that can be "pumped" in order to have it execute continuations posted back to it + /// When overridden in a derived class, dispatches an asynchronous message to a synchronization context. /// - class CustomSynchronizationContext : SynchronizationContext { - readonly ConcurrentQueue> _items = new(); - readonly AutoResetEvent _workItemsWaiting = new(false); - readonly Func _task; - ExceptionDispatchInfo? _caughtException; - bool _done; - - /// - /// Constructor for the custom context - /// - /// Task to execute - public CustomSynchronizationContext(Func task) => - _task = task ?? throw new ArgumentNullException(nameof(task), "Please remember to pass a Task to be executed"); - - /// - /// When overridden in a derived class, dispatches an asynchronous message to a synchronization context. - /// - /// Callback function - /// Callback state - public override void Post(SendOrPostCallback function, object? state) { - _items.Enqueue(Tuple.Create(function, state)); - _workItemsWaiting.Set(); - } + /// Callback function + /// Callback state + public override void Post(SendOrPostCallback function, object? state) { + _items.Enqueue(Tuple.Create(function, state)); + _workItemsWaiting.Set(); + } - /// - /// Enqueues the function to be executed and executes all resulting continuations until it is completely done - /// - public void Run() { - async void PostCallback(object? _) { - try { - await _task().ConfigureAwait(false); - } - catch (Exception exception) { - _caughtException = ExceptionDispatchInfo.Capture(exception); - throw; - } - finally { - Post(_ => _done = true, null); - } + /// + /// Enqueues the function to be executed and executes all resulting continuations until it is completely done + /// + public void Run() { + async void PostCallback(object? _) { + try { + await _task().ConfigureAwait(false); } + catch (Exception exception) { + _caughtException = ExceptionDispatchInfo.Capture(exception); + throw; + } + finally { + Post(_ => _done = true, null); + } + } - Post(PostCallback, null); + Post(PostCallback, null); - while (!_done) { - if (_items.TryDequeue(out var task)) { - task.Item1(task.Item2); - if (_caughtException == null) { - continue; - } - _caughtException.Throw(); - } - else { - _workItemsWaiting.WaitOne(); + while (!_done) { + if (_items.TryDequeue(out var task)) { + task.Item1(task.Item2); + if (_caughtException == null) { + continue; } + _caughtException.Throw(); + } + else { + _workItemsWaiting.WaitOne(); } } + } - /// - /// When overridden in a derived class, dispatches a synchronous message to a synchronization context. - /// - /// Callback function - /// Callback state - public override void Send(SendOrPostCallback function, object? state) => throw new NotSupportedException("Cannot send to same thread"); + /// + /// When overridden in a derived class, dispatches a synchronous message to a synchronization context. + /// + /// Callback function + /// Callback state + public override void Send(SendOrPostCallback function, object? state) => throw new NotSupportedException("Cannot send to same thread"); - /// - /// When overridden in a derived class, creates a copy of the synchronization context. Not needed, so just return ourselves. - /// - /// Copy of the context - public override SynchronizationContext CreateCopy() => this; - } + /// + /// When overridden in a derived class, creates a copy of the synchronization context. Not needed, so just return ourselves. + /// + /// Copy of the context + public override SynchronizationContext CreateCopy() => this; } } \ No newline at end of file diff --git a/test/RestSharp.InteractiveTests/TwitterClient.cs b/test/RestSharp.InteractiveTests/TwitterClient.cs index 480581a26..24b95e8c7 100644 --- a/test/RestSharp.InteractiveTests/TwitterClient.cs +++ b/test/RestSharp.InteractiveTests/TwitterClient.cs @@ -93,7 +93,7 @@ class TwitterAuthenticator : AuthenticatorBase { async Task GetToken() { var options = new RestClientOptions(_baseUrl) { - Authenticator = new HttpBasicAuthenticator(_clientId, _clientSecret), + Authenticator = new HttpBasicAuthenticator(_clientId, _clientSecret) }; using var client = new RestClient(options); diff --git a/test/RestSharp.Tests.Integrated/CookieTests.cs b/test/RestSharp.Tests.Integrated/CookieTests.cs index e43a18c15..30c4d2743 100644 --- a/test/RestSharp.Tests.Integrated/CookieTests.cs +++ b/test/RestSharp.Tests.Integrated/CookieTests.cs @@ -73,14 +73,14 @@ public class CookieTests { var response = await _client.ExecuteAsync(request); response.Content.Should().Be("success"); - Cookie? notFoundCookie = FindCookie("cookie_empty_domain"); + var notFoundCookie = FindCookie("cookie_empty_domain"); notFoundCookie.Should().BeNull(); - HeaderParameter? emptyDomainCookieHeader = response.Headers! + var emptyDomainCookieHeader = response.Headers! .SingleOrDefault(h => h.Name == KnownHeaders.SetCookie && ((string)h.Value!).StartsWith("cookie_empty_domain")); emptyDomainCookieHeader.Should().NotBeNull(); ((string)emptyDomainCookieHeader!.Value!).Should().Contain("domain=;"); - Cookie? FindCookie(string name) => response!.Cookies!.FirstOrDefault(p => p.Name == name); + Cookie? FindCookie(string name) => response.Cookies!.FirstOrDefault(p => p.Name == name); } } diff --git a/test/RestSharp.Tests.Integrated/Fixtures/CaptureFixture.cs b/test/RestSharp.Tests.Integrated/Fixtures/CaptureFixture.cs index 73211c908..ef8297c4f 100644 --- a/test/RestSharp.Tests.Integrated/Fixtures/CaptureFixture.cs +++ b/test/RestSharp.Tests.Integrated/Fixtures/CaptureFixture.cs @@ -1,26 +1,23 @@ using System.Collections.Specialized; using System.Net; -namespace RestSharp.Tests.Integrated.Fixtures; +namespace RestSharp.Tests.Integrated.Fixtures; -public class CaptureFixture -{ +public class CaptureFixture { public CaptureFixture() => RequestHeadCapturer.Initialize(); - protected class RequestHeadCapturer - { + protected class RequestHeadCapturer { public const string Resource = "Capture"; public static NameValueCollection? CapturedHeaders { get; set; } public static void Initialize() => CapturedHeaders = null; - public static void Capture(HttpListenerContext context) - { + // ReSharper disable once UnusedMember.Global + public static void Capture(HttpListenerContext context) { var request = context.Request; CapturedHeaders = request.Headers; } } - -} \ No newline at end of file +} diff --git a/test/RestSharp.Tests.Integrated/HttpHeadersTests.cs b/test/RestSharp.Tests.Integrated/HttpHeadersTests.cs index d5714eadd..434a23828 100644 --- a/test/RestSharp.Tests.Integrated/HttpHeadersTests.cs +++ b/test/RestSharp.Tests.Integrated/HttpHeadersTests.cs @@ -1,7 +1,5 @@ using System.Net; -using RestSharp.Tests.Integrated.Fixtures; using RestSharp.Tests.Integrated.Server; -using RestSharp.Tests.Shared.Fixtures; namespace RestSharp.Tests.Integrated; diff --git a/test/RestSharp.Tests.Integrated/MultipartFormDataTests.cs b/test/RestSharp.Tests.Integrated/MultipartFormDataTests.cs index 0004593da..0dc147825 100644 --- a/test/RestSharp.Tests.Integrated/MultipartFormDataTests.cs +++ b/test/RestSharp.Tests.Integrated/MultipartFormDataTests.cs @@ -187,20 +187,4 @@ static class RequestHandler { response.Content.Should().Be(expected); } - [Fact] - public async Task ShouldHaveJsonContentType() { - var jsonData = new { - Company = "Microsoft", - ZipCode = "LS339", - Country = "USA" - }; - - var request = new RestRequest { - Method = Method.Post, - AlwaysMultipartFormData = true - }; - request.AddJsonBody(jsonData); - - var response = await _client.ExecuteAsync(request); - } } diff --git a/test/RestSharp.Tests.Integrated/NonProtocolExceptionHandlingTests.cs b/test/RestSharp.Tests.Integrated/NonProtocolExceptionHandlingTests.cs index 5c31e8a25..6f6d8ebda 100644 --- a/test/RestSharp.Tests.Integrated/NonProtocolExceptionHandlingTests.cs +++ b/test/RestSharp.Tests.Integrated/NonProtocolExceptionHandlingTests.cs @@ -6,6 +6,7 @@ namespace RestSharp.Tests.Integrated; public sealed class NonProtocolExceptionHandlingTests : IDisposable { // ReSharper disable once ClassNeverInstantiated.Local class StupidClass { + // ReSharper disable once UnusedMember.Local public string Property { get; set; } = null!; } diff --git a/test/RestSharp.Tests.Integrated/OAuth1Tests.cs b/test/RestSharp.Tests.Integrated/OAuth1Tests.cs index 026acba22..b81fd4d51 100644 --- a/test/RestSharp.Tests.Integrated/OAuth1Tests.cs +++ b/test/RestSharp.Tests.Integrated/OAuth1Tests.cs @@ -25,7 +25,7 @@ class QueueItem { } [Fact] - public void Can_Authenticate_OAuth1_With_Querystring_Parameters() { + public async Task Can_Authenticate_OAuth1_With_Querystring_Parameters() { const string consumerKey = "enterConsumerKeyHere"; const string consumerSecret = "enterConsumerSecretHere"; const string baseUrl = "http://restsharp.org"; @@ -43,7 +43,7 @@ class QueueItem { var request = new RestRequest(); var authenticator = OAuth1Authenticator.ForRequestToken(consumerKey, consumerSecret); authenticator.ParameterHandling = OAuthParameterHandling.UrlOrPostParameters; - authenticator.Authenticate(client, request); + await authenticator.Authenticate(client, request); var requestUri = client.BuildUri(request); var actual = requestUri.ParseQuery().Select(x => x.Key).ToList(); diff --git a/test/RestSharp.Tests.Integrated/PostTests.cs b/test/RestSharp.Tests.Integrated/PostTests.cs index e3482013f..d31e7c801 100644 --- a/test/RestSharp.Tests.Integrated/PostTests.cs +++ b/test/RestSharp.Tests.Integrated/PostTests.cs @@ -15,7 +15,7 @@ public class PostTests { var request = new RestRequest("post/json").AddJsonBody(body); var response = await _client.ExecutePostAsync(request); - response!.Data!.Message.Should().Be(body.Data); + response.Data!.Message.Should().Be(body.Data); } [Fact] diff --git a/test/RestSharp.Tests.Integrated/ProxyTests.cs b/test/RestSharp.Tests.Integrated/ProxyTests.cs index f13f5a6a4..cec1571bd 100644 --- a/test/RestSharp.Tests.Integrated/ProxyTests.cs +++ b/test/RestSharp.Tests.Integrated/ProxyTests.cs @@ -6,7 +6,7 @@ namespace RestSharp.Tests.Integrated; public class ProxyTests { [Fact] public async Task Set_Invalid_Proxy_Fails() { - using var server = HttpServerFixture.StartServer((_, __) => { }); + using var server = HttpServerFixture.StartServer((_, _) => { }); var client = new RestClient(new RestClientOptions(server.Url) { Proxy = new WebProxy("non_existent_proxy", false) }); var request = new RestRequest(); diff --git a/test/RestSharp.Tests.Integrated/PutTests.cs b/test/RestSharp.Tests.Integrated/PutTests.cs index 78cf363bc..1a0e09f89 100644 --- a/test/RestSharp.Tests.Integrated/PutTests.cs +++ b/test/RestSharp.Tests.Integrated/PutTests.cs @@ -1,5 +1,4 @@ using System.Text.Json; -using RestSharp.Tests.Integrated.Fixtures; using RestSharp.Tests.Integrated.Server; using static RestSharp.Tests.Integrated.Server.HttpServer; @@ -25,7 +24,7 @@ public class PutTests { var response = await _client.PutAsync(request); var expected = JsonSerializer.Serialize(body, Options); - response!.Content.Should().Be(expected); + response.Content.Should().Be(expected); } [Fact] diff --git a/test/RestSharp.Tests.Integrated/RedirectTests.cs b/test/RestSharp.Tests.Integrated/RedirectTests.cs index 11b304808..47b4954a2 100644 --- a/test/RestSharp.Tests.Integrated/RedirectTests.cs +++ b/test/RestSharp.Tests.Integrated/RedirectTests.cs @@ -22,7 +22,7 @@ namespace RestSharp.Tests.Integrated; public class RedirectTests { readonly RestClient _client; - public RedirectTests(TestServerFixture fixture, ITestOutputHelper output) { + public RedirectTests(TestServerFixture fixture) { var options = new RestClientOptions(fixture.Server.Url) { FollowRedirects = true }; diff --git a/test/RestSharp.Tests.Integrated/RequestFailureTests.cs b/test/RestSharp.Tests.Integrated/RequestFailureTests.cs index 13f2557c2..7c62b5ea5 100644 --- a/test/RestSharp.Tests.Integrated/RequestFailureTests.cs +++ b/test/RestSharp.Tests.Integrated/RequestFailureTests.cs @@ -1,5 +1,6 @@ using System.Net; using RestSharp.Tests.Integrated.Server; +// ReSharper disable ClassNeverInstantiated.Local namespace RestSharp.Tests.Integrated; @@ -73,6 +74,7 @@ public class RequestFailureTests { } class Response { + // ReSharper disable once UnusedMember.Local public string Message { get; set; } = null!; } } \ No newline at end of file diff --git a/test/RestSharp.Tests.Integrated/RequestHeadTests.cs b/test/RestSharp.Tests.Integrated/RequestHeadTests.cs index 1c5d98eb1..77c2d1414 100644 --- a/test/RestSharp.Tests.Integrated/RequestHeadTests.cs +++ b/test/RestSharp.Tests.Integrated/RequestHeadTests.cs @@ -7,13 +7,11 @@ namespace RestSharp.Tests.Integrated; public class RequestHeadTests : CaptureFixture { [Fact] public async Task Does_Not_Pass_Default_Credentials_When_Server_Does_Not_Negotiate() { - const Method httpMethod = Method.Get; - using var server = SimpleServer.Create(Handlers.Generic()); var client = new RestClient(new RestClientOptions(server.Url) { UseDefaultCredentials = true }); - var request = new RestRequest(RequestHeadCapturer.Resource, httpMethod); + var request = new RestRequest(RequestHeadCapturer.Resource); await client.ExecuteAsync(request); @@ -29,29 +27,27 @@ public class RequestHeadTests : CaptureFixture { [Fact] public async Task Does_Not_Pass_Default_Credentials_When_UseDefaultCredentials_Is_False() { - const Method httpMethod = Method.Get; - using var server = SimpleServer.Create(Handlers.Generic(), AuthenticationSchemes.Negotiate); var client = new RestClient(new RestClientOptions(server.Url) { UseDefaultCredentials = false }); - var request = new RestRequest(RequestHeadCapturer.Resource, httpMethod); + var request = new RestRequest(RequestHeadCapturer.Resource); var response = await client.ExecuteAsync(request); Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); Assert.Null(RequestHeadCapturer.CapturedHeaders); } - [Fact(Skip = "Doesn't work on Linux")] + [Fact] public async Task Passes_Default_Credentials_When_UseDefaultCredentials_Is_True() { - const Method httpMethod = Method.Get; + if (!OperatingSystem.IsWindows()) return; using var server = SimpleServer.Create(Handlers.Generic(), AuthenticationSchemes.Negotiate); var client = new RestClient(new RestClientOptions(server.Url) { UseDefaultCredentials = true }); - var request = new RestRequest(RequestHeadCapturer.Resource, httpMethod); + var request = new RestRequest(RequestHeadCapturer.Resource); var response = await client.ExecuteAsync(request); - response.StatusCode.ToString().Should().BeOneOf(HttpStatusCode.OK.ToString(),HttpStatusCode.Unauthorized.ToString()); + response.StatusCode.Should().BeOneOf(HttpStatusCode.OK, HttpStatusCode.Unauthorized); RequestHeadCapturer.CapturedHeaders.Should().NotBeNull(); var keys = RequestHeadCapturer.CapturedHeaders!.Keys.Cast().ToArray(); @@ -62,4 +58,4 @@ public class RequestHeadTests : CaptureFixture { "Authorization header not present in HTTP request from client, even though UseDefaultCredentials = true" ); } -} \ No newline at end of file +} diff --git a/test/RestSharp.Tests.Integrated/Server/Handlers/FileHandlers.cs b/test/RestSharp.Tests.Integrated/Server/Handlers/FileHandlers.cs index 7d7231e9e..d7cc03811 100644 --- a/test/RestSharp.Tests.Integrated/Server/Handlers/FileHandlers.cs +++ b/test/RestSharp.Tests.Integrated/Server/Handlers/FileHandlers.cs @@ -1,39 +1,19 @@ +using System.Diagnostics.CodeAnalysis; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using RestSharp.Extensions; namespace RestSharp.Tests.Integrated.Server.Handlers; -public static class FileHandlers { - public static async Task HandleUpload(string assetPath, HttpRequest req) { - if (!req.HasFormContentType) { - return Results.BadRequest("It's not a form"); - } - - var form = await req.ReadFormAsync(); - var file = form.Files["file"]; - - if (file is null) { - return Results.BadRequest("File parameter 'file' is not present"); - } - - await using var stream = file.OpenReadStream(); - - var received = await stream.ReadAsBytes(default); - var expected = await File.ReadAllBytesAsync(Path.Combine(assetPath, file.FileName)); - - var response = new UploadResponse(file.FileName, file.Length, received.SequenceEqual(expected)); - return Results.Json(response); - } -} - [ApiController] public class UploadController : ControllerBase { [HttpPost] [Route("upload")] + [SuppressMessage("Performance", "CA1822:Mark members as static")] public async Task Upload([FromForm] FormFile formFile) { var assetPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets"); var file = formFile.File; + await using var stream = file.OpenReadStream(); var received = await stream.ReadAsBytes(default); diff --git a/test/RestSharp.Tests.Integrated/Server/Handlers/RequestHandlers.cs b/test/RestSharp.Tests.Integrated/Server/Handlers/RequestHandlers.cs index af34c0d73..7ee727e03 100644 --- a/test/RestSharp.Tests.Integrated/Server/Handlers/RequestHandlers.cs +++ b/test/RestSharp.Tests.Integrated/Server/Handlers/RequestHandlers.cs @@ -2,10 +2,6 @@ namespace RestSharp.Tests.Integrated.Server.Handlers; -public static class RequestHandlers { - public static IResult ParseRequest(HttpContext ctx) => Results.Ok(new ParsedRequest(ctx.Request)); -} - public class ParsedRequest { public ParsedRequest(HttpRequest request) { Method = request.Method; diff --git a/test/RestSharp.Tests.Integrated/Server/Models.cs b/test/RestSharp.Tests.Integrated/Server/Models.cs index 9bf592861..9fd14e186 100644 --- a/test/RestSharp.Tests.Integrated/Server/Models.cs +++ b/test/RestSharp.Tests.Integrated/Server/Models.cs @@ -1,11 +1,5 @@ -using Microsoft.AspNetCore.Http; - -namespace RestSharp.Tests.Integrated.Server; +namespace RestSharp.Tests.Integrated.Server; record TestServerResponse(string Name, string Value); -record UploadRequest(string Filename, IFormFile File); - -public record UploadResponse(string FileName, long Length, bool Equal); - -record ContentResponse(string Content); +public record UploadResponse(string FileName, long Length, bool Equal); \ No newline at end of file diff --git a/test/RestSharp.Tests.Integrated/StatusCodeTests.cs b/test/RestSharp.Tests.Integrated/StatusCodeTests.cs index 6ba326fc8..e78a386db 100644 --- a/test/RestSharp.Tests.Integrated/StatusCodeTests.cs +++ b/test/RestSharp.Tests.Integrated/StatusCodeTests.cs @@ -8,7 +8,7 @@ namespace RestSharp.Tests.Integrated; -public class StatusCodeTests : IDisposable { +public sealed class StatusCodeTests : IDisposable { public StatusCodeTests() { _server = SimpleServer.Create(UrlToStatusCodeHandler); _client = new RestClient(_server.Url, configureSerialization: cfg => cfg.UseXmlSerializer()); diff --git a/test/RestSharp.Tests.Integrated/StructuredSyntaxSuffixTests.cs b/test/RestSharp.Tests.Integrated/StructuredSyntaxSuffixTests.cs index 7c1617c00..1011f88b1 100644 --- a/test/RestSharp.Tests.Integrated/StructuredSyntaxSuffixTests.cs +++ b/test/RestSharp.Tests.Integrated/StructuredSyntaxSuffixTests.cs @@ -7,7 +7,7 @@ namespace RestSharp.Tests.Integrated; -public class StructuredSyntaxSuffixTests : IDisposable { +public sealed class StructuredSyntaxSuffixTests : IDisposable { readonly TestHttpServer _server; readonly string _url; diff --git a/test/RestSharp.Tests.Legacy/RequestBodyTests.cs b/test/RestSharp.Tests.Legacy/RequestBodyTests.cs deleted file mode 100644 index d6193fa19..000000000 --- a/test/RestSharp.Tests.Legacy/RequestBodyTests.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Diagnostics.CodeAnalysis; - -namespace RestSharp.Tests.Legacy; - -public class RequestBodyTests { - [Fact(Skip = "Setting the content type for GET requests doesn't seem to be possible on Windows")] - [SuppressMessage("Usage", "xUnit1004:Test methods should not be skipped")] - public async Task GetRequestWithContentType() { - var options = new RestClientOptions("https://endim2jwvq8mr.x.pipedream.net/"); - var client = new RestClient(options); - - var request = new RestRequest("resource"); - request.AddHeader("Content-Type", "application/force-download"); - var response = await client.GetAsync(request); - } -} \ No newline at end of file diff --git a/test/RestSharp.Tests.Legacy/RestSharp.Tests.Legacy.csproj b/test/RestSharp.Tests.Legacy/RestSharp.Tests.Legacy.csproj deleted file mode 100644 index 442bc31df..000000000 --- a/test/RestSharp.Tests.Legacy/RestSharp.Tests.Legacy.csproj +++ /dev/null @@ -1,15 +0,0 @@ - - - net472 - disable - - - - - - - - - - - diff --git a/test/RestSharp.Tests.Serializers.Json/SampleData.cs b/test/RestSharp.Tests.Serializers.Json/SampleData.cs index c1170c507..171d4b2ac 100644 --- a/test/RestSharp.Tests.Serializers.Json/SampleData.cs +++ b/test/RestSharp.Tests.Serializers.Json/SampleData.cs @@ -1,4 +1,5 @@ -namespace RestSharp.Tests.Serializers.Json; +// ReSharper disable UnusedMember.Global +namespace RestSharp.Tests.Serializers.Json; public class TestClass { public string SimpleString { get; set; } diff --git a/test/RestSharp.Tests.Serializers.Xml/NamespacedXmlTests.cs b/test/RestSharp.Tests.Serializers.Xml/NamespacedXmlTests.cs index 6e20a4016..8b4ad7809 100644 --- a/test/RestSharp.Tests.Serializers.Xml/NamespacedXmlTests.cs +++ b/test/RestSharp.Tests.Serializers.Xml/NamespacedXmlTests.cs @@ -47,7 +47,7 @@ public class NamespacedXmlTests { var friends = new XElement(ns + "Friends"); - for (var i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { friends.Add( new XElement( ns + "Friend", @@ -55,6 +55,7 @@ public class NamespacedXmlTests { new XAttribute(ns + "Since", DateTime.Now.Year - i) ) ); + } root.Add(friends); @@ -97,7 +98,7 @@ public class NamespacedXmlTests { var friends = new XElement(ns + "Friends"); - for (var i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { friends.Add( new XElement( ns + "Friend", @@ -105,6 +106,7 @@ public class NamespacedXmlTests { new XElement(ns + "Since", DateTime.Now.Year - i) ) ); + } root.Add(friends); @@ -169,7 +171,7 @@ public class NamespacedXmlTests { }; var xml = new XmlDeserializer { Namespace = @namespace }; - var output = xml.Deserialize(new RestResponse() { Content = doc.ToString() }); + var output = xml.Deserialize(new RestResponse { Content = doc.ToString() }); Assert.Equal(expected.AttributeValue, output.AttributeValue); } diff --git a/test/RestSharp.Tests.Serializers.Xml/SampleClasses/twitter.cs b/test/RestSharp.Tests.Serializers.Xml/SampleClasses/twitter.cs index ec0af5146..df64ad212 100644 --- a/test/RestSharp.Tests.Serializers.Xml/SampleClasses/twitter.cs +++ b/test/RestSharp.Tests.Serializers.Xml/SampleClasses/twitter.cs @@ -1,5 +1,6 @@ using RestSharp.Serializers; // ReSharper disable InconsistentNaming +// ReSharper disable UnusedMember.Global #pragma warning disable CS8981 namespace RestSharp.Tests.Serializers.Xml.SampleClasses; @@ -88,8 +89,6 @@ public class user { public int utc_offset { get; set; } } -public class StatusList : List { } - public class complexStatus { public bool truncated { get; set; } @@ -113,6 +112,4 @@ public class complexStatus { public long id { get; set; } public string text { get; set; } -} - -public class StatusComplexList : List { } \ No newline at end of file +} \ No newline at end of file diff --git a/test/RestSharp.Tests.Serializers.Xml/XmlAttributeDeserializerTests.cs b/test/RestSharp.Tests.Serializers.Xml/XmlAttributeDeserializerTests.cs index 08a5d3a53..9f6277c6f 100644 --- a/test/RestSharp.Tests.Serializers.Xml/XmlAttributeDeserializerTests.cs +++ b/test/RestSharp.Tests.Serializers.Xml/XmlAttributeDeserializerTests.cs @@ -18,9 +18,7 @@ public class XmlAttributeDeserializerTests { string PathFor(string sampleFile) => Path.Combine(_sampleDataPath, sampleFile); - public XmlAttributeDeserializerTests(ITestOutputHelper output) { - _output = output; - } + public XmlAttributeDeserializerTests(ITestOutputHelper output) => _output = output; [Fact] public void Can_Deserialize_Lists_of_Simple_Types() { @@ -578,7 +576,7 @@ public class XmlAttributeDeserializerTests { var friends = new XElement("Friends"); - for (var i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { friends.Add( new XElement( "Friend", @@ -586,6 +584,7 @@ public class XmlAttributeDeserializerTests { new XAttribute("Since", DateTime.Now.Year - i) ) ); + } root.Add(friends); @@ -627,7 +626,7 @@ public class XmlAttributeDeserializerTests { var friends = new XElement("Friends"); - for (var i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { friends.Add( new XElement( "Friend", @@ -635,6 +634,7 @@ public class XmlAttributeDeserializerTests { new XAttribute("Since", DateTime.Now.Year - i) ) ); + } root.Add(friends); @@ -676,7 +676,7 @@ public class XmlAttributeDeserializerTests { var friends = new XElement("Friends"); - for (var i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { friends.Add( new XElement( "Friend", @@ -684,6 +684,7 @@ public class XmlAttributeDeserializerTests { new XAttribute("Since", DateTime.Now.Year - i) ) ); + } root.Add(friends); @@ -744,7 +745,7 @@ public class XmlAttributeDeserializerTests { var friends = new XElement("Friends"); - for (var i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { friends.Add( new XElement( "Friend", @@ -752,6 +753,7 @@ public class XmlAttributeDeserializerTests { new XElement("Since", DateTime.Now.Year - i) ) ); + } root.Add(friends); diff --git a/test/RestSharp.Tests.Serializers.Xml/XmlDeserializerTests.cs b/test/RestSharp.Tests.Serializers.Xml/XmlDeserializerTests.cs index b4efffa21..c1e39af0f 100644 --- a/test/RestSharp.Tests.Serializers.Xml/XmlDeserializerTests.cs +++ b/test/RestSharp.Tests.Serializers.Xml/XmlDeserializerTests.cs @@ -9,11 +9,11 @@ namespace RestSharp.Tests.Serializers.Xml; public class XmlDeserializerTests { const string GuidString = "AC1FC4BC-087A-4242-B8EE-C53EBE9887A5"; - #if NETCORE +#if NETCORE readonly string _sampleDataPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SampleData"); - #else +#else readonly string _sampleDataPath = Path.Combine(Directory.GetCurrentDirectory(), "SampleData"); - #endif +#endif string PathFor(string sampleFile) => Path.Combine(_sampleDataPath, sampleFile); @@ -43,14 +43,15 @@ public class XmlDeserializerTests { var friends = new XElement("Friends"); - for (var i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { friends.Add( new XElement( "Friend", - new XElement("Name", "Friend" + i), + new XElement("Name", "Friend" + i), new XAttribute("Since", DateTime.Now.Year - i) ) ); + } root.Add(friends); @@ -92,14 +93,15 @@ public class XmlDeserializerTests { var friends = new XElement("Friends"); - for (var i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { friends.Add( new XElement( "Friend", - new XElement("Name", "Friend" + i), + new XElement("Name", "Friend" + i), new XAttribute("Since", DateTime.Now.Year - i) ) ); + } root.Add(friends); @@ -141,14 +143,15 @@ public class XmlDeserializerTests { var friends = new XElement("Friends"); - for (var i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { friends.Add( new XElement( "Friend", - new XElement("Name", "Friend" + i), + new XElement("Name", "Friend" + i), new XAttribute("Since", DateTime.Now.Year - i) ) ); + } root.Add(friends); @@ -206,14 +209,15 @@ public class XmlDeserializerTests { var friends = new XElement("Friends"); - for (var i = 0; i < 10; i++) + for (var i = 0; i < 10; i++) { friends.Add( new XElement( "Friend", - new XElement("Name", "Friend" + i), + new XElement("Name", "Friend" + i), new XElement("Since", DateTime.Now.Year - i) ) ); + } root.Add(friends); doc.Add(root); @@ -644,23 +648,20 @@ public class XmlDeserializerTests { [Fact] public void Can_throw_format_exception_xml() { - var xmlpath = PathFor("GoodreadsFormatError.xml"); - var doc = XDocument.Load(xmlpath); + var xmlPath = PathFor("GoodreadsFormatError.xml"); + var doc = XDocument.Load(xmlPath); var response = new RestResponse { Content = doc.ToString() }; var d = new XmlDeserializer(); Assert.Throws( - () => { - var note = d.Deserialize(response); - var message = note; - } + () => d.Deserialize(response) ); } [Fact] public void Can_Deserialize_Google_Weather_Xml() { - var xmlpath = PathFor("GoogleWeather.xml"); - var doc = XDocument.Load(xmlpath); + var xmlPath = PathFor("GoogleWeather.xml"); + var doc = XDocument.Load(xmlPath); var response = new RestResponse { Content = doc.ToString() }; var d = new XmlDeserializer(); var output = d.Deserialize(response)!; @@ -682,8 +683,9 @@ public class XmlDeserializerTests { [Fact] public void Can_Deserialize_Into_Struct() { const string content = "oneOneOnetwoTwoTwo3"; - var xml = new XmlDeserializer(); - var output = xml.Deserialize(new RestResponse { Content = content }); + + var xml = new XmlDeserializer(); + var output = xml.Deserialize(new RestResponse { Content = content }); Assert.Equal("oneOneOne", output.One); Assert.Equal("twoTwoTwo", output.Two); @@ -692,8 +694,8 @@ public class XmlDeserializerTests { [Fact] public void Can_Deserialize_Lastfm_Xml() { - var xmlpath = PathFor("Lastfm.xml"); - var doc = XDocument.Load(xmlpath); + var xmlPath = PathFor("Lastfm.xml"); + var doc = XDocument.Load(xmlPath); var response = new RestResponse { Content = doc.ToString() }; var d = new XmlDeserializer(); var output = d.Deserialize(response)!; @@ -707,8 +709,8 @@ public class XmlDeserializerTests { [Fact] public void Can_Deserialize_Lists_of_Simple_Types() { - var xmlpath = PathFor("xmllists.xml"); - var doc = XDocument.Load(xmlpath); + var xmlPath = PathFor("xmllists.xml"); + var doc = XDocument.Load(xmlPath); var xml = new XmlDeserializer(); var output = xml.Deserialize( @@ -716,7 +718,7 @@ public class XmlDeserializerTests { )!; Assert.False(output.Names[0].Length == 0); - Assert.False(output.Numbers.Sum() == 0); + Assert.False(output.Numbers.Sum() == 0); } [Fact] @@ -1087,4 +1089,4 @@ public class XmlDeserializerTests { Assert.Null(p.ReadOnlyProxy); } -} \ No newline at end of file +} diff --git a/test/RestSharp.Tests.Serializers.Xml/XmlSerializerTests.cs b/test/RestSharp.Tests.Serializers.Xml/XmlSerializerTests.cs index e88e0e73c..4f1eba686 100644 --- a/test/RestSharp.Tests.Serializers.Xml/XmlSerializerTests.cs +++ b/test/RestSharp.Tests.Serializers.Xml/XmlSerializerTests.cs @@ -21,7 +21,7 @@ public class XmlSerializerTests { Age = 50, Price = 19.95m, StartDate = new DateTime(2009, 12, 18, 10, 2, 23), - Items = new List { new() { Name = "One", Value = 1 }, } + Items = new List { new() { Name = "One", Value = 1 } } }, new Item { Name = "Two", Value = 2 }, new Item { Name = "Three", Value = 3 } diff --git a/test/RestSharp.Tests.Shared/Fixtures/Handlers.cs b/test/RestSharp.Tests.Shared/Fixtures/Handlers.cs index 5d6351541..8183d4607 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/Handlers.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/Handlers.cs @@ -15,23 +15,6 @@ public static class Handlers { /// public static Action EchoValue(string value) => ctx => ctx.Response.OutputStream.WriteStringUtf8(value); - /// - /// Response to a request like this: http://localhost:8888/assets/koala.jpg - /// by streaming the file located at "assets\koala.jpg" back to the client. - /// - public static void FileHandler(HttpListenerContext context, string path) { - var pathToFile = Path.Combine( - path, - Path.Combine( - context.Request.Url.Segments.Select(s => s.Replace("/", "")).ToArray() - ) - ); - - using var reader = new StreamReader(pathToFile); - - reader.BaseStream.CopyTo(context.Response.OutputStream); - } - /// /// T should be a class that implements methods whose names match the urls being called, and take one parameter, an /// HttpListenerContext. diff --git a/test/RestSharp.Tests.Shared/Fixtures/RequestBodyCapturer.cs b/test/RestSharp.Tests.Shared/Fixtures/RequestBodyCapturer.cs index 3adc07fec..bb21fe4ae 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/RequestBodyCapturer.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/RequestBodyCapturer.cs @@ -11,6 +11,7 @@ public class RequestBodyCapturer { public static string CapturedEntityBody { get; set; } public static Uri CapturedUrl { get; set; } + // ReSharper disable once UnusedMember.Global public static void Capture(HttpListenerContext context) { var request = context.Request; diff --git a/test/RestSharp.Tests.Shared/Fixtures/TestHttpServer.cs b/test/RestSharp.Tests.Shared/Fixtures/TestHttpServer.cs index 8fb323d53..b3c49b16e 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/TestHttpServer.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/TestHttpServer.cs @@ -20,11 +20,7 @@ public class TestHttpServer : IDisposable { ) : this(port, new List { new(url, handlerAction) }, hostName) { } - public TestHttpServer( - int port, - List handlers, - string hostName = "localhost" - ) { + public TestHttpServer(int port, List handlers, string hostName = "localhost") { _requestHandlers = handlers; Port = port > 0 ? port : GetRandomUnusedPort(); @@ -79,7 +75,7 @@ public class TestHttpServer : IDisposable { } else { context.Response.ContentType("text/plain").StatusCode(404); - responseString = "No handler provided for URL: " + context.Request.RawUrl; + responseString = $"No handler provided for URL: {context.Request.RawUrl}"; } context.Request.ClearContent(); @@ -88,7 +84,7 @@ public class TestHttpServer : IDisposable { if (responseString != null) { var buffer = Encoding.UTF8.GetBytes(responseString); context.Response.ContentLength64 += buffer.Length; - context.Response.OutputStream.Write(buffer, 0, buffer.Length); + await context.Response.OutputStream.WriteAsync(buffer, 0, buffer.Length, cancellationToken); } } finally { @@ -99,8 +95,7 @@ public class TestHttpServer : IDisposable { } catch (HttpListenerException ex) { //when the listener is stopped, it will throw an exception for being cancelled, so just ignore it - if (ex.Message != "The I/O operation has been aborted because of either a thread exit or an application request") - throw; + if (ex.Message != "The I/O operation has been aborted because of either a thread exit or an application request") throw; } } @@ -114,4 +109,4 @@ public class TestHttpServer : IDisposable { _listener.Stop(); } } -} \ No newline at end of file +} diff --git a/test/RestSharp.Tests.Shared/Fixtures/TestHttpServerExtensions.cs b/test/RestSharp.Tests.Shared/Fixtures/TestHttpServerExtensions.cs index 53d05abf1..b1202c772 100644 --- a/test/RestSharp.Tests.Shared/Fixtures/TestHttpServerExtensions.cs +++ b/test/RestSharp.Tests.Shared/Fixtures/TestHttpServerExtensions.cs @@ -5,10 +5,7 @@ namespace RestSharp.Tests.Shared.Fixtures; public static class TestHttpServerExtensions { static readonly Dictionary RequestContent = new(); - internal static void ClearContent(this HttpListenerRequest request) { - if (RequestContent.ContainsKey(request)) - RequestContent.Remove(request); - } + internal static void ClearContent(this HttpListenerRequest request) => RequestContent.Remove(request); public static HttpListenerResponse ContentType(this HttpListenerResponse response, string contentType) { response.ContentType = contentType; diff --git a/test/RestSharp.Tests/AddRangeTests.cs b/test/RestSharp.Tests/AddRangeTests.cs index f5d5887ca..0b39babe4 100644 --- a/test/RestSharp.Tests/AddRangeTests.cs +++ b/test/RestSharp.Tests/AddRangeTests.cs @@ -4,7 +4,7 @@ public class AddRangeTests { [Fact] public async Task ShouldParseOutLongRangeSpecifier() { var restClient = new RestClient("http://localhost"); - var req = new RestRequest("bob", Method.Get); + var req = new RestRequest("bob"); const long start = (long)int.MaxValue + 1; const long end = start + 1; @@ -15,7 +15,7 @@ public class AddRangeTests { [Fact] public async Task ShouldParseOutRangeSpecifier() { var restClient = new RestClient("http://localhost"); - var req = new RestRequest("bob", Method.Get); + var req = new RestRequest("bob"); req.AddHeader("Range", "pages=1-2"); await restClient.ExecuteAsync(req); diff --git a/test/RestSharp.Tests/AuthenticatorTests.cs b/test/RestSharp.Tests/AuthenticatorTests.cs new file mode 100644 index 000000000..a646c1071 --- /dev/null +++ b/test/RestSharp.Tests/AuthenticatorTests.cs @@ -0,0 +1,66 @@ +using System.Net; +using RestSharp.Authenticators; +using RichardSzalay.MockHttp; + +namespace RestSharp.Tests; + +public class AuthenticatorTests { + [Fact] + public async Task Should_add_authorization_header() { + const string auth = "LetMeIn"; + const string url = "https://dummy.org"; + + var mockHttp = new MockHttpMessageHandler(); + + mockHttp + .When(HttpMethod.Get, url) + .WithHeaders(KnownHeaders.Authorization, auth) + .Respond(HttpStatusCode.OK); + + var options = new RestClientOptions(url) { + ConfigureMessageHandler = _ => mockHttp, + Authenticator = new TestAuthenticator(ParameterType.HttpHeader, KnownHeaders.Authorization, auth) + }; + var client = new RestClient(options); + var response = await client.ExecuteGetAsync(new RestRequest()); + response.StatusCode.Should().Be(HttpStatusCode.OK); + } + + [Fact] + public async Task Should_add_authorization_form_parameter() { + const string auth = "LetMeIn"; + const string url = "https://dummy.org"; + + var mockHttp = new MockHttpMessageHandler(); + + mockHttp + .When(HttpMethod.Post, url) + .WithFormData("token", auth) + .Respond(HttpStatusCode.OK); + + var options = new RestClientOptions(url) { + ConfigureMessageHandler = _ => mockHttp, + Authenticator = new TestAuthenticator(ParameterType.GetOrPost, "token", auth) + }; + var client = new RestClient(options); + var response = await client.ExecutePostAsync(new RestRequest()); + response.StatusCode.Should().Be(HttpStatusCode.OK); + } + + class TestAuthenticator : IAuthenticator { + readonly ParameterType _type; + readonly string _name; + readonly string _value; + + public TestAuthenticator(ParameterType type, string name, string value) { + _type = type; + _name = name; + _value = value; + } + + public ValueTask Authenticate(IRestClient client, RestRequest request) { + request.AddParameter(_name, _value, _type); + return default; + } + } +} diff --git a/test/RestSharp.Tests/MultipartFormTests.cs b/test/RestSharp.Tests/MultipartFormTests.cs new file mode 100644 index 000000000..d31f99f84 --- /dev/null +++ b/test/RestSharp.Tests/MultipartFormTests.cs @@ -0,0 +1,44 @@ +using System.Net; +using RichardSzalay.MockHttp; + +namespace RestSharp.Tests; + +public class MultipartFormTests { + [Fact] + public async Task ShouldHaveJsonContentType() { + const string url = "https://dummy.org"; + + var jsonData = new { + Company = "Microsoft", + ZipCode = "LS339", + Country = "USA" + }; + + var mockHttp = new MockHttpMessageHandler(); + + mockHttp + .When(HttpMethod.Post, url) + .With(CheckRequest) + .Respond(HttpStatusCode.OK); + + var options = new RestClientOptions(url) { + ConfigureMessageHandler = h => mockHttp + }; + var client = new RestClient(options); + + var request = new RestRequest { + Method = Method.Post, + AlwaysMultipartFormData = true + }; + request.AddJsonBody(jsonData); + + var response = await client.ExecuteAsync(request); + response.StatusCode.Should().Be(HttpStatusCode.OK); + + bool CheckRequest(HttpRequestMessage msg) { + if (msg.Content is not MultipartFormDataContent formDataContent) return false; + + return formDataContent.First().Headers.ContentType!.MediaType == "application/json"; + } + } +} diff --git a/test/RestSharp.Tests/ObjectParameterTests.cs b/test/RestSharp.Tests/ObjectParameterTests.cs index b67c49510..65de48aa2 100644 --- a/test/RestSharp.Tests/ObjectParameterTests.cs +++ b/test/RestSharp.Tests/ObjectParameterTests.cs @@ -4,9 +4,7 @@ namespace RestSharp.Tests; public partial class ObjectParameterTests { - public ObjectParameterTests() { - Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; - } + public ObjectParameterTests() => Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; [Fact] public void Can_Add_Object_with_IntegerArray_property() { @@ -78,7 +76,7 @@ public partial class ObjectParameterTests { [Fact] public void Can_Add_Object_Static_with_IntegerArray_as_Object_property() { - var items = new int[] { 1, 2, 3 }; + var items = new[] { 1, 2, 3 }; var @object = new { Items = (object)items }; var request = new RestRequest().AddObjectStatic(@object); @@ -644,7 +642,7 @@ public partial class ObjectParameterTests { new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", "Hello"), new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", "world"), new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", "from"), - new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", ".NET"), + new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", ".NET") }); } @@ -661,7 +659,7 @@ public partial class ObjectParameterTests { new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", "Hello"), new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", "world"), new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", "from"), - new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", ".NET"), + new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", ".NET") }); } @@ -678,7 +676,7 @@ public partial class ObjectParameterTests { new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", "Hello"), new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", "world"), new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", "from"), - new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", ".NET"), + new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", ".NET") }); } @@ -695,7 +693,7 @@ public partial class ObjectParameterTests { new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", "Hello"), new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", "world"), new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", "from"), - new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", ".NET"), + new GetOrPostParameter($"{nameof(ArrayData.Array)}[]", ".NET") }); } @@ -728,6 +726,7 @@ public partial class ObjectParameterTests { } public sealed record StringValue(string Value) { + // ReSharper disable once UnusedMember.Global public ReadOnlySpan AsSpan => Value.AsSpan(); } } diff --git a/test/RestSharp.Tests/OptionsTests.cs b/test/RestSharp.Tests/OptionsTests.cs index ea8acb5c7..e1270a792 100644 --- a/test/RestSharp.Tests/OptionsTests.cs +++ b/test/RestSharp.Tests/OptionsTests.cs @@ -9,7 +9,7 @@ public class OptionsTests { value.Should().BeTrue(); HttpMessageHandler Configure(HttpMessageHandler handler) { - value = ((handler as HttpClientHandler)!).AllowAutoRedirect; + value = (handler as HttpClientHandler)!.AllowAutoRedirect; return handler; } } diff --git a/test/RestSharp.Tests/ParametersTests.cs b/test/RestSharp.Tests/ParametersTests.cs index 719e96ed5..760ecee5b 100644 --- a/test/RestSharp.Tests/ParametersTests.cs +++ b/test/RestSharp.Tests/ParametersTests.cs @@ -1,6 +1,3 @@ -using System.Collections; -using System.IO; - namespace RestSharp.Tests; public class ParametersTests { @@ -27,49 +24,47 @@ public class ParametersTests { public void AddUrlSegmentWithInt() { const string name = "foo"; - var request = new RestRequest().AddUrlSegment(name, 1); var actual = request.Parameters.FirstOrDefault(x => x.Name == name); var expected = new UrlSegmentParameter(name, "1"); - + expected.Should().BeEquivalentTo(actual); } [Fact] public void AddUrlSegmentModifiesUrlSegmentWithInt() { - const string name = "foo"; - var pathTemplate = "/{0}/resource"; - var path = String.Format(pathTemplate, "{" + name + "}"); - var urlSegmentValue = 1; + const string name = "foo"; + const string pathTemplate = "/{0}/resource"; + const int urlSegmentValue = 1; + + var path = string.Format(pathTemplate, $"{{{name}}}"); var request = new RestRequest(path).AddUrlSegment(name, urlSegmentValue); - var expected = String.Format(pathTemplate, urlSegmentValue); + var expected = string.Format(pathTemplate, urlSegmentValue); var client = new RestClient(BaseUrl); var actual = client.BuildUri(request).AbsolutePath; - expected.Should().BeEquivalentTo(actual); } [Fact] public void AddUrlSegmentModifiesUrlSegmentWithString() { - const string name = "foo"; - var pathTemplate = "/{0}/resource"; - var path = String.Format(pathTemplate, "{" + name + "}"); - var urlSegmentValue = "bar"; + const string name = "foo"; + const string pathTemplate = "/{0}/resource"; + const string urlSegmentValue = "bar"; + var path = string.Format(pathTemplate, $"{{{name}}}"); var request = new RestRequest(path).AddUrlSegment(name, urlSegmentValue); - var expected = String.Format(pathTemplate, urlSegmentValue); + var expected = string.Format(pathTemplate, urlSegmentValue); var client = new RestClient(BaseUrl); var actual = client.BuildUri(request).AbsolutePath; expected.Should().BeEquivalentTo(actual); - } -} \ No newline at end of file +} diff --git a/test/RestSharp.Tests/RestClientTests.cs b/test/RestSharp.Tests/RestClientTests.cs index dec57ad90..276f1e92a 100644 --- a/test/RestSharp.Tests/RestClientTests.cs +++ b/test/RestSharp.Tests/RestClientTests.cs @@ -120,15 +120,18 @@ public class RestClientTests { [Fact] public void ConfigureHttpClient_does_not_duplicate_user_agent_for_same_client() { // arrange - var httpClient = new HttpClient(); + var httpClient = new HttpClient(); var clientOptions = new RestClientOptions(); // act - var restClient1 = new RestClient(httpClient, clientOptions); - var restClient2 = new RestClient(httpClient, clientOptions); + var unused = new RestClient(httpClient, clientOptions); + var dummy = new RestClient(httpClient, clientOptions); // assert - Assert.Contains(httpClient.DefaultRequestHeaders.UserAgent, agent => $"{agent.Product.Name}/{agent.Product.Version}" == clientOptions.UserAgent); + Assert.Contains( + httpClient.DefaultRequestHeaders.UserAgent, + agent => $"{agent.Product.Name}/{agent.Product.Version}" == clientOptions.UserAgent + ); Assert.Single(httpClient.DefaultRequestHeaders.UserAgent); } } diff --git a/test/RestSharp.Tests/RestSharp.Tests.csproj b/test/RestSharp.Tests/RestSharp.Tests.csproj index 32ca5db5f..6db9fbd8c 100644 --- a/test/RestSharp.Tests/RestSharp.Tests.csproj +++ b/test/RestSharp.Tests/RestSharp.Tests.csproj @@ -1,6 +1,8 @@  + + diff --git a/test/RestSharp.Tests/UrlBuilderTests.cs b/test/RestSharp.Tests/UrlBuilderTests.cs index bdd336c2d..97b8b4af9 100644 --- a/test/RestSharp.Tests/UrlBuilderTests.cs +++ b/test/RestSharp.Tests/UrlBuilderTests.cs @@ -97,7 +97,7 @@ public void GET_with_Invalid_Url_string_throws_exception() [Fact] public void GET_with_multiple_instances_of_same_key() { - var request = new RestRequest("v1/people/~/network/updates", Method.Get); + var request = new RestRequest("v1/people/~/network/updates"); request.AddParameter("type", "STAT"); request.AddParameter("type", "PICT");