diff --git a/RestSharp.sln b/RestSharp.sln index 829682f2d..c81d31282 100644 --- a/RestSharp.sln +++ b/RestSharp.sln @@ -1,35 +1,39 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26730.16 +# Visual Studio Version 17 +VisualStudioVersion = 17.3.32811.315 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestSharp", "src\RestSharp\RestSharp.csproj", "{43A1D5D2-650D-40DD-A6C0-14F92689C70B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp", "src\RestSharp\RestSharp.csproj", "{43A1D5D2-650D-40DD-A6C0-14F92689C70B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{9051DDA0-E563-45D5-9504-085EBAACF469}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestSharp.Tests", "test\RestSharp.Tests\RestSharp.Tests.csproj", "{B1C55C9B-3287-4EB2-8ADD-795DBC77013D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.Tests", "test\RestSharp.Tests\RestSharp.Tests.csproj", "{B1C55C9B-3287-4EB2-8ADD-795DBC77013D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestSharp.Tests.Integrated", "test\RestSharp.Tests.Integrated\RestSharp.Tests.Integrated.csproj", "{AC3B3DDC-F011-4E19-8C9B-F748B19ED3C0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.Tests.Integrated", "test\RestSharp.Tests.Integrated\RestSharp.Tests.Integrated.csproj", "{AC3B3DDC-F011-4E19-8C9B-F748B19ED3C0}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestSharp.Serializers.NewtonsoftJson", "src\RestSharp.Serializers.NewtonsoftJson\RestSharp.Serializers.NewtonsoftJson.csproj", "{4205A187-9732-4DA8-B0BE-77A2C6B8C6A1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.Serializers.NewtonsoftJson", "src\RestSharp.Serializers.NewtonsoftJson\RestSharp.Serializers.NewtonsoftJson.csproj", "{4205A187-9732-4DA8-B0BE-77A2C6B8C6A1}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Serializers", "Serializers", "{8C7B43EB-2F93-483C-B433-E28F9386AD67}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestSharp.Tests.Shared", "test\RestSharp.Tests.Shared\RestSharp.Tests.Shared.csproj", "{73896669-F05C-41AC-9F6F-A11F549EDEDC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.Tests.Shared", "test\RestSharp.Tests.Shared\RestSharp.Tests.Shared.csproj", "{73896669-F05C-41AC-9F6F-A11F549EDEDC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestSharp.Tests.Serializers.Json", "test\RestSharp.Tests.Serializers.Json\RestSharp.Tests.Serializers.Json.csproj", "{8BF81225-2F85-4412-AD18-6579CBA1879B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.Tests.Serializers.Json", "test\RestSharp.Tests.Serializers.Json\RestSharp.Tests.Serializers.Json.csproj", "{8BF81225-2F85-4412-AD18-6579CBA1879B}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Perf", "Perf", "{1C42C435-8826-4044-8775-A1DA40EF4866}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestSharp.Benchmarks", "benchmarks\RestSharp.Benchmarks\RestSharp.Benchmarks.csproj", "{997AEFE5-D7D4-4033-A31A-07F476D6FE5D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.Benchmarks", "benchmarks\RestSharp.Benchmarks\RestSharp.Benchmarks.csproj", "{997AEFE5-D7D4-4033-A31A-07F476D6FE5D}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestSharp.InteractiveTests", "test\RestSharp.InteractiveTests\RestSharp.InteractiveTests.csproj", "{6D7D1D60-4473-4C52-800C-9B892C6640A5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.InteractiveTests", "test\RestSharp.InteractiveTests\RestSharp.InteractiveTests.csproj", "{6D7D1D60-4473-4C52-800C-9B892C6640A5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestSharp.Tests.Serializers.Xml", "test\RestSharp.Tests.Serializers.Xml\RestSharp.Tests.Serializers.Xml.csproj", "{E6D94C12-9AD7-46E6-AB62-3676F25FDE51}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.Tests.Serializers.Xml", "test\RestSharp.Tests.Serializers.Xml\RestSharp.Tests.Serializers.Xml.csproj", "{E6D94C12-9AD7-46E6-AB62-3676F25FDE51}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestSharp.Serializers.Xml", "src\RestSharp.Serializers.Xml\RestSharp.Serializers.Xml.csproj", "{4A35B1C5-520D-4267-BA70-2DCEAC0A5662}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.Serializers.Xml", "src\RestSharp.Serializers.Xml\RestSharp.Serializers.Xml.csproj", "{4A35B1C5-520D-4267-BA70-2DCEAC0A5662}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestSharp.Tests.Legacy", "test\RestSharp.Tests.Legacy\RestSharp.Tests.Legacy.csproj", "{5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.Tests.Legacy", "test\RestSharp.Tests.Legacy\RestSharp.Tests.Legacy.csproj", "{5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.Serializers.CsvHelper", "src\RestSharp.Serializers.CsvHelper\RestSharp.Serializers.CsvHelper.csproj", "{2150E333-8FDC-42A3-9474-1A3956D46DE8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestSharp.Tests.Serializers.Csv", "test\RestSharp.Tests.Serializers.Csv\RestSharp.Tests.Serializers.Csv.csproj", "{E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -380,13 +384,70 @@ Global {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Release|x64.Build.0 = Release|Any CPU {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Release|x86.ActiveCfg = Release|Any CPU {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0}.Release|x86.Build.0 = Release|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug.Appveyor|Any CPU.ActiveCfg = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug.Appveyor|Any CPU.Build.0 = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug.Appveyor|ARM.ActiveCfg = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug.Appveyor|ARM.Build.0 = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug.Appveyor|Mixed Platforms.ActiveCfg = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug.Appveyor|Mixed Platforms.Build.0 = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug.Appveyor|x64.ActiveCfg = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug.Appveyor|x64.Build.0 = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug.Appveyor|x86.ActiveCfg = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug.Appveyor|x86.Build.0 = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug|ARM.ActiveCfg = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug|ARM.Build.0 = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug|x64.ActiveCfg = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug|x64.Build.0 = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug|x86.ActiveCfg = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Debug|x86.Build.0 = Debug|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Release|Any CPU.Build.0 = Release|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Release|ARM.ActiveCfg = Release|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Release|ARM.Build.0 = Release|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Release|x64.ActiveCfg = Release|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Release|x64.Build.0 = Release|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Release|x86.ActiveCfg = Release|Any CPU + {2150E333-8FDC-42A3-9474-1A3956D46DE8}.Release|x86.Build.0 = Release|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug.Appveyor|Any CPU.ActiveCfg = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug.Appveyor|Any CPU.Build.0 = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug.Appveyor|ARM.ActiveCfg = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug.Appveyor|ARM.Build.0 = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug.Appveyor|Mixed Platforms.ActiveCfg = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug.Appveyor|Mixed Platforms.Build.0 = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug.Appveyor|x64.ActiveCfg = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug.Appveyor|x64.Build.0 = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug.Appveyor|x86.ActiveCfg = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug.Appveyor|x86.Build.0 = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug|ARM.ActiveCfg = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug|ARM.Build.0 = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug|x64.ActiveCfg = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug|x64.Build.0 = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug|x86.ActiveCfg = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Debug|x86.Build.0 = Debug|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Release|Any CPU.Build.0 = Release|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Release|ARM.ActiveCfg = Release|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Release|ARM.Build.0 = Release|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Release|x64.ActiveCfg = Release|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Release|x64.Build.0 = Release|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Release|x86.ActiveCfg = Release|Any CPU + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {77FF357B-03FA-4FA5-A68F-BFBE5800FEBA} - EndGlobalSection GlobalSection(NestedProjects) = preSolution {B1C55C9B-3287-4EB2-8ADD-795DBC77013D} = {9051DDA0-E563-45D5-9504-085EBAACF469} {AC3B3DDC-F011-4E19-8C9B-F748B19ED3C0} = {9051DDA0-E563-45D5-9504-085EBAACF469} @@ -398,5 +459,10 @@ Global {E6D94C12-9AD7-46E6-AB62-3676F25FDE51} = {9051DDA0-E563-45D5-9504-085EBAACF469} {4A35B1C5-520D-4267-BA70-2DCEAC0A5662} = {8C7B43EB-2F93-483C-B433-E28F9386AD67} {5A8A5BBE-28DA-4C89-B393-BE39A96E8DC0} = {9051DDA0-E563-45D5-9504-085EBAACF469} + {2150E333-8FDC-42A3-9474-1A3956D46DE8} = {8C7B43EB-2F93-483C-B433-E28F9386AD67} + {E6D94FFD-7811-40BE-ABC4-6D6AB41F0060} = {9051DDA0-E563-45D5-9504-085EBAACF469} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {77FF357B-03FA-4FA5-A68F-BFBE5800FEBA} EndGlobalSection EndGlobal diff --git a/src/RestSharp.Serializers.CsvHelper/CsvHelperSerializer.cs b/src/RestSharp.Serializers.CsvHelper/CsvHelperSerializer.cs new file mode 100644 index 000000000..ee9fbd2aa --- /dev/null +++ b/src/RestSharp.Serializers.CsvHelper/CsvHelperSerializer.cs @@ -0,0 +1,139 @@ +using CsvHelper; +using CsvHelper.Configuration; +using System.Collections; +using System.Globalization; +using System.Reflection; + +namespace RestSharp.Serializers.CsvHelper { + public class CsvHelperSerializer : IDeserializer, IRestSerializer, ISerializer { + private const string TextCsvContentType = "text/csv"; + + private readonly CsvConfiguration _configuration; + + public ISerializer Serializer { + get { + return this; + } + } + + public IDeserializer Deserializer { + get { + return this; + } + } + + public string[] AcceptedContentTypes { + get { + return new string[] { TextCsvContentType, "application/x-download" }; + } + } + + public SupportsContentType SupportsContentType { + get { + return x => Array.IndexOf(AcceptedContentTypes, x) != -1 || x.Contains("csv"); + } + } + + public DataFormat DataFormat { + get { + return DataFormat.None; + } + } + + public string ContentType { get; set; } = TextCsvContentType; + + public CsvHelperSerializer() { + _configuration = new CsvConfiguration(CultureInfo.InvariantCulture); + } + + public CsvHelperSerializer(CsvConfiguration configuration) { + _configuration = configuration; + } + + public T? Deserialize(RestResponse response) { + try { + if (response.Content == null) { + throw new InvalidOperationException(message: "Response content is null"); + } + else { + using (StringReader stringReader = new StringReader(response.Content)) + using (CsvReader csvReader = new CsvReader(stringReader, CultureInfo.CurrentCulture)) { + Type? @interface = typeof(T).GetInterface("IEnumerable`1"); + + if (@interface == null) { + csvReader.Read(); + + return csvReader.GetRecord(); + } + else { + Type itemType = @interface.GenericTypeArguments[0]; + T result; + + try { + result = Activator.CreateInstance(); + } + catch (MissingMethodException) { + throw new InvalidOperationException(message: "The type must contain a public, parameterless constructor."); + } + + MethodInfo? method = typeof(T).GetMethod(name: "Add"); + + if (method == null) { + throw new InvalidOperationException(message: "If the type implements IEnumerable, then it must contain a public \"Add(T)\" method."); + } + else { + foreach (object record in csvReader.GetRecords(itemType)) { + method.Invoke(result, new object[] + { + record + }); + } + } + + return result; + } + } + } + } + catch (Exception exception) { + throw new DeserializationException(response, exception); + } + } + + public string? Serialize(Parameter parameter) { + return Serialize(parameter.Value); + } + + public string? Serialize(object? obj) { + if (obj == null) { + return null; + } + else { + using (StringWriter stringWriter = new StringWriter()) + using (CsvWriter csvWriter = new CsvWriter(stringWriter, _configuration)) { + if (obj is IEnumerable records) { + IEnumerator enumerator = records.GetEnumerator(); + + if (enumerator.MoveNext()) { + csvWriter.WriteHeader(enumerator.Current.GetType()); + csvWriter.NextRecord(); + csvWriter.WriteRecords(records); + } + + if (enumerator is IDisposable disposable) { + disposable.Dispose(); + } + } + else { + csvWriter.WriteHeader(obj.GetType()); + csvWriter.NextRecord(); + csvWriter.WriteRecord(obj); + csvWriter.NextRecord(); + } + + return stringWriter.ToString(); + } + } + } + } +} \ No newline at end of file diff --git a/src/RestSharp.Serializers.CsvHelper/RestClientExtensions.cs b/src/RestSharp.Serializers.CsvHelper/RestClientExtensions.cs new file mode 100644 index 000000000..33504a621 --- /dev/null +++ b/src/RestSharp.Serializers.CsvHelper/RestClientExtensions.cs @@ -0,0 +1,14 @@ +using CsvHelper.Configuration; + +namespace RestSharp.Serializers.CsvHelper { + [PublicAPI] + public static class RestClientExtensions { + public static RestClient UseCsvHelper(this RestClient client) { + return client.UseSerializer(); + } + + public static RestClient UseCsvHelper(this RestClient client, CsvConfiguration configuration) { + return client.UseSerializer(() => new CsvHelperSerializer(configuration)); + } + } +} \ No newline at end of file diff --git a/src/RestSharp.Serializers.CsvHelper/RestSharp.Serializers.CsvHelper.csproj b/src/RestSharp.Serializers.CsvHelper/RestSharp.Serializers.CsvHelper.csproj new file mode 100644 index 000000000..174971e7c --- /dev/null +++ b/src/RestSharp.Serializers.CsvHelper/RestSharp.Serializers.CsvHelper.csproj @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/test/RestSharp.Tests.Serializers.Csv/CsvHelperTests.cs b/test/RestSharp.Tests.Serializers.Csv/CsvHelperTests.cs new file mode 100644 index 000000000..98659739b --- /dev/null +++ b/test/RestSharp.Tests.Serializers.Csv/CsvHelperTests.cs @@ -0,0 +1,156 @@ +using CsvHelper.Configuration; +using RestSharp.Serializers.CsvHelper; +using RestSharp.Serializers.Json; +using RestSharp.Tests.Shared.Extensions; +using RestSharp.Tests.Shared.Fixtures; +using System.Globalization; +using System.Net; +using System.Text; + +namespace RestSharp.Tests.Serializers.Csv { + public class CsvHelperTests { + private static readonly Fixture Fixture = new Fixture(); + + [Fact] + public async Task Use_CsvHelper_For_Response() { + var expected = Fixture.Create(); + + expected.DateTimeValue = new DateTime(expected.DateTimeValue.Year, expected.DateTimeValue.Month, expected.DateTimeValue.Day, expected.DateTimeValue.Hour, expected.DateTimeValue.Minute, expected.DateTimeValue.Second); + + using var server = HttpServerFixture.StartServer( + (_, response) => { + var serializer = new CsvHelperSerializer(); + + response.ContentType = "text/csv"; + response.ContentEncoding = Encoding.UTF8; + response.OutputStream.WriteStringUtf8(serializer.Serialize(expected)!); + } + ); + + var client = new RestClient(server.Url).UseCsvHelper(); + + var actual = await client.GetAsync(new RestRequest()); + + actual.Should().BeEquivalentTo(expected); + } + + [Fact] + public async Task Use_CsvHelper_For_Collection_Response() { + var count = Fixture.Create(); + var expected = new List(count); + + for (int i = 0; i < count; i++) { + var item = Fixture.Create(); + + item.DateTimeValue = new DateTime(item.DateTimeValue.Year, item.DateTimeValue.Month, item.DateTimeValue.Day, item.DateTimeValue.Hour, item.DateTimeValue.Minute, item.DateTimeValue.Second); + + expected.Add(item); + } + + using var server = HttpServerFixture.StartServer( + (_, response) => { + var serializer = new CsvHelperSerializer(); + + response.ContentType = "text/csv"; + response.ContentEncoding = Encoding.UTF8; + response.OutputStream.WriteStringUtf8(serializer.Serialize(expected)); + } + ); + + var client = new RestClient(server.Url).UseCsvHelper(); + + var actual = await client.GetAsync>(new RestRequest()); + + actual.Should().BeEquivalentTo(expected); + } + + [Fact] + public async Task DeserilizationFails_IsSuccessfull_Should_BeFalse() { + using var server = HttpServerFixture.StartServer( + (_, response) => { + response.StatusCode = (int)HttpStatusCode.OK; + response.ContentType = "text/csv"; + response.ContentEncoding = Encoding.UTF8; + response.OutputStream.WriteStringUtf8("invalid csv"); + } + ); + + var client = new RestClient(server.Url).UseCsvHelper(); + + var response = await client.ExecuteAsync(new RestRequest()); + + response.IsSuccessStatusCode.Should().BeTrue(); + response.IsSuccessful.Should().BeFalse(); + } + + [Fact] + public async Task DeserilizationSucceeds_IsSuccessfull_Should_BeTrue() { + var item = Fixture.Create(); + + using var server = HttpServerFixture.StartServer( + (_, response) => { + var serializer = new SystemTextJsonSerializer(); + + response.StatusCode = (int)HttpStatusCode.OK; + response.ContentType = "text/csv"; + response.ContentEncoding = Encoding.UTF8; + response.OutputStream.WriteStringUtf8(serializer.Serialize(item)!); + } + ); + + var client = new RestClient(server.Url).UseSystemTextJson(); + + var response = await client.ExecuteAsync(new RestRequest()); + + response.IsSuccessStatusCode.Should().BeTrue(); + response.IsSuccessful.Should().BeTrue(); + } + + [Fact] + public async Task SerializedObject_Should_Be() { + var serializer = new CsvHelperSerializer(new CsvConfiguration(CultureInfo.InvariantCulture) { + NewLine = ";" + }); + + var item = new TestObject() { + Int32Value = 32, + SingleValue = 16.5f, + StringValue = "hello", + TimeSpanValue = TimeSpan.FromMinutes(10), + DateTimeValue = new DateTime(2024, 1, 20) + }; + + serializer.Serialize(item).Should().Be("StringValue,Int32Value,DecimalValue,DoubleValue,SingleValue,DateTimeValue,TimeSpanValue;hello,32,0,0,16.5,01/20/2024 00:00:00,00:10:00;"); + } + + [Fact] + public async Task SerializedCollection_Should_Be() { + var serializer = new CsvHelperSerializer(new CsvConfiguration(CultureInfo.InvariantCulture) { + NewLine = ";" + }); + + var items = new TestObject[] { + new TestObject() { + Int32Value = 32, + SingleValue = 16.5f, + StringValue = "hello", + TimeSpanValue = TimeSpan.FromMinutes(10), + DateTimeValue = new DateTime(2024, 1, 20) + }, + new TestObject() { + Int32Value = 65, + DecimalValue = 89.555m, + TimeSpanValue = TimeSpan.FromSeconds(61), + DateTimeValue = new DateTime(2022, 8, 19, 5, 15, 21) + }, + new TestObject() { + SingleValue = 80000, + DoubleValue = 20.00001, + StringValue = "String, with comma" + } + }; + + serializer.Serialize(items).Should().Be("StringValue,Int32Value,DecimalValue,DoubleValue,SingleValue,DateTimeValue,TimeSpanValue;hello,32,0,0,16.5,01/20/2024 00:00:00,00:10:00;,65,89.555,0,0,08/19/2022 05:15:21,00:01:01;\"String, with comma\",0,0,20.00001,80000,01/01/0001 00:00:00,00:00:00;"); + } + } +} diff --git a/test/RestSharp.Tests.Serializers.Csv/RestSharp.Tests.Serializers.Csv.csproj b/test/RestSharp.Tests.Serializers.Csv/RestSharp.Tests.Serializers.Csv.csproj new file mode 100644 index 000000000..da85d7934 --- /dev/null +++ b/test/RestSharp.Tests.Serializers.Csv/RestSharp.Tests.Serializers.Csv.csproj @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/test/RestSharp.Tests.Serializers.Csv/TestObject.cs b/test/RestSharp.Tests.Serializers.Csv/TestObject.cs new file mode 100644 index 000000000..f6eac2b67 --- /dev/null +++ b/test/RestSharp.Tests.Serializers.Csv/TestObject.cs @@ -0,0 +1,11 @@ +namespace RestSharp.Tests.Serializers.Csv { + internal class TestObject { + public string StringValue { get; set; } + public int Int32Value { get; set; } + public decimal DecimalValue { get; set; } + public double DoubleValue { get; set; } + public float SingleValue { get; set; } + public DateTime DateTimeValue { get; set; } + public TimeSpan TimeSpanValue { get; set; } + } +}