diff --git a/RestSharp.Net7/RestSharp.Net7.csproj b/RestSharp.Net7/RestSharp.Net7.csproj new file mode 100644 index 000000000..04bc6dcbf --- /dev/null +++ b/RestSharp.Net7/RestSharp.Net7.csproj @@ -0,0 +1,27 @@ + + + + net7.0 + RestSharp + RestSharp + false + disable + FRAMEWORK + CS0618;CS0612;SYSLIB0014;CS0108;CS0114;CS0162;CS8632 + + + + + <_Parameter1>RestSharp.Tests.Coverage + + + + + + + + + + + + diff --git a/RestSharp.Tests.Coverage/AttributeAndContribTests.cs b/RestSharp.Tests.Coverage/AttributeAndContribTests.cs new file mode 100644 index 000000000..d797c4122 --- /dev/null +++ b/RestSharp.Tests.Coverage/AttributeAndContribTests.cs @@ -0,0 +1,204 @@ +using System; +using System.Globalization; +using RestSharp.Deserializers; +using RestSharp.Serializers; +using RestSharp.Contrib; +using Xunit; + +namespace RestSharp.Tests +{ + public class AttributeAndContribTests + { + // DeserializeAsAttribute + [Fact] + public void DeserializeAsAttribute_Name() + { + var attr = new DeserializeAsAttribute { Name = "custom_name" }; + Assert.Equal("custom_name", attr.Name); + } + + [Fact] + public void DeserializeAsAttribute_Attribute() + { + var attr = new DeserializeAsAttribute { Attribute = true }; + Assert.True(attr.Attribute); + } + + // SerializeAsAttribute + [Fact] + public void SerializeAsAttribute_Defaults() + { + var attr = new SerializeAsAttribute(); + Assert.Equal(NameStyle.AsIs, attr.NameStyle); + Assert.Equal(int.MaxValue, attr.Index); + Assert.Equal(CultureInfo.InvariantCulture, attr.Culture); + } + + [Fact] + public void SerializeAsAttribute_TransformName_AsIs() + { + var attr = new SerializeAsAttribute { NameStyle = NameStyle.AsIs }; + Assert.Equal("TestInput", attr.TransformName("TestInput")); + } + + [Fact] + public void SerializeAsAttribute_TransformName_CamelCase() + { + var attr = new SerializeAsAttribute { NameStyle = NameStyle.CamelCase }; + Assert.Equal("testInput", attr.TransformName("TestInput")); + } + + [Fact] + public void SerializeAsAttribute_TransformName_LowerCase() + { + var attr = new SerializeAsAttribute { NameStyle = NameStyle.LowerCase }; + Assert.Equal("testinput", attr.TransformName("TestInput")); + } + + [Fact] + public void SerializeAsAttribute_TransformName_PascalCase() + { + var attr = new SerializeAsAttribute { NameStyle = NameStyle.PascalCase }; + Assert.Equal("TestInput", attr.TransformName("test_input")); + } + + [Fact] + public void SerializeAsAttribute_TransformName_With_CustomName() + { + var attr = new SerializeAsAttribute { Name = "CustomName", NameStyle = NameStyle.LowerCase }; + Assert.Equal("customname", attr.TransformName("OriginalInput")); + } + + [Fact] + public void SerializeAsAttribute_All_Properties() + { + var attr = new SerializeAsAttribute + { + Name = "myProp", + Attribute = true, + Culture = CultureInfo.CurrentCulture, + NameStyle = NameStyle.CamelCase, + Index = 5 + }; + Assert.Equal("myProp", attr.Name); + Assert.True(attr.Attribute); + Assert.Equal(5, attr.Index); + } + + // NameStyle enum values + [Fact] + public void NameStyle_Enum_Values() + { + Assert.Equal(NameStyle.AsIs, (NameStyle)0); + Assert.Equal(NameStyle.CamelCase, (NameStyle)1); + Assert.Equal(NameStyle.LowerCase, (NameStyle)2); + Assert.Equal(NameStyle.PascalCase, (NameStyle)3); + } + + // HttpUtility tests + [Fact] + public void HttpUtility_HtmlEncode_Basic() + { + Assert.Equal("<b>", HttpUtility.HtmlEncode("")); + } + + [Fact] + public void HttpUtility_HtmlEncode_Ampersand() + { + Assert.Equal("a & b", HttpUtility.HtmlEncode("a & b")); + } + + [Fact] + public void HttpUtility_HtmlEncode_Quotes() + { + Assert.Equal(""test"", HttpUtility.HtmlEncode("\"test\"")); + } + + [Fact] + public void HttpUtility_HtmlDecode_Basic() + { + Assert.Equal("", HttpUtility.HtmlDecode("<b>")); + } + + [Fact] + public void HttpUtility_HtmlDecode_Numeric() + { + Assert.Equal("A", HttpUtility.HtmlDecode("A")); + } + + [Fact] + public void HttpUtility_HtmlEncode_Null() + { + Assert.Null(HttpUtility.HtmlEncode((string)null)); + } + + [Fact] + public void HttpUtility_HtmlDecode_Null() + { + Assert.Null(HttpUtility.HtmlDecode(null)); + } + + [Fact] + public void HttpUtility_UrlEncode_Basic() + { + var result = HttpUtility.UrlEncode("hello world"); + Assert.Equal("hello+world", result); + } + + [Fact] + public void HttpUtility_UrlDecode_Basic() + { + var result = HttpUtility.UrlDecode("hello+world"); + Assert.Equal("hello world", result); + } + + [Fact] + public void HttpUtility_UrlEncode_Null() + { + Assert.Null(HttpUtility.UrlEncode((string)null)); + } + + [Fact] + public void HttpUtility_UrlDecode_Null() + { + Assert.Null(HttpUtility.UrlDecode((string)null)); + } + + [Fact] + public void HttpUtility_UrlEncode_SpecialChars() + { + var result = HttpUtility.UrlEncode("a=1&b=2"); + Assert.Contains("%3d", result, StringComparison.OrdinalIgnoreCase); + Assert.Contains("%26", result, StringComparison.OrdinalIgnoreCase); + } + + [Fact] + public void HttpUtility_UrlDecode_Percent() + { + var result = HttpUtility.UrlDecode("hello%20world"); + Assert.Equal("hello world", result); + } + + [Fact] + public void HttpUtility_ParseQueryString() + { + var result = HttpUtility.ParseQueryString("a=1&b=2"); + Assert.Equal("1", result["a"]); + Assert.Equal("2", result["b"]); + } + + [Fact] + public void HttpUtility_ParseQueryString_Empty() + { + var result = HttpUtility.ParseQueryString(""); + Assert.Equal(0, result.Count); + } + + [Fact] + public void HttpUtility_ParseQueryString_With_QuestionMark() + { + var result = HttpUtility.ParseQueryString("?a=1"); + Assert.Equal("1", result["a"]); + } + } +} diff --git a/RestSharp.Tests.Coverage/AuthenticatorTests.cs b/RestSharp.Tests.Coverage/AuthenticatorTests.cs new file mode 100644 index 000000000..f4284345a --- /dev/null +++ b/RestSharp.Tests.Coverage/AuthenticatorTests.cs @@ -0,0 +1,135 @@ +using System; +using System.Linq; +using Xunit; + +namespace RestSharp.Tests +{ + public class AuthenticatorTests + { + [Fact] + public void HttpBasicAuthenticator_Adds_Authorization_Header() + { + var auth = new HttpBasicAuthenticator("user", "pass"); + var client = new RestClient("http://example.com"); + var request = new RestRequest(); + + auth.Authenticate(client, request); + + var header = request.Parameters.FirstOrDefault( + p => p.Name == "Authorization" && p.Type == ParameterType.HttpHeader); + Assert.NotNull(header); + Assert.StartsWith("Basic ", header.Value.ToString()); + } + + [Fact] + public void HttpBasicAuthenticator_Encodes_Credentials_Correctly() + { + var auth = new HttpBasicAuthenticator("admin", "secret"); + var client = new RestClient("http://example.com"); + var request = new RestRequest(); + + auth.Authenticate(client, request); + + var header = request.Parameters.First(p => p.Name == "Authorization"); + var expectedToken = Convert.ToBase64String( + System.Text.Encoding.UTF8.GetBytes("admin:secret")); + Assert.Equal("Basic " + expectedToken, header.Value.ToString()); + } + + [Fact] + public void HttpBasicAuthenticator_Does_Not_Add_Duplicate() + { + var auth = new HttpBasicAuthenticator("user", "pass"); + var client = new RestClient("http://example.com"); + var request = new RestRequest(); + + auth.Authenticate(client, request); + auth.Authenticate(client, request); + + var headers = request.Parameters + .Where(p => p.Name.Equals("Authorization", StringComparison.OrdinalIgnoreCase)) + .ToList(); + Assert.Single(headers); + } + + [Fact] + public void SimpleAuthenticator_Adds_Username_And_Password_Parameters() + { + var auth = new SimpleAuthenticator("username", "admin", "password", "secret"); + var client = new RestClient("http://example.com"); + var request = new RestRequest(); + + auth.Authenticate(client, request); + + Assert.Equal(2, request.Parameters.Count); + Assert.Contains(request.Parameters, p => p.Name == "username" && p.Value.ToString() == "admin"); + Assert.Contains(request.Parameters, p => p.Name == "password" && p.Value.ToString() == "secret"); + } + + [Fact] + public void OAuth2UriQueryParameterAuthenticator_Adds_Token_Parameter() + { + var auth = new OAuth2UriQueryParameterAuthenticator("mytoken123"); + var client = new RestClient("http://example.com"); + var request = new RestRequest(); + + auth.Authenticate(client, request); + + var param = request.Parameters.FirstOrDefault( + p => p.Name == "oauth_token" && p.Type == ParameterType.GetOrPost); + Assert.NotNull(param); + Assert.Equal("mytoken123", param.Value.ToString()); + } + + [Fact] + public void OAuth2UriQueryParameterAuthenticator_AccessToken_Property() + { + var auth = new OAuth2UriQueryParameterAuthenticator("token456"); + Assert.Equal("token456", auth.AccessToken); + } + + [Fact] + public void OAuth2AuthorizationRequestHeaderAuthenticator_Adds_Header() + { + var auth = new OAuth2AuthorizationRequestHeaderAuthenticator("bearertoken"); + var client = new RestClient("http://example.com"); + var request = new RestRequest(); + + auth.Authenticate(client, request); + + var header = request.Parameters.FirstOrDefault( + p => p.Name == "Authorization" && p.Type == ParameterType.HttpHeader); + Assert.NotNull(header); + Assert.Equal("OAuth bearertoken", header.Value.ToString()); + } + + [Fact] + public void OAuth2AuthorizationRequestHeaderAuthenticator_Does_Not_Add_Duplicate() + { + var auth = new OAuth2AuthorizationRequestHeaderAuthenticator("token"); + var client = new RestClient("http://example.com"); + var request = new RestRequest(); + + auth.Authenticate(client, request); + auth.Authenticate(client, request); + + var headers = request.Parameters + .Where(p => p.Name.Equals("Authorization", StringComparison.OrdinalIgnoreCase)) + .ToList(); + Assert.Single(headers); + } + + [Fact] + public void NtlmAuthenticator_Sets_DefaultCredentials() + { + var auth = new NtlmAuthenticator(); + var client = new RestClient("http://example.com"); + var request = new RestRequest(); + + auth.Authenticate(client, request); + + Assert.NotNull(request.Credentials); + Assert.Same(System.Net.CredentialCache.DefaultCredentials, request.Credentials); + } + } +} diff --git a/RestSharp.Tests.Coverage/CoverageBoostTests.cs b/RestSharp.Tests.Coverage/CoverageBoostTests.cs new file mode 100644 index 000000000..645eedce7 --- /dev/null +++ b/RestSharp.Tests.Coverage/CoverageBoostTests.cs @@ -0,0 +1,398 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.IO; +using System.Globalization; +using System.Linq; +using Newtonsoft.Json.Linq; +using RestSharp.Authenticators.OAuth; +using RestSharp.Contrib; +using RestSharp.Extensions; +using Xunit; + +namespace RestSharp.Tests +{ + public class CoverageBoostTests + { + // WebParameterCollection constructors + [Fact] + public void WebParameterCollection_NameValueCollection_Ctor() + { + var nvc = new NameValueCollection { { "a", "1" }, { "b", "2" } }; + var coll = new WebParameterCollection(nvc); + Assert.Equal(2, coll.Count); + } + + [Fact] + public void WebParameterCollection_Capacity_Ctor() + { + var coll = new WebParameterCollection(10); + Assert.Equal(0, coll.Count); + } + + [Fact] + public void WebParameterCollection_Dictionary_Ctor() + { + var dict = new Dictionary { { "x", "1" } }; + var coll = new WebParameterCollection(dict); + Assert.Single(coll); + } + + [Fact] + public void WebParameterCollection_Enumerable_Ctor() + { + var pairs = new List { new WebParameter("k", "v") }; + var coll = new WebParameterCollection(pairs); + Assert.Single(coll); + } + + [Fact] + public void WebParameterCollection_Add_Override() + { + var coll = new WebParameterCollection(); + coll.Add("name", "value"); + Assert.IsType(coll[0]); + } + + // MiscExtensions - SaveAs + [Fact] + public void SaveAs_Creates_File() + { + var data = new byte[] { 1, 2, 3, 4, 5 }; + var path = Path.Combine(Path.GetTempPath(), $"test_{Guid.NewGuid()}.bin"); + try + { + data.SaveAs(path); + Assert.True(File.Exists(path)); + Assert.Equal(data, File.ReadAllBytes(path)); + } + finally + { + if (File.Exists(path)) File.Delete(path); + } + } + + // MiscExtensions - CopyTo + [Fact] + public void CopyTo_Copies_Stream() + { + var source = new MemoryStream(new byte[] { 10, 20, 30 }); + var dest = new MemoryStream(); + source.CopyTo(dest); + Assert.Equal(3, dest.Length); + } + + // MiscExtensions - AsString for JToken + [Fact] + public void JToken_AsString_String() + { + var token = JToken.FromObject("hello"); + Assert.Equal("hello", token.AsString()); + } + + [Fact] + public void JToken_AsString_NonString() + { + var token = JToken.FromObject(42); + Assert.Equal("42", token.AsString()); + } + + [Fact] + public void JToken_AsString_With_Culture() + { + var token = JToken.FromObject(3.14); + var result = token.AsString(CultureInfo.InvariantCulture); + Assert.NotNull(result); + } + + [Fact] + public void JToken_AsString_With_Culture_String() + { + var token = JToken.FromObject("test"); + var result = token.AsString(CultureInfo.InvariantCulture); + Assert.Equal("test", result); + } + + // MiscExtensions - byte[].AsString + [Fact] + public void ByteArray_AsString_Null() + { + byte[] buffer = null; + Assert.Equal("", buffer.AsString()); + } + + [Fact] + public void ByteArray_AsString_UTF8() + { + var buffer = System.Text.Encoding.UTF8.GetBytes("hello"); + Assert.Equal("hello", buffer.AsString()); + } + + // RestClientExtensions + [Fact] + public void RestClientExtensions_ExecuteAsync_Invokes() + { + var client = new RestClient("http://localhost:1"); + var request = new RestRequest("/test"); + bool called = false; + var handle = RestClientExtensions.ExecuteAsync(client, request, (response) => + { + called = true; + }); + Assert.NotNull(handle); + } + + // RestRequestAsyncHandle + [Fact] + public void RestRequestAsyncHandle_Abort() + { + var handle = new RestRequestAsyncHandle(); + // No web request set, Abort should not throw + handle.Abort(); + } + + // HttpFile properties + [Fact] + public void HttpFile_All_Properties() + { + var file = new HttpFile + { + Name = "upload", + FileName = "doc.pdf", + ContentType = "application/pdf", + ContentLength = 1024, + Writer = (s) => { } + }; + Assert.Equal("upload", file.Name); + Assert.Equal("doc.pdf", file.FileName); + Assert.Equal("application/pdf", file.ContentType); + Assert.Equal(1024, file.ContentLength); + Assert.NotNull(file.Writer); + } + + // RestRequest additional coverage + [Fact] + public void RestRequest_AddFile_Bytes() + { + var request = new RestRequest(); + request.AddFile("file", new byte[] { 1, 2, 3 }, "test.bin"); + Assert.Single(request.Files); + } + + [Fact] + public void RestRequest_AddFile_Writer() + { + var request = new RestRequest(); + request.AddFile("file", (s) => s.WriteByte(1), "test.bin"); + Assert.Single(request.Files); + } + + [Fact] + public void RestRequest_AddFile_Path() + { + var path = Path.GetTempFileName(); + try + { + File.WriteAllBytes(path, new byte[] { 1, 2, 3 }); + var request = new RestRequest(); + request.AddFile("file", path); + Assert.Single(request.Files); + } + finally + { + File.Delete(path); + } + } + + [Fact] + public void RestRequest_Timeout_Property() + { + var request = new RestRequest(); + request.Timeout = 5000; + Assert.Equal(5000, request.Timeout); + } + + [Fact] + public void RestRequest_Credentials_Property() + { + var request = new RestRequest(); + var cred = new System.Net.NetworkCredential("user", "pass"); + request.Credentials = cred; + Assert.Same(cred, request.Credentials); + } + + // RestResponseCookie coverage + [Fact] + public void RestResponseCookie_All_Properties() + { + var cookie = new RestResponseCookie + { + Comment = "test", + CommentUri = new Uri("http://example.com"), + Discard = true, + Domain = ".test.com", + Expired = false, + Expires = DateTime.Now, + HttpOnly = true, + Name = "sid", + Path = "/", + Port = "443", + Secure = true, + TimeStamp = DateTime.Now, + Value = "xyz", + Version = 1 + }; + Assert.Equal("test", cookie.Comment); + Assert.Equal("sid", cookie.Name); + Assert.True(cookie.HttpOnly); + } + + // HttpEncoder coverage + [Fact] + public void HttpEncoder_HtmlEncode_HighChar() + { + var result = HttpUtility.HtmlEncode("\u00A9"); // © + Assert.NotNull(result); + } + + [Fact] + public void HttpEncoder_UrlEncode_AllChars() + { + // Test various characters that need encoding + var result = HttpUtility.UrlEncode("!@#$%^&*()"); + Assert.NotNull(result); + Assert.Contains("%", result); + } + + [Fact] + public void HttpEncoder_UrlDecode_Plus_And_Percent() + { + Assert.Equal("a b", HttpUtility.UrlDecode("a+b")); + Assert.Equal("a&b", HttpUtility.UrlDecode("a%26b")); + } + + // Http class - additional internal method coverage + [Fact] + public void Http_Post_With_Files_And_Parameters() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Parameters.Add(new HttpParameter { Name = "field", Value = "value" }); + http.Files.Add(new HttpFile + { + Name = "file", + FileName = "test.txt", + ContentType = "text/plain", + Writer = (s) => + { + var bytes = System.Text.Encoding.UTF8.GetBytes("test content"); + s.Write(bytes, 0, bytes.Length); + } + }); + + var response = http.Post(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Http_Get_With_If_Modified_Since() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Headers.Add(new HttpHeader { Name = "If-Modified-Since", Value = DateTime.UtcNow.ToString("R") }); + + var response = http.Get(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Http_Get_With_Expect_Header() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Headers.Add(new HttpHeader { Name = "Expect", Value = "custom-expect" }); + + var response = http.Get(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Http_Get_With_Multiple_Custom_Headers() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Headers.Add(new HttpHeader { Name = "X-Custom-1", Value = "value1" }); + http.Headers.Add(new HttpHeader { Name = "X-Custom-2", Value = "value2" }); + + var response = http.Get(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Http_Get_With_UserAgent_Header() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Headers.Add(new HttpHeader { Name = "User-Agent", Value = "CustomUA" }); + + var response = http.Get(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Http_Get_With_Date_Header() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Headers.Add(new HttpHeader { Name = "Date", Value = DateTime.UtcNow.ToString("R") }); + + var response = http.Get(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Http_Get_With_Host_Header() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Headers.Add(new HttpHeader { Name = "Host", Value = "example.com" }); + + var response = http.Get(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Http_Get_With_ContentLength_Header() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Headers.Add(new HttpHeader { Name = "Content-Length", Value = "0" }); + + var response = http.Get(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Http_Get_With_Range_Header() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Headers.Add(new HttpHeader { Name = "Range", Value = "bytes=0-100" }); + + var response = http.Get(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Http_Post_With_Only_Parameters_No_Body() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Parameters.Add(new HttpParameter { Name = "a", Value = "1" }); + http.Parameters.Add(new HttpParameter { Name = "b", Value = "2" }); + + var response = http.Post(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + } +} diff --git a/RestSharp.Tests.Coverage/DotNetXmlTests.cs b/RestSharp.Tests.Coverage/DotNetXmlTests.cs new file mode 100644 index 000000000..a04669fd7 --- /dev/null +++ b/RestSharp.Tests.Coverage/DotNetXmlTests.cs @@ -0,0 +1,101 @@ +using System; +using System.Text; +using System.Xml.Serialization; +using RestSharp.Deserializers; +using RestSharp.Serializers; +using Xunit; + +namespace RestSharp.Tests +{ + public class DotNetXmlTests + { + [Fact] + public void DotNetXmlSerializer_Default_ContentType() + { + var s = new DotNetXmlSerializer(); + Assert.Equal("application/xml", s.ContentType); + } + + [Fact] + public void DotNetXmlSerializer_Default_Encoding() + { + var s = new DotNetXmlSerializer(); + Assert.Equal(Encoding.UTF8, s.Encoding); + } + + [Fact] + public void DotNetXmlSerializer_Constructor_With_Namespace() + { + var s = new DotNetXmlSerializer("http://example.com/ns"); + Assert.Equal("http://example.com/ns", s.Namespace); + } + + [Fact] + public void DotNetXmlSerializer_Serialize() + { + var s = new DotNetXmlSerializer(); + var result = s.Serialize(new DotNetTestObj { Name = "Test", Value = 42 }); + Assert.Contains("Test", result); + Assert.Contains("42", result); + } + + [Fact] + public void DotNetXmlSerializer_Properties() + { + var s = new DotNetXmlSerializer(); + s.RootElement = "Root"; + s.DateFormat = "yyyy-MM-dd"; + s.ContentType = "text/xml"; + Assert.Equal("Root", s.RootElement); + Assert.Equal("yyyy-MM-dd", s.DateFormat); + Assert.Equal("text/xml", s.ContentType); + } + + [Fact] + public void DotNetXmlDeserializer_Deserialize() + { + var d = new DotNetXmlDeserializer(); + var xml = "Hello99"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal("Hello", obj.Name); + Assert.Equal(99, obj.Value); + } + + [Fact] + public void DotNetXmlDeserializer_Deserialize_Empty_Content() + { + var d = new DotNetXmlDeserializer(); + var response = new RestResponse { Content = "" }; + var obj = d.Deserialize(response); + Assert.Null(obj); + } + + [Fact] + public void DotNetXmlDeserializer_Deserialize_Null_Content() + { + var d = new DotNetXmlDeserializer(); + var response = new RestResponse { Content = null }; + var obj = d.Deserialize(response); + Assert.Null(obj); + } + + [Fact] + public void DotNetXmlDeserializer_Properties() + { + var d = new DotNetXmlDeserializer(); + d.DateFormat = "yyyy-MM-dd"; + d.Namespace = "http://ns"; + d.RootElement = "Root"; + Assert.Equal("yyyy-MM-dd", d.DateFormat); + Assert.Equal("http://ns", d.Namespace); + Assert.Equal("Root", d.RootElement); + } + } + + public class DotNetTestObj + { + public string Name { get; set; } + public int Value { get; set; } + } +} diff --git a/RestSharp.Tests.Coverage/FactoryAndEnumTests.cs b/RestSharp.Tests.Coverage/FactoryAndEnumTests.cs new file mode 100644 index 000000000..9cb24a9c5 --- /dev/null +++ b/RestSharp.Tests.Coverage/FactoryAndEnumTests.cs @@ -0,0 +1,68 @@ +using System; +using Xunit; + +namespace RestSharp.Tests +{ + public class FactoryAndEnumTests + { + [Fact] + public void SimpleFactory_Creates_Instance() + { + var factory = new SimpleFactory(); + var http = factory.Create(); + Assert.NotNull(http); + Assert.IsType(http); + } + + [Fact] + public void Method_Enum_Values() + { + Assert.Equal(Method.GET, (Method)0); + Assert.Equal(Method.POST, (Method)1); + Assert.Equal(Method.PUT, (Method)2); + Assert.Equal(Method.DELETE, (Method)3); + Assert.Equal(Method.HEAD, (Method)4); + Assert.Equal(Method.OPTIONS, (Method)5); + Assert.Equal(Method.PATCH, (Method)6); + } + + [Fact] + public void DataFormat_Enum_Values() + { + Assert.Equal(DataFormat.Json, (DataFormat)0); + Assert.Equal(DataFormat.Xml, (DataFormat)1); + } + + [Fact] + public void ResponseStatus_Enum_Values() + { + Assert.Equal(ResponseStatus.None, (ResponseStatus)0); + Assert.Equal(ResponseStatus.Completed, (ResponseStatus)1); + Assert.Equal(ResponseStatus.Error, (ResponseStatus)2); + Assert.Equal(ResponseStatus.TimedOut, (ResponseStatus)3); + Assert.Equal(ResponseStatus.Aborted, (ResponseStatus)4); + } + + [Fact] + public void DateFormat_Constants() + { + Assert.Equal("s", DateFormat.Iso8601); + Assert.Equal("u", DateFormat.RoundTrip); + } + + [Fact] + public void RestRequestAsyncHandle_Defaults() + { + var handle = new RestRequestAsyncHandle(); + Assert.Null(handle.WebRequest); + } + + [Fact] + public void RestRequestAsyncHandle_Abort_Without_WebRequest() + { + var handle = new RestRequestAsyncHandle(); + // should not throw + handle.Abort(); + } + } +} diff --git a/RestSharp.Tests.Coverage/FileParameterTests.cs b/RestSharp.Tests.Coverage/FileParameterTests.cs new file mode 100644 index 000000000..bc5d78bdb --- /dev/null +++ b/RestSharp.Tests.Coverage/FileParameterTests.cs @@ -0,0 +1,77 @@ +using System.IO; +using Xunit; + +namespace RestSharp.Tests +{ + public class FileParameterTests + { + [Fact] + public void Create_With_Name_Data_Filename_ContentType() + { + var data = new byte[] { 1, 2, 3, 4, 5 }; + var fp = FileParameter.Create("file", data, "test.txt", "text/plain"); + + Assert.Equal("file", fp.Name); + Assert.Equal("test.txt", fp.FileName); + Assert.Equal("text/plain", fp.ContentType); + Assert.Equal(5, fp.ContentLength); + Assert.NotNull(fp.Writer); + } + + [Fact] + public void Create_With_Name_Data_Filename_No_ContentType() + { + var data = new byte[] { 10, 20, 30 }; + var fp = FileParameter.Create("doc", data, "doc.pdf"); + + Assert.Equal("doc", fp.Name); + Assert.Equal("doc.pdf", fp.FileName); + Assert.Null(fp.ContentType); + Assert.Equal(3, fp.ContentLength); + } + + [Fact] + public void Writer_Writes_Data_To_Stream() + { + var data = new byte[] { 1, 2, 3, 4, 5 }; + var fp = FileParameter.Create("file", data, "test.bin", "application/octet-stream"); + + using (var ms = new MemoryStream()) + { + fp.Writer(ms); + Assert.Equal(data, ms.ToArray()); + } + } + + [Fact] + public void Properties_Can_Be_Set() + { + var fp = new FileParameter(); + fp.Name = "myfile"; + fp.FileName = "upload.jpg"; + fp.ContentType = "image/jpeg"; + fp.ContentLength = 12345; + fp.Writer = s => { }; + + Assert.Equal("myfile", fp.Name); + Assert.Equal("upload.jpg", fp.FileName); + Assert.Equal("image/jpeg", fp.ContentType); + Assert.Equal(12345, fp.ContentLength); + Assert.NotNull(fp.Writer); + } + + [Fact] + public void Create_Empty_Data() + { + var data = new byte[0]; + var fp = FileParameter.Create("empty", data, "empty.txt", "text/plain"); + + Assert.Equal(0, fp.ContentLength); + using (var ms = new MemoryStream()) + { + fp.Writer(ms); + Assert.Empty(ms.ToArray()); + } + } + } +} diff --git a/RestSharp.Tests.Coverage/HttpCookieTests.cs b/RestSharp.Tests.Coverage/HttpCookieTests.cs new file mode 100644 index 000000000..f1cb38575 --- /dev/null +++ b/RestSharp.Tests.Coverage/HttpCookieTests.cs @@ -0,0 +1,45 @@ +using System; +using Xunit; + +namespace RestSharp.Tests +{ + public class HttpCookieTests + { + [Fact] + public void All_Properties_Can_Be_Set() + { + var cookie = new HttpCookie(); + var now = DateTime.Now; + + cookie.Comment = "test comment"; + cookie.CommentUri = new Uri("http://example.com"); + cookie.Discard = true; + cookie.Domain = ".example.com"; + cookie.Expired = false; + cookie.Expires = now; + cookie.HttpOnly = true; + cookie.Name = "session"; + cookie.Path = "/"; + cookie.Port = "80"; + cookie.Secure = true; + cookie.TimeStamp = now; + cookie.Value = "abc123"; + cookie.Version = 2; + + Assert.Equal("test comment", cookie.Comment); + Assert.Equal("http://example.com/", cookie.CommentUri.ToString()); + Assert.True(cookie.Discard); + Assert.Equal(".example.com", cookie.Domain); + Assert.False(cookie.Expired); + Assert.Equal(now, cookie.Expires); + Assert.True(cookie.HttpOnly); + Assert.Equal("session", cookie.Name); + Assert.Equal("/", cookie.Path); + Assert.Equal("80", cookie.Port); + Assert.True(cookie.Secure); + Assert.Equal(now, cookie.TimeStamp); + Assert.Equal("abc123", cookie.Value); + Assert.Equal(2, cookie.Version); + } + } +} diff --git a/RestSharp.Tests.Coverage/HttpResponseTests.cs b/RestSharp.Tests.Coverage/HttpResponseTests.cs new file mode 100644 index 000000000..b02851ee1 --- /dev/null +++ b/RestSharp.Tests.Coverage/HttpResponseTests.cs @@ -0,0 +1,124 @@ +using System; +using System.Net; +using System.Text; +using Xunit; + +namespace RestSharp.Tests +{ + public class HttpResponseTests + { + [Fact] + public void Default_Constructor_Initializes_Collections() + { + var response = new HttpResponse(); + Assert.NotNull(response.Headers); + Assert.NotNull(response.Cookies); + } + + [Fact] + public void StatusCode_Can_Be_Set() + { + var response = new HttpResponse(); + response.StatusCode = HttpStatusCode.OK; + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + [Fact] + public void StatusDescription_Can_Be_Set() + { + var response = new HttpResponse(); + response.StatusDescription = "Not Found"; + Assert.Equal("Not Found", response.StatusDescription); + } + + [Fact] + public void ContentType_Can_Be_Set() + { + var response = new HttpResponse(); + response.ContentType = "text/html"; + Assert.Equal("text/html", response.ContentType); + } + + [Fact] + public void ContentLength_Can_Be_Set() + { + var response = new HttpResponse(); + response.ContentLength = 2048; + Assert.Equal(2048, response.ContentLength); + } + + [Fact] + public void ContentEncoding_Can_Be_Set() + { + var response = new HttpResponse(); + response.ContentEncoding = "utf-8"; + Assert.Equal("utf-8", response.ContentEncoding); + } + + [Fact] + public void RawBytes_Can_Be_Set() + { + var response = new HttpResponse(); + var data = new byte[] { 1, 2, 3 }; + response.RawBytes = data; + Assert.Equal(data, response.RawBytes); + } + + [Fact] + public void Content_Lazy_Loaded_From_RawBytes() + { + var response = new HttpResponse(); + response.RawBytes = Encoding.UTF8.GetBytes("Hello World"); + Assert.Equal("Hello World", response.Content); + } + + [Fact] + public void Content_Returns_Empty_When_RawBytes_Null() + { + var response = new HttpResponse(); + response.RawBytes = null; + Assert.Equal("", response.Content); + } + + [Fact] + public void ResponseUri_Can_Be_Set() + { + var response = new HttpResponse(); + response.ResponseUri = new Uri("http://example.com"); + Assert.Equal("http://example.com/", response.ResponseUri.ToString()); + } + + [Fact] + public void Server_Can_Be_Set() + { + var response = new HttpResponse(); + response.Server = "Apache"; + Assert.Equal("Apache", response.Server); + } + + [Fact] + public void ResponseStatus_Can_Be_Set() + { + var response = new HttpResponse(); + response.ResponseStatus = ResponseStatus.Error; + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void ErrorMessage_Can_Be_Set() + { + var response = new HttpResponse(); + response.ErrorMessage = "Connection refused"; + Assert.Equal("Connection refused", response.ErrorMessage); + } + + [Fact] + public void ErrorException_Can_Be_Set() + { + var response = new HttpResponse(); + var ex = new Exception("test"); + response.ErrorException = ex; + Assert.Same(ex, response.ErrorException); + } + } +} diff --git a/RestSharp.Tests.Coverage/HttpSyncTests.cs b/RestSharp.Tests.Coverage/HttpSyncTests.cs new file mode 100644 index 000000000..4d9603c3f --- /dev/null +++ b/RestSharp.Tests.Coverage/HttpSyncTests.cs @@ -0,0 +1,339 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Security.Cryptography.X509Certificates; +using Xunit; + +namespace RestSharp.Tests +{ + public class HttpSyncTests + { + [Fact] + public void Create_Returns_New_Http_Instance() + { + var http = new Http(); + var created = http.Create(); + Assert.NotNull(created); + Assert.IsType(created); + } + + [Fact] + public void Default_Constructor_Initializes_Collections() + { + var http = new Http(); + Assert.NotNull(http.Headers); + Assert.NotNull(http.Files); + Assert.NotNull(http.Parameters); + Assert.NotNull(http.Cookies); + Assert.Empty(http.Headers); + Assert.Empty(http.Files); + Assert.Empty(http.Parameters); + Assert.Empty(http.Cookies); + } + + [Fact] + public void All_Properties_Can_Be_Set() + { + var http = new Http(); + http.UserAgent = "TestAgent/1.0"; + http.Timeout = 30000; + http.Credentials = new NetworkCredential("user", "pass"); + http.CookieContainer = new CookieContainer(); + http.FollowRedirects = true; + http.ClientCertificates = new X509CertificateCollection(); + http.MaxRedirects = 5; + http.RequestBody = "{\"test\":true}"; + http.RequestContentType = "application/json"; + http.Url = new Uri("http://example.com"); + http.Proxy = new WebProxy("http://proxy.com"); + + Assert.Equal("TestAgent/1.0", http.UserAgent); + Assert.Equal(30000, http.Timeout); + Assert.NotNull(http.Credentials); + Assert.NotNull(http.CookieContainer); + Assert.True(http.FollowRedirects); + Assert.NotNull(http.ClientCertificates); + Assert.Equal(5, http.MaxRedirects); + Assert.Equal("{\"test\":true}", http.RequestBody); + Assert.Equal("application/json", http.RequestContentType); + Assert.Equal(new Uri("http://example.com"), http.Url); + Assert.NotNull(http.Proxy); + } + + [Fact] + public void Headers_Can_Be_Added() + { + var http = new Http(); + http.Headers.Add(new HttpHeader { Name = "X-Custom", Value = "test" }); + Assert.Single(http.Headers); + } + + [Fact] + public void Parameters_Can_Be_Added() + { + var http = new Http(); + http.Parameters.Add(new HttpParameter { Name = "param1", Value = "value1" }); + Assert.Single(http.Parameters); + } + + [Fact] + public void Cookies_Can_Be_Added() + { + var http = new Http(); + http.Cookies.Add(new HttpCookie { Name = "session", Value = "abc" }); + Assert.Single(http.Cookies); + } + + [Fact] + public void Files_Can_Be_Added() + { + var http = new Http(); + http.Files.Add(new HttpFile { Name = "file", FileName = "test.txt" }); + Assert.Single(http.Files); + } + + [Fact] + public void Get_Makes_Request_To_Invalid_Url_Returns_Error() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + + var response = http.Get(); + Assert.NotNull(response); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + Assert.NotNull(response.ErrorMessage); + } + + [Fact] + public void Post_Makes_Request_To_Invalid_Url_Returns_Error() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + + var response = http.Post(); + Assert.NotNull(response); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Put_Makes_Request_To_Invalid_Url_Returns_Error() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + + var response = http.Put(); + Assert.NotNull(response); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Delete_Makes_Request_To_Invalid_Url_Returns_Error() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + + var response = http.Delete(); + Assert.NotNull(response); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Head_Makes_Request_To_Invalid_Url_Returns_Error() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + + var response = http.Head(); + Assert.NotNull(response); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Options_Makes_Request_To_Invalid_Url_Returns_Error() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + + var response = http.Options(); + Assert.NotNull(response); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Patch_Makes_Request_To_Invalid_Url_Returns_Error() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + + var response = http.Patch(); + Assert.NotNull(response); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Post_With_Body_To_Invalid_Url_Returns_Error() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.RequestBody = "{\"key\":\"value\"}"; + http.RequestContentType = "application/json"; + + var response = http.Post(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Post_With_Parameters() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Parameters.Add(new HttpParameter { Name = "key", Value = "value" }); + + var response = http.Post(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Post_With_Files() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Files.Add(new HttpFile + { + Name = "file", + FileName = "test.txt", + ContentType = "text/plain", + Writer = (s) => { var bytes = System.Text.Encoding.UTF8.GetBytes("hello"); s.Write(bytes, 0, bytes.Length); } + }); + + var response = http.Post(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Get_With_Headers() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Headers.Add(new HttpHeader { Name = "Accept", Value = "application/json" }); + http.Headers.Add(new HttpHeader { Name = "X-Custom", Value = "test" }); + + var response = http.Get(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Get_With_Cookies() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Cookies.Add(new HttpCookie { Name = "session", Value = "abc" }); + + var response = http.Get(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Get_With_UserAgent() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.UserAgent = "TestAgent"; + + var response = http.Get(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Get_With_Credentials() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Credentials = new NetworkCredential("user", "pass"); + + var response = http.Get(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Get_With_Timeout() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Timeout = 1000; + + var response = http.Get(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Get_With_Proxy() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Proxy = new WebProxy("http://nonexistent.proxy:8080"); + + var response = http.Get(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Get_With_FollowRedirects() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.FollowRedirects = true; + http.MaxRedirects = 3; + + var response = http.Get(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Get_With_ContentType_Header() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Headers.Add(new HttpHeader { Name = "Content-Type", Value = "application/json" }); + + var response = http.Get(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Get_With_Referer_Header() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.Headers.Add(new HttpHeader { Name = "Referer", Value = "http://example.com" }); + + var response = http.Get(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Put_With_Body() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.RequestBody = "{\"update\":true}"; + http.RequestContentType = "application/json"; + + var response = http.Put(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Patch_With_Body() + { + var http = new Http(); + http.Url = new Uri("http://localhost:1/nonexistent"); + http.RequestBody = "{\"patch\":true}"; + http.RequestContentType = "application/json"; + + var response = http.Patch(); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + } +} diff --git a/RestSharp.Tests.Coverage/HttpTests.cs b/RestSharp.Tests.Coverage/HttpTests.cs new file mode 100644 index 000000000..8da4eee23 --- /dev/null +++ b/RestSharp.Tests.Coverage/HttpTests.cs @@ -0,0 +1,183 @@ +using System; +using System.Linq; +using System.Net; +using Xunit; + +namespace RestSharp.Tests +{ + public class HttpTests + { + [Fact] + public void Default_Constructor_Initializes_Collections() + { + var http = new Http(); + Assert.NotNull(http.Headers); + Assert.Empty(http.Headers); + Assert.NotNull(http.Parameters); + Assert.Empty(http.Parameters); + Assert.NotNull(http.Cookies); + Assert.Empty(http.Cookies); + Assert.NotNull(http.Files); + Assert.Empty(http.Files); + } + + [Fact] + public void HasParameters_False_By_Default() + { + var http = new TestableHttp(); + Assert.False(http.TestHasParameters); + } + + [Fact] + public void HasParameters_True_When_Parameters_Added() + { + var http = new TestableHttp(); + http.Parameters.Add(new HttpParameter { Name = "key", Value = "val" }); + Assert.True(http.TestHasParameters); + } + + [Fact] + public void HasCookies_False_By_Default() + { + var http = new TestableHttp(); + Assert.False(http.TestHasCookies); + } + + [Fact] + public void HasCookies_True_When_Cookies_Added() + { + var http = new TestableHttp(); + http.Cookies.Add(new HttpCookie { Name = "session", Value = "abc" }); + Assert.True(http.TestHasCookies); + } + + [Fact] + public void HasBody_False_By_Default() + { + var http = new TestableHttp(); + Assert.False(http.TestHasBody); + } + + [Fact] + public void HasBody_True_When_RequestBody_Set() + { + var http = new TestableHttp(); + http.RequestBody = "body content"; + Assert.True(http.TestHasBody); + } + + [Fact] + public void HasFiles_False_By_Default() + { + var http = new TestableHttp(); + Assert.False(http.TestHasFiles); + } + + [Fact] + public void HasFiles_True_When_Files_Added() + { + var http = new TestableHttp(); + http.Files.Add(new HttpFile { Name = "file", FileName = "test.txt", Writer = s => { } }); + Assert.True(http.TestHasFiles); + } + + [Fact] + public void UserAgent_Can_Be_Set() + { + var http = new Http(); + http.UserAgent = "TestAgent/1.0"; + Assert.Equal("TestAgent/1.0", http.UserAgent); + } + + [Fact] + public void Timeout_Can_Be_Set() + { + var http = new Http(); + http.Timeout = 5000; + Assert.Equal(5000, http.Timeout); + } + + [Fact] + public void Url_Can_Be_Set() + { + var http = new Http(); + http.Url = new Uri("http://example.com"); + Assert.Equal("http://example.com/", http.Url.ToString()); + } + + [Fact] + public void RequestBody_Can_Be_Set() + { + var http = new Http(); + http.RequestBody = "test body"; + Assert.Equal("test body", http.RequestBody); + } + + [Fact] + public void RequestContentType_Can_Be_Set() + { + var http = new Http(); + http.RequestContentType = "application/json"; + Assert.Equal("application/json", http.RequestContentType); + } + + [Fact] + public void Credentials_Can_Be_Set() + { + var http = new Http(); + http.Credentials = new NetworkCredential("user", "pass"); + Assert.NotNull(http.Credentials); + } + + [Fact] + public void CookieContainer_Can_Be_Set() + { + var http = new Http(); + var container = new CookieContainer(); + http.CookieContainer = container; + Assert.Same(container, http.CookieContainer); + } + + [Fact] + public void FollowRedirects_Can_Be_Set() + { + var http = new Http(); + http.FollowRedirects = true; + Assert.True(http.FollowRedirects); + } + + [Fact] + public void MaxRedirects_Can_Be_Set() + { + var http = new Http(); + http.MaxRedirects = 10; + Assert.Equal(10, http.MaxRedirects); + } + + [Fact] + public void Proxy_Can_Be_Set() + { + var http = new Http(); + var proxy = new WebProxy("http://proxy.local"); + http.Proxy = proxy; + Assert.Same(proxy, http.Proxy); + } + + [Fact] + public void IHttpFactory_Create_Returns_Http() + { + var http = new Http(); + var created = ((IHttpFactory)http).Create(); + Assert.NotNull(created); + Assert.IsType(created); + } + + private class TestableHttp : Http + { + public bool TestHasParameters => HasParameters; + public bool TestHasCookies => HasCookies; + public bool TestHasBody => HasBody; + public bool TestHasFiles => HasFiles; + } + } +} diff --git a/RestSharp.Tests.Coverage/HttpUtilityTests.cs b/RestSharp.Tests.Coverage/HttpUtilityTests.cs new file mode 100644 index 000000000..b74b2c740 --- /dev/null +++ b/RestSharp.Tests.Coverage/HttpUtilityTests.cs @@ -0,0 +1,227 @@ +using System.Text; +using RestSharp.Contrib; +using Xunit; + +namespace RestSharp.Tests +{ + public class HttpUtilityTests + { + // UrlEncode with byte arrays + [Fact] + public void UrlEncode_Bytes() + { + var bytes = Encoding.UTF8.GetBytes("hello world"); + var result = HttpUtility.UrlEncode(bytes, 0, bytes.Length); + Assert.Equal("hello+world", result); + } + + [Fact] + public void UrlEncode_Bytes_Null_Returns_Null() + { + Assert.Null(HttpUtility.UrlEncode((byte[])null, 0, 0)); + } + + [Fact] + public void UrlDecode_Bytes() + { + var bytes = Encoding.UTF8.GetBytes("hello+world"); + var result = HttpUtility.UrlDecode(bytes, 0, bytes.Length, Encoding.UTF8); + Assert.Equal("hello world", result); + } + + [Fact] + public void UrlDecode_Bytes_Null_Returns_Null() + { + Assert.Null(HttpUtility.UrlDecode((byte[])null, 0, 0, Encoding.UTF8)); + } + + [Fact] + public void UrlEncode_String_With_Encoding() + { + var result = HttpUtility.UrlEncode("hello world", Encoding.UTF8); + Assert.Equal("hello+world", result); + } + + [Fact] + public void UrlDecode_String_With_Encoding() + { + var result = HttpUtility.UrlDecode("hello+world", Encoding.UTF8); + Assert.Equal("hello world", result); + } + + [Fact] + public void UrlEncodeToBytes_String() + { + var result = HttpUtility.UrlEncodeToBytes("hello"); + Assert.NotNull(result); + Assert.Equal("hello", Encoding.ASCII.GetString(result)); + } + + [Fact] + public void UrlEncodeToBytes_Null_Returns_Null() + { + Assert.Null(HttpUtility.UrlEncodeToBytes((string)null)); + } + + [Fact] + public void UrlDecodeToBytes_String() + { + var result = HttpUtility.UrlDecodeToBytes("hello"); + Assert.NotNull(result); + } + + [Fact] + public void UrlDecodeToBytes_Null_Returns_Null() + { + Assert.Null(HttpUtility.UrlDecodeToBytes((string)null)); + } + + [Fact] + public void UrlEncodeToBytes_Bytes() + { + var bytes = Encoding.UTF8.GetBytes("hello"); + var result = HttpUtility.UrlEncodeToBytes(bytes); + Assert.NotNull(result); + } + + [Fact] + public void UrlEncodeToBytes_Bytes_Null() + { + Assert.Null(HttpUtility.UrlEncodeToBytes((byte[])null)); + } + + [Fact] + public void UrlDecodeToBytes_Bytes() + { + var bytes = Encoding.UTF8.GetBytes("hello"); + var result = HttpUtility.UrlDecodeToBytes(bytes); + Assert.NotNull(result); + } + + [Fact] + public void UrlDecodeToBytes_Bytes_Null() + { + Assert.Null(HttpUtility.UrlDecodeToBytes((byte[])null)); + } + + [Fact] + public void UrlEncodeToBytes_Bytes_WithRange() + { + var bytes = Encoding.UTF8.GetBytes("hello world"); + var result = HttpUtility.UrlEncodeToBytes(bytes, 0, bytes.Length); + Assert.NotNull(result); + Assert.Contains((byte)'+', result); + } + + [Fact] + public void UrlDecodeToBytes_Bytes_WithRange() + { + var bytes = Encoding.UTF8.GetBytes("hello+world"); + var result = HttpUtility.UrlDecodeToBytes(bytes, 0, bytes.Length); + Assert.NotNull(result); + Assert.Contains((byte)' ', result); + } + + [Fact] + public void HtmlEncode_Null_Returns_Null() + { + Assert.Null(HttpUtility.HtmlEncode(null)); + } + + [Fact] + public void HtmlDecode_Null_Returns_Null() + { + Assert.Null(HttpUtility.HtmlDecode(null)); + } + + [Fact] + public void HtmlEncode_NoSpecialChars() + { + Assert.Equal("hello", HttpUtility.HtmlEncode("hello")); + } + + [Fact] + public void HtmlEncode_AllSpecialChars() + { + Assert.Equal("<>&"", HttpUtility.HtmlEncode("<>&\"")); + } + + [Fact] + public void HtmlDecode_Entities() + { + Assert.Equal("<>&\"", HttpUtility.HtmlDecode("<>&"")); + } + + [Fact] + public void HtmlDecode_Hex_NumericEntity() + { + var result = HttpUtility.HtmlDecode("A"); + Assert.Equal("A", result); + } + + [Fact] + public void UrlEncode_Unicode() + { + var result = HttpUtility.UrlEncode("日本語"); + Assert.NotNull(result); + Assert.Contains("%", result); + } + + [Fact] + public void UrlDecode_PercentEncoded() + { + var result = HttpUtility.UrlDecode("%E6%97%A5%E6%9C%AC%E8%AA%9E"); + Assert.Equal("日本語", result); + } + + [Fact] + public void ParseQueryString_Multiple_Values() + { + var result = HttpUtility.ParseQueryString("a=1&b=2&c=3"); + Assert.Equal(3, result.Count); + Assert.Equal("1", result["a"]); + Assert.Equal("3", result["c"]); + } + + [Fact] + public void ParseQueryString_Encoded_Values() + { + var result = HttpUtility.ParseQueryString("name=hello+world&val=a%26b"); + Assert.Equal("hello world", result["name"]); + Assert.Equal("a&b", result["val"]); + } + + [Fact] + public void ParseQueryString_No_Value() + { + var result = HttpUtility.ParseQueryString("key"); + Assert.NotNull(result); + } + + [Fact] + public void UrlEncode_Empty_Returns_Empty() + { + Assert.Equal("", HttpUtility.UrlEncode("")); + } + + [Fact] + public void UrlDecode_Empty_Returns_Empty() + { + Assert.Equal("", HttpUtility.UrlDecode("")); + } + + [Fact] + public void HtmlEncode_HighUnicode() + { + var result = HttpUtility.HtmlEncode("©"); + Assert.NotNull(result); + } + + [Fact] + public void ParseQueryString_Duplicate_Keys() + { + var result = HttpUtility.ParseQueryString("a=1&a=2"); + Assert.NotNull(result["a"]); + } + } +} diff --git a/RestSharp.Tests.Coverage/JsonSerializerTests.cs b/RestSharp.Tests.Coverage/JsonSerializerTests.cs new file mode 100644 index 000000000..25dbacd09 --- /dev/null +++ b/RestSharp.Tests.Coverage/JsonSerializerTests.cs @@ -0,0 +1,92 @@ +using RestSharp.Serializers; +using Xunit; + +namespace RestSharp.Tests +{ + public class JsonSerializerTests + { + [Fact] + public void Default_Constructor_Sets_ContentType() + { + var serializer = new JsonSerializer(); + Assert.Equal("application/json", serializer.ContentType); + } + + [Fact] + public void Serialize_Simple_Object() + { + var serializer = new JsonSerializer(); + var result = serializer.Serialize(new { Name = "Test", Value = 42 }); + Assert.Contains("Test", result); + Assert.Contains("42", result); + } + + [Fact] + public void Serialize_Null_Values_Included() + { + var serializer = new JsonSerializer(); + var result = serializer.Serialize(new { Name = (string)null, Value = 0 }); + Assert.Contains("null", result); + } + + [Fact] + public void Serialize_Nested_Object() + { + var serializer = new JsonSerializer(); + var result = serializer.Serialize(new + { + Person = new { Name = "John", Age = 30 }, + Items = new[] { "A", "B", "C" } + }); + Assert.Contains("John", result); + Assert.Contains("\"A\"", result); + } + + [Fact] + public void Custom_Serializer_Constructor() + { + var customSerializer = new Newtonsoft.Json.JsonSerializer + { + NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore + }; + var serializer = new JsonSerializer(customSerializer); + Assert.Equal("application/json", serializer.ContentType); + + var result = serializer.Serialize(new { Name = (string)null, Value = 42 }); + Assert.DoesNotContain("Name", result); + Assert.Contains("42", result); + } + + [Fact] + public void ContentType_Can_Be_Changed() + { + var serializer = new JsonSerializer(); + serializer.ContentType = "text/json"; + Assert.Equal("text/json", serializer.ContentType); + } + + [Fact] + public void DateFormat_Property() + { + var serializer = new JsonSerializer(); + serializer.DateFormat = "yyyy-MM-dd"; + Assert.Equal("yyyy-MM-dd", serializer.DateFormat); + } + + [Fact] + public void RootElement_Property() + { + var serializer = new JsonSerializer(); + serializer.RootElement = "data"; + Assert.Equal("data", serializer.RootElement); + } + + [Fact] + public void Namespace_Property() + { + var serializer = new JsonSerializer(); + serializer.Namespace = "ns"; + Assert.Equal("ns", serializer.Namespace); + } + } +} diff --git a/RestSharp.Tests.Coverage/MiscExtensionsTests.cs b/RestSharp.Tests.Coverage/MiscExtensionsTests.cs new file mode 100644 index 000000000..f2743fb34 --- /dev/null +++ b/RestSharp.Tests.Coverage/MiscExtensionsTests.cs @@ -0,0 +1,121 @@ +using System; +using System.Globalization; +using System.IO; +using System.Text; +using Newtonsoft.Json.Linq; +using RestSharp.Extensions; +using Xunit; + +namespace RestSharp.Tests +{ + public class MiscExtensionsTests + { + [Fact] + public void ReadAsBytes_Reads_Stream() + { + var data = new byte[] { 1, 2, 3, 4, 5 }; + using (var stream = new MemoryStream(data)) + { + var result = stream.ReadAsBytes(); + Assert.Equal(data, result); + } + } + + [Fact] + public void ReadAsBytes_Empty_Stream() + { + using (var stream = new MemoryStream()) + { + var result = stream.ReadAsBytes(); + Assert.Empty(result); + } + } + + [Fact] + public void CopyTo_Copies_Stream_Content() + { + var data = new byte[] { 10, 20, 30, 40, 50 }; + using (var input = new MemoryStream(data)) + using (var output = new MemoryStream()) + { + input.CopyTo(output); + Assert.Equal(data, output.ToArray()); + } + } + + [Fact] + public void CopyTo_Empty_Stream() + { + using (var input = new MemoryStream()) + using (var output = new MemoryStream()) + { + input.CopyTo(output); + Assert.Empty(output.ToArray()); + } + } + + [Fact] + public void AsString_JToken_String_Type() + { + var token = JToken.Parse("\"hello\""); + Assert.Equal("hello", token.AsString()); + } + + [Fact] + public void AsString_JToken_Number_Type() + { + var token = JToken.Parse("42"); + Assert.Equal("42", token.AsString()); + } + + [Fact] + public void AsString_JToken_With_Culture() + { + var token = new JValue(3.14); + var result = token.AsString(CultureInfo.InvariantCulture); + Assert.Equal("3.14", result); + } + + [Fact] + public void AsString_JToken_String_With_Culture() + { + var token = JToken.Parse("\"test\""); + var result = token.AsString(CultureInfo.InvariantCulture); + Assert.Equal("test", result); + } + + [Fact] + public void AsString_ByteArray_Utf8() + { + var bytes = Encoding.UTF8.GetBytes("Hello World"); + var result = bytes.AsString(); + Assert.Equal("Hello World", result); + } + + [Fact] + public void AsString_ByteArray_Null_Returns_Empty() + { + byte[] bytes = null; + var result = bytes.AsString(); + Assert.Equal("", result); + } + + [Fact] + public void SaveAs_Writes_File() + { + var tmpPath = Path.GetTempFileName(); + try + { + var data = new byte[] { 1, 2, 3, 4 }; + data.SaveAs(tmpPath); + var read = File.ReadAllBytes(tmpPath); + Assert.Equal(data, read); + } + finally + { + if (File.Exists(tmpPath)) + File.Delete(tmpPath); + } + } + } +} diff --git a/RestSharp.Tests.Coverage/OAuth1AuthenticatorTests.cs b/RestSharp.Tests.Coverage/OAuth1AuthenticatorTests.cs new file mode 100644 index 000000000..2c130ec3a --- /dev/null +++ b/RestSharp.Tests.Coverage/OAuth1AuthenticatorTests.cs @@ -0,0 +1,173 @@ +using System; +using System.Linq; +using RestSharp.Authenticators; +using RestSharp.Authenticators.OAuth; +using Xunit; + +namespace RestSharp.Tests +{ + public class OAuth1AuthenticatorTests + { + [Fact] + public void ForRequestToken_Creates_Authenticator() + { + var auth = OAuth1Authenticator.ForRequestToken("key", "secret"); + Assert.NotNull(auth); + Assert.Equal(OAuthParameterHandling.HttpAuthorizationHeader, auth.ParameterHandling); + Assert.Equal(OAuthSignatureMethod.HmacSha1, auth.SignatureMethod); + Assert.Equal(OAuthSignatureTreatment.Escaped, auth.SignatureTreatment); + } + + [Fact] + public void ForRequestToken_With_Callback() + { + var auth = OAuth1Authenticator.ForRequestToken("key", "secret", "http://callback.com"); + Assert.NotNull(auth); + } + + [Fact] + public void ForAccessToken_Creates_Authenticator() + { + var auth = OAuth1Authenticator.ForAccessToken("key", "secret", "token", "token_secret"); + Assert.NotNull(auth); + } + + [Fact] + public void ForAccessToken_With_Verifier() + { + var auth = OAuth1Authenticator.ForAccessToken("key", "secret", "token", "token_secret", "verifier"); + Assert.NotNull(auth); + } + + [Fact] + public void ForAccessTokenRefresh() + { + var auth = OAuth1Authenticator.ForAccessTokenRefresh("key", "secret", "token", "token_secret", "session"); + Assert.NotNull(auth); + } + + [Fact] + public void ForAccessTokenRefresh_With_Verifier() + { + var auth = OAuth1Authenticator.ForAccessTokenRefresh("key", "secret", "token", "token_secret", "verifier", "session"); + Assert.NotNull(auth); + } + + [Fact] + public void ForClientAuthentication_Creates_Authenticator() + { + var auth = OAuth1Authenticator.ForClientAuthentication("key", "secret", "user", "pass"); + Assert.NotNull(auth); + } + + [Fact] + public void ForProtectedResource_Creates_Authenticator() + { + var auth = OAuth1Authenticator.ForProtectedResource("key", "secret", "access_token", "access_secret"); + Assert.NotNull(auth); + } + + [Fact] + public void Authenticate_RequestToken_Adds_Authorization_Header() + { + var auth = OAuth1Authenticator.ForRequestToken("key", "secret"); + var client = new RestClient("http://example.com"); + var request = new RestRequest("/oauth/request_token"); + + auth.Authenticate(client, request); + + var header = request.Parameters.FirstOrDefault( + p => p.Name == "Authorization" && p.Type == ParameterType.HttpHeader); + Assert.NotNull(header); + Assert.StartsWith("OAuth ", header.Value.ToString()); + } + + [Fact] + public void Authenticate_AccessToken_Adds_Authorization_Header() + { + var auth = OAuth1Authenticator.ForAccessToken("key", "secret", "request_token", "request_secret", "verifier"); + var client = new RestClient("http://example.com"); + var request = new RestRequest("/oauth/access_token"); + + auth.Authenticate(client, request); + + var header = request.Parameters.FirstOrDefault( + p => p.Name == "Authorization" && p.Type == ParameterType.HttpHeader); + Assert.NotNull(header); + Assert.Contains("oauth_", header.Value.ToString()); + } + + [Fact] + public void Authenticate_ProtectedResource_Adds_Authorization_Header() + { + var auth = OAuth1Authenticator.ForProtectedResource("key", "secret", "access_token", "access_secret"); + var client = new RestClient("http://example.com"); + var request = new RestRequest("/api/resource"); + + auth.Authenticate(client, request); + + var header = request.Parameters.FirstOrDefault( + p => p.Name == "Authorization" && p.Type == ParameterType.HttpHeader); + Assert.NotNull(header); + } + + [Fact] + public void Authenticate_ClientAuth_Adds_Authorization_Header() + { + var auth = OAuth1Authenticator.ForClientAuthentication("key", "secret", "user", "pass"); + var client = new RestClient("http://example.com"); + var request = new RestRequest("/oauth/access_token"); + + auth.Authenticate(client, request); + + var header = request.Parameters.FirstOrDefault( + p => p.Name == "Authorization" && p.Type == ParameterType.HttpHeader); + Assert.NotNull(header); + } + + [Fact] + public void Authenticate_With_Realm() + { + var auth = OAuth1Authenticator.ForRequestToken("key", "secret"); + auth.Realm = "example_realm"; + var client = new RestClient("http://example.com"); + var request = new RestRequest("/oauth/request_token"); + + auth.Authenticate(client, request); + + var header = request.Parameters.FirstOrDefault( + p => p.Name == "Authorization" && p.Type == ParameterType.HttpHeader); + Assert.Contains("realm=", header.Value.ToString()); + } + + [Fact] + public void Authenticate_UrlOrPostParameters_Mode() + { + var auth = OAuth1Authenticator.ForRequestToken("key", "secret"); + auth.ParameterHandling = OAuthParameterHandling.UrlOrPostParameters; + var client = new RestClient("http://example.com"); + var request = new RestRequest("/oauth/request_token"); + + auth.Authenticate(client, request); + + var oauthParams = request.Parameters.Where( + p => p.Name.StartsWith("oauth_") && p.Type == ParameterType.GetOrPost).ToList(); + Assert.NotEmpty(oauthParams); + } + + [Fact] + public void Authenticate_POST_With_Body_Parameters() + { + var auth = OAuth1Authenticator.ForProtectedResource("key", "secret", "token", "token_secret"); + var client = new RestClient("http://example.com"); + var request = new RestRequest("/api/resource", Method.POST); + request.AddParameter("status", "Hello World"); + + auth.Authenticate(client, request); + + var header = request.Parameters.FirstOrDefault( + p => p.Name == "Authorization" && p.Type == ParameterType.HttpHeader); + Assert.NotNull(header); + } + } +} diff --git a/RestSharp.Tests.Coverage/OAuthInternalTests.cs b/RestSharp.Tests.Coverage/OAuthInternalTests.cs new file mode 100644 index 000000000..c2c543fdb --- /dev/null +++ b/RestSharp.Tests.Coverage/OAuthInternalTests.cs @@ -0,0 +1,731 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using System.Security.Cryptography; +using RestSharp.Authenticators.OAuth; +using RestSharp.Authenticators.OAuth.Extensions; +using Xunit; + +namespace RestSharp.Tests +{ + public class OAuthInternalTests + { + // OAuthTools tests + [Fact] + public void OAuthTools_GetNonce_Returns_16_Char_String() + { + var nonce = OAuthTools.GetNonce(); + Assert.Equal(16, nonce.Length); + Assert.True(nonce.All(c => char.IsLetterOrDigit(c))); + } + + [Fact] + public void OAuthTools_GetNonce_Returns_Unique_Values() + { + var nonce1 = OAuthTools.GetNonce(); + var nonce2 = OAuthTools.GetNonce(); + Assert.NotEqual(nonce1, nonce2); + } + + [Fact] + public void OAuthTools_GetTimestamp_Returns_Positive_Number() + { + var ts = OAuthTools.GetTimestamp(); + Assert.True(long.Parse(ts) > 0); + } + + [Fact] + public void OAuthTools_GetTimestamp_With_DateTime() + { + var ts = OAuthTools.GetTimestamp(new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Utc)); + Assert.Equal("1577836800", ts); + } + + [Fact] + public void OAuthTools_UrlEncodeRelaxed() + { + Assert.Equal("hello%20world", OAuthTools.UrlEncodeRelaxed("hello world")); + } + + [Fact] + public void OAuthTools_UrlEncodeStrict() + { + var result = OAuthTools.UrlEncodeStrict("hello world"); + Assert.DoesNotContain(" ", result); + } + + [Fact] + public void OAuthTools_ConstructRequestUrl_Http_Port80() + { + var url = OAuthTools.ConstructRequestUrl(new Uri("http://example.com:80/api/test")); + Assert.Equal("http://example.com/api/test", url); + } + + [Fact] + public void OAuthTools_ConstructRequestUrl_Https_Port443() + { + var url = OAuthTools.ConstructRequestUrl(new Uri("https://example.com:443/api/test")); + Assert.Equal("https://example.com/api/test", url); + } + + [Fact] + public void OAuthTools_ConstructRequestUrl_NonStandard_Port() + { + var url = OAuthTools.ConstructRequestUrl(new Uri("http://example.com:8080/api")); + Assert.Equal("http://example.com:8080/api", url); + } + + [Fact] + public void OAuthTools_ConstructRequestUrl_Null_Throws() + { + Assert.Throws(() => OAuthTools.ConstructRequestUrl(null)); + } + + [Fact] + public void OAuthTools_NormalizeRequestParameters() + { + var parameters = new WebParameterCollection(); + parameters.Add("b", "2"); + parameters.Add("a", "1"); + var result = OAuthTools.NormalizeRequestParameters(parameters); + Assert.Contains("a", result); + Assert.Contains("b", result); + } + + [Fact] + public void OAuthTools_SortParametersExcludingSignature() + { + var parameters = new WebParameterCollection(); + parameters.Add("z_param", "3"); + parameters.Add("a_param", "1"); + parameters.Add("oauth_signature", "sig_value"); + var sorted = OAuthTools.SortParametersExcludingSignature(parameters); + Assert.DoesNotContain(sorted, p => p.Name == "oauth_signature"); + } + + [Fact] + public void OAuthTools_ConcatenateRequestElements() + { + var parameters = new WebParameterCollection(); + parameters.Add("oauth_consumer_key", "key"); + var result = OAuthTools.ConcatenateRequestElements("GET", "http://example.com/api", parameters); + Assert.StartsWith("GET&", result); + } + + [Fact] + public void OAuthTools_GetSignature_HmacSha1() + { + var sig = OAuthTools.GetSignature( + OAuthSignatureMethod.HmacSha1, + OAuthSignatureTreatment.Escaped, + "base_string", + "consumer_secret", + "token_secret"); + Assert.False(string.IsNullOrEmpty(sig)); + } + + [Fact] + public void OAuthTools_GetSignature_PlainText_Throws() + { + Assert.Throws(() => OAuthTools.GetSignature( + OAuthSignatureMethod.PlainText, + OAuthSignatureTreatment.Escaped, + "base_string", + "consumer_secret", + "token_secret")); + } + + [Fact] + public void OAuthTools_GetSignature_Without_TokenSecret() + { + var sig = OAuthTools.GetSignature( + OAuthSignatureMethod.HmacSha1, + "base_string", + "consumer_secret"); + Assert.False(string.IsNullOrEmpty(sig)); + } + + [Fact] + public void OAuthTools_GetSignature_With_TokenSecret() + { + var sig = OAuthTools.GetSignature( + OAuthSignatureMethod.HmacSha1, + "base_string", + "consumer_secret", + "token_secret"); + Assert.False(string.IsNullOrEmpty(sig)); + } + + [Fact] + public void OAuthTools_GetSignature_Unescaped() + { + var sig = OAuthTools.GetSignature( + OAuthSignatureMethod.HmacSha1, + OAuthSignatureTreatment.Unescaped, + "base_string", + "consumer_secret", + "token_secret"); + Assert.False(string.IsNullOrEmpty(sig)); + } + + // WebPair tests + [Fact] + public void WebPair_Constructor_Sets_Properties() + { + var pair = new WebPair("key", "value"); + Assert.Equal("key", pair.Name); + Assert.Equal("value", pair.Value); + } + + [Fact] + public void WebPair_Value_Can_Be_Changed() + { + var pair = new WebPair("key", "value"); + pair.Value = "newval"; + Assert.Equal("newval", pair.Value); + } + + // WebParameter tests + [Fact] + public void WebParameter_Constructor() + { + var param = new WebParameter("name", "val"); + Assert.Equal("name", param.Name); + Assert.Equal("val", param.Value); + } + + // WebPairCollection tests + [Fact] + public void WebPairCollection_Add_By_Name_Value() + { + var coll = new WebPairCollection(); + coll.Add("key", "val"); + Assert.Single(coll); + } + + [Fact] + public void WebPairCollection_Indexer() + { + var coll = new WebPairCollection(); + coll.Add("key", "val"); + Assert.Equal("key", coll[0].Name); + } + + [Fact] + public void WebPairCollection_RemoveAll() + { + var coll = new WebPairCollection(); + coll.Add("a", "1"); + coll.Add("b", "2"); + coll.Add("c", "3"); + var toRemove = coll.Where(p => p.Name == "b"); + coll.RemoveAll(toRemove); + Assert.Equal(2, coll.Count); + } + + [Fact] + public void WebPairCollection_Sort() + { + var coll = new WebPairCollection(); + coll.Add("z", "3"); + coll.Add("a", "1"); + coll.Add("m", "2"); + coll.Sort((x, y) => string.CompareOrdinal(x.Name, y.Name)); + Assert.Equal("a", coll[0].Name); + Assert.Equal("m", coll[1].Name); + Assert.Equal("z", coll[2].Name); + } + + [Fact] + public void WebPairCollection_AddCollection() + { + var coll = new WebPairCollection(); + coll.Add("a", "1"); + var dict = new Dictionary { { "b", "2" } }; + coll.AddCollection(dict); + Assert.Equal(2, coll.Count); + } + + // WebParameterCollection tests + [Fact] + public void WebParameterCollection_Add() + { + var coll = new WebParameterCollection(); + coll.Add("key", "val"); + Assert.Single(coll); + } + + [Fact] + public void WebParameterCollection_Constructor_With_Existing() + { + var existing = new WebParameterCollection(); + existing.Add("a", "1"); + existing.Add("b", "2"); + var copy = new WebParameterCollection(existing); + Assert.Equal(2, copy.Count); + } + + // OAuthExtensions tests + [Fact] + public void ToRequestValue_HmacSha1() + { + var result = OAuthSignatureMethod.HmacSha1.ToRequestValue(); + Assert.Equal("HMAC-SHA1", result); + } + + [Fact] + public void ToRequestValue_PlainText() + { + var result = OAuthSignatureMethod.PlainText.ToRequestValue(); + Assert.Equal("PLAINTEXT", result); + } + + [Fact] + public void ToRequestValue_RsaSha1() + { + var result = OAuthSignatureMethod.RsaSha1.ToRequestValue(); + Assert.Equal("RSA-SHA1", result); + } + + [Fact] + public void FromRequestValue_HmacSha1() + { + var result = "HMAC-SHA1".FromRequestValue(); + Assert.Equal(OAuthSignatureMethod.HmacSha1, result); + } + + [Fact] + public void FromRequestValue_RsaSha1() + { + var result = "RSA-SHA1".FromRequestValue(); + Assert.Equal(OAuthSignatureMethod.RsaSha1, result); + } + + [Fact] + public void FromRequestValue_PlainText() + { + var result = "PLAINTEXT".FromRequestValue(); + Assert.Equal(OAuthSignatureMethod.PlainText, result); + } + + [Fact] + public void HashWith_Produces_Result() + { + using (var hmac = new HMACSHA1(new byte[] { 1, 2, 3 })) + { + var result = "test".HashWith(hmac); + Assert.False(string.IsNullOrEmpty(result)); + } + } + + // TimeExtensions tests + [Fact] + public void ToUnixTime_Returns_Epoch_For_1970() + { + var dt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + Assert.Equal(0, dt.ToUnixTime()); + } + + [Fact] + public void ToUnixTime_Returns_Positive_For_Recent() + { + var dt = new DateTime(2020, 1, 1, 0, 0, 0, DateTimeKind.Utc); + Assert.Equal(1577836800, dt.ToUnixTime()); + } + + [Fact] + public void FromUnixTime_Returns_DateTime() + { + var dt = ((long)0).FromUnixTime(); + Assert.Equal(1970, dt.Year); + } + + [Fact] + public void FromNow_Returns_Future_DateTime() + { + var span = TimeSpan.FromHours(1); + var result = span.FromNow(); + Assert.True(result > DateTime.Now.AddMinutes(59)); + } + + // OAuth StringExtensions tests + [Fact] + public void IsNullOrBlank_Null() + { + string s = null; + Assert.True(s.IsNullOrBlank()); + } + + [Fact] + public void IsNullOrBlank_Empty() + { + Assert.True("".IsNullOrBlank()); + } + + [Fact] + public void IsNullOrBlank_Whitespace() + { + Assert.True(" ".IsNullOrBlank()); + } + + [Fact] + public void IsNullOrBlank_NonEmpty() + { + Assert.False("hello".IsNullOrBlank()); + } + + [Fact] + public void EqualsIgnoreCase_True() + { + Assert.True("Hello".EqualsIgnoreCase("hello")); + } + + [Fact] + public void EqualsIgnoreCase_False() + { + Assert.False("Hello".EqualsIgnoreCase("world")); + } + + [Fact] + public void EqualsAny_True() + { + Assert.True("hello".EqualsAny("world", "hello", "test")); + } + + [Fact] + public void EqualsAny_False() + { + Assert.False("hello".EqualsAny("world", "test")); + } + + [Fact] + public void FormatWith_Formats_String() + { + Assert.Equal("Hello World", "{0} {1}".FormatWith("Hello", "World")); + } + + [Fact] + public void FormatWithInvariantCulture_Formats() + { + Assert.Equal("Value: 42", "Value: {0}".FormatWithInvariantCulture(42)); + } + + [Fact] + public void Then_Concatenates() + { + Assert.Equal("HelloWorld", "Hello".Then("World")); + } + + [Fact] + public void OAuthStringExt_UrlEncode() + { + var result = Authenticators.OAuth.Extensions.StringExtensions.UrlEncode("hello world"); + Assert.Equal("hello%20world", result); + } + + [Fact] + public void OAuthStringExt_UrlDecode() + { + var result = Authenticators.OAuth.Extensions.StringExtensions.UrlDecode("hello%20world"); + Assert.Equal("hello world", result); + } + + [Fact] + public void AsUri_Converts_String() + { + var uri = "http://example.com".AsUri(); + Assert.Equal("http://example.com/", uri.ToString()); + } + + [Fact] + public void ToBase64String_Converts() + { + var bytes = new byte[] { 72, 101, 108, 108, 111 }; + Assert.Equal("SGVsbG8=", bytes.ToBase64String()); + } + + [Fact] + public void GetBytes_Converts() + { + var bytes = "Hi".GetBytes(); + Assert.Equal(2, bytes.Length); + } + + [Fact] + public void PercentEncode_Encodes() + { + var result = "A".PercentEncode(); + Assert.Equal("%41", result); + } + + [Fact] + public void ParseQueryString_Parses() + { + var result = "a=1&b=2".ParseQueryString(); + Assert.Equal("1", result["a"]); + Assert.Equal("2", result["b"]); + } + + [Fact] + public void ParseQueryString_With_QuestionMark() + { + var result = "?a=1&b=2".ParseQueryString(); + Assert.Equal(2, result.Count); + } + + [Fact] + public void ParseQueryString_Empty() + { + var result = "".ParseQueryString(); + Assert.Empty(result); + } + + // CollectionExtensions tests + [Fact] + public void AsEnumerable_Single_Item() + { + var result = "hello".AsEnumerable(); + Assert.Single(result); + } + + [Fact] + public void And_Two_Items() + { + var result = "hello".And("world"); + Assert.Equal(2, result.Count()); + } + + [Fact] + public void And_Collection_Plus_Item() + { + var items = new List { "a", "b" }; + var result = items.And("c").ToList(); + Assert.Equal(3, result.Count); + } + + [Fact] + public void TryWithKey_Existing_Key() + { + var dict = new Dictionary { { "key", 42 } }; + Assert.Equal(42, dict.TryWithKey("key")); + } + + [Fact] + public void TryWithKey_Missing_Key() + { + var dict = new Dictionary { { "key", 42 } }; + Assert.Equal(0, dict.TryWithKey("missing")); + } + + [Fact] + public void ForEach_Executes_Action() + { + var list = new List { 1, 2, 3 }; + var sum = 0; + list.ForEach(x => sum += x); + Assert.Equal(6, sum); + } + + [Fact] + public void Concatenate_WebParameterCollection() + { + var coll = new WebParameterCollection(); + coll.Add("a", "1"); + coll.Add("b", "2"); + var result = coll.Concatenate("=", "&"); + Assert.Equal("a=1&b=2", result); + } + + [Fact] + public void AddRange_From_NameValueCollection() + { + var dict = new Dictionary(); + var nvc = new NameValueCollection(); + nvc.Add("key1", "val1"); + nvc.Add("key2", "val2"); + dict.AddRange(nvc); + Assert.Equal(2, dict.Count); + } + + [Fact] + public void ToQueryString_From_NameValueCollection() + { + var nvc = new NameValueCollection(); + nvc.Add("a", "1"); + nvc.Add("b", "2"); + var result = nvc.ToQueryString(); + Assert.StartsWith("?", result); + Assert.Contains("a=1", result); + } + + [Fact] + public void ToQueryString_Empty_Collection() + { + var nvc = new NameValueCollection(); + var result = nvc.ToQueryString(); + Assert.Equal("", result); + } + + [Fact] + public void ToEnumerable_Converts() + { + var objects = new object[] { "a", "b", "c" }; + var result = objects.ToEnumerable().ToList(); + Assert.Equal(3, result.Count); + } + + // OAuthWorkflow tests + [Fact] + public void OAuthWorkflow_Properties() + { + var wf = new OAuthWorkflow(); + wf.Version = "1.0"; + wf.ConsumerKey = "ck"; + wf.ConsumerSecret = "cs"; + wf.Token = "t"; + wf.TokenSecret = "ts"; + wf.CallbackUrl = "http://cb"; + wf.Verifier = "v"; + wf.SessionHandle = "sh"; + wf.SignatureMethod = OAuthSignatureMethod.HmacSha1; + wf.SignatureTreatment = OAuthSignatureTreatment.Escaped; + wf.ParameterHandling = OAuthParameterHandling.HttpAuthorizationHeader; + wf.ClientUsername = "cu"; + wf.ClientPassword = "cp"; + wf.RequestTokenUrl = "http://rt"; + wf.AccessTokenUrl = "http://at"; + wf.AuthorizationUrl = "http://auth"; + + Assert.Equal("1.0", wf.Version); + Assert.Equal("ck", wf.ConsumerKey); + Assert.Equal("cs", wf.ConsumerSecret); + Assert.Equal("t", wf.Token); + Assert.Equal("ts", wf.TokenSecret); + Assert.Equal("http://cb", wf.CallbackUrl); + Assert.Equal("v", wf.Verifier); + Assert.Equal("sh", wf.SessionHandle); + Assert.Equal("cu", wf.ClientUsername); + Assert.Equal("cp", wf.ClientPassword); + Assert.Equal("http://rt", wf.RequestTokenUrl); + Assert.Equal("http://at", wf.AccessTokenUrl); + Assert.Equal("http://auth", wf.AuthorizationUrl); + } + + [Fact] + public void OAuthWorkflow_BuildRequestTokenInfo() + { + var wf = new OAuthWorkflow + { + ConsumerKey = "key", + ConsumerSecret = "secret", + RequestTokenUrl = "http://example.com/request_token", + SignatureMethod = OAuthSignatureMethod.HmacSha1, + SignatureTreatment = OAuthSignatureTreatment.Escaped, + ParameterHandling = OAuthParameterHandling.HttpAuthorizationHeader, + Version = "1.0" + }; + + var info = wf.BuildRequestTokenInfo("GET"); + Assert.NotNull(info); + Assert.Equal("GET", info.WebMethod); + Assert.Equal("key", info.ConsumerKey); + Assert.False(string.IsNullOrEmpty(info.Signature)); + Assert.False(string.IsNullOrEmpty(info.Nonce)); + Assert.False(string.IsNullOrEmpty(info.Timestamp)); + } + + [Fact] + public void OAuthWorkflow_BuildAccessTokenInfo() + { + var wf = new OAuthWorkflow + { + ConsumerKey = "key", + ConsumerSecret = "secret", + Token = "request_token", + TokenSecret = "request_secret", + AccessTokenUrl = "http://example.com/access_token", + SignatureMethod = OAuthSignatureMethod.HmacSha1, + SignatureTreatment = OAuthSignatureTreatment.Escaped, + ParameterHandling = OAuthParameterHandling.HttpAuthorizationHeader, + Version = "1.0", + Verifier = "verifier" + }; + + var info = wf.BuildAccessTokenInfo("POST"); + Assert.NotNull(info); + Assert.Equal("POST", info.WebMethod); + } + + [Fact] + public void OAuthWorkflow_BuildProtectedResourceInfo() + { + var wf = new OAuthWorkflow + { + ConsumerKey = "key", + ConsumerSecret = "secret", + Token = "access_token", + TokenSecret = "access_secret", + SignatureMethod = OAuthSignatureMethod.HmacSha1, + SignatureTreatment = OAuthSignatureTreatment.Escaped, + ParameterHandling = OAuthParameterHandling.HttpAuthorizationHeader, + Version = "1.0" + }; + + var info = wf.BuildProtectedResourceInfo("GET", null, "http://example.com/resource"); + Assert.NotNull(info); + Assert.Equal("GET", info.WebMethod); + } + + [Fact] + public void OAuthWorkflow_BuildClientAuthAccessTokenInfo() + { + var wf = new OAuthWorkflow + { + ConsumerKey = "key", + ConsumerSecret = "secret", + AccessTokenUrl = "http://example.com/access_token", + SignatureMethod = OAuthSignatureMethod.HmacSha1, + SignatureTreatment = OAuthSignatureTreatment.Escaped, + ParameterHandling = OAuthParameterHandling.HttpAuthorizationHeader, + ClientUsername = "user", + ClientPassword = "pass", + Version = "1.0" + }; + + var info = wf.BuildClientAuthAccessTokenInfo("POST", null); + Assert.NotNull(info); + Assert.Equal("user", info.ClientUsername); + } + + // HttpPostParameter tests + [Fact] + public void HttpPostParameter_Constructor() + { + var param = new HttpPostParameter("name", "value"); + Assert.Equal("name", param.Name); + Assert.Equal("value", param.Value); + Assert.Equal(HttpPostParameterType.Field, param.Type); + } + + [Fact] + public void HttpPostParameter_CreateFile_With_Path() + { + var param = HttpPostParameter.CreateFile("file", "test.txt", "/tmp/test.txt", "text/plain"); + Assert.Equal(HttpPostParameterType.File, param.Type); + Assert.Equal("test.txt", param.FileName); + Assert.Equal("text/plain", param.ContentType); + Assert.Equal("/tmp/test.txt", param.FilePath); + } + + [Fact] + public void HttpPostParameter_CreateFile_With_Stream() + { + var stream = new System.IO.MemoryStream(); + var param = HttpPostParameter.CreateFile("file", "test.txt", stream, "text/plain"); + Assert.Equal(HttpPostParameterType.File, param.Type); + Assert.Equal("test.txt", param.FileName); + Assert.Same(stream, param.FileStream); + } + } +} diff --git a/RestSharp.Tests.Coverage/OAuthTests.cs b/RestSharp.Tests.Coverage/OAuthTests.cs new file mode 100644 index 000000000..984107590 --- /dev/null +++ b/RestSharp.Tests.Coverage/OAuthTests.cs @@ -0,0 +1,161 @@ +using System; +using System.Linq; +using RestSharp.Authenticators.OAuth; +using Xunit; + +namespace RestSharp.Tests +{ + public class OAuthTests + { + [Fact] + public void OAuthSignatureMethod_Enum_Values() + { + Assert.Equal(OAuthSignatureMethod.HmacSha1, (OAuthSignatureMethod)0); + Assert.Equal(OAuthSignatureMethod.PlainText, (OAuthSignatureMethod)1); + Assert.Equal(OAuthSignatureMethod.RsaSha1, (OAuthSignatureMethod)2); + } + + [Fact] + public void OAuthParameterHandling_Enum_Values() + { + Assert.Equal(OAuthParameterHandling.HttpAuthorizationHeader, (OAuthParameterHandling)0); + Assert.Equal(OAuthParameterHandling.UrlOrPostParameters, (OAuthParameterHandling)1); + } + + [Fact] + public void OAuthSignatureTreatment_Enum_Values() + { + Assert.Equal(OAuthSignatureTreatment.Escaped, (OAuthSignatureTreatment)0); + Assert.Equal(OAuthSignatureTreatment.Unescaped, (OAuthSignatureTreatment)1); + } + + [Fact] + public void OAuthType_Enum_Values() + { + Assert.Equal(OAuthType.RequestToken, (OAuthType)0); + Assert.Equal(OAuthType.AccessToken, (OAuthType)1); + Assert.Equal(OAuthType.ProtectedResource, (OAuthType)2); + Assert.Equal(OAuthType.ClientAuthentication, (OAuthType)3); + } + + [Fact] + public void OAuthWebQueryInfo_ConsumerKey_Property() + { + var info = new OAuthWebQueryInfo(); + info.ConsumerKey = "ck"; + Assert.Equal("ck", info.ConsumerKey); + } + + [Fact] + public void OAuthWebQueryInfo_Token_Property() + { + var info = new OAuthWebQueryInfo(); + info.Token = "t"; + Assert.Equal("t", info.Token); + } + + [Fact] + public void OAuthWebQueryInfo_Nonce_Property() + { + var info = new OAuthWebQueryInfo(); + info.Nonce = "n"; + Assert.Equal("n", info.Nonce); + } + + [Fact] + public void OAuthWebQueryInfo_Timestamp_Property() + { + var info = new OAuthWebQueryInfo(); + info.Timestamp = "123"; + Assert.Equal("123", info.Timestamp); + } + + [Fact] + public void OAuthWebQueryInfo_Signature_Property() + { + var info = new OAuthWebQueryInfo(); + info.Signature = "sig"; + Assert.Equal("sig", info.Signature); + } + + [Fact] + public void OAuthWebQueryInfo_SignatureMethod_Property() + { + var info = new OAuthWebQueryInfo(); + info.SignatureMethod = "HMAC-SHA1"; + Assert.Equal("HMAC-SHA1", info.SignatureMethod); + } + + [Fact] + public void OAuthWebQueryInfo_Version_Property() + { + var info = new OAuthWebQueryInfo(); + info.Version = "1.0"; + Assert.Equal("1.0", info.Version); + } + + [Fact] + public void OAuthWebQueryInfo_Callback_Property() + { + var info = new OAuthWebQueryInfo(); + info.Callback = "http://cb"; + Assert.Equal("http://cb", info.Callback); + } + + [Fact] + public void OAuthWebQueryInfo_Verifier_Property() + { + var info = new OAuthWebQueryInfo(); + info.Verifier = "v"; + Assert.Equal("v", info.Verifier); + } + + [Fact] + public void OAuthWebQueryInfo_WebMethod_Property() + { + var info = new OAuthWebQueryInfo(); + info.WebMethod = "POST"; + Assert.Equal("POST", info.WebMethod); + } + + [Fact] + public void OAuthWebQueryInfo_ParameterHandling_Property() + { + var info = new OAuthWebQueryInfo(); + info.ParameterHandling = OAuthParameterHandling.HttpAuthorizationHeader; + Assert.Equal(OAuthParameterHandling.HttpAuthorizationHeader, info.ParameterHandling); + } + + [Fact] + public void OAuthWebQueryInfo_ClientMode_Property() + { + var info = new OAuthWebQueryInfo(); + info.ClientMode = "client"; + Assert.Equal("client", info.ClientMode); + } + + [Fact] + public void OAuthWebQueryInfo_ClientUsername_Property() + { + var info = new OAuthWebQueryInfo(); + info.ClientUsername = "cu"; + Assert.Equal("cu", info.ClientUsername); + } + + [Fact] + public void OAuthWebQueryInfo_ClientPassword_Property() + { + var info = new OAuthWebQueryInfo(); + info.ClientPassword = "cp"; + Assert.Equal("cp", info.ClientPassword); + } + + [Fact] + public void OAuthWebQueryInfo_UserAgent_Property() + { + var info = new OAuthWebQueryInfo(); + info.UserAgent = "ua"; + Assert.Equal("ua", info.UserAgent); + } + } +} diff --git a/RestSharp.Tests.Coverage/ParameterTests.cs b/RestSharp.Tests.Coverage/ParameterTests.cs new file mode 100644 index 000000000..cda4f00fa --- /dev/null +++ b/RestSharp.Tests.Coverage/ParameterTests.cs @@ -0,0 +1,97 @@ +using Xunit; + +namespace RestSharp.Tests +{ + public class ParameterTests + { + [Fact] + public void Properties_Can_Be_Set() + { + var p = new Parameter(); + p.Name = "test"; + p.Value = "value"; + p.Type = ParameterType.GetOrPost; + + Assert.Equal("test", p.Name); + Assert.Equal("value", p.Value); + Assert.Equal(ParameterType.GetOrPost, p.Type); + } + + [Fact] + public void ToString_Returns_Name_Value_Pair() + { + var p = new Parameter { Name = "key", Value = "val", Type = ParameterType.GetOrPost }; + var str = p.ToString(); + Assert.Contains("key", str); + Assert.Contains("val", str); + } + + [Fact] + public void ToString_With_Null_Value() + { + var p = new Parameter { Name = "key", Value = null, Type = ParameterType.Cookie }; + var str = p.ToString(); + Assert.Contains("key", str); + } + + [Fact] + public void All_Parameter_Types() + { + Assert.Equal(ParameterType.Cookie, (ParameterType)0); + Assert.Equal(ParameterType.GetOrPost, (ParameterType)1); + Assert.Equal(ParameterType.UrlSegment, (ParameterType)2); + Assert.Equal(ParameterType.HttpHeader, (ParameterType)3); + Assert.Equal(ParameterType.RequestBody, (ParameterType)4); + } + + [Fact] + public void HttpHeader_Properties() + { + var h = new HttpHeader(); + h.Name = "Content-Type"; + h.Value = "application/json"; + + Assert.Equal("Content-Type", h.Name); + Assert.Equal("application/json", h.Value); + } + + [Fact] + public void HttpParameter_Properties() + { + var p = new HttpParameter(); + p.Name = "key"; + p.Value = "val"; + + Assert.Equal("key", p.Name); + Assert.Equal("val", p.Value); + } + + [Fact] + public void HttpCookie_Properties() + { + var c = new HttpCookie(); + c.Name = "session"; + c.Value = "abc123"; + + Assert.Equal("session", c.Name); + Assert.Equal("abc123", c.Value); + } + + [Fact] + public void HttpFile_Properties() + { + var f = new HttpFile(); + f.Name = "file"; + f.FileName = "test.txt"; + f.ContentType = "text/plain"; + f.ContentLength = 100; + f.Writer = s => { }; + + Assert.Equal("file", f.Name); + Assert.Equal("test.txt", f.FileName); + Assert.Equal("text/plain", f.ContentType); + Assert.Equal(100, f.ContentLength); + Assert.NotNull(f.Writer); + } + } +} diff --git a/RestSharp.Tests.Coverage/ReflectionExtensionsTests.cs b/RestSharp.Tests.Coverage/ReflectionExtensionsTests.cs new file mode 100644 index 000000000..b2dcabbed --- /dev/null +++ b/RestSharp.Tests.Coverage/ReflectionExtensionsTests.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Reflection; +using RestSharp.Extensions; +using Xunit; + +namespace RestSharp.Tests +{ + public class ReflectionExtensionsTests + { + [Fact] + public void GetAttribute_From_Property_Returns_Attribute() + { + var prop = typeof(TestClassWithAttributes).GetProperty("Name"); + var attr = prop.GetAttribute(); + Assert.NotNull(attr); + } + + [Fact] + public void GetAttribute_From_Property_Returns_Null_When_Missing() + { + var prop = typeof(TestClassWithAttributes).GetProperty("Age"); + var attr = prop.GetAttribute(); + Assert.Null(attr); + } + + [Fact] + public void GetAttribute_From_Type_Returns_Attribute() + { + var attr = typeof(TestClassWithAttributes).GetAttribute(); + Assert.NotNull(attr); + } + + [Fact] + public void GetAttribute_From_Type_Returns_Null_When_Missing() + { + var attr = typeof(TestClassNoAttr).GetAttribute(); + Assert.Null(attr); + } + + [Fact] + public void IsSubclassOfRawGeneric_Returns_True() + { + Assert.True(typeof(StringList).IsSubclassOfRawGeneric(typeof(List<>))); + } + + [Fact] + public void IsSubclassOfRawGeneric_Returns_False() + { + Assert.False(typeof(string).IsSubclassOfRawGeneric(typeof(List<>))); + } + + [Fact] + public void ChangeType_Converts_String_To_Int() + { + var result = "42".ChangeType(typeof(int)); + Assert.Equal(42, result); + } + + [Fact] + public void ChangeType_Converts_Int_To_String() + { + var result = 42.ChangeType(typeof(string)); + Assert.Equal("42", result); + } + + [Fact] + public void ChangeType_With_Culture() + { + var result = 3.14.ChangeType(typeof(string), CultureInfo.InvariantCulture); + Assert.Equal("3.14", result); + } + + [Fact] + public void FindEnumValue_Finds_By_Name() + { + var result = typeof(Method).FindEnumValue("GET", CultureInfo.InvariantCulture); + Assert.Equal(Method.GET, result); + } + + [Fact] + public void FindEnumValue_Finds_Post() + { + var result = typeof(Method).FindEnumValue("POST", CultureInfo.InvariantCulture); + Assert.Equal(Method.POST, result); + } + + [Fact] + public void FindEnumValue_Finds_Case_Insensitive() + { + var result = typeof(ParameterType).FindEnumValue("Cookie", CultureInfo.InvariantCulture); + Assert.Equal(ParameterType.Cookie, result); + } + + [Serializable] + private class TestClassWithAttributes + { + [Obsolete] + public string Name { get; set; } + public int Age { get; set; } + } + + private class TestClassNoAttr + { + public string Value { get; set; } + } + + private class StringList : List { } + } +} diff --git a/RestSharp.Tests.Coverage/RestClientAdditionalTests.cs b/RestSharp.Tests.Coverage/RestClientAdditionalTests.cs new file mode 100644 index 000000000..100d7c237 --- /dev/null +++ b/RestSharp.Tests.Coverage/RestClientAdditionalTests.cs @@ -0,0 +1,296 @@ +using System; +using System.Linq; +using System.Net; +using RestSharp.Deserializers; +using Xunit; + +namespace RestSharp.Tests +{ + public class RestClientAdditionalTests + { + [Fact] + public void AddDefaultParameter_GetOrPost() + { + var client = new RestClient("http://example.com"); + client.AddDefaultParameter("key", "value"); + Assert.Contains(client.DefaultParameters, p => p.Name == "key" && p.Type == ParameterType.GetOrPost); + } + + [Fact] + public void AddDefaultParameter_WithType() + { + var client = new RestClient("http://example.com"); + client.AddDefaultParameter("key", "value", ParameterType.HttpHeader); + Assert.Contains(client.DefaultParameters, p => p.Name == "key" && p.Type == ParameterType.HttpHeader); + } + + [Fact] + public void AddDefaultParameter_RequestBody_Throws() + { + var client = new RestClient("http://example.com"); + Assert.Throws(() => + client.AddDefaultParameter(new Parameter { Name = "body", Value = "data", Type = ParameterType.RequestBody })); + } + + [Fact] + public void AddDefaultHeader() + { + var client = new RestClient("http://example.com"); + client.AddDefaultHeader("X-Api-Key", "12345"); + Assert.Contains(client.DefaultParameters, p => p.Name == "X-Api-Key" && p.Type == ParameterType.HttpHeader); + } + + [Fact] + public void AddDefaultUrlSegment() + { + var client = new RestClient("http://example.com"); + client.AddDefaultUrlSegment("version", "v2"); + Assert.Contains(client.DefaultParameters, p => p.Name == "version" && p.Type == ParameterType.UrlSegment); + } + + [Fact] + public void AddHandler_And_RemoveHandler() + { + var client = new RestClient("http://example.com"); + client.AddHandler("text/csv", new JsonDeserializer()); + client.RemoveHandler("text/csv"); + } + + [Fact] + public void ClearHandlers() + { + var client = new RestClient("http://example.com"); + client.ClearHandlers(); + } + + [Fact] + public void BaseUrl_Strips_Trailing_Slash() + { + var client = new RestClient(); + client.BaseUrl = "http://example.com/"; + Assert.Equal("http://example.com", client.BaseUrl); + } + + [Fact] + public void BuildUri_With_UrlSegment() + { + var client = new RestClient("http://example.com"); + var request = new RestRequest("/users/{id}"); + request.AddUrlSegment("id", "42"); + var uri = client.BuildUri(request); + Assert.Contains("42", uri.ToString()); + } + + [Fact] + public void BuildUri_With_GetOrPost_Params_On_GET() + { + var client = new RestClient("http://example.com"); + var request = new RestRequest("/search", Method.GET); + request.AddParameter("q", "test"); + var uri = client.BuildUri(request); + Assert.Contains("?q=test", uri.ToString()); + } + + [Fact] + public void BuildUri_No_QueryString_On_POST() + { + var client = new RestClient("http://example.com"); + var request = new RestRequest("/api", Method.POST); + request.AddParameter("key", "val"); + var uri = client.BuildUri(request); + Assert.DoesNotContain("?", uri.ToString()); + } + + [Fact] + public void BuildUri_Empty_Resource() + { + var client = new RestClient("http://example.com"); + var request = new RestRequest(); + var uri = client.BuildUri(request); + Assert.Equal("http://example.com/", uri.ToString()); + } + + [Fact] + public void BuildUri_Resource_With_Leading_Slash() + { + var client = new RestClient("http://example.com"); + var request = new RestRequest("/api/test"); + var uri = client.BuildUri(request); + Assert.Contains("api/test", uri.ToString()); + } + + [Fact] + public void Properties() + { + var client = new RestClient(); + client.MaxRedirects = 5; + client.FollowRedirects = false; + client.CookieContainer = new CookieContainer(); + client.UserAgent = "Custom/1.0"; + client.Timeout = 5000; + client.UseSynchronizationContext = true; + + Assert.Equal(5, client.MaxRedirects); + Assert.False(client.FollowRedirects); + Assert.NotNull(client.CookieContainer); + Assert.Equal("Custom/1.0", client.UserAgent); + Assert.Equal(5000, client.Timeout); + Assert.True(client.UseSynchronizationContext); + } + + [Fact] + public void Execute_Invalid_BaseUrl_Returns_Error() + { + var client = new RestClient("http://localhost:1"); + var request = new RestRequest("/test"); + var response = client.Execute(request); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Execute_Generic_Invalid_BaseUrl_Returns_Error() + { + var client = new RestClient("http://localhost:1"); + var request = new RestRequest("/test"); + var response = client.Execute(request); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Execute_With_Default_Headers() + { + var client = new RestClient("http://localhost:1"); + client.AddDefaultHeader("X-Test", "value"); + var request = new RestRequest("/test"); + var response = client.Execute(request); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Execute_With_Authenticator() + { + var client = new RestClient("http://localhost:1"); + client.Authenticator = new HttpBasicAuthenticator("user", "pass"); + var request = new RestRequest("/test"); + var response = client.Execute(request); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Execute_With_CookieContainer() + { + var client = new RestClient("http://localhost:1"); + client.CookieContainer = new CookieContainer(); + var request = new RestRequest("/test"); + var response = client.Execute(request); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Execute_POST() + { + var client = new RestClient("http://localhost:1"); + var request = new RestRequest("/test", Method.POST); + request.AddParameter("key", "val"); + var response = client.Execute(request); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Execute_PUT() + { + var client = new RestClient("http://localhost:1"); + var request = new RestRequest("/test", Method.PUT); + request.AddParameter("key", "val"); + var response = client.Execute(request); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Execute_DELETE() + { + var client = new RestClient("http://localhost:1"); + var request = new RestRequest("/test", Method.DELETE); + var response = client.Execute(request); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Execute_HEAD() + { + var client = new RestClient("http://localhost:1"); + var request = new RestRequest("/test", Method.HEAD); + var response = client.Execute(request); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Execute_OPTIONS() + { + var client = new RestClient("http://localhost:1"); + var request = new RestRequest("/test", Method.OPTIONS); + var response = client.Execute(request); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Execute_PATCH() + { + var client = new RestClient("http://localhost:1"); + var request = new RestRequest("/test", Method.PATCH); + var response = client.Execute(request); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Execute_With_Cookie_Parameter() + { + var client = new RestClient("http://localhost:1"); + var request = new RestRequest("/test"); + request.AddCookie("session", "abc"); + var response = client.Execute(request); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Execute_With_Custom_Timeout() + { + var client = new RestClient("http://localhost:1"); + client.Timeout = 500; + var request = new RestRequest("/test"); + var response = client.Execute(request); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void Execute_With_Default_Parameters_No_Override() + { + var client = new RestClient("http://localhost:1"); + client.AddDefaultParameter("defaultKey", "defaultVal"); + var request = new RestRequest("/test"); + request.AddParameter("requestKey", "requestVal"); + var response = client.Execute(request); + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + } + + [Fact] + public void FollowRedirects_Default_True() + { + var client = new RestClient(); + Assert.True(client.FollowRedirects); + } + + [Fact] + public void UserAgent_Contains_RestSharp() + { + var client = new RestClient(); + Assert.Contains("RestSharp", client.UserAgent); + } + + public class TestData + { + public string Name { get; set; } + public int Value { get; set; } + } + } +} diff --git a/RestSharp.Tests.Coverage/RestClientExecuteTests.cs b/RestSharp.Tests.Coverage/RestClientExecuteTests.cs new file mode 100644 index 000000000..edaa8c96b --- /dev/null +++ b/RestSharp.Tests.Coverage/RestClientExecuteTests.cs @@ -0,0 +1,106 @@ +using System; +using System.Linq; +using System.Net; +using RestSharp.Deserializers; +using Xunit; + +namespace RestSharp.Tests +{ + public class RestClientExecuteTests + { + [Fact] + public void Execute_Adds_Accept_Header() + { + var client = new RestClient("http://localhost:12345"); + var request = new RestRequest("/test"); + + try + { + client.Execute(request); + } + catch { } + + var accept = client.DefaultParameters.FirstOrDefault( + p => p.Name == "Accept" && p.Type == ParameterType.HttpHeader); + Assert.NotNull(accept); + } + + [Fact] + public void Execute_Sets_Error_On_Exception() + { + var client = new RestClient("http://localhost:1"); + var request = new RestRequest("/nonexistent"); + + var response = client.Execute(request); + + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + Assert.NotNull(response.ErrorMessage); + Assert.NotNull(response.ErrorException); + } + + [Fact] + public void Execute_Generic_Sets_Error_On_Exception() + { + var client = new RestClient("http://localhost:1"); + var request = new RestRequest("/nonexistent"); + + var response = client.Execute(request); + + Assert.Equal(ResponseStatus.Error, response.ResponseStatus); + Assert.NotNull(response.ErrorMessage); + } + + [Fact] + public void DownloadData_Returns_Bytes_Or_Null_On_Error() + { + var client = new RestClient("http://localhost:1"); + var request = new RestRequest("/test"); + + var data = client.DownloadData(request); + // On connection failure, RawBytes will be null + Assert.Null(data); + } + + [Fact] + public void ConvertToRestResponse_Preserves_Properties() + { + var client = new RestClient("http://example.com"); + var request = new RestRequest("/test"); + + // Execute against an unreachable host to test error handling path + var response = client.Execute(request); + Assert.NotNull(response); + Assert.IsType(response); + } + + [Fact] + public void Execute_With_Authenticator_Calls_Authenticate() + { + var client = new RestClient("http://localhost:1"); + client.Authenticator = new HttpBasicAuthenticator("user", "pass"); + var request = new RestRequest("/test"); + + var response = client.Execute(request); + + var authHeader = request.Parameters.FirstOrDefault( + p => p.Name == "Authorization" && p.Type == ParameterType.HttpHeader); + Assert.NotNull(authHeader); + } + + [Fact] + public void Deserialize_Handles_Missing_Content_Type() + { + var client = new RestClient("http://example.com"); + var request = new RestRequest("/test"); + + // Execute against unreachable host - should not crash + var response = client.Execute(request); + Assert.NotNull(response); + } + + private class SimpleObj + { + public string Name { get; set; } + } + } +} diff --git a/RestSharp.Tests.Coverage/RestClientTests.cs b/RestSharp.Tests.Coverage/RestClientTests.cs new file mode 100644 index 000000000..c80b7f6cf --- /dev/null +++ b/RestSharp.Tests.Coverage/RestClientTests.cs @@ -0,0 +1,303 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using RestSharp.Deserializers; +using Xunit; + +namespace RestSharp.Tests +{ + public class RestClientTests + { + [Fact] + public void Default_Constructor_Registers_Default_Handlers() + { + var client = new RestClient(); + Assert.NotNull(client.DefaultParameters); + Assert.NotNull(client.UserAgent); + Assert.Contains("RestSharp", client.UserAgent); + Assert.True(client.FollowRedirects); + } + + [Fact] + public void Constructor_With_BaseUrl() + { + var client = new RestClient("http://example.com"); + Assert.Equal("http://example.com", client.BaseUrl); + } + + [Fact] + public void BaseUrl_Strips_Trailing_Slash() + { + var client = new RestClient(); + client.BaseUrl = "http://example.com/"; + Assert.Equal("http://example.com", client.BaseUrl); + } + + [Fact] + public void BaseUrl_Preserves_Path_Without_Trailing_Slash() + { + var client = new RestClient(); + client.BaseUrl = "http://example.com/api"; + Assert.Equal("http://example.com/api", client.BaseUrl); + } + + [Fact] + public void AddDefaultParameter_Adds_Parameter() + { + var client = new RestClient("http://example.com"); + client.AddDefaultParameter("key", "value"); + Assert.Single(client.DefaultParameters); + Assert.Equal("key", client.DefaultParameters[0].Name); + } + + [Fact] + public void AddDefaultParameter_With_Type() + { + var client = new RestClient("http://example.com"); + client.AddDefaultParameter("key", "value", ParameterType.HttpHeader); + Assert.Equal(ParameterType.HttpHeader, client.DefaultParameters[0].Type); + } + + [Fact] + public void AddDefaultParameter_RequestBody_Throws() + { + var client = new RestClient("http://example.com"); + var p = new Parameter { Name = "body", Value = "data", Type = ParameterType.RequestBody }; + Assert.Throws(() => client.AddDefaultParameter(p)); + } + + [Fact] + public void AddDefaultHeader_Adds_HttpHeader_Parameter() + { + var client = new RestClient("http://example.com"); + client.AddDefaultHeader("X-Api-Key", "12345"); + Assert.Single(client.DefaultParameters); + Assert.Equal(ParameterType.HttpHeader, client.DefaultParameters[0].Type); + Assert.Equal("X-Api-Key", client.DefaultParameters[0].Name); + } + + [Fact] + public void AddDefaultUrlSegment_Adds_UrlSegment_Parameter() + { + var client = new RestClient("http://example.com"); + client.AddDefaultUrlSegment("version", "v2"); + Assert.Single(client.DefaultParameters); + Assert.Equal(ParameterType.UrlSegment, client.DefaultParameters[0].Type); + Assert.Equal("version", client.DefaultParameters[0].Name); + } + + [Fact] + public void AddHandler_And_RemoveHandler() + { + var client = new RestClient(); + var handler = new JsonDeserializer(); + client.AddHandler("application/custom", handler); + client.RemoveHandler("application/custom"); + // no exception means success + } + + [Fact] + public void ClearHandlers_Removes_All() + { + var client = new RestClient(); + client.ClearHandlers(); + // after clearing, adding a new handler should work fine + client.AddHandler("text/plain", new JsonDeserializer()); + } + + [Fact] + public void BuildUri_With_QueryString_Parameters() + { + var client = new RestClient("http://example.com"); + var request = new RestRequest("resource"); + request.AddParameter("foo", "bar"); + request.AddParameter("baz", "qux"); + + var uri = client.BuildUri(request); + Assert.Contains("foo=bar", uri.ToString()); + Assert.Contains("baz=qux", uri.ToString()); + } + + [Fact] + public void BuildUri_POST_Does_Not_Add_QueryString() + { + var client = new RestClient("http://example.com"); + var request = new RestRequest("resource", Method.POST); + request.AddParameter("foo", "bar"); + + var uri = client.BuildUri(request); + Assert.DoesNotContain("?", uri.ToString()); + } + + [Fact] + public void BuildUri_With_Multiple_UrlSegments() + { + var client = new RestClient("http://example.com"); + var request = new RestRequest("api/{version}/users/{id}"); + request.AddUrlSegment("version", "v2"); + request.AddUrlSegment("id", "42"); + + var uri = client.BuildUri(request); + Assert.Equal("http://example.com/api/v2/users/42", uri.ToString()); + } + + [Fact] + public void BuildUri_With_Empty_BaseUrl_And_Resource() + { + var client = new RestClient("http://example.com"); + var request = new RestRequest(); + + var uri = client.BuildUri(request); + Assert.Equal("http://example.com/", uri.ToString()); + } + + [Fact] + public void BuildUri_Strips_Trailing_Slash_On_Resource_Before_QueryString() + { + var client = new RestClient("http://example.com"); + var request = new RestRequest("resource/"); + request.AddParameter("key", "val"); + + var uri = client.BuildUri(request); + Assert.Contains("resource?key=val", uri.ToString()); + } + + [Fact] + public void Timeout_Can_Be_Set() + { + var client = new RestClient("http://example.com"); + client.Timeout = 30000; + Assert.Equal(30000, client.Timeout); + } + + [Fact] + public void UserAgent_Can_Be_Set() + { + var client = new RestClient("http://example.com"); + client.UserAgent = "CustomAgent/1.0"; + Assert.Equal("CustomAgent/1.0", client.UserAgent); + } + + [Fact] + public void CookieContainer_Can_Be_Set() + { + var client = new RestClient("http://example.com"); + var container = new CookieContainer(); + client.CookieContainer = container; + Assert.Same(container, client.CookieContainer); + } + + [Fact] + public void MaxRedirects_Can_Be_Set() + { + var client = new RestClient("http://example.com"); + client.MaxRedirects = 5; + Assert.Equal(5, client.MaxRedirects); + } + + [Fact] + public void Authenticator_Can_Be_Set() + { + var client = new RestClient("http://example.com"); + var auth = new HttpBasicAuthenticator("user", "pass"); + client.Authenticator = auth; + Assert.Same(auth, client.Authenticator); + } + + [Fact] + public void FollowRedirects_Defaults_True() + { + var client = new RestClient(); + Assert.True(client.FollowRedirects); + } + + [Fact] + public void FollowRedirects_Can_Be_Set_False() + { + var client = new RestClient(); + client.FollowRedirects = false; + Assert.False(client.FollowRedirects); + } + + [Fact] + public void BuildUri_PUT_Does_Not_Add_QueryString() + { + var client = new RestClient("http://example.com"); + var request = new RestRequest("resource", Method.PUT); + request.AddParameter("foo", "bar"); + + var uri = client.BuildUri(request); + Assert.DoesNotContain("?", uri.ToString()); + } + + [Fact] + public void BuildUri_PATCH_Does_Not_Add_QueryString() + { + var client = new RestClient("http://example.com"); + var request = new RestRequest("resource", Method.PATCH); + request.AddParameter("foo", "bar"); + + var uri = client.BuildUri(request); + Assert.DoesNotContain("?", uri.ToString()); + } + + [Fact] + public void BuildUri_DELETE_Adds_QueryString() + { + var client = new RestClient("http://example.com"); + var request = new RestRequest("resource", Method.DELETE); + request.AddParameter("id", "42"); + + var uri = client.BuildUri(request); + Assert.Contains("id=42", uri.ToString()); + } + + [Fact] + public void BuildUri_HEAD_Adds_QueryString() + { + var client = new RestClient("http://example.com"); + var request = new RestRequest("resource", Method.HEAD); + request.AddParameter("check", "true"); + + var uri = client.BuildUri(request); + Assert.Contains("check=true", uri.ToString()); + } + + [Fact] + public void BuildUri_OPTIONS_Adds_QueryString() + { + var client = new RestClient("http://example.com"); + var request = new RestRequest("resource", Method.OPTIONS); + request.AddParameter("verbose", "1"); + + var uri = client.BuildUri(request); + Assert.Contains("verbose=1", uri.ToString()); + } + + [Fact] + public void Proxy_Can_Be_Set() + { + var client = new RestClient("http://example.com"); + var proxy = new WebProxy("http://proxy.local:8080"); + client.Proxy = proxy; + Assert.Same(proxy, client.Proxy); + } + + [Fact] + public void ClientCertificates_Can_Be_Set() + { + var client = new RestClient("http://example.com"); + var certs = new System.Security.Cryptography.X509Certificates.X509CertificateCollection(); + client.ClientCertificates = certs; + Assert.Same(certs, client.ClientCertificates); + } + + [Fact] + public void HttpFactory_Is_Set_By_Default() + { + var client = new RestClient(); + Assert.NotNull(client.HttpFactory); + } + } +} diff --git a/RestSharp.Tests.Coverage/RestRequestTests.cs b/RestSharp.Tests.Coverage/RestRequestTests.cs new file mode 100644 index 000000000..68adf8400 --- /dev/null +++ b/RestSharp.Tests.Coverage/RestRequestTests.cs @@ -0,0 +1,384 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using RestSharp.Serializers; +using Xunit; + +namespace RestSharp.Tests +{ + public class RestRequestTests + { + [Fact] + public void Default_Constructor_Sets_Defaults() + { + var request = new RestRequest(); + Assert.NotNull(request.Parameters); + Assert.Empty(request.Parameters); + Assert.NotNull(request.Files); + Assert.Empty(request.Files); + Assert.Equal(Method.GET, request.Method); + Assert.Equal(DataFormat.Xml, request.RequestFormat); + Assert.NotNull(request.JsonSerializer); + Assert.NotNull(request.XmlSerializer); + } + + [Fact] + public void Constructor_With_Method_Sets_Method() + { + var request = new RestRequest(Method.POST); + Assert.Equal(Method.POST, request.Method); + } + + [Fact] + public void Constructor_With_Resource_Sets_Resource() + { + var request = new RestRequest("resource/foo"); + Assert.Equal("resource/foo", request.Resource); + Assert.Equal(Method.GET, request.Method); + } + + [Fact] + public void Constructor_With_Resource_And_Method() + { + var request = new RestRequest("resource/foo", Method.PUT); + Assert.Equal("resource/foo", request.Resource); + Assert.Equal(Method.PUT, request.Method); + } + + [Fact] + public void Constructor_With_Uri_Sets_Resource() + { + var uri = new Uri("/api/resource", UriKind.Relative); + var request = new RestRequest(uri); + Assert.Equal("/api/resource", request.Resource); + } + + [Fact] + public void Constructor_With_Absolute_Uri_Uses_AbsolutePath_And_Query() + { + var uri = new Uri("http://example.com/api/resource?key=val"); + var request = new RestRequest(uri, Method.POST); + Assert.Equal("/api/resource?key=val", request.Resource); + Assert.Equal(Method.POST, request.Method); + } + + [Fact] + public void AddParameter_Adds_GetOrPost_Parameter() + { + var request = new RestRequest(); + request.AddParameter("name", "value"); + Assert.Single(request.Parameters); + Assert.Equal("name", request.Parameters[0].Name); + Assert.Equal("value", request.Parameters[0].Value); + Assert.Equal(ParameterType.GetOrPost, request.Parameters[0].Type); + } + + [Fact] + public void AddParameter_With_Type() + { + var request = new RestRequest(); + request.AddParameter("Authorization", "Bearer token", ParameterType.HttpHeader); + Assert.Single(request.Parameters); + Assert.Equal(ParameterType.HttpHeader, request.Parameters[0].Type); + } + + [Fact] + public void AddParameter_With_Parameter_Object() + { + var request = new RestRequest(); + var param = new Parameter { Name = "test", Value = "val", Type = ParameterType.Cookie }; + request.AddParameter(param); + Assert.Single(request.Parameters); + Assert.Equal(ParameterType.Cookie, request.Parameters[0].Type); + } + + [Fact] + public void AddHeader_Adds_HttpHeader_Parameter() + { + var request = new RestRequest(); + request.AddHeader("X-Custom", "value"); + Assert.Single(request.Parameters); + Assert.Equal(ParameterType.HttpHeader, request.Parameters[0].Type); + Assert.Equal("X-Custom", request.Parameters[0].Name); + } + + [Fact] + public void AddCookie_Adds_Cookie_Parameter() + { + var request = new RestRequest(); + request.AddCookie("session", "abc123"); + Assert.Single(request.Parameters); + Assert.Equal(ParameterType.Cookie, request.Parameters[0].Type); + Assert.Equal("session", request.Parameters[0].Name); + } + + [Fact] + public void AddUrlSegment_Adds_UrlSegment_Parameter() + { + var request = new RestRequest(); + request.AddUrlSegment("id", "42"); + Assert.Single(request.Parameters); + Assert.Equal(ParameterType.UrlSegment, request.Parameters[0].Type); + Assert.Equal("id", request.Parameters[0].Name); + } + + [Fact] + public void AddBody_Json_Format() + { + var request = new RestRequest(); + request.RequestFormat = DataFormat.Json; + request.AddBody(new { Name = "Test", Value = 123 }); + var bodyParam = request.Parameters.FirstOrDefault(p => p.Type == ParameterType.RequestBody); + Assert.NotNull(bodyParam); + Assert.Contains("Test", bodyParam.Value.ToString()); + } + + [Fact] + public void AddBody_Xml_Format() + { + var request = new RestRequest(); + request.RequestFormat = DataFormat.Xml; + request.AddBody(new TestPoco { Name = "Foo", Age = 25 }); + var bodyParam = request.Parameters.FirstOrDefault(p => p.Type == ParameterType.RequestBody); + Assert.NotNull(bodyParam); + Assert.Contains("Foo", bodyParam.Value.ToString()); + } + + [Fact] + public void AddBody_With_XmlNamespace() + { + var request = new RestRequest(); + request.RequestFormat = DataFormat.Xml; + request.AddBody(new TestPoco { Name = "Bar" }, "http://example.com/ns"); + var bodyParam = request.Parameters.FirstOrDefault(p => p.Type == ParameterType.RequestBody); + Assert.NotNull(bodyParam); + } + + [Fact] + public void AddObject_Adds_Parameters_For_All_Properties() + { + var request = new RestRequest(); + var obj = new TestPoco { Name = "Test", Age = 30 }; + request.AddObject(obj); + Assert.Equal(2, request.Parameters.Count); + Assert.Contains(request.Parameters, p => p.Name == "Name" && p.Value.ToString() == "Test"); + Assert.Contains(request.Parameters, p => p.Name == "Age" && p.Value.ToString() == "30"); + } + + [Fact] + public void AddObject_With_Whitelist() + { + var request = new RestRequest(); + var obj = new TestPoco { Name = "Test", Age = 30 }; + request.AddObject(obj, "Name"); + Assert.Single(request.Parameters); + Assert.Equal("Name", request.Parameters[0].Name); + } + + [Fact] + public void AddObject_Skips_Null_Values() + { + var request = new RestRequest(); + var obj = new TestPoco { Name = null, Age = 30 }; + request.AddObject(obj); + Assert.Single(request.Parameters); + Assert.Equal("Age", request.Parameters[0].Name); + } + + [Fact] + public void AddFile_With_Bytes() + { + var request = new RestRequest(); + var bytes = new byte[] { 1, 2, 3, 4, 5 }; + request.AddFile("file", bytes, "test.txt"); + Assert.Single(request.Files); + Assert.Equal("file", request.Files[0].Name); + Assert.Equal("test.txt", request.Files[0].FileName); + } + + [Fact] + public void AddFile_With_Bytes_And_ContentType() + { + var request = new RestRequest(); + var bytes = new byte[] { 1, 2, 3 }; + request.AddFile("file", bytes, "test.pdf", "application/pdf"); + Assert.Single(request.Files); + Assert.Equal("application/pdf", request.Files[0].ContentType); + } + + [Fact] + public void AddFile_With_Writer() + { + var request = new RestRequest(); + Action writer = s => { }; + request.AddFile("doc", writer, "doc.txt"); + Assert.Single(request.Files); + Assert.Equal("doc", request.Files[0].Name); + Assert.Equal("doc.txt", request.Files[0].FileName); + } + + [Fact] + public void AddFile_With_Writer_And_ContentType() + { + var request = new RestRequest(); + Action writer = s => { }; + request.AddFile("doc", writer, "doc.xml", "application/xml"); + Assert.Single(request.Files); + Assert.Equal("application/xml", request.Files[0].ContentType); + } + + [Fact] + public void Method_Property_Defaults_To_GET() + { + var request = new RestRequest(); + Assert.Equal(Method.GET, request.Method); + } + + [Fact] + public void Method_Property_Can_Be_Set() + { + var request = new RestRequest(); + request.Method = Method.DELETE; + Assert.Equal(Method.DELETE, request.Method); + } + + [Fact] + public void RequestFormat_Defaults_To_Xml() + { + var request = new RestRequest(); + Assert.Equal(DataFormat.Xml, request.RequestFormat); + } + + [Fact] + public void IncreaseNumAttempts_Increments_Attempts() + { + var request = new RestRequest(); + Assert.Equal(0, request.Attempts); + request.IncreaseNumAttempts(); + Assert.Equal(1, request.Attempts); + request.IncreaseNumAttempts(); + Assert.Equal(2, request.Attempts); + } + + [Fact] + public void OnBeforeDeserialization_Defaults_To_NoOp() + { + var request = new RestRequest(); + Assert.NotNull(request.OnBeforeDeserialization); + // should not throw + request.OnBeforeDeserialization(new RestResponse()); + } + + [Fact] + public void Timeout_Can_Be_Set() + { + var request = new RestRequest(); + request.Timeout = 5000; + Assert.Equal(5000, request.Timeout); + } + + [Fact] + public void RootElement_Can_Be_Set() + { + var request = new RestRequest(); + request.RootElement = "data"; + Assert.Equal("data", request.RootElement); + } + + [Fact] + public void DateFormat_Can_Be_Set() + { + var request = new RestRequest(); + request.DateFormat = "yyyy-MM-dd"; + Assert.Equal("yyyy-MM-dd", request.DateFormat); + } + + [Fact] + public void XmlNamespace_Can_Be_Set() + { + var request = new RestRequest(); + request.XmlNamespace = "http://example.com/ns"; + Assert.Equal("http://example.com/ns", request.XmlNamespace); + } + + [Fact] + public void Credentials_Can_Be_Set() + { + var request = new RestRequest(); + var creds = new System.Net.NetworkCredential("user", "pass"); + request.Credentials = creds; + Assert.Equal(creds, request.Credentials); + } + + [Fact] + public void UserState_Can_Be_Set() + { + var request = new RestRequest(); + request.UserState = "custom state"; + Assert.Equal("custom state", request.UserState); + } + + [Fact] + public void AddParameter_Returns_This() + { + var request = new RestRequest(); + var result = request.AddParameter("name", "value"); + Assert.Same(request, result); + } + + [Fact] + public void AddHeader_Returns_This() + { + var request = new RestRequest(); + var result = request.AddHeader("name", "value"); + Assert.Same(request, result); + } + + [Fact] + public void AddCookie_Returns_This() + { + var request = new RestRequest(); + var result = request.AddCookie("name", "value"); + Assert.Same(request, result); + } + + [Fact] + public void AddUrlSegment_Returns_This() + { + var request = new RestRequest(); + var result = request.AddUrlSegment("name", "value"); + Assert.Same(request, result); + } + + [Fact] + public void AddObject_Returns_This() + { + var request = new RestRequest(); + var result = request.AddObject(new TestPoco { Name = "x" }); + Assert.Same(request, result); + } + + [Fact] + public void AddObject_With_Array_Property() + { + var request = new RestRequest(); + var obj = new TestPocoWithArray { Tags = new[] { "a", "b", "c" } }; + request.AddObject(obj); + var param = request.Parameters.FirstOrDefault(p => p.Name == "Tags"); + Assert.NotNull(param); + Assert.Equal("a,b,c", param.Value); + } + + private class TestPoco + { + public string Name { get; set; } + public int Age { get; set; } + } + + private class TestPocoWithArray + { + public string[] Tags { get; set; } + } + } +} diff --git a/RestSharp.Tests.Coverage/RestResponseTests.cs b/RestSharp.Tests.Coverage/RestResponseTests.cs new file mode 100644 index 000000000..473fefc6d --- /dev/null +++ b/RestSharp.Tests.Coverage/RestResponseTests.cs @@ -0,0 +1,204 @@ +using System; +using System.Net; +using System.Text; +using Xunit; + +namespace RestSharp.Tests +{ + public class RestResponseTests + { + [Fact] + public void Default_Constructor_Initializes_Collections() + { + var response = new RestResponse(); + Assert.NotNull(response.Headers); + Assert.Empty(response.Headers); + Assert.NotNull(response.Cookies); + Assert.Empty(response.Cookies); + } + + [Fact] + public void Content_From_RawBytes() + { + var response = new RestResponse(); + response.RawBytes = Encoding.UTF8.GetBytes("Hello World"); + Assert.Equal("Hello World", response.Content); + } + + [Fact] + public void Content_Returns_Empty_When_RawBytes_Null() + { + var response = new RestResponse(); + response.RawBytes = null; + Assert.Equal("", response.Content); + } + + [Fact] + public void Content_Can_Be_Set_Directly() + { + var response = new RestResponse(); + response.Content = "direct content"; + Assert.Equal("direct content", response.Content); + } + + [Fact] + public void StatusCode_Can_Be_Set() + { + var response = new RestResponse(); + response.StatusCode = HttpStatusCode.OK; + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + + [Fact] + public void StatusDescription_Can_Be_Set() + { + var response = new RestResponse(); + response.StatusDescription = "OK"; + Assert.Equal("OK", response.StatusDescription); + } + + [Fact] + public void ContentType_Can_Be_Set() + { + var response = new RestResponse(); + response.ContentType = "application/json"; + Assert.Equal("application/json", response.ContentType); + } + + [Fact] + public void ContentLength_Can_Be_Set() + { + var response = new RestResponse(); + response.ContentLength = 1024; + Assert.Equal(1024, response.ContentLength); + } + + [Fact] + public void ContentEncoding_Can_Be_Set() + { + var response = new RestResponse(); + response.ContentEncoding = "gzip"; + Assert.Equal("gzip", response.ContentEncoding); + } + + [Fact] + public void ResponseUri_Can_Be_Set() + { + var response = new RestResponse(); + var uri = new Uri("http://example.com/resource"); + response.ResponseUri = uri; + Assert.Equal(uri, response.ResponseUri); + } + + [Fact] + public void Server_Can_Be_Set() + { + var response = new RestResponse(); + response.Server = "nginx"; + Assert.Equal("nginx", response.Server); + } + + [Fact] + public void ResponseStatus_Defaults_To_None() + { + var response = new RestResponse(); + Assert.Equal(ResponseStatus.None, response.ResponseStatus); + } + + [Fact] + public void ResponseStatus_Can_Be_Set() + { + var response = new RestResponse(); + response.ResponseStatus = ResponseStatus.Completed; + Assert.Equal(ResponseStatus.Completed, response.ResponseStatus); + } + + [Fact] + public void ErrorMessage_Can_Be_Set() + { + var response = new RestResponse(); + response.ErrorMessage = "Something went wrong"; + Assert.Equal("Something went wrong", response.ErrorMessage); + } + + [Fact] + public void ErrorException_Can_Be_Set() + { + var response = new RestResponse(); + var ex = new InvalidOperationException("test"); + response.ErrorException = ex; + Assert.Same(ex, response.ErrorException); + } + + [Fact] + public void Request_Can_Be_Set() + { + var response = new RestResponse(); + var request = new RestRequest("/test"); + response.Request = request; + Assert.Same(request, response.Request); + } + + [Fact] + public void Generic_RestResponse_Cast_Operator() + { + var response = new RestResponse(); + response.Content = "test"; + response.StatusCode = HttpStatusCode.OK; + response.ContentType = "text/plain"; + response.ContentEncoding = "utf-8"; + response.ContentLength = 4; + response.Server = "test-server"; + response.ResponseStatus = ResponseStatus.Completed; + response.ResponseUri = new Uri("http://example.com"); + response.StatusDescription = "OK"; + response.RawBytes = Encoding.UTF8.GetBytes("test"); + + var genericResponse = (RestResponse)response; + Assert.Equal(HttpStatusCode.OK, genericResponse.StatusCode); + Assert.Equal("text/plain", genericResponse.ContentType); + Assert.Equal("utf-8", genericResponse.ContentEncoding); + Assert.Equal(4, genericResponse.ContentLength); + Assert.Equal("test-server", genericResponse.Server); + Assert.Equal(ResponseStatus.Completed, genericResponse.ResponseStatus); + Assert.Equal("OK", genericResponse.StatusDescription); + } + + [Fact] + public void Generic_RestResponse_Data_Can_Be_Set() + { + var response = new RestResponse(); + response.Data = 42; + Assert.Equal(42, response.Data); + } + + [Fact] + public void RestResponseCookie_Properties() + { + var cookie = new RestResponseCookie(); + cookie.Name = "session"; + cookie.Value = "abc123"; + cookie.Domain = "example.com"; + cookie.Path = "/"; + cookie.HttpOnly = true; + cookie.Secure = true; + cookie.Expired = false; + cookie.Expires = new DateTime(2025, 12, 31); + cookie.Discard = false; + cookie.Port = "443"; + cookie.Version = 1; + cookie.Comment = "Session cookie"; + cookie.CommentUri = new Uri("http://example.com/cookies"); + cookie.TimeStamp = DateTime.UtcNow; + + Assert.Equal("session", cookie.Name); + Assert.Equal("abc123", cookie.Value); + Assert.Equal("example.com", cookie.Domain); + Assert.Equal("/", cookie.Path); + Assert.True(cookie.HttpOnly); + Assert.True(cookie.Secure); + Assert.False(cookie.Expired); + Assert.Equal(1, cookie.Version); + } + } +} diff --git a/RestSharp.Tests.Coverage/RestSharp.Tests.Coverage.csproj b/RestSharp.Tests.Coverage/RestSharp.Tests.Coverage.csproj new file mode 100644 index 000000000..1bfa7053b --- /dev/null +++ b/RestSharp.Tests.Coverage/RestSharp.Tests.Coverage.csproj @@ -0,0 +1,50 @@ + + + + net7.0 + false + disable + FRAMEWORK + CS0618;CS0612;SYSLIB0014;CS0108;CS0114;CS0162;CS8632 + false + true + + + + + + + + + + + + + + + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/RestSharp.Tests.Coverage/StringExtensionsTests.cs b/RestSharp.Tests.Coverage/StringExtensionsTests.cs new file mode 100644 index 000000000..a18a19557 --- /dev/null +++ b/RestSharp.Tests.Coverage/StringExtensionsTests.cs @@ -0,0 +1,281 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using RestSharp.Extensions; +using Xunit; + +namespace RestSharp.Tests +{ + public class StringExtensionsTests + { + [Fact] + public void HasValue_Returns_True_For_NonEmpty() + { + Assert.True("hello".HasValue()); + } + + [Fact] + public void HasValue_Returns_False_For_Empty() + { + Assert.False("".HasValue()); + } + + [Fact] + public void HasValue_Returns_False_For_Null() + { + string s = null; + Assert.False(s.HasValue()); + } + + [Fact] + public void RemoveUnderscoresAndDashes_Removes_Underscores() + { + Assert.Equal("helloworld", "hello_world".RemoveUnderscoresAndDashes()); + } + + [Fact] + public void RemoveUnderscoresAndDashes_Removes_Dashes() + { + Assert.Equal("helloworld", "hello-world".RemoveUnderscoresAndDashes()); + } + + [Fact] + public void RemoveUnderscoresAndDashes_Removes_Both() + { + Assert.Equal("abc def", "a_b-c d_e-f".RemoveUnderscoresAndDashes()); + } + + [Fact] + public void RemoveSurroundingQuotes_Removes_Quotes() + { + Assert.Equal("hello", "\"hello\"".RemoveSurroundingQuotes()); + } + + [Fact] + public void RemoveSurroundingQuotes_Preserves_String_Without_Quotes() + { + Assert.Equal("hello", "hello".RemoveSurroundingQuotes()); + } + + [Fact] + public void RemoveSurroundingQuotes_Preserves_String_With_Only_Leading_Quote() + { + Assert.Equal("\"hello", "\"hello".RemoveSurroundingQuotes()); + } + + [Fact] + public void ToPascalCase_Converts_Underscored() + { + var result = "some_test_string".ToPascalCase(CultureInfo.InvariantCulture); + Assert.Equal("SomeTestString", result); + } + + [Fact] + public void ToPascalCase_With_Single_Word() + { + var result = "hello".ToPascalCase(CultureInfo.InvariantCulture); + Assert.Equal("Hello", result); + } + + [Fact] + public void ToPascalCase_With_Empty_String() + { + var result = "".ToPascalCase(CultureInfo.InvariantCulture); + Assert.Equal("", result); + } + + [Fact] + public void ToPascalCase_With_Null_String() + { + string s = null; + var result = s.ToPascalCase(CultureInfo.InvariantCulture); + Assert.Null(result); + } + + [Fact] + public void ToPascalCase_All_Uppercase() + { + var result = "HELLO".ToPascalCase(CultureInfo.InvariantCulture); + Assert.Equal("Hello", result); + } + + [Fact] + public void ToPascalCase_Without_Removing_Underscores() + { + var result = "some_test".ToPascalCase(false, CultureInfo.InvariantCulture); + Assert.Contains("_", result); + } + + [Fact] + public void ToCamelCase_Converts_Underscored() + { + var result = "some_test_string".ToCamelCase(CultureInfo.InvariantCulture); + Assert.Equal("someTestString", result); + } + + [Fact] + public void MakeInitialLowerCase_Converts() + { + Assert.Equal("hello", "Hello".MakeInitialLowerCase()); + } + + [Fact] + public void IsUpperCase_Returns_True() + { + Assert.True("ABC".IsUpperCase()); + } + + [Fact] + public void IsUpperCase_Returns_False_For_Mixed() + { + Assert.False("AbC".IsUpperCase()); + } + + [Fact] + public void IsUpperCase_Returns_False_For_Lower() + { + Assert.False("abc".IsUpperCase()); + } + + [Fact] + public void AddUnderscores_Converts_PascalCase() + { + Assert.Equal("My_Property_Name", "MyPropertyName".AddUnderscores()); + } + + [Fact] + public void AddDashes_Converts_PascalCase() + { + Assert.Equal("My-Property-Name", "MyPropertyName".AddDashes()); + } + + [Fact] + public void GetNameVariants_Returns_Multiple_Variants() + { + var variants = "MyProperty".GetNameVariants(CultureInfo.InvariantCulture).ToList(); + Assert.Contains("MyProperty", variants); + Assert.Contains("myProperty", variants); + Assert.Contains("myproperty", variants); + Assert.Contains("My_Property", variants); + Assert.Contains("my_property", variants); + Assert.Contains("My-Property", variants); + Assert.Contains("my-property", variants); + } + + [Fact] + public void GetNameVariants_Empty_String_Returns_Empty() + { + var variants = "".GetNameVariants(CultureInfo.InvariantCulture).ToList(); + Assert.Empty(variants); + } + + [Fact] + public void GetNameVariants_Null_Returns_Empty() + { + string s = null; + var variants = s.GetNameVariants(CultureInfo.InvariantCulture).ToList(); + Assert.Empty(variants); + } + + [Fact] + public void Matches_Returns_True_For_Match() + { + Assert.True("hello123".Matches(@"\d+")); + } + + [Fact] + public void Matches_Returns_False_For_No_Match() + { + Assert.False("hello".Matches(@"^\d+$")); + } + + [Fact] + public void UrlEncode_Encodes_Special_Characters() + { + var result = "hello world&foo=bar".UrlEncode(); + Assert.DoesNotContain(" ", result); + Assert.Contains("%26", result); + } + + [Fact] + public void UrlDecode_Decodes_Encoded_Characters() + { + var encoded = "hello%20world"; + var result = encoded.UrlDecode(); + Assert.Equal("hello world", result); + } + + [Fact] + public void ParseJsonDate_Unix_Timestamp() + { + var result = "1265686800".ParseJsonDate(CultureInfo.InvariantCulture); + Assert.Equal(2010, result.Year); + } + + [Fact] + public void ParseJsonDate_Date_Constructor() + { + var result = "new Date(1265686800000)".ParseJsonDate(CultureInfo.InvariantCulture); + Assert.Equal(2010, result.Year); + } + + [Fact] + public void ParseJsonDate_Iso8601_Format() + { + var result = "2010-02-08T11:11:11Z".ParseJsonDate(CultureInfo.InvariantCulture); + Assert.Equal(2010, result.Year); + Assert.Equal(2, result.Month); + Assert.Equal(8, result.Day); + } + + [Fact] + public void ParseJsonDate_WCF_Format() + { + var result = "\\/Date(1265686800000)\\/".ParseJsonDate(CultureInfo.InvariantCulture); + Assert.Equal(2010, result.Year); + } + + [Fact] + public void ParseJsonDate_With_Quotes() + { + var result = "\"2010-02-08T11:11:11Z\"".ParseJsonDate(CultureInfo.InvariantCulture); + Assert.Equal(2010, result.Year); + } + + [Fact] + public void ParseJsonDate_With_Newlines() + { + var result = "\n2010-02-08T11:11:11Z\r".ParseJsonDate(CultureInfo.InvariantCulture); + Assert.Equal(2010, result.Year); + } + + [Fact] + public void ParseJsonDate_WCF_Format_With_Timezone_Offset() + { + var result = "\\/Date(1265686800000+0000)\\/".ParseJsonDate(CultureInfo.InvariantCulture); + Assert.Equal(2010, result.Year); + } + + [Fact] + public void ParseJsonDate_Invalid_Returns_Default() + { + var result = "not-a-date".ParseJsonDate(CultureInfo.InvariantCulture); + Assert.Equal(default(DateTime), result); + } + + [Fact] + public void HtmlEncode_Encodes_Special_Characters() + { + var result = "
".HtmlEncode(); + Assert.Contains("<", result); + } + + [Fact] + public void HtmlDecode_Decodes_Entities() + { + var result = "<div>".HtmlDecode(); + Assert.Equal("
", result); + } + } +} diff --git a/RestSharp.Tests.Coverage/ValidationTests.cs b/RestSharp.Tests.Coverage/ValidationTests.cs new file mode 100644 index 000000000..24899f1f5 --- /dev/null +++ b/RestSharp.Tests.Coverage/ValidationTests.cs @@ -0,0 +1,87 @@ +using System; +using RestSharp.Validation; +using Xunit; + +namespace RestSharp.Tests +{ + public class ValidationTests + { + [Fact] + public void IsBetween_Valid_Does_Not_Throw() + { + Validate.IsBetween(5, 1, 10); + } + + [Fact] + public void IsBetween_At_Min_Does_Not_Throw() + { + Validate.IsBetween(1, 1, 10); + } + + [Fact] + public void IsBetween_At_Max_Does_Not_Throw() + { + Validate.IsBetween(10, 1, 10); + } + + [Fact] + public void IsBetween_Below_Min_Throws() + { + Assert.Throws(() => Validate.IsBetween(0, 1, 10)); + } + + [Fact] + public void IsBetween_Above_Max_Throws() + { + Assert.Throws(() => Validate.IsBetween(11, 1, 10)); + } + + [Fact] + public void IsValidLength_Valid_Does_Not_Throw() + { + Validate.IsValidLength("hello", 10); + } + + [Fact] + public void IsValidLength_Exact_Max_Does_Not_Throw() + { + Validate.IsValidLength("hello", 5); + } + + [Fact] + public void IsValidLength_Null_Does_Not_Throw() + { + Validate.IsValidLength(null, 5); + } + + [Fact] + public void IsValidLength_Too_Long_Throws() + { + Assert.Throws(() => Validate.IsValidLength("hello world", 5)); + } + + [Fact] + public void IsValidLength_Empty_String_Does_Not_Throw() + { + Validate.IsValidLength("", 0); + } + + [Fact] + public void Require_Argument_Valid_Does_Not_Throw() + { + Require.Argument("param", "value"); + } + + [Fact] + public void Require_Argument_Null_Throws() + { + Assert.Throws(() => Require.Argument("param", null)); + } + + [Fact] + public void Require_Argument_Object_Does_Not_Throw() + { + Require.Argument("param", new object()); + } + } +} diff --git a/RestSharp.Tests.Coverage/WebPairCollectionTests.cs b/RestSharp.Tests.Coverage/WebPairCollectionTests.cs new file mode 100644 index 000000000..de797c3f9 --- /dev/null +++ b/RestSharp.Tests.Coverage/WebPairCollectionTests.cs @@ -0,0 +1,245 @@ +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; +using RestSharp.Authenticators.OAuth; +using Xunit; + +namespace RestSharp.Tests +{ + public class WebPairCollectionTests + { + [Fact] + public void Default_Constructor_Empty() + { + var coll = new WebPairCollection(); + Assert.Equal(0, coll.Count); + } + + [Fact] + public void Constructor_With_Capacity() + { + var coll = new WebPairCollection(10); + Assert.Equal(0, coll.Count); + } + + [Fact] + public void Constructor_With_Pairs() + { + var pairs = new List { new WebPair("a", "1"), new WebPair("b", "2") }; + var coll = new WebPairCollection(pairs); + Assert.Equal(2, coll.Count); + } + + [Fact] + public void Constructor_With_Dictionary() + { + var dict = new Dictionary { { "a", "1" }, { "b", "2" } }; + var coll = new WebPairCollection(dict); + Assert.Equal(2, coll.Count); + } + + [Fact] + public void Constructor_With_NameValueCollection() + { + var nvc = new NameValueCollection { { "a", "1" }, { "b", "2" } }; + var coll = new WebPairCollection(nvc); + Assert.Equal(2, coll.Count); + } + + [Fact] + public void Indexer_By_Name() + { + var coll = new WebPairCollection(); + coll.Add("test", "value"); + Assert.Equal("value", coll["test"].Value); + } + + [Fact] + public void Names_Property() + { + var coll = new WebPairCollection(); + coll.Add("a", "1"); + coll.Add("b", "2"); + Assert.Contains("a", coll.Names); + Assert.Contains("b", coll.Names); + } + + [Fact] + public void Values_Property() + { + var coll = new WebPairCollection(); + coll.Add("a", "1"); + coll.Add("b", "2"); + Assert.Contains("1", coll.Values); + Assert.Contains("2", coll.Values); + } + + [Fact] + public void AddRange_NameValueCollection() + { + var coll = new WebPairCollection(); + var nvc = new NameValueCollection { { "a", "1" } }; + coll.AddRange(nvc); + Assert.Single(coll); + } + + [Fact] + public void AddRange_WebPairCollection() + { + var coll = new WebPairCollection(); + var other = new WebPairCollection(); + other.Add("a", "1"); + coll.AddRange(other); + Assert.Single(coll); + } + + [Fact] + public void AddRange_IEnumerable() + { + var coll = new WebPairCollection(); + var list = new List { new WebPair("a", "1") }; + coll.AddRange(list); + Assert.Single(coll); + } + + [Fact] + public void RemoveAll() + { + var coll = new WebPairCollection(); + coll.Add("a", "1"); + coll.Add("b", "2"); + var toRemove = coll.Where(p => p.Name == "a").ToList(); + var result = coll.RemoveAll(toRemove); + Assert.True(result); + Assert.Single(coll); + } + + [Fact] + public void RemoveAll_Empty_Returns_False() + { + var coll = new WebPairCollection(); + var result = coll.RemoveAll(new List()); + Assert.False(result); + } + + [Fact] + public void Clear() + { + var coll = new WebPairCollection(); + coll.Add("a", "1"); + coll.Clear(); + Assert.Equal(0, coll.Count); + } + + [Fact] + public void Contains() + { + var coll = new WebPairCollection(); + var pair = new WebPair("a", "1"); + coll.Add(pair); + Assert.True(coll.Contains(pair)); + } + + [Fact] + public void CopyTo() + { + var coll = new WebPairCollection(); + coll.Add("a", "1"); + coll.Add("b", "2"); + var array = new WebPair[2]; + coll.CopyTo(array, 0); + Assert.Equal("a", array[0].Name); + } + + [Fact] + public void Remove() + { + var coll = new WebPairCollection(); + var pair = new WebPair("a", "1"); + coll.Add(pair); + Assert.True(coll.Remove(pair)); + Assert.Equal(0, coll.Count); + } + + [Fact] + public void IsReadOnly() + { + var coll = new WebPairCollection(); + Assert.False(coll.IsReadOnly); + } + + [Fact] + public void IndexOf() + { + var coll = new WebPairCollection(); + var pair = new WebPair("a", "1"); + coll.Add(pair); + Assert.Equal(0, coll.IndexOf(pair)); + } + + [Fact] + public void Insert() + { + var coll = new WebPairCollection(); + coll.Add("b", "2"); + coll.Insert(0, new WebPair("a", "1")); + Assert.Equal("a", coll[0].Name); + } + + [Fact] + public void RemoveAt() + { + var coll = new WebPairCollection(); + coll.Add("a", "1"); + coll.Add("b", "2"); + coll.RemoveAt(0); + Assert.Single(coll); + Assert.Equal("b", coll[0].Name); + } + + [Fact] + public void IntIndexer_Set() + { + var coll = new WebPairCollection(); + coll.Add("a", "1"); + coll[0] = new WebPair("b", "2"); + Assert.Equal("b", coll[0].Name); + } + + [Fact] + public void Sort() + { + var coll = new WebPairCollection(); + coll.Add("c", "3"); + coll.Add("a", "1"); + coll.Add("b", "2"); + coll.Sort((l, r) => string.Compare(l.Name, r.Name, StringComparison.Ordinal)); + Assert.Equal("a", coll[0].Name); + Assert.Equal("b", coll[1].Name); + Assert.Equal("c", coll[2].Name); + } + + [Fact] + public void GetEnumerator_Enumerates() + { + var coll = new WebPairCollection(); + coll.Add("a", "1"); + coll.Add("b", "2"); + var count = 0; + foreach (var item in coll) + { + count++; + } + Assert.Equal(2, count); + } + + [Fact] + public void Add_WebPair_Object() + { + var coll = new WebPairCollection(); + coll.Add(new WebPair("key", "val")); + Assert.Equal("key", coll[0].Name); + } + } +} diff --git a/RestSharp.Tests.Coverage/XmlAttributeDeserializerTests.cs b/RestSharp.Tests.Coverage/XmlAttributeDeserializerTests.cs new file mode 100644 index 000000000..7cc48035d --- /dev/null +++ b/RestSharp.Tests.Coverage/XmlAttributeDeserializerTests.cs @@ -0,0 +1,284 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using RestSharp.Deserializers; +using Xunit; + +namespace RestSharp.Tests +{ + public class XmlAttributeDeserializerTests + { + [Fact] + public void Default_Culture_Is_Invariant() + { + var d = new XmlAttributeDeserializer(); + Assert.Equal(CultureInfo.InvariantCulture, d.Culture); + } + + [Fact] + public void Deserialize_Simple_Element() + { + var d = new XmlAttributeDeserializer(); + var xml = "Hello42"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal("Hello", obj.Name); + Assert.Equal(42, obj.Value); + } + + [Fact] + public void Deserialize_Null_Content_Returns_Default() + { + var d = new XmlAttributeDeserializer(); + var response = new RestResponse(); + // Set Content field to null via RawBytes=null and reflection, + // since Content derives from RawBytes (returns "" for null bytes) + // The deserializer checks response.Content == null + var prop = typeof(RestResponse).GetProperty("Content"); + // We need to create a response where Content is actually null + // The code checks `response.Content == null` so we need to construct carefully + // RestResponse.Content returns "" when RawBytes is null, so the null check + // in XmlAttributeDeserializer won't hit via normal RestResponse. + // Just verify it doesn't crash on valid minimal XML + response = new RestResponse { Content = "" }; + var obj = d.Deserialize(response); + Assert.NotNull(obj); + } + + [Fact] + public void Deserialize_With_RootElement() + { + var d = new XmlAttributeDeserializer { RootElement = "Data" }; + var xml = "Test1"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal("Test", obj.Name); + } + + [Fact] + public void Deserialize_Attributes() + { + var d = new XmlAttributeDeserializer(); + var xml = "AttrName99"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal("AttrName", obj.Name); + Assert.Equal(99, obj.Value); + } + + [Fact] + public void Deserialize_Boolean_Property() + { + var d = new XmlAttributeDeserializer(); + var xml = "true"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.True(obj.Active); + } + + [Fact] + public void Deserialize_DateTime_Property() + { + var d = new XmlAttributeDeserializer(); + var xml = "2024-06-15T12:00:00"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal(2024, obj.Created.Year); + } + + [Fact] + public void Deserialize_Decimal_Property() + { + var d = new XmlAttributeDeserializer(); + var xml = "19.99"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal(19.99m, obj.Amount); + } + + [Fact] + public void Deserialize_Long_Property() + { + var d = new XmlAttributeDeserializer(); + var xml = "9999999999"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal(9999999999, obj.BigNum); + } + + [Fact] + public void Deserialize_Double_Property() + { + var d = new XmlAttributeDeserializer(); + var xml = "3.14"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal(3.14, obj.Ratio, 2); + } + + [Fact] + public void Deserialize_Nullable_Property() + { + var d = new XmlAttributeDeserializer(); + var xml = "42"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal(42, obj.NullableVal); + } + + [Fact] + public void Deserialize_Nullable_Missing_Returns_Null() + { + var d = new XmlAttributeDeserializer(); + var xml = ""; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Null(obj.NullableVal); + } + + [Fact] + public void Deserialize_Guid_Property() + { + var d = new XmlAttributeDeserializer(); + var guid = Guid.NewGuid(); + var xml = $"{guid}"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal(guid, obj.Id); + } + + [Fact] + public void Deserialize_Uri_Property() + { + var d = new XmlAttributeDeserializer(); + var xml = "http://example.com/test"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal("http://example.com/test", obj.Link.ToString()); + } + + [Fact] + public void Deserialize_Enum_Property() + { + var d = new XmlAttributeDeserializer(); + var xml = "Completed"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal(ResponseStatus.Completed, obj.Status); + } + + [Fact] + public void Deserialize_List_Property() + { + var d = new XmlAttributeDeserializer(); + var xml = "A1B2"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal(2, obj.Items.Count); + } + + [Fact] + public void Deserialize_String_Property_From_Attribute() + { + var d = new XmlAttributeDeserializer(); + var xml = "FromElement7"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal("FromElement", obj.Name); + Assert.Equal(7, obj.Value); + } + + [Fact] + public void Deserialize_With_Namespace() + { + var d = new XmlAttributeDeserializer { Namespace = "http://example.com/ns" }; + var xml = "NSTest5"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal("NSTest", obj.Name); + } + + [Fact] + public void Deserialize_With_DateFormat() + { + var d = new XmlAttributeDeserializer { DateFormat = "yyyy-MM-dd" }; + var xml = "2024-06-15"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal(2024, obj.Created.Year); + Assert.Equal(6, obj.Created.Month); + } + + [Fact] + public void Deserialize_Float_Property() + { + var d = new XmlAttributeDeserializer(); + var xml = "1.5"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal(1.5f, obj.Score, 1); + } + + [Fact] + public void Deserialize_Short_Property() + { + var d = new XmlAttributeDeserializer(); + var xml = "123"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal(123, obj.SmallNum); + } + + [Fact] + public void Deserialize_With_DeserializeAs_Attribute() + { + var d = new XmlAttributeDeserializer(); + var xml = "Custom"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal("Custom", obj.CustomProp); + } + + [Fact] + public void Deserialize_Int_From_Attribute_Xml() + { + var d = new XmlAttributeDeserializer(); + var xml = "Test100"; + var response = new RestResponse { Content = xml }; + var obj = d.Deserialize(response); + Assert.Equal(100, obj.Value); + } + + public class TestItem + { + public string Name { get; set; } + public int Value { get; set; } + } + + public class AttrItem + { + public string Name { get; set; } + public int Value { get; set; } + } + + public class BoolItem { public bool Active { get; set; } } + public class DateItem { public DateTime Created { get; set; } } + public class DecItem { public decimal Amount { get; set; } } + public class LongItem { public long BigNum { get; set; } } + public class DoubleItem { public double Ratio { get; set; } } + public class NullableItem { public int? NullableVal { get; set; } } + public class GuidItem { public Guid Id { get; set; } } + public class UriItem { public Uri Link { get; set; } } + public class EnumItem { public ResponseStatus Status { get; set; } } + public class ListItem { public List Items { get; set; } } + public class NestedItem { public TestItem Child { get; set; } } + public class FloatItem { public float Score { get; set; } } + public class ShortItem { public short SmallNum { get; set; } } + + public class DeserializeAsItem + { + [DeserializeAs(Name = "custom_name")] + public string CustomProp { get; set; } + } + } +} diff --git a/RestSharp.Tests.Coverage/XmlSerializerEdgeTests.cs b/RestSharp.Tests.Coverage/XmlSerializerEdgeTests.cs new file mode 100644 index 000000000..259838565 --- /dev/null +++ b/RestSharp.Tests.Coverage/XmlSerializerEdgeTests.cs @@ -0,0 +1,359 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using RestSharp.Deserializers; +using RestSharp.Serializers; +using Xunit; + +namespace RestSharp.Tests +{ + public class XmlSerializerEdgeTests + { + [Fact] + public void XmlSerializer_Default_ContentType() + { + var serializer = new XmlSerializer(); + Assert.Equal("text/xml", serializer.ContentType); + } + + [Fact] + public void XmlSerializer_Namespace_Property() + { + var serializer = new XmlSerializer(); + serializer.Namespace = "http://example.com/ns"; + Assert.Equal("http://example.com/ns", serializer.Namespace); + } + + [Fact] + public void XmlSerializer_DateFormat_Property() + { + var serializer = new XmlSerializer(); + serializer.DateFormat = "yyyy-MM-dd"; + Assert.Equal("yyyy-MM-dd", serializer.DateFormat); + } + + [Fact] + public void XmlSerializer_RootElement_Property() + { + var serializer = new XmlSerializer(); + serializer.RootElement = "Root"; + Assert.Equal("Root", serializer.RootElement); + } + + [Fact] + public void XmlSerializer_Serialize_Simple_Object() + { + var serializer = new XmlSerializer(); + var result = serializer.Serialize(new SimpleObj { Name = "Test", Value = 42 }); + Assert.Contains("Test", result); + Assert.Contains("42", result); + } + + [Fact] + public void XmlDeserializer_Default_Culture() + { + var d = new XmlDeserializer(); + Assert.Equal(CultureInfo.InvariantCulture, d.Culture); + } + + [Fact] + public void XmlDeserializer_RootElement_Property() + { + var d = new XmlDeserializer(); + d.RootElement = "data"; + Assert.Equal("data", d.RootElement); + } + + [Fact] + public void XmlDeserializer_Namespace_Property() + { + var d = new XmlDeserializer(); + d.Namespace = "http://example.com/ns"; + Assert.Equal("http://example.com/ns", d.Namespace); + } + + [Fact] + public void XmlDeserializer_DateFormat_Property() + { + var d = new XmlDeserializer(); + d.DateFormat = "yyyy-MM-dd"; + Assert.Equal("yyyy-MM-dd", d.DateFormat); + } + + [Fact] + public void XmlDeserializer_Deserialize_Simple() + { + var d = new XmlDeserializer(); + var response = new RestResponse { Content = "Hello99" }; + var obj = d.Deserialize(response); + Assert.Equal("Hello", obj.Name); + Assert.Equal(99, obj.Value); + } + + [Fact] + public void XmlDeserializer_Deserialize_With_RootElement() + { + var d = new XmlDeserializer { RootElement = "Data" }; + var response = new RestResponse { Content = "Test1" }; + var obj = d.Deserialize(response); + Assert.Equal("Test", obj.Name); + } + + [Fact] + public void JsonDeserializer_Default_Culture() + { + var d = new JsonDeserializer(); + Assert.Equal(CultureInfo.InvariantCulture, d.Culture); + } + + [Fact] + public void JsonDeserializer_Deserialize_With_RootElement() + { + var d = new JsonDeserializer { RootElement = "data" }; + var response = new RestResponse { Content = "{\"data\": {\"Name\": \"Test\", \"Value\": 42}}" }; + var obj = d.Deserialize(response); + Assert.Equal("Test", obj.Name); + Assert.Equal(42, obj.Value); + } + + [Fact] + public void JsonDeserializer_Deserialize_List() + { + var d = new JsonDeserializer(); + var response = new RestResponse { Content = "[{\"Name\": \"A\", \"Value\": 1}, {\"Name\": \"B\", \"Value\": 2}]" }; + var list = d.Deserialize>(response); + Assert.Equal(2, list.Count); + Assert.Equal("A", list[0].Name); + Assert.Equal("B", list[1].Name); + } + + [Fact] + public void JsonDeserializer_Deserialize_List_With_RootElement() + { + var d = new JsonDeserializer { RootElement = "items" }; + var response = new RestResponse { Content = "{\"items\": [{\"Name\": \"A\"}, {\"Name\": \"B\"}]}" }; + var list = d.Deserialize>(response); + Assert.Equal(2, list.Count); + } + + [Fact] + public void JsonDeserializer_Deserialize_Dictionary() + { + var d = new JsonDeserializer(); + var response = new RestResponse { Content = "{\"key1\": \"val1\", \"key2\": \"val2\"}" }; + var dict = d.Deserialize>(response); + Assert.Equal(2, dict.Count); + Assert.Equal("val1", dict["key1"]); + } + + [Fact] + public void JsonDeserializer_Deserialize_With_DateFormat() + { + var d = new JsonDeserializer { DateFormat = "yyyy-MM-dd" }; + var response = new RestResponse { Content = "{\"Date\": \"2024-06-15\"}" }; + var obj = d.Deserialize(response); + Assert.Equal(2024, obj.Date.Year); + Assert.Equal(6, obj.Date.Month); + Assert.Equal(15, obj.Date.Day); + } + + [Fact] + public void JsonDeserializer_Deserialize_Nullable_Int() + { + var d = new JsonDeserializer(); + var response = new RestResponse { Content = "{\"NullableValue\": 42}" }; + var obj = d.Deserialize(response); + Assert.Equal(42, obj.NullableValue); + } + + [Fact] + public void JsonDeserializer_Deserialize_Null_Nullable_Int() + { + var d = new JsonDeserializer(); + var response = new RestResponse { Content = "{\"NullableValue\": null}" }; + var obj = d.Deserialize(response); + Assert.Null(obj.NullableValue); + } + + [Fact] + public void JsonDeserializer_Deserialize_Enum() + { + var d = new JsonDeserializer(); + var response = new RestResponse { Content = "{\"Status\": \"Completed\"}" }; + var obj = d.Deserialize(response); + Assert.Equal(ResponseStatus.Completed, obj.Status); + } + + [Fact] + public void JsonDeserializer_Deserialize_Guid() + { + var d = new JsonDeserializer(); + var guid = Guid.NewGuid(); + var response = new RestResponse { Content = "{\"Id\": \"" + guid + "\"}" }; + var obj = d.Deserialize(response); + Assert.Equal(guid, obj.Id); + } + + [Fact] + public void JsonDeserializer_Deserialize_EmptyGuid() + { + var d = new JsonDeserializer(); + var response = new RestResponse { Content = "{\"Id\": \"\"}" }; + var obj = d.Deserialize(response); + Assert.Equal(Guid.Empty, obj.Id); + } + + [Fact] + public void JsonDeserializer_Deserialize_Uri() + { + var d = new JsonDeserializer(); + var response = new RestResponse { Content = "{\"Link\": \"http://example.com/test\"}" }; + var obj = d.Deserialize(response); + Assert.Equal("http://example.com/test", obj.Link.ToString()); + } + + [Fact] + public void JsonDeserializer_Deserialize_Decimal() + { + var d = new JsonDeserializer(); + var response = new RestResponse { Content = "{\"Amount\": \"19.99\"}" }; + var obj = d.Deserialize(response); + Assert.Equal(19.99m, obj.Amount); + } + + [Fact] + public void JsonDeserializer_Deserialize_Nested_Object() + { + var d = new JsonDeserializer(); + var response = new RestResponse { Content = "{\"Inner\": {\"Name\": \"nested\", \"Value\": 1}}" }; + var obj = d.Deserialize(response); + Assert.NotNull(obj.Inner); + Assert.Equal("nested", obj.Inner.Name); + } + + [Fact] + public void JsonDeserializer_Deserialize_Nested_List() + { + var d = new JsonDeserializer(); + var response = new RestResponse { Content = "{\"Items\": [{\"Name\": \"A\"}, {\"Name\": \"B\"}]}" }; + var obj = d.Deserialize(response); + Assert.Equal(2, obj.Items.Count); + } + + [Fact] + public void JsonDeserializer_Deserialize_Nested_Dictionary() + { + var d = new JsonDeserializer(); + var response = new RestResponse { Content = "{\"Data\": {\"key1\": \"val1\", \"key2\": \"val2\"}}" }; + var obj = d.Deserialize(response); + Assert.Equal(2, obj.Data.Count); + } + + [Fact] + public void JsonDeserializer_Deserialize_Boolean_Property() + { + var d = new JsonDeserializer(); + var response = new RestResponse { Content = "{\"Active\": true}" }; + var obj = d.Deserialize(response); + Assert.True(obj.Active); + } + + [Fact] + public void JsonDeserializer_Deserialize_Long_Property() + { + var d = new JsonDeserializer(); + var response = new RestResponse { Content = "{\"BigNumber\": 9999999999}" }; + var obj = d.Deserialize(response); + Assert.Equal(9999999999L, obj.BigNumber); + } + + [Fact] + public void JsonDeserializer_Deserialize_Double_Property() + { + var d = new JsonDeserializer(); + var response = new RestResponse { Content = "{\"Ratio\": 3.14}" }; + var obj = d.Deserialize(response); + Assert.Equal(3.14, obj.Ratio, 2); + } + + [Fact] + public void JsonDeserializer_Deserialize_DateTimeOffset() + { + var d = new JsonDeserializer(); + var response = new RestResponse { Content = "{\"Stamp\": \"2024-06-15T12:00:00Z\"}" }; + var obj = d.Deserialize(response); + Assert.Equal(2024, obj.Stamp.Year); + } + + public class SimpleObj + { + public string Name { get; set; } + public int Value { get; set; } + } + + public class ObjWithDate + { + public DateTime Date { get; set; } + } + + public class ObjWithNullable + { + public int? NullableValue { get; set; } + } + + public class ObjWithEnum + { + public ResponseStatus Status { get; set; } + } + + public class ObjWithGuid + { + public Guid Id { get; set; } + } + + public class ObjWithUri + { + public Uri Link { get; set; } + } + + public class ObjWithDecimal + { + public decimal Amount { get; set; } + } + + public class ObjWithNested + { + public SimpleObj Inner { get; set; } + } + + public class ObjWithList + { + public List Items { get; set; } + } + + public class ObjWithDict + { + public Dictionary Data { get; set; } + } + + public class ObjWithBool + { + public bool Active { get; set; } + } + + public class ObjWithLong + { + public long BigNumber { get; set; } + } + + public class ObjWithDouble + { + public double Ratio { get; set; } + } + + public class ObjWithDateTimeOffset + { + public DateTimeOffset Stamp { get; set; } + } + } +}