From 6a0c7c417bc49ba950cc386dfb490ebc1ecc4633 Mon Sep 17 00:00:00 2001 From: Jan Korf Date: Wed, 28 Nov 2018 21:51:39 +0100 Subject: [PATCH] Initial unit test --- .../BaseClientTests.cs | 123 +++++++ .../ExchangeClientTests.cs | 336 +++++++++--------- .../RestClientTests.cs | 81 +++++ .../TestBaseClient.cs} | 36 +- .../TestImplementations/TestHelpers.cs | 51 +++ .../TestImplementations/TestObjects.cs | 15 + .../TestImplementations/TestRestClient.cs | 115 ++++++ CryptoExchange.Net/BaseClient.cs | 23 +- CryptoExchange.Net/Logging/Log.cs | 7 +- 9 files changed, 595 insertions(+), 192 deletions(-) create mode 100644 CryptoExchange.Net.UnitTests/BaseClientTests.cs create mode 100644 CryptoExchange.Net.UnitTests/RestClientTests.cs rename CryptoExchange.Net.UnitTests/{TestImplementation.cs => TestImplementations/TestBaseClient.cs} (54%) create mode 100644 CryptoExchange.Net.UnitTests/TestImplementations/TestHelpers.cs create mode 100644 CryptoExchange.Net.UnitTests/TestImplementations/TestObjects.cs create mode 100644 CryptoExchange.Net.UnitTests/TestImplementations/TestRestClient.cs diff --git a/CryptoExchange.Net.UnitTests/BaseClientTests.cs b/CryptoExchange.Net.UnitTests/BaseClientTests.cs new file mode 100644 index 0000000..a27fbda --- /dev/null +++ b/CryptoExchange.Net.UnitTests/BaseClientTests.cs @@ -0,0 +1,123 @@ +using CryptoExchange.Net.Authentication; +using CryptoExchange.Net.Logging; +using CryptoExchange.Net.Objects; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace CryptoExchange.Net.UnitTests +{ + [TestFixture()] + public class BaseClientTests + { + [TestCase(null, null)] + [TestCase("", "")] + [TestCase("test", null)] + [TestCase("test", "")] + [TestCase(null, "test")] + [TestCase("", "test")] + public void SettingEmptyValuesForAPICredentials_Should_ThrowException(string key, string secret) + { + // arrange + // act + // assert + Assert.Throws(typeof(ArgumentException), () => new TestBaseClient(new ClientOptions() { ApiCredentials = new ApiCredentials(key, secret) })); + } + + [TestCase] + public void SettingLogOutput_Should_RedirectLogOutput() + { + // arrange + var stringBuilder = new StringBuilder(); + var client = new TestBaseClient(new ClientOptions() + { + LogWriters = new List { new StringWriter(stringBuilder) } + }); + + // act + client.Log(LogVerbosity.Info, "Test"); + + // assert + Assert.IsFalse(string.IsNullOrEmpty(stringBuilder.ToString())); + } + + [TestCase(LogVerbosity.None, LogVerbosity.Error, false)] + [TestCase(LogVerbosity.None, LogVerbosity.Warning, false)] + [TestCase(LogVerbosity.None, LogVerbosity.Info, false)] + [TestCase(LogVerbosity.None, LogVerbosity.Debug, false)] + [TestCase(LogVerbosity.Error, LogVerbosity.Error, true)] + [TestCase(LogVerbosity.Error, LogVerbosity.Warning, false)] + [TestCase(LogVerbosity.Error, LogVerbosity.Info, false)] + [TestCase(LogVerbosity.Error, LogVerbosity.Debug, false)] + [TestCase(LogVerbosity.Warning, LogVerbosity.Error, true)] + [TestCase(LogVerbosity.Warning, LogVerbosity.Warning, true)] + [TestCase(LogVerbosity.Warning, LogVerbosity.Info, false)] + [TestCase(LogVerbosity.Warning, LogVerbosity.Debug, false)] + [TestCase(LogVerbosity.Info, LogVerbosity.Error, true)] + [TestCase(LogVerbosity.Info, LogVerbosity.Warning, true)] + [TestCase(LogVerbosity.Info, LogVerbosity.Info, true)] + [TestCase(LogVerbosity.Info, LogVerbosity.Debug, false)] + [TestCase(LogVerbosity.Debug, LogVerbosity.Error, true)] + [TestCase(LogVerbosity.Debug, LogVerbosity.Warning, true)] + [TestCase(LogVerbosity.Debug, LogVerbosity.Info, true)] + [TestCase(LogVerbosity.Debug, LogVerbosity.Debug, true)] + public void SettingLogVerbosity_Should_RestrictLogging(LogVerbosity verbosity, LogVerbosity testVerbosity, bool expected) + { + // arrange + var stringBuilder = new StringBuilder(); + var client = new TestBaseClient(new ClientOptions() + { + LogWriters = new List { new StringWriter(stringBuilder) }, + LogVerbosity = verbosity + }); + + // act + client.Log(testVerbosity, "Test"); + + // assert + Assert.AreEqual(!string.IsNullOrEmpty(stringBuilder.ToString()), expected); + } + + [TestCase] + public void DeserializingValidJson_Should_GiveSuccessfulResult() + { + // arrange + var client = new TestBaseClient(); + + // act + var result = client.Deserialize("{\"testProperty\": 123}"); + + // assert + Assert.IsTrue(result.Success); + } + + [TestCase] + public void DeserializingInvalidJson_Should_GiveErrorResult() + { + // arrange + var client = new TestBaseClient(); + + // act + var result = client.Deserialize("{\"testProperty\": 123"); + + // assert + Assert.IsFalse(result.Success); + Assert.IsTrue(result.Error != null); + } + + [TestCase] + public void FillingPathParameters_Should_ResultInValidUrl() + { + // arrange + var client = new TestBaseClient(); + + // act + var result = client.FillParameters("http://test.api/{}/path/{}", "1", "test"); + + // assert + Assert.IsTrue(result == "http://test.api/1/path/test"); + } + } +} diff --git a/CryptoExchange.Net.UnitTests/ExchangeClientTests.cs b/CryptoExchange.Net.UnitTests/ExchangeClientTests.cs index 2ba836a..9c4dc2b 100644 --- a/CryptoExchange.Net.UnitTests/ExchangeClientTests.cs +++ b/CryptoExchange.Net.UnitTests/ExchangeClientTests.cs @@ -21,207 +21,207 @@ namespace CryptoExchange.Net.UnitTests [TestFixture()] public class ExchangeClientTests { - [TestCase(null, null)] - [TestCase("", "")] - [TestCase("test", null)] - [TestCase("test", "")] - [TestCase(null, "test")] - [TestCase("", "test")] - public void SettingEmptyValuesForAPICredentials_Should_ThrowException(string key, string secret) - { - // arrange - var client = PrepareClient(""); + //[TestCase(null, null)] + //[TestCase("", "")] + //[TestCase("test", null)] + //[TestCase("test", "")] + //[TestCase(null, "test")] + //[TestCase("", "test")] + //public void SettingEmptyValuesForAPICredentials_Should_ThrowException(string key, string secret) + //{ + // // arrange + // var client = PrepareClient(""); - // act - // assert - Assert.Throws(typeof(ArgumentException), () => client.SetApiCredentails(key, secret)); - } + // // act + // // assert + // Assert.Throws(typeof(ArgumentException), () => client.SetApiCredentails(key, secret)); + //} - [TestCase()] - public void SettingLogOutput_Should_RedirectLogOutput() - { - // arrange - var stringBuilder = new StringBuilder(); - var client = PrepareClient("{}", true, LogVerbosity.Debug, new StringWriter(stringBuilder)); + //[TestCase()] + //public void SettingLogOutput_Should_RedirectLogOutput() + //{ + // // arrange + // var stringBuilder = new StringBuilder(); + // var client = PrepareClient("{}", true, LogVerbosity.Debug, new StringWriter(stringBuilder)); - // act - client.TestCall(); + // // act + // client.TestCall(); - // assert - Assert.IsFalse(string.IsNullOrEmpty(stringBuilder.ToString())); - } + // // assert + // Assert.IsFalse(string.IsNullOrEmpty(stringBuilder.ToString())); + //} - [TestCase()] - public void ObjectDeserializationFail_Should_GiveFailedResult() - { - // arrange - var errorMessage = "TestErrorMessage"; - var client = PrepareClient(JsonConvert.SerializeObject(errorMessage)); + //[TestCase()] + //public void ObjectDeserializationFail_Should_GiveFailedResult() + //{ + // // arrange + // var errorMessage = "TestErrorMessage"; + // var client = PrepareClient(JsonConvert.SerializeObject(errorMessage)); - // act - var result = client.TestCall(); + // // act + // var result = client.TestCall(); - // assert - Assert.IsFalse(result.Success); - Assert.AreNotEqual(0, result.Error.Code); - Assert.IsTrue(result.Error.Message.Contains(errorMessage)); - } + // // assert + // Assert.IsFalse(result.Success); + // Assert.AreNotEqual(0, result.Error.Code); + // Assert.IsTrue(result.Error.Message.Contains(errorMessage)); + //} - [TestCase()] - public void InvalidJson_Should_GiveFailedResult() - { - // arrange - var errorMessage = "TestErrorMessage"; - var client = PrepareClient(JsonConvert.SerializeObject(errorMessage)); + //[TestCase()] + //public void InvalidJson_Should_GiveFailedResult() + //{ + // // arrange + // var errorMessage = "TestErrorMessage"; + // var client = PrepareClient(JsonConvert.SerializeObject(errorMessage)); - // act - var result = client.TestCall(); + // // act + // var result = client.TestCall(); - // assert - Assert.IsFalse(result.Success); - Assert.AreNotEqual(0, result.Error.Code); - Assert.IsTrue(result.Error.Message.Contains(errorMessage)); - } + // // assert + // Assert.IsFalse(result.Success); + // Assert.AreNotEqual(0, result.Error.Code); + // Assert.IsTrue(result.Error.Message.Contains(errorMessage)); + //} - [TestCase()] - public void WhenUsingRateLimiterTotalRequests_Should_BeDelayed() - { - // arrange - var client = PrepareClient(JsonConvert.SerializeObject(new TestObject())); - client.AddRateLimiter(new RateLimiterTotal(1, TimeSpan.FromSeconds(5))); + //[TestCase()] + //public void WhenUsingRateLimiterTotalRequests_Should_BeDelayed() + //{ + // // arrange + // var client = PrepareClient(JsonConvert.SerializeObject(new TestObject())); + // client.AddRateLimiter(new RateLimiterTotal(1, TimeSpan.FromSeconds(5))); - // act - var sw = Stopwatch.StartNew(); - client.TestCall(); - client.TestCall(); - client.TestCall(); - sw.Stop(); + // // act + // var sw = Stopwatch.StartNew(); + // client.TestCall(); + // client.TestCall(); + // client.TestCall(); + // sw.Stop(); - // assert - Assert.IsTrue(sw.ElapsedMilliseconds > 9000); - } + // // assert + // Assert.IsTrue(sw.ElapsedMilliseconds > 9000); + //} - [TestCase()] - public void WhenUsingRateLimiterPerEndpointRequests_Should_BeDelayed() - { - // arrange - var client = PrepareClient(JsonConvert.SerializeObject(new TestObject())); - client.AddRateLimiter(new RateLimiterTotal(1, TimeSpan.FromSeconds(5))); + //[TestCase()] + //public void WhenUsingRateLimiterPerEndpointRequests_Should_BeDelayed() + //{ + // // arrange + // var client = PrepareClient(JsonConvert.SerializeObject(new TestObject())); + // client.AddRateLimiter(new RateLimiterTotal(1, TimeSpan.FromSeconds(5))); - // act - var sw = Stopwatch.StartNew(); - client.TestCall(); - client.TestCall(); - client.TestCall(); - sw.Stop(); + // // act + // var sw = Stopwatch.StartNew(); + // client.TestCall(); + // client.TestCall(); + // client.TestCall(); + // sw.Stop(); - // assert - Assert.IsTrue(sw.ElapsedMilliseconds > 9000); - } + // // assert + // Assert.IsTrue(sw.ElapsedMilliseconds > 9000); + //} - [TestCase()] - public void WhenRemovingRateLimiterRequest_Should_NoLongerBeDelayed() - { - // arrange - var client = PrepareClient(JsonConvert.SerializeObject(new TestObject())); - client.AddRateLimiter(new RateLimiterTotal(1, TimeSpan.FromSeconds(5))); - client.RemoveRateLimiters(); + //[TestCase()] + //public void WhenRemovingRateLimiterRequest_Should_NoLongerBeDelayed() + //{ + // // arrange + // var client = PrepareClient(JsonConvert.SerializeObject(new TestObject())); + // client.AddRateLimiter(new RateLimiterTotal(1, TimeSpan.FromSeconds(5))); + // client.RemoveRateLimiters(); - // act - var sw = Stopwatch.StartNew(); - client.TestCall(); - client.TestCall(); - client.TestCall(); - sw.Stop(); + // // act + // var sw = Stopwatch.StartNew(); + // client.TestCall(); + // client.TestCall(); + // client.TestCall(); + // sw.Stop(); - // assert - Assert.IsTrue(sw.ElapsedMilliseconds < 5000); - } + // // assert + // Assert.IsTrue(sw.ElapsedMilliseconds < 5000); + //} - [TestCase()] - public void ReceivingErrorStatusCode_Should_NotSuccess() - { - // arrange - var client = PrepareExceptionClient(JsonConvert.SerializeObject(new TestObject()), "InvalidStatusCodeResponse", 203); + //[TestCase()] + //public void ReceivingErrorStatusCode_Should_NotSuccess() + //{ + // // arrange + // var client = PrepareExceptionClient(JsonConvert.SerializeObject(new TestObject()), "InvalidStatusCodeResponse", 203); - // act - var result = client.TestCall(); + // // act + // var result = client.TestCall(); - // assert - Assert.IsFalse(result.Success); - Assert.IsNotNull(result.Error); - Assert.IsTrue(result.Error.Message.Contains("InvalidStatusCodeResponse")); - } + // // assert + // Assert.IsFalse(result.Success); + // Assert.IsNotNull(result.Error); + // Assert.IsTrue(result.Error.Message.Contains("InvalidStatusCodeResponse")); + //} - private TestImplementation PrepareClient(string responseData, bool withOptions = true, LogVerbosity verbosity = LogVerbosity.Warning, TextWriter tw = null) - { - var expectedBytes = Encoding.UTF8.GetBytes(responseData); - var responseStream = new MemoryStream(); - responseStream.Write(expectedBytes, 0, expectedBytes.Length); - responseStream.Seek(0, SeekOrigin.Begin); + //private TestRestClient PrepareClient(string responseData, bool withOptions = true, LogVerbosity verbosity = LogVerbosity.Warning, TextWriter tw = null) + //{ + // var expectedBytes = Encoding.UTF8.GetBytes(responseData); + // var responseStream = new MemoryStream(); + // responseStream.Write(expectedBytes, 0, expectedBytes.Length); + // responseStream.Seek(0, SeekOrigin.Begin); - var response = new Mock(); - response.Setup(c => c.GetResponseStream()).Returns(responseStream); + // var response = new Mock(); + // response.Setup(c => c.GetResponseStream()).Returns(responseStream); - var request = new Mock(); - request.Setup(c => c.Headers).Returns(new WebHeaderCollection()); - request.Setup(c => c.Uri).Returns(new Uri("http://www.test.com")); - request.Setup(c => c.GetResponse()).Returns(Task.FromResult(response.Object)); + // var request = new Mock(); + // request.Setup(c => c.Headers).Returns(new WebHeaderCollection()); + // request.Setup(c => c.Uri).Returns(new Uri("http://www.test.com")); + // request.Setup(c => c.GetResponse()).Returns(Task.FromResult(response.Object)); - var factory = new Mock(); - factory.Setup(c => c.Create(It.IsAny())) - .Returns(request.Object); - TestImplementation client; - if (withOptions) - { - var options = new ClientOptions() - { - ApiCredentials = new ApiCredentials("Test", "Test2"), - LogVerbosity = verbosity - }; - if (tw != null) - options.LogWriters = new List() { tw }; + // var factory = new Mock(); + // factory.Setup(c => c.Create(It.IsAny())) + // .Returns(request.Object); + // TestRestClient client; + // if (withOptions) + // { + // var options = new ClientOptions() + // { + // ApiCredentials = new ApiCredentials("Test", "Test2"), + // LogVerbosity = verbosity + // }; + // if (tw != null) + // options.LogWriters = new List() { tw }; - client = new TestImplementation(options); - } - else - { - client = new TestImplementation(); - } - client.RequestFactory = factory.Object; - return client; - } + // client = new TestRestClient(options); + // } + // else + // { + // client = new TestRestClient(); + // } + // client.RequestFactory = factory.Object; + // return client; + //} - private TestImplementation PrepareExceptionClient(string responseData, string exceptionMessage, int statusCode, bool credentials = true) - { - var expectedBytes = Encoding.UTF8.GetBytes(responseData); - var responseStream = new MemoryStream(); - responseStream.Write(expectedBytes, 0, expectedBytes.Length); - responseStream.Seek(0, SeekOrigin.Begin); + //private TestRestClient PrepareExceptionClient(string responseData, string exceptionMessage, int statusCode, bool credentials = true) + //{ + // var expectedBytes = Encoding.UTF8.GetBytes(responseData); + // var responseStream = new MemoryStream(); + // responseStream.Write(expectedBytes, 0, expectedBytes.Length); + // responseStream.Seek(0, SeekOrigin.Begin); - var we = new WebException(); - var r = new HttpWebResponse(); - var re = new HttpResponseMessage(); + // var we = new WebException(); + // var r = new HttpWebResponse(); + // var re = new HttpResponseMessage(); - typeof(HttpResponseMessage).GetField("_statusCode", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(re, (HttpStatusCode)statusCode); - typeof(HttpWebResponse).GetField("_httpResponseMessage", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(r, re); - typeof(WebException).GetField("_message", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(we, exceptionMessage); - typeof(WebException).GetField("_response", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(we, r); + // typeof(HttpResponseMessage).GetField("_statusCode", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(re, (HttpStatusCode)statusCode); + // typeof(HttpWebResponse).GetField("_httpResponseMessage", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(r, re); + // typeof(WebException).GetField("_message", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(we, exceptionMessage); + // typeof(WebException).GetField("_response", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(we, r); - var response = new Mock(); - response.Setup(c => c.GetResponseStream()).Throws(we); + // var response = new Mock(); + // response.Setup(c => c.GetResponseStream()).Throws(we); - var request = new Mock(); - request.Setup(c => c.Headers).Returns(new WebHeaderCollection()); - request.Setup(c => c.GetResponse()).Returns(Task.FromResult(response.Object)); + // var request = new Mock(); + // request.Setup(c => c.Headers).Returns(new WebHeaderCollection()); + // request.Setup(c => c.GetResponse()).Returns(Task.FromResult(response.Object)); - var factory = new Mock(); - factory.Setup(c => c.Create(It.IsAny())) - .Returns(request.Object); + // var factory = new Mock(); + // factory.Setup(c => c.Create(It.IsAny())) + // .Returns(request.Object); - TestImplementation client = credentials ? new TestImplementation(new ClientOptions() { ApiCredentials = new ApiCredentials("Test", "Test2") }) : new TestImplementation(); - client.RequestFactory = factory.Object; - return client; - } + // TestRestClient client = credentials ? new TestRestClient(new ClientOptions() { ApiCredentials = new ApiCredentials("Test", "Test2") }) : new TestRestClient(); + // client.RequestFactory = factory.Object; + // return client; + //} } } diff --git a/CryptoExchange.Net.UnitTests/RestClientTests.cs b/CryptoExchange.Net.UnitTests/RestClientTests.cs new file mode 100644 index 0000000..988e22d --- /dev/null +++ b/CryptoExchange.Net.UnitTests/RestClientTests.cs @@ -0,0 +1,81 @@ +using CryptoExchange.Net.Authentication; +using CryptoExchange.Net.Logging; +using CryptoExchange.Net.Objects; +using CryptoExchange.Net.UnitTests.TestImplementations; +using Newtonsoft.Json; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace CryptoExchange.Net.UnitTests +{ + [TestFixture()] + public class RestClientTests + { + [TestCase] + public void RequestingData_Should_ResultInData() + { + // arrange + var client = new TestRestClient(); + var expected = new TestObject() { DecimalData = 1.23M, IntData = 10, StringData = "Some data" }; + client.SetResponse(JsonConvert.SerializeObject(expected)); + + // act + var result = client.Request().Result; + + // assert + Assert.IsTrue(result.Success); + Assert.IsTrue(TestHelpers.AreEqual(expected, result.Data)); + } + + [TestCase] + public void ReceivingInvalidData_Should_ResultInError() + { + // arrange + var client = new TestRestClient(); + client.SetResponse("{\"property\": 123"); + + // act + var result = client.Request().Result; + + // assert + Assert.IsFalse(result.Success); + Assert.IsTrue(result.Error != null); + } + + [TestCase] + public void ReceivingErrorCode_Should_ResultInError() + { + // arrange + var client = new TestRestClient(); + client.SetErrorWithoutResponse(System.Net.HttpStatusCode.BadRequest, "Invalid request"); + + // act + var result = client.Request().Result; + + // assert + Assert.IsFalse(result.Success); + Assert.IsTrue(result.Error != null); + } + + [TestCase] + public void ReceivingErrorAndParsingError_Should_ResultInParsedError() + { + // arrange + var client = new ParseErrorTestRestClient(); + client.SetErrorWithResponse("{\"errorMessage\": \"Invalid request\", \"errorCode\": 123}", System.Net.HttpStatusCode.BadRequest); + + // act + var result = client.Request().Result; + + // assert + Assert.IsFalse(result.Success); + Assert.IsTrue(result.Error != null); + Assert.IsTrue(result.Error is ServerError); + Assert.IsTrue(result.Error.Code == 123); + Assert.IsTrue(result.Error.Message == "Invalid request"); + } + } +} diff --git a/CryptoExchange.Net.UnitTests/TestImplementation.cs b/CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs similarity index 54% rename from CryptoExchange.Net.UnitTests/TestImplementation.cs rename to CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs index 8ac145e..9357401 100644 --- a/CryptoExchange.Net.UnitTests/TestImplementation.cs +++ b/CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs @@ -1,27 +1,33 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using CryptoExchange.Net.Authentication; -using CryptoExchange.Net.Interfaces; +using CryptoExchange.Net.Logging; using CryptoExchange.Net.Objects; namespace CryptoExchange.Net.UnitTests { - public class TestImplementation: RestClient - { - public TestImplementation(): base(new ClientOptions(), null) { } - - public TestImplementation(ClientOptions exchangeOptions) : base(exchangeOptions, exchangeOptions.ApiCredentials == null ? null : new TestAuthProvider(exchangeOptions.ApiCredentials)) + public class TestBaseClient: BaseClient + { + public TestBaseClient(): base(new ClientOptions(), null) { } - public void SetApiCredentails(string key, string secret) + public TestBaseClient(ClientOptions exchangeOptions) : base(exchangeOptions, exchangeOptions.ApiCredentials == null ? null : new TestAuthProvider(exchangeOptions.ApiCredentials)) { - SetAuthenticationProvider(new TestAuthProvider(new ApiCredentials(key, secret))); } - public CallResult TestCall() + public void Log(LogVerbosity verbosity, string data) { - return ExecuteRequest(new Uri("http://www.test.com")).Result; + log.Write(verbosity, data); + } + + public CallResult Deserialize(string data) + { + return Deserialize(data, false); + } + + public string FillParameters(string path, params string[] values) + { + return FillPathParameter(path, values); } } @@ -46,10 +52,4 @@ namespace CryptoExchange.Net.UnitTests return toSign; } } - - public class TestObject - { - public int Id { get; set; } - public List Data { get; set; } - } } diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/TestHelpers.cs b/CryptoExchange.Net.UnitTests/TestImplementations/TestHelpers.cs new file mode 100644 index 0000000..b856d0f --- /dev/null +++ b/CryptoExchange.Net.UnitTests/TestImplementations/TestHelpers.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Text; + +namespace CryptoExchange.Net.UnitTests.TestImplementations +{ + public class TestHelpers + { + [ExcludeFromCodeCoverage] + public static bool AreEqual(T self, T to, params string[] ignore) where T : class + { + if (self != null && to != null) + { + var type = self.GetType(); + var ignoreList = new List(ignore); + foreach (var pi in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)) + { + if (ignoreList.Contains(pi.Name)) + { + continue; + } + + var selfValue = type.GetProperty(pi.Name).GetValue(self, null); + var toValue = type.GetProperty(pi.Name).GetValue(to, null); + + if (pi.PropertyType.IsClass && !pi.PropertyType.Module.ScopeName.Equals("System.Private.CoreLib.dll")) + { + // Check of "CommonLanguageRuntimeLibrary" is needed because string is also a class + if (AreEqual(selfValue, toValue, ignore)) + { + continue; + } + + return false; + } + + if (selfValue != toValue && (selfValue == null || !selfValue.Equals(toValue))) + { + return false; + } + } + + return true; + } + + return self == to; + } + } +} diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/TestObjects.cs b/CryptoExchange.Net.UnitTests/TestImplementations/TestObjects.cs new file mode 100644 index 0000000..7a6f2cc --- /dev/null +++ b/CryptoExchange.Net.UnitTests/TestImplementations/TestObjects.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Text; + +namespace CryptoExchange.Net.UnitTests.TestImplementations +{ + public class TestObject + { + [JsonProperty("other")] + public string StringData { get; set; } + public int IntData { get; set; } + public decimal DecimalData { get; set; } + } +} diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/TestRestClient.cs b/CryptoExchange.Net.UnitTests/TestImplementations/TestRestClient.cs new file mode 100644 index 0000000..e9248af --- /dev/null +++ b/CryptoExchange.Net.UnitTests/TestImplementations/TestRestClient.cs @@ -0,0 +1,115 @@ +using CryptoExchange.Net.Interfaces; +using CryptoExchange.Net.Objects; +using Moq; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Http; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace CryptoExchange.Net.UnitTests.TestImplementations +{ + public class TestRestClient: RestClient + { + public TestRestClient() : base(new ClientOptions(), null) + { + RequestFactory = new Mock().Object; + } + + public TestRestClient(ClientOptions exchangeOptions) : base(exchangeOptions, exchangeOptions.ApiCredentials == null ? null : new TestAuthProvider(exchangeOptions.ApiCredentials)) + { + } + + public void SetResponse(string responseData) + { + var expectedBytes = Encoding.UTF8.GetBytes(responseData); + var responseStream = new MemoryStream(); + responseStream.Write(expectedBytes, 0, expectedBytes.Length); + responseStream.Seek(0, SeekOrigin.Begin); + + var response = new Mock(); + response.Setup(c => c.GetResponseStream()).Returns(responseStream); + + var request = new Mock(); + request.Setup(c => c.Headers).Returns(new WebHeaderCollection()); + request.Setup(c => c.Uri).Returns(new Uri("http://www.test.com")); + request.Setup(c => c.GetResponse()).Returns(Task.FromResult(response.Object)); + + var factory = Mock.Get(RequestFactory); + factory.Setup(c => c.Create(It.IsAny())) + .Returns(request.Object); + } + + public void SetErrorWithoutResponse(HttpStatusCode code, string message) + { + var we = new WebException(); + var r = new HttpWebResponse(); + var re = new HttpResponseMessage(); + + typeof(HttpResponseMessage).GetField("_statusCode", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(re, code); + typeof(HttpWebResponse).GetField("_httpResponseMessage", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(r, re); + typeof(WebException).GetField("_message", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(we, message); + typeof(WebException).GetField("_response", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(we, r); + + var response = new Mock(); + response.Setup(c => c.GetResponseStream()).Throws(we); + + var request = new Mock(); + request.Setup(c => c.Headers).Returns(new WebHeaderCollection()); + request.Setup(c => c.GetResponse()).Returns(Task.FromResult(response.Object)); + + var factory = Mock.Get(RequestFactory); + factory.Setup(c => c.Create(It.IsAny())) + .Returns(request.Object); + } + + public void SetErrorWithResponse(string responseData, HttpStatusCode code) + { + var expectedBytes = Encoding.UTF8.GetBytes(responseData); + var responseStream = new MemoryStream(); + responseStream.Write(expectedBytes, 0, expectedBytes.Length); + responseStream.Seek(0, SeekOrigin.Begin); + + var we = new WebException(); + var r = new HttpWebResponse(); + var re = new HttpResponseMessage(); + + typeof(HttpResponseMessage).GetField("_statusCode", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(re, code); + typeof(HttpWebResponse).GetField("_httpResponseMessage", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(r, re); + typeof(WebException).GetField("_message", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(we, ""); + typeof(WebException).GetField("_response", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(we, r); + + var response = new Mock(); + response.Setup(c => c.GetResponseStream()).Returns(responseStream); + + var request = new Mock(); + request.Setup(c => c.Headers).Returns(new WebHeaderCollection()); + request.Setup(c => c.GetResponse()).Returns(Task.FromResult(response.Object)); + + var factory = Mock.Get(RequestFactory); + factory.Setup(c => c.Create(It.IsAny())) + .Returns(request.Object); + } + + public async Task> Request() where T:class + { + return await ExecuteRequest(new Uri("http://www.test.com")); + } + } + + public class ParseErrorTestRestClient: TestRestClient + { + public ParseErrorTestRestClient() { } + public ParseErrorTestRestClient(ClientOptions exchangeOptions) : base(exchangeOptions) { } + + protected override Error ParseErrorResponse(string error) + { + var data = JToken.Parse(error); + return new ServerError((int)data["errorCode"], (string)data["errorMessage"]); + } + } +} diff --git a/CryptoExchange.Net/BaseClient.cs b/CryptoExchange.Net/BaseClient.cs index f725c61..a938bf2 100644 --- a/CryptoExchange.Net/BaseClient.cs +++ b/CryptoExchange.Net/BaseClient.cs @@ -70,7 +70,28 @@ namespace CryptoExchange.Net /// protected CallResult Deserialize(string data, bool checkObject = true, JsonSerializer serializer = null) { - return Deserialize(JToken.Parse(data), checkObject, serializer); + try + { + return Deserialize(JToken.Parse(data), checkObject, serializer); + } + catch (JsonReaderException jre) + { + var info = $"Deserialize JsonReaderException: {jre.Message}, Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}. Data: {data}"; + log.Write(LogVerbosity.Error, info); + return new CallResult(default(T), new DeserializeError(info)); + } + catch (JsonSerializationException jse) + { + var info = $"Deserialize JsonSerializationException: {jse.Message}. Data: {data}"; + log.Write(LogVerbosity.Error, info); + return new CallResult(default(T), new DeserializeError(info)); + } + catch (Exception ex) + { + var info = $"Deserialize Unknown Exception: {ex.Message}. Data: {data}"; + log.Write(LogVerbosity.Error, info); + return new CallResult(default(T), new DeserializeError(info)); + } } /// diff --git a/CryptoExchange.Net/Logging/Log.cs b/CryptoExchange.Net/Logging/Log.cs index 98823bd..e98cf78 100644 --- a/CryptoExchange.Net/Logging/Log.cs +++ b/CryptoExchange.Net/Logging/Log.cs @@ -17,11 +17,8 @@ namespace CryptoExchange.Net.Logging get => level; set { - if (level != value) - { - Write(LogVerbosity.Info, "Loglevel set to " + value); - level = value; - } + if (level != value) + level = value; } }