From 1de446493e70a40099e4cbc96f5e148128500e25 Mon Sep 17 00:00:00 2001 From: JKorf Date: Tue, 31 Mar 2026 21:42:31 +0200 Subject: [PATCH] wip --- .../CallResultTests.cs | 1 - .../{ => ClientTests}/BaseClientTests.cs | 3 +- .../{ => ClientTests}/RestClientTests.cs | 89 ++-- .../ClientTests/SocketClientTests.cs | 251 +++++++++ .../ConverterTests/ArrayConverterTests.cs | 109 ++++ .../ConverterTests/BoolConverterTests.cs | 57 ++ .../ConverterTests/DateTimeConverterTests.cs | 119 +++++ .../ConverterTests/DecimalConverterTests.cs | 49 ++ .../ConverterTests/EnumConverterTests.cs | 147 ++++++ .../SharedModelConversionTests.cs | 46 ++ .../TestAuthenticationProvider.cs | 2 - .../Implementations/TestCredentials.cs | 2 - .../Implementations/TestEnvironment.cs | 3 - .../Implementations/TestRestApiClient.cs | 17 +- .../Implementations/TestRestClient.cs | 6 - .../Implementations/TestRestMessageHandler.cs | 33 ++ .../Implementations/TestRestOptions.cs | 3 - .../TestSerializerContext.cs | 13 +- .../Implementations/TestSocketApiClient.cs | 21 +- .../Implementations/TestSocketClient.cs | 26 + .../TestSocketMessageHandler.cs | 26 + .../Implementations/TestSubscription.cs | 34 ++ CryptoExchange.Net.UnitTests/OptionsTests.cs | 3 +- .../SharedQuantityTests.cs | 1 - .../SocketClientTests.cs | 234 --------- .../SystemTextJsonConverterTests.cs | 490 ------------------ .../TestImplementations/TestBaseClient.cs | 88 ---- .../TestImplementations/TestHelpers.cs | 49 -- .../TestImplementations/TestObjects.cs | 14 - .../TestImplementations/TestRestClient.cs | 213 -------- .../TestRestMessageHandler.cs | 32 -- 31 files changed, 972 insertions(+), 1209 deletions(-) rename CryptoExchange.Net.UnitTests/{ => ClientTests}/BaseClientTests.cs (95%) rename CryptoExchange.Net.UnitTests/{ => ClientTests}/RestClientTests.cs (83%) create mode 100644 CryptoExchange.Net.UnitTests/ClientTests/SocketClientTests.cs create mode 100644 CryptoExchange.Net.UnitTests/ConverterTests/ArrayConverterTests.cs create mode 100644 CryptoExchange.Net.UnitTests/ConverterTests/BoolConverterTests.cs create mode 100644 CryptoExchange.Net.UnitTests/ConverterTests/DateTimeConverterTests.cs create mode 100644 CryptoExchange.Net.UnitTests/ConverterTests/DecimalConverterTests.cs create mode 100644 CryptoExchange.Net.UnitTests/ConverterTests/EnumConverterTests.cs create mode 100644 CryptoExchange.Net.UnitTests/ConverterTests/SharedModelConversionTests.cs create mode 100644 CryptoExchange.Net.UnitTests/Implementations/TestRestMessageHandler.cs rename CryptoExchange.Net.UnitTests/{ => Implementations}/TestSerializerContext.cs (51%) create mode 100644 CryptoExchange.Net.UnitTests/Implementations/TestSocketClient.cs create mode 100644 CryptoExchange.Net.UnitTests/Implementations/TestSocketMessageHandler.cs create mode 100644 CryptoExchange.Net.UnitTests/Implementations/TestSubscription.cs delete mode 100644 CryptoExchange.Net.UnitTests/SocketClientTests.cs delete mode 100644 CryptoExchange.Net.UnitTests/SystemTextJsonConverterTests.cs delete mode 100644 CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs delete mode 100644 CryptoExchange.Net.UnitTests/TestImplementations/TestHelpers.cs delete mode 100644 CryptoExchange.Net.UnitTests/TestImplementations/TestObjects.cs delete mode 100644 CryptoExchange.Net.UnitTests/TestImplementations/TestRestClient.cs delete mode 100644 CryptoExchange.Net.UnitTests/TestImplementations/TestRestMessageHandler.cs diff --git a/CryptoExchange.Net.UnitTests/CallResultTests.cs b/CryptoExchange.Net.UnitTests/CallResultTests.cs index b54bc48..a0daea0 100644 --- a/CryptoExchange.Net.UnitTests/CallResultTests.cs +++ b/CryptoExchange.Net.UnitTests/CallResultTests.cs @@ -3,7 +3,6 @@ using CryptoExchange.Net.Objects.Errors; using NUnit.Framework; using NUnit.Framework.Legacy; using System; -using System.Collections.Generic; using System.Net; using System.Net.Http; diff --git a/CryptoExchange.Net.UnitTests/BaseClientTests.cs b/CryptoExchange.Net.UnitTests/ClientTests/BaseClientTests.cs similarity index 95% rename from CryptoExchange.Net.UnitTests/BaseClientTests.cs rename to CryptoExchange.Net.UnitTests/ClientTests/BaseClientTests.cs index f791ccd..d025316 100644 --- a/CryptoExchange.Net.UnitTests/BaseClientTests.cs +++ b/CryptoExchange.Net.UnitTests/ClientTests/BaseClientTests.cs @@ -1,7 +1,6 @@ using NUnit.Framework; -using NUnit.Framework.Legacy; -namespace CryptoExchange.Net.UnitTests +namespace CryptoExchange.Net.UnitTests.ClientTests { [TestFixture()] public class BaseClientTests diff --git a/CryptoExchange.Net.UnitTests/RestClientTests.cs b/CryptoExchange.Net.UnitTests/ClientTests/RestClientTests.cs similarity index 83% rename from CryptoExchange.Net.UnitTests/RestClientTests.cs rename to CryptoExchange.Net.UnitTests/ClientTests/RestClientTests.cs index e43fc38..ef12157 100644 --- a/CryptoExchange.Net.UnitTests/RestClientTests.cs +++ b/CryptoExchange.Net.UnitTests/ClientTests/RestClientTests.cs @@ -2,8 +2,6 @@ using CryptoExchange.Net.UnitTests.TestImplementations; using NUnit.Framework; using System; -using System.Collections.Generic; -using System.Linq; using System.Net.Http; using System.Threading.Tasks; using System.Threading; @@ -14,8 +12,9 @@ using CryptoExchange.Net.RateLimiting.Filters; using CryptoExchange.Net.RateLimiting.Interfaces; using System.Text.Json; using CryptoExchange.Net.UnitTests.Implementations; +using CryptoExchange.Net.Testing; -namespace CryptoExchange.Net.UnitTests +namespace CryptoExchange.Net.UnitTests.ClientTests { [TestFixture()] public class RestClientTests @@ -26,8 +25,8 @@ namespace CryptoExchange.Net.UnitTests // arrange var client = new TestRestClient(); var expected = new TestObject() { DecimalData = 1.23M, IntData = 10, StringData = "Some data" }; - var strData = JsonSerializer.Serialize(expected, new JsonSerializerOptions { TypeInfoResolver = new TestSerializerContext() }), out _); - client.ApiClient1.SetNextResponse(strData, 200); + var strData = JsonSerializer.Serialize(expected, new JsonSerializerOptions { TypeInfoResolver = new TestSerializerContext() }); + client.ApiClient1.SetNextResponse(strData, System.Net.HttpStatusCode.OK); // act var result = await client.ApiClient1.GetResponseAsync(); @@ -38,14 +37,14 @@ namespace CryptoExchange.Net.UnitTests } [TestCase] - public void ReceivingInvalidData_Should_ResultInError() + public async Task ReceivingInvalidData_Should_ResultInError() { // arrange var client = new TestRestClient(); - client.SetResponse("{\"property\": 123", out _); + client.ApiClient1.SetNextResponse("{\"property\": 123", System.Net.HttpStatusCode.OK); // act - var result = client.Api1.Request().Result; + var result = await client.ApiClient1.GetResponseAsync(); // assert ClassicAssert.IsFalse(result.Success); @@ -57,10 +56,10 @@ namespace CryptoExchange.Net.UnitTests { // arrange var client = new TestRestClient(); - client.SetErrorWithoutResponse(System.Net.HttpStatusCode.BadRequest, "Invalid request"); + client.ApiClient1.SetNextResponse("Invalid request", System.Net.HttpStatusCode.BadRequest); // act - var result = await client.Api1.Request(); + var result = await client.ApiClient1.GetResponseAsync(); // assert ClassicAssert.IsFalse(result.Success); @@ -72,10 +71,10 @@ namespace CryptoExchange.Net.UnitTests { // arrange var client = new TestRestClient(); - client.SetErrorWithResponse("{\"errorMessage\": \"Invalid request\", \"errorCode\": 123}", System.Net.HttpStatusCode.BadRequest); + client.ApiClient1.SetNextResponse("{\"errorMessage\": \"Invalid request\", \"errorCode\": 123}", System.Net.HttpStatusCode.BadRequest); // act - var result = await client.Api1.Request(); + var result = await client.ApiClient1.GetResponseAsync(); // assert ClassicAssert.IsFalse(result.Success); @@ -83,17 +82,16 @@ namespace CryptoExchange.Net.UnitTests Assert.That(result.Error is ServerError); } - [TestCase] public async Task ReceivingErrorAndNotParsingErrorAndInvalidJson_Should_ContainData() { // arrange var client = new TestRestClient(); var response = "..."; - client.SetErrorWithResponse(response, System.Net.HttpStatusCode.BadRequest); + client.ApiClient1.SetNextResponse(response, System.Net.HttpStatusCode.BadRequest); // act - var result = await client.Api1.Request(); + var result = await client.ApiClient1.GetResponseAsync(); // assert ClassicAssert.IsFalse(result.Success); @@ -106,11 +104,11 @@ namespace CryptoExchange.Net.UnitTests public async Task ReceivingErrorAndParsingError_Should_ResultInParsedError() { // arrange - var client = new ParseErrorTestRestClient(); - client.SetErrorWithResponse("{\"errorMessage\": \"Invalid request\", \"errorCode\": 123}", System.Net.HttpStatusCode.BadRequest); + var client = new TestRestClient(); + client.ApiClient1.SetNextResponse("{\"errorMessage\": \"Invalid request\", \"errorCode\": 123}", System.Net.HttpStatusCode.BadRequest); // act - var result = await client.Api2.Request(); + var result = await client.ApiClient1.GetResponseAsync(); // assert ClassicAssert.IsFalse(result.Success); @@ -120,23 +118,6 @@ namespace CryptoExchange.Net.UnitTests Assert.That(result.Error.Message == "Invalid request"); } - [TestCase] - public void SettingOptions_Should_ResultInOptionsSet() - { - // arrange - // act - var options = new TestClientOptions(); - options.Api1Options.TimestampRecalculationInterval = TimeSpan.FromMinutes(10); - options.Api1Options.OutputOriginalData = true; - options.RequestTimeout = TimeSpan.FromMinutes(1); - var client = new TestBaseClient(options); - - // assert - Assert.That(((TestClientOptions)client.ClientOptions).Api1Options.TimestampRecalculationInterval == TimeSpan.FromMinutes(10)); - Assert.That(((TestClientOptions)client.ClientOptions).Api1Options.OutputOriginalData == true); - Assert.That(((TestClientOptions)client.ClientOptions).RequestTimeout == TimeSpan.FromMinutes(1)); - } - [TestCase("GET", HttpMethodParameterPosition.InUri)] // No need to test InBody for GET since thats not valid [TestCase("POST", HttpMethodParameterPosition.InBody)] [TestCase("POST", HttpMethodParameterPosition.InUri)] @@ -150,28 +131,22 @@ namespace CryptoExchange.Net.UnitTests // act var client = new TestRestClient(); - client.Api1.SetParameterPosition(new HttpMethod(method), pos); + var httpMethod = new HttpMethod(method); + client.ApiClient1.SetParameterPosition(httpMethod, pos); + client.ApiClient1.SetNextResponse("{}", System.Net.HttpStatusCode.OK); - client.SetResponse("{}", out var request); - - await client.Api1.RequestWithParams(new HttpMethod(method), new ParameterCollection + var result = await client.ApiClient1.GetResponseAsync(httpMethod, new ParameterCollection { { "TestParam1", "Value1" }, { "TestParam2", 2 }, - }, - new Dictionary - { - { "TestHeader", "123" } }); // assert - Assert.That(request.Method == new HttpMethod(method)); - Assert.That((request.Content?.Contains("TestParam1") == true) == (pos == HttpMethodParameterPosition.InBody)); - Assert.That((request.Uri.ToString().Contains("TestParam1")) == (pos == HttpMethodParameterPosition.InUri)); - Assert.That((request.Content?.Contains("TestParam2") == true) == (pos == HttpMethodParameterPosition.InBody)); - Assert.That((request.Uri.ToString().Contains("TestParam2")) == (pos == HttpMethodParameterPosition.InUri)); - Assert.That(request.GetHeaders().First().Key == "TestHeader"); - Assert.That(request.GetHeaders().First().Value.Contains("123")); + Assert.That(result.RequestMethod == new HttpMethod(method)); + Assert.That(result.RequestBody?.Contains("TestParam1") == true == (pos == HttpMethodParameterPosition.InBody)); + Assert.That((result.RequestUrl?.ToString().Contains("TestParam1")) == (pos == HttpMethodParameterPosition.InUri)); + Assert.That(result.RequestBody?.Contains("TestParam2") == true == (pos == HttpMethodParameterPosition.InBody)); + Assert.That((result.RequestUrl?.ToString().Contains("TestParam2")) == (pos == HttpMethodParameterPosition.InUri)); } @@ -190,12 +165,12 @@ namespace CryptoExchange.Net.UnitTests for (var i = 0; i < requests + 1; i++) { - var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default); - Assert.That(i == requests? triggered : !triggered); + var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default); + Assert.That(i == requests ? triggered : !triggered); } triggered = false; await Task.Delay((int)Math.Round(perSeconds * 1000) + 10); - var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default); + var result2 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default); Assert.That(!triggered); } @@ -216,7 +191,7 @@ namespace CryptoExchange.Net.UnitTests for (var i = 0; i < 2; i++) { var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default); - bool expected = i == 1 ? (expectLimiting ? evnt.DelayTime > TimeSpan.Zero : evnt == null) : evnt == null; + bool expected = i == 1 ? expectLimiting ? evnt.DelayTime > TimeSpan.Zero : evnt == null : evnt == null; Assert.That(expected); } } @@ -273,7 +248,7 @@ namespace CryptoExchange.Net.UnitTests { var rateLimiter = new RateLimitGate("Test"); rateLimiter.AddGuard(new RateLimitGuard(RateLimitGuard.PerEndpoint, new ExactPathFilter("/sapi/test"), 1, TimeSpan.FromSeconds(0.1), RateLimitWindowType.Fixed)); - + var requestDefinition = new RequestDefinition(endpoint, HttpMethod.Get); RateLimitEvent evnt = null; @@ -281,7 +256,7 @@ namespace CryptoExchange.Net.UnitTests for (var i = 0; i < 2; i++) { var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default); - bool expected = i == 1 ? (expectLimited ? evnt.DelayTime > TimeSpan.Zero : evnt == null) : evnt == null; + bool expected = i == 1 ? expectLimited ? evnt.DelayTime > TimeSpan.Zero : evnt == null : evnt == null; Assert.That(expected); } } @@ -301,7 +276,7 @@ namespace CryptoExchange.Net.UnitTests for (var i = 0; i < 2; i++) { var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default); - bool expected = i == 1 ? (expectLimited ? evnt.DelayTime > TimeSpan.Zero : evnt == null) : evnt == null; + bool expected = i == 1 ? expectLimited ? evnt.DelayTime > TimeSpan.Zero : evnt == null : evnt == null; Assert.That(expected); } } diff --git a/CryptoExchange.Net.UnitTests/ClientTests/SocketClientTests.cs b/CryptoExchange.Net.UnitTests/ClientTests/SocketClientTests.cs new file mode 100644 index 0000000..9a7f2ea --- /dev/null +++ b/CryptoExchange.Net.UnitTests/ClientTests/SocketClientTests.cs @@ -0,0 +1,251 @@ +using CryptoExchange.Net.Objects; +using CryptoExchange.Net.Testing; +using CryptoExchange.Net.UnitTests.Implementations; +using CryptoExchange.Net.UnitTests.TestImplementations; +using NUnit.Framework; +using System; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; + +namespace CryptoExchange.Net.UnitTests +{ + [TestFixture] + public class SocketClientTests + { + [TestCase] + public void SettingOptions_Should_ResultInOptionsSet() + { + //arrange + //act + var client = new TestSocketClient(options => + { + options.ExchangeOptions.MaxSocketConnections = 1; + }); + + //assert + Assert.That(1 == client.ApiClient1.ApiOptions.MaxSocketConnections); + } + + [TestCase] + public async Task Test() + { + var client = new TestSocketClient(); + var socket = TestHelpers.ConfigureSocketClient(client, "wss://localhost"); + + var expected = new TestObject() { DecimalData = 1.23M, IntData = 10, StringData = "Some data" }; + var strData = JsonSerializer.Serialize(expected, new JsonSerializerOptions { TypeInfoResolver = new TestSerializerContext() }); + + TestObject? received = null; + var resetEvent = new AsyncResetEvent(false); + + await client.ApiClient1.SubscribeToUpdatesAsync(x => + { + received = x.Data; + resetEvent.Set(); + }, default); + + socket.InvokeMessage(strData); + + await resetEvent.WaitAsync(TimeSpan.FromSeconds(1)); + + Assert.That(received != null); + } + + //[TestCase(true)] + //[TestCase(false)] + //public void ConnectSocket_Should_ReturnConnectionResult(bool canConnect) + //{ + // //arrange + // var client = new TestSocketClient(); + // var socket = client.CreateSocket(); + // socket.CanConnect = canConnect; + + // //act + // var connectResult = client.SubClient.ConnectSocketSub( + // new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, "")); + + // //assert + // Assert.That(connectResult.Success == canConnect); + //} + + //[TestCase] + //public void SocketMessages_Should_BeProcessedInDataHandlers() + //{ + // // arrange + // var client = new TestSocketClient(options => + // { + // options.ReconnectInterval = TimeSpan.Zero; + // }); + // var socket = client.CreateSocket(); + // socket.CanConnect = true; + // var sub = new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, ""); + // var rstEvent = new ManualResetEvent(false); + // Dictionary result = null; + + // client.SubClient.ConnectSocketSub(sub); + + // var subObj = new TestSubscription>(Mock.Of(), (messageEvent) => + // { + // result = messageEvent.Data; + // rstEvent.Set(); + // }); + // sub.AddSubscription(subObj); + + // // act + // socket.InvokeMessage("{\"property\": \"123\", \"action\": \"update\", \"topic\": \"topic\"}"); + // rstEvent.WaitOne(1000); + + // // assert + // Assert.That(result["property"] == "123"); + //} + + //[TestCase(false)] + //[TestCase(true)] + //public void SocketMessages_Should_ContainOriginalDataIfEnabled(bool enabled) + //{ + // // arrange + // var client = new TestSocketClient(options => + // { + // options.ReconnectInterval = TimeSpan.Zero; + // options.SubOptions.OutputOriginalData = enabled; + // }); + // var socket = client.CreateSocket(); + // socket.CanConnect = true; + // var sub = new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, ""); + // var rstEvent = new ManualResetEvent(false); + // string original = null; + + // client.SubClient.ConnectSocketSub(sub); + // var subObj = new TestSubscription>(Mock.Of(), (messageEvent) => + // { + // original = messageEvent.OriginalData; + // rstEvent.Set(); + // }); + // sub.AddSubscription(subObj); + // var msgToSend = JsonSerializer.Serialize(new { topic = "topic", action = "update", property = "123" }); + + // // act + // socket.InvokeMessage(msgToSend); + // rstEvent.WaitOne(1000); + + // // assert + // Assert.That(original == (enabled ? msgToSend : null)); + //} + + //[TestCase()] + //public void UnsubscribingStream_Should_CloseTheSocket() + //{ + // // arrange + // var client = new TestSocketClient(options => + // { + // options.ReconnectInterval = TimeSpan.Zero; + // }); + // var socket = client.CreateSocket(); + // socket.CanConnect = true; + // var sub = new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, ""); + // client.SubClient.ConnectSocketSub(sub); + + // var subscription = new TestSubscription>(Mock.Of(), (messageEvent) => { }); + // var ups = new UpdateSubscription(sub, subscription); + // sub.AddSubscription(subscription); + + // // act + // client.UnsubscribeAsync(ups).Wait(); + + // // assert + // Assert.That(socket.Connected == false); + //} + + //[TestCase()] + //public void UnsubscribingAll_Should_CloseAllSockets() + //{ + // // arrange + // var client = new TestSocketClient(options => { options.ReconnectInterval = TimeSpan.Zero; }); + // var socket1 = client.CreateSocket(); + // var socket2 = client.CreateSocket(); + // socket1.CanConnect = true; + // socket2.CanConnect = true; + // var sub1 = new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket1), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, ""); + // var sub2 = new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket2), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, ""); + // client.SubClient.ConnectSocketSub(sub1); + // client.SubClient.ConnectSocketSub(sub2); + // var subscription1 = new TestSubscription>(Mock.Of(), (messageEvent) => { }); + // var subscription2 = new TestSubscription>(Mock.Of(), (messageEvent) => { }); + + // sub1.AddSubscription(subscription1); + // sub2.AddSubscription(subscription2); + // var ups1 = new UpdateSubscription(sub1, subscription1); + // var ups2 = new UpdateSubscription(sub2, subscription2); + + // // act + // client.UnsubscribeAllAsync().Wait(); + + // // assert + // Assert.That(socket1.Connected == false); + // Assert.That(socket2.Connected == false); + //} + + //[TestCase()] + //public void FailingToConnectSocket_Should_ReturnError() + //{ + // // arrange + // var client = new TestSocketClient(options => { options.ReconnectInterval = TimeSpan.Zero; }); + // var socket = client.CreateSocket(); + // socket.CanConnect = false; + // var sub1 = new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, ""); + + // // act + // var connectResult = client.SubClient.ConnectSocketSub(sub1); + + // // assert + // ClassicAssert.IsFalse(connectResult.Success); + //} + + //[TestCase()] + //public async Task ErrorResponse_ShouldNot_ConfirmSubscription() + //{ + // // arrange + // var channel = "trade_btcusd"; + // var client = new TestSocketClient(opt => + // { + // opt.OutputOriginalData = true; + // opt.SocketSubscriptionsCombineTarget = 1; + // }); + // var socket = client.CreateSocket(); + // socket.CanConnect = true; + // client.SubClient.ConnectSocketSub(new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, "")); + + // // act + // var sub = client.SubClient.SubscribeToSomethingAsync(channel, onUpdate => { }, ct: default); + // socket.InvokeMessage(JsonSerializer.Serialize(new { channel, action = "subscribe", status = "error" })); + // await sub; + + // // assert + // ClassicAssert.IsTrue(client.SubClient.TestSubscription.Status != SubscriptionStatus.Subscribed); + //} + + //[TestCase()] + //public async Task SuccessResponse_Should_ConfirmSubscription() + //{ + // // arrange + // var channel = "trade_btcusd"; + // var client = new TestSocketClient(opt => + // { + // opt.OutputOriginalData = true; + // opt.SocketSubscriptionsCombineTarget = 1; + // }); + // var socket = client.CreateSocket(); + // socket.CanConnect = true; + // client.SubClient.ConnectSocketSub(new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, "")); + + // // act + // var sub = client.SubClient.SubscribeToSomethingAsync(channel, onUpdate => { }, ct: default); + // socket.InvokeMessage(JsonSerializer.Serialize(new { channel, action = "subscribe", status = "confirmed" })); + // await sub; + + // // assert + // Assert.That(client.SubClient.TestSubscription.Status == SubscriptionStatus.Subscribed); + //} + } +} diff --git a/CryptoExchange.Net.UnitTests/ConverterTests/ArrayConverterTests.cs b/CryptoExchange.Net.UnitTests/ConverterTests/ArrayConverterTests.cs new file mode 100644 index 0000000..fa822e8 --- /dev/null +++ b/CryptoExchange.Net.UnitTests/ConverterTests/ArrayConverterTests.cs @@ -0,0 +1,109 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters; +using CryptoExchange.Net.Converters.SystemTextJson; +using NUnit.Framework; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace CryptoExchange.Net.UnitTests.ConverterTests +{ + public class ArrayConverterTests + { + [Test()] + public void TestArrayConverter() + { + var data = new Test() + { + Prop1 = 2, + Prop2 = null, + Prop3 = "123", + Prop3Again = "123", + Prop4 = null, + Prop5 = new Test2 + { + Prop21 = 3, + Prop22 = "456" + }, + Prop6 = new Test3 + { + Prop31 = 4, + Prop32 = "789" + }, + Prop7 = TestEnum.Two, + TestInternal = new Test + { + Prop1 = 10 + }, + Prop8 = new Test3 + { + Prop31 = 5, + Prop32 = "101" + }, + }; + + var options = new JsonSerializerOptions() + { + TypeInfoResolver = new TestSerializerContext() + }; + var serialized = JsonSerializer.Serialize(data); + var deserialized = JsonSerializer.Deserialize(serialized); + + Assert.That(deserialized.Prop1, Is.EqualTo(2)); + Assert.That(deserialized.Prop2, Is.Null); + Assert.That(deserialized.Prop3, Is.EqualTo("123")); + Assert.That(deserialized.Prop3Again, Is.EqualTo("123")); + Assert.That(deserialized.Prop4, Is.Null); + Assert.That(deserialized.Prop5.Prop21, Is.EqualTo(3)); + Assert.That(deserialized.Prop5.Prop22, Is.EqualTo("456")); + Assert.That(deserialized.Prop6.Prop31, Is.EqualTo(4)); + Assert.That(deserialized.Prop6.Prop32, Is.EqualTo("789")); + Assert.That(deserialized.Prop7, Is.EqualTo(TestEnum.Two)); + Assert.That(deserialized.TestInternal.Prop1, Is.EqualTo(10)); + Assert.That(deserialized.Prop8.Prop31, Is.EqualTo(5)); + Assert.That(deserialized.Prop8.Prop32, Is.EqualTo("101")); + } + } + + [JsonConverter(typeof(ArrayConverter))] + public record Test + { + [ArrayProperty(0)] + public int Prop1 { get; set; } + [ArrayProperty(1)] + public int? Prop2 { get; set; } + [ArrayProperty(2)] + public string Prop3 { get; set; } + [ArrayProperty(2)] + public string Prop3Again { get; set; } + [ArrayProperty(3)] + public string Prop4 { get; set; } + [ArrayProperty(4)] + public Test2 Prop5 { get; set; } + [ArrayProperty(5)] + public Test3 Prop6 { get; set; } + [ArrayProperty(6), JsonConverter(typeof(EnumConverter))] + public TestEnum? Prop7 { get; set; } + [ArrayProperty(7)] + public Test TestInternal { get; set; } + [ArrayProperty(8), JsonConversion] + public Test3 Prop8 { get; set; } + } + + [JsonConverter(typeof(ArrayConverter))] + public record Test2 + { + [ArrayProperty(0)] + public int Prop21 { get; set; } + [ArrayProperty(1)] + public string Prop22 { get; set; } + } + + public record Test3 + { + [JsonPropertyName("prop31")] + public int Prop31 { get; set; } + [JsonPropertyName("prop32")] + public string Prop32 { get; set; } + } + +} diff --git a/CryptoExchange.Net.UnitTests/ConverterTests/BoolConverterTests.cs b/CryptoExchange.Net.UnitTests/ConverterTests/BoolConverterTests.cs new file mode 100644 index 0000000..e0bc121 --- /dev/null +++ b/CryptoExchange.Net.UnitTests/ConverterTests/BoolConverterTests.cs @@ -0,0 +1,57 @@ +using CryptoExchange.Net.Converters.SystemTextJson; +using NUnit.Framework; +using System.Text.Json; + +namespace CryptoExchange.Net.UnitTests.ConverterTests +{ + public class BoolConverterTests + { + [TestCase("1", true)] + [TestCase("true", true)] + [TestCase("yes", true)] + [TestCase("y", true)] + [TestCase("on", true)] + [TestCase("-1", false)] + [TestCase("0", false)] + [TestCase("n", false)] + [TestCase("no", false)] + [TestCase("false", false)] + [TestCase("off", false)] + [TestCase("", null)] + public void TestBoolConverter(string value, bool? expected) + { + var val = value == null ? "null" : $"\"{value}\""; + var output = JsonSerializer.Deserialize($"{{ \"Value\": {val} }}", SerializerOptions.WithConverters(new TestSerializerContext())); + Assert.That(output.Value == expected); + } + + [TestCase("1", true)] + [TestCase("true", true)] + [TestCase("yes", true)] + [TestCase("y", true)] + [TestCase("on", true)] + [TestCase("-1", false)] + [TestCase("0", false)] + [TestCase("n", false)] + [TestCase("no", false)] + [TestCase("false", false)] + [TestCase("off", false)] + [TestCase("", false)] + public void TestBoolConverterNotNullable(string value, bool expected) + { + var val = value == null ? "null" : $"\"{value}\""; + var output = JsonSerializer.Deserialize($"{{ \"Value\": {val} }}", SerializerOptions.WithConverters(new TestSerializerContext())); + Assert.That(output.Value == expected); + } + } + + public class STJBoolObject + { + public bool? Value { get; set; } + } + + public class NotNullableSTJBoolObject + { + public bool Value { get; set; } + } +} diff --git a/CryptoExchange.Net.UnitTests/ConverterTests/DateTimeConverterTests.cs b/CryptoExchange.Net.UnitTests/ConverterTests/DateTimeConverterTests.cs new file mode 100644 index 0000000..92ed666 --- /dev/null +++ b/CryptoExchange.Net.UnitTests/ConverterTests/DateTimeConverterTests.cs @@ -0,0 +1,119 @@ +using CryptoExchange.Net.Converters.SystemTextJson; +using NUnit.Framework; +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace CryptoExchange.Net.UnitTests.ConverterTests +{ + public class DateTimeConverterTests + { + [TestCase("2021-05-12")] + [TestCase("20210512")] + [TestCase("210512")] + [TestCase("1620777600.000")] + [TestCase("1620777600000")] + [TestCase("2021-05-12T00:00:00.000Z")] + [TestCase("2021-05-12T00:00:00.000000000Z")] + [TestCase("0.000000", true)] + [TestCase("0", true)] + [TestCase("", true)] + [TestCase(" ", true)] + public void TestDateTimeConverterString(string input, bool expectNull = false) + { + var output = JsonSerializer.Deserialize($"{{ \"time\": \"{input}\" }}"); + Assert.That(output.Time == (expectNull ? null : new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc))); + } + + [TestCase(1620777600.000)] + [TestCase(1620777600000d)] + public void TestDateTimeConverterDouble(double input) + { + var output = JsonSerializer.Deserialize($"{{ \"time\": {input} }}"); + Assert.That(output.Time == new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); + } + + [TestCase(1620777600)] + [TestCase(1620777600000)] + [TestCase(1620777600000000)] + [TestCase(1620777600000000000)] + [TestCase(0, true)] + public void TestDateTimeConverterLong(long input, bool expectNull = false) + { + var output = JsonSerializer.Deserialize($"{{ \"time\": {input} }}"); + Assert.That(output.Time == (expectNull ? null : new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc))); + } + + [TestCase(1620777600)] + [TestCase(1620777600.000)] + public void TestDateTimeConverterFromSeconds(double input) + { + var output = DateTimeConverter.ConvertFromSeconds(input); + Assert.That(output == new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); + } + + [Test] + public void TestDateTimeConverterToSeconds() + { + var output = DateTimeConverter.ConvertToSeconds(new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); + Assert.That(output == 1620777600); + } + + [TestCase(1620777600000)] + [TestCase(1620777600000.000)] + public void TestDateTimeConverterFromMilliseconds(double input) + { + var output = DateTimeConverter.ConvertFromMilliseconds(input); + Assert.That(output == new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); + } + + [Test] + public void TestDateTimeConverterToMilliseconds() + { + var output = DateTimeConverter.ConvertToMilliseconds(new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); + Assert.That(output == 1620777600000); + } + + [TestCase(1620777600000000)] + public void TestDateTimeConverterFromMicroseconds(long input) + { + var output = DateTimeConverter.ConvertFromMicroseconds(input); + Assert.That(output == new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); + } + + [Test] + public void TestDateTimeConverterToMicroseconds() + { + var output = DateTimeConverter.ConvertToMicroseconds(new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); + Assert.That(output == 1620777600000000); + } + + [TestCase(1620777600000000000)] + public void TestDateTimeConverterFromNanoseconds(long input) + { + var output = DateTimeConverter.ConvertFromNanoseconds(input); + Assert.That(output == new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); + } + + [Test] + public void TestDateTimeConverterToNanoseconds() + { + var output = DateTimeConverter.ConvertToNanoseconds(new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); + Assert.That(output == 1620777600000000000); + } + + [TestCase()] + public void TestDateTimeConverterNull() + { + var output = JsonSerializer.Deserialize($"{{ \"time\": null }}"); + Assert.That(output.Time == null); + } + } + + public class STJTimeObject + { + [JsonConverter(typeof(DateTimeConverter))] + [JsonPropertyName("time")] + public DateTime? Time { get; set; } + } +} diff --git a/CryptoExchange.Net.UnitTests/ConverterTests/DecimalConverterTests.cs b/CryptoExchange.Net.UnitTests/ConverterTests/DecimalConverterTests.cs new file mode 100644 index 0000000..4503b01 --- /dev/null +++ b/CryptoExchange.Net.UnitTests/ConverterTests/DecimalConverterTests.cs @@ -0,0 +1,49 @@ +using CryptoExchange.Net.Converters.SystemTextJson; +using NUnit.Framework; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace CryptoExchange.Net.UnitTests.ConverterTests +{ + public class DecimalConverterTests + { + [TestCase("1", 1)] + [TestCase("1.1", 1.1)] + [TestCase("-1.1", -1.1)] + [TestCase(null, null)] + [TestCase("", null)] + [TestCase("null", null)] + [TestCase("nan", null)] + [TestCase("1E+2", 100)] + [TestCase("1E-2", 0.01)] + [TestCase("Infinity", 999)] // 999 is workaround for not being able to specify decimal.MinValue + [TestCase("-Infinity", -999)] // -999 is workaround for not being able to specify decimal.MaxValue + [TestCase("80228162514264337593543950335", 999)] // 999 is workaround for not being able to specify decimal.MaxValue + [TestCase("-80228162514264337593543950335", -999)] // -999 is workaround for not being able to specify decimal.MaxValue + public void TestDecimalConverterString(string value, decimal? expected) + { + var result = JsonSerializer.Deserialize("{ \"test\": \"" + value + "\"}"); + Assert.That(result.Test, Is.EqualTo(expected == -999 ? decimal.MinValue : expected == 999 ? decimal.MaxValue : expected)); + } + + [TestCase("1", 1)] + [TestCase("1.1", 1.1)] + [TestCase("-1.1", -1.1)] + [TestCase("null", null)] + [TestCase("1E+2", 100)] + [TestCase("1E-2", 0.01)] + [TestCase("80228162514264337593543950335", -999)] // -999 is workaround for not being able to specify decimal.MaxValue + public void TestDecimalConverterNumber(string value, decimal? expected) + { + var result = JsonSerializer.Deserialize("{ \"test\": " + value + "}"); + Assert.That(result.Test, Is.EqualTo(expected == -999 ? decimal.MaxValue : expected)); + } + } + + public class STJDecimalObject + { + [JsonConverter(typeof(DecimalConverter))] + [JsonPropertyName("test")] + public decimal? Test { get; set; } + } +} diff --git a/CryptoExchange.Net.UnitTests/ConverterTests/EnumConverterTests.cs b/CryptoExchange.Net.UnitTests/ConverterTests/EnumConverterTests.cs new file mode 100644 index 0000000..18a427e --- /dev/null +++ b/CryptoExchange.Net.UnitTests/ConverterTests/EnumConverterTests.cs @@ -0,0 +1,147 @@ +using CryptoExchange.Net.Attributes; +using CryptoExchange.Net.Converters.SystemTextJson; +using CryptoExchange.Net.Objects; +using CryptoExchange.Net.Testing; +using NUnit.Framework; +using System; +using System.Diagnostics; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace CryptoExchange.Net.UnitTests.ConverterTests +{ + public class EnumConverterTests + { + [TestCase(TestEnum.One, "1")] + [TestCase(TestEnum.Two, "2")] + [TestCase(TestEnum.Three, "three")] + [TestCase(TestEnum.Four, "Four")] + [TestCase(null, null)] + public void TestEnumConverterNullableGetStringTests(TestEnum? value, string expected) + { + var output = EnumConverter.GetString(value); + Assert.That(output == expected); + } + + [TestCase(TestEnum.One, "1")] + [TestCase(TestEnum.Two, "2")] + [TestCase(TestEnum.Three, "three")] + [TestCase(TestEnum.Four, "Four")] + public void TestEnumConverterGetStringTests(TestEnum value, string expected) + { + var output = EnumConverter.GetString(value); + Assert.That(output == expected); + } + + [TestCase("1", TestEnum.One)] + [TestCase("2", TestEnum.Two)] + [TestCase("3", TestEnum.Three)] + [TestCase("three", TestEnum.Three)] + [TestCase("Four", TestEnum.Four)] + [TestCase("four", TestEnum.Four)] + [TestCase("Four1", null)] + [TestCase(null, null)] + public void TestEnumConverterNullableDeserializeTests(string value, TestEnum? expected) + { + var val = value == null ? "null" : $"\"{value}\""; + var output = JsonSerializer.Deserialize($"{{ \"Value\": {val} }}", SerializerOptions.WithConverters(new TestSerializerContext())); + Assert.That(output.Value == expected); + } + + [TestCase("1", TestEnum.One)] + [TestCase("2", TestEnum.Two)] + [TestCase("3", TestEnum.Three)] + [TestCase("three", TestEnum.Three)] + [TestCase("Four", TestEnum.Four)] + [TestCase("four", TestEnum.Four)] + [TestCase("Four1", (TestEnum)(-9))] + [TestCase(null, (TestEnum)(-9))] + public void TestEnumConverterNotNullableDeserializeTests(string value, TestEnum expected) + { + var val = value == null ? "null" : $"\"{value}\""; + var output = JsonSerializer.Deserialize($"{{ \"Value\": {val} }}"); + Assert.That(output.Value == expected); + } + + [Test] + public void TestEnumConverterMapsUndefinedValueCorrectlyIfDefaultIsDefined() + { + var output = JsonSerializer.Deserialize($"\"TestUndefined\""); + Assert.That((int)output == -99); + } + + [TestCase("1", TestEnum.One)] + [TestCase("2", TestEnum.Two)] + [TestCase("3", TestEnum.Three)] + [TestCase("three", TestEnum.Three)] + [TestCase("Four", TestEnum.Four)] + [TestCase("four", TestEnum.Four)] + [TestCase("Four1", null)] + [TestCase(null, null)] + public void TestEnumConverterParseStringTests(string value, TestEnum? expected) + { + var result = EnumConverter.ParseString(value); + Assert.That(result == expected); + } + + [Test] + public void TestEnumConverterParseNullOnNonNullableOnlyLogsOnce() + { + LibraryHelpers.StaticLogger = new TraceLogger(); + var listener = new EnumValueTraceListener(); + Trace.Listeners.Add(listener); + EnumConverter.Reset(); + try + { + Assert.Throws(() => + { + var result = JsonSerializer.Deserialize("{\"Value\": null}", SerializerOptions.WithConverters(new TestSerializerContext())); + }); + + Assert.DoesNotThrow(() => + { + var result2 = JsonSerializer.Deserialize("{\"Value\": null}", SerializerOptions.WithConverters(new TestSerializerContext())); + }); + } + finally + { + Trace.Listeners.Remove(listener); + } + } + } + public class STJEnumObject + { + public TestEnum? Value { get; set; } + } + + public class NotNullableSTJEnumObject + { + public TestEnum Value { get; set; } + } + + [JsonConverter(typeof(EnumConverter))] + public enum TestEnum + { + [Map("1")] + One, + [Map("2")] + Two, + [Map("three", "3")] + Three, + Four + } + + [JsonConverter(typeof(EnumConverter))] + public enum TestEnum2 + { + [Map("-9")] + Minus9 = -9, + [Map("1")] + One, + [Map("2")] + Two, + [Map("three", "3")] + Three, + Four + } +} diff --git a/CryptoExchange.Net.UnitTests/ConverterTests/SharedModelConversionTests.cs b/CryptoExchange.Net.UnitTests/ConverterTests/SharedModelConversionTests.cs new file mode 100644 index 0000000..e910885 --- /dev/null +++ b/CryptoExchange.Net.UnitTests/ConverterTests/SharedModelConversionTests.cs @@ -0,0 +1,46 @@ +using CryptoExchange.Net.Converters.SystemTextJson; +using CryptoExchange.Net.SharedApis; +using NUnit.Framework; +using System; +using System.Text.Json; + +namespace CryptoExchange.Net.UnitTests +{ + [TestFixture()] + public class SharedModelConversionTests + { + [TestCase(TradingMode.Spot, "ETH", "USDT", null)] + [TestCase(TradingMode.PerpetualLinear, "ETH", "USDT", null)] + [TestCase(TradingMode.DeliveryLinear, "ETH", "USDT", 1748432430)] + public void TestSharedSymbolConversion(TradingMode tradingMode, string baseAsset, string quoteAsset, int? deliverTime) + { + DateTime? time = deliverTime == null ? null : DateTimeConverter.ParseFromDouble(deliverTime.Value); + var symbol = new SharedSymbol(tradingMode, baseAsset, quoteAsset, time); + + var serialized = JsonSerializer.Serialize(symbol); + var restored = JsonSerializer.Deserialize(serialized); + + Assert.That(restored.TradingMode, Is.EqualTo(symbol.TradingMode)); + Assert.That(restored.BaseAsset, Is.EqualTo(symbol.BaseAsset)); + Assert.That(restored.QuoteAsset, Is.EqualTo(symbol.QuoteAsset)); + Assert.That(restored.DeliverTime, Is.EqualTo(symbol.DeliverTime)); + } + + [TestCase(0.1, null, null)] + [TestCase(0.1, 0.1, null)] + [TestCase(0.1, 0.1, 0.1)] + [TestCase(null, 0.1, null)] + [TestCase(null, 0.1, 0.1)] + public void TestSharedQuantityConversion(double? baseQuantity, double? quoteQuantity, double? contractQuantity) + { + var symbol = new SharedOrderQuantity((decimal?)baseQuantity, (decimal?)quoteQuantity, (decimal?)contractQuantity); + + var serialized = JsonSerializer.Serialize(symbol); + var restored = JsonSerializer.Deserialize(serialized); + + Assert.That(restored.QuantityInBaseAsset, Is.EqualTo(symbol.QuantityInBaseAsset)); + Assert.That(restored.QuantityInQuoteAsset, Is.EqualTo(symbol.QuantityInQuoteAsset)); + Assert.That(restored.QuantityInContracts, Is.EqualTo(symbol.QuantityInContracts)); + } + } +} diff --git a/CryptoExchange.Net.UnitTests/Implementations/TestAuthenticationProvider.cs b/CryptoExchange.Net.UnitTests/Implementations/TestAuthenticationProvider.cs index 047aef8..8027c0f 100644 --- a/CryptoExchange.Net.UnitTests/Implementations/TestAuthenticationProvider.cs +++ b/CryptoExchange.Net.UnitTests/Implementations/TestAuthenticationProvider.cs @@ -1,9 +1,7 @@ using CryptoExchange.Net.Authentication; using CryptoExchange.Net.Clients; using CryptoExchange.Net.Objects; -using System; using System.Collections.Generic; -using System.Text; namespace CryptoExchange.Net.UnitTests.Implementations { diff --git a/CryptoExchange.Net.UnitTests/Implementations/TestCredentials.cs b/CryptoExchange.Net.UnitTests/Implementations/TestCredentials.cs index 463c9b5..d995f4f 100644 --- a/CryptoExchange.Net.UnitTests/Implementations/TestCredentials.cs +++ b/CryptoExchange.Net.UnitTests/Implementations/TestCredentials.cs @@ -1,7 +1,5 @@ using CryptoExchange.Net.Authentication; using System; -using System.Collections.Generic; -using System.Text; namespace CryptoExchange.Net.UnitTests.Implementations { diff --git a/CryptoExchange.Net.UnitTests/Implementations/TestEnvironment.cs b/CryptoExchange.Net.UnitTests/Implementations/TestEnvironment.cs index f80c293..f84579c 100644 --- a/CryptoExchange.Net.UnitTests/Implementations/TestEnvironment.cs +++ b/CryptoExchange.Net.UnitTests/Implementations/TestEnvironment.cs @@ -1,7 +1,4 @@ using CryptoExchange.Net.Objects; -using System; -using System.Collections.Generic; -using System.Text; namespace CryptoExchange.Net.UnitTests.Implementations { diff --git a/CryptoExchange.Net.UnitTests/Implementations/TestRestApiClient.cs b/CryptoExchange.Net.UnitTests/Implementations/TestRestApiClient.cs index 4cf6c32..a89a7b4 100644 --- a/CryptoExchange.Net.UnitTests/Implementations/TestRestApiClient.cs +++ b/CryptoExchange.Net.UnitTests/Implementations/TestRestApiClient.cs @@ -1,5 +1,6 @@ using CryptoExchange.Net.Clients; using CryptoExchange.Net.Converters.MessageParsing.DynamicConverters; +using CryptoExchange.Net.Converters.SystemTextJson; using CryptoExchange.Net.Interfaces; using CryptoExchange.Net.Objects; using CryptoExchange.Net.SharedApis; @@ -16,7 +17,7 @@ namespace CryptoExchange.Net.UnitTests.Implementations { internal class TestRestApiClient : RestApiClient { - protected override IRestMessageHandler MessageHandler => throw new NotImplementedException(); + protected override IRestMessageHandler MessageHandler { get; } = new TestRestMessageHandler(); public TestRestApiClient(ILogger logger, HttpClient? httpClient, TestRestOptions options) : base(logger, httpClient, options.Environment.RestClientAddress, options, options.ExchangeOptions) @@ -30,7 +31,7 @@ namespace CryptoExchange.Net.UnitTests.Implementations protected override TestAuthenticationProvider CreateAuthenticationProvider(TestCredentials credentials) => new TestAuthenticationProvider(credentials); - protected override IMessageSerializer CreateSerializer() => throw new NotImplementedException(); + protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(SerializerOptions.WithConverters(new TestSerializerContext())); internal void SetNextResponse(string data, HttpStatusCode code) { @@ -46,12 +47,18 @@ namespace CryptoExchange.Net.UnitTests.Implementations RequestFactory = factory; } - internal async Task> GetResponseAsync() + internal async Task> GetResponseAsync(HttpMethod? httpMethod = null, ParameterCollection? collection = null) { - var definition = new RequestDefinition("/path", HttpMethod.Get) + var definition = new RequestDefinition("/path", httpMethod ?? HttpMethod.Get) { + Weight = 0 }; - return await SendAsync(BaseAddress, definition, new ParameterCollection(), default); + return await SendAsync(BaseAddress, definition, collection ?? new ParameterCollection(), default); + } + + internal void SetParameterPosition(HttpMethod httpMethod, HttpMethodParameterPosition pos) + { + ParameterPositions[httpMethod] = pos; } } } diff --git a/CryptoExchange.Net.UnitTests/Implementations/TestRestClient.cs b/CryptoExchange.Net.UnitTests/Implementations/TestRestClient.cs index dadeaac..e812220 100644 --- a/CryptoExchange.Net.UnitTests/Implementations/TestRestClient.cs +++ b/CryptoExchange.Net.UnitTests/Implementations/TestRestClient.cs @@ -1,14 +1,8 @@ using CryptoExchange.Net.Clients; -using CryptoExchange.Net.Testing.Implementations; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Net; using System.Net.Http; -using System.Text; namespace CryptoExchange.Net.UnitTests.Implementations { diff --git a/CryptoExchange.Net.UnitTests/Implementations/TestRestMessageHandler.cs b/CryptoExchange.Net.UnitTests/Implementations/TestRestMessageHandler.cs new file mode 100644 index 0000000..9bf8d0a --- /dev/null +++ b/CryptoExchange.Net.UnitTests/Implementations/TestRestMessageHandler.cs @@ -0,0 +1,33 @@ +using CryptoExchange.Net.Converters.SystemTextJson; +using CryptoExchange.Net.Converters.SystemTextJson.MessageHandlers; +using CryptoExchange.Net.Objects; +using CryptoExchange.Net.Objects.Errors; +using System.IO; +using System.Net.Http.Headers; +using System.Text.Json; +using System.Threading.Tasks; + +namespace CryptoExchange.Net.UnitTests.Implementations +{ + internal class TestRestMessageHandler : JsonRestMessageHandler + { + public override JsonSerializerOptions Options { get; } = SerializerOptions.WithConverters(new TestSerializerContext()); + + public override async ValueTask ParseErrorResponse(int httpStatusCode, HttpResponseHeaders responseHeaders, Stream responseStream) + { + var (jsonError, jsonDocument) = await GetJsonDocument(responseStream).ConfigureAwait(false); + if (jsonError != null) + return jsonError; + + int? code = jsonDocument!.RootElement.TryGetProperty("errorCode", out var codeProp) ? codeProp.GetInt32() : null; + var msg = jsonDocument.RootElement.TryGetProperty("errorMessage", out var msgProp) ? msgProp.GetString() : null; + if (msg == null) + return new ServerError(ErrorInfo.Unknown); + + if (code == null) + return new ServerError(ErrorInfo.Unknown with { Message = msg }); + + return new ServerError(code.Value, new ErrorInfo(ErrorType.Unknown, false, "Error") with { Message = msg }); + } + } +} diff --git a/CryptoExchange.Net.UnitTests/Implementations/TestRestOptions.cs b/CryptoExchange.Net.UnitTests/Implementations/TestRestOptions.cs index bf8205b..7547208 100644 --- a/CryptoExchange.Net.UnitTests/Implementations/TestRestOptions.cs +++ b/CryptoExchange.Net.UnitTests/Implementations/TestRestOptions.cs @@ -1,7 +1,4 @@ using CryptoExchange.Net.Objects.Options; -using System; -using System.Collections.Generic; -using System.Text; namespace CryptoExchange.Net.UnitTests.Implementations { diff --git a/CryptoExchange.Net.UnitTests/TestSerializerContext.cs b/CryptoExchange.Net.UnitTests/Implementations/TestSerializerContext.cs similarity index 51% rename from CryptoExchange.Net.UnitTests/TestSerializerContext.cs rename to CryptoExchange.Net.UnitTests/Implementations/TestSerializerContext.cs index ce23994..dd1b403 100644 --- a/CryptoExchange.Net.UnitTests/TestSerializerContext.cs +++ b/CryptoExchange.Net.UnitTests/Implementations/TestSerializerContext.cs @@ -1,4 +1,5 @@ -using CryptoExchange.Net.UnitTests.TestImplementations; +using CryptoExchange.Net.UnitTests.ConverterTests; +using CryptoExchange.Net.UnitTests.TestImplementations; using System.Collections.Generic; using System.Text.Json.Serialization; @@ -11,6 +12,16 @@ namespace CryptoExchange.Net.UnitTests [JsonSerializable(typeof(Dictionary))] [JsonSerializable(typeof(IDictionary))] [JsonSerializable(typeof(TestObject))] + + [JsonSerializable(typeof(Test))] + [JsonSerializable(typeof(Test2))] + [JsonSerializable(typeof(Test3))] + [JsonSerializable(typeof(NotNullableSTJBoolObject))] + [JsonSerializable(typeof(STJBoolObject))] + [JsonSerializable(typeof(NotNullableSTJEnumObject))] + [JsonSerializable(typeof(STJEnumObject))] + [JsonSerializable(typeof(STJDecimalObject))] + [JsonSerializable(typeof(STJTimeObject))] internal partial class TestSerializerContext : JsonSerializerContext { } diff --git a/CryptoExchange.Net.UnitTests/Implementations/TestSocketApiClient.cs b/CryptoExchange.Net.UnitTests/Implementations/TestSocketApiClient.cs index ca18015..1bdc8d0 100644 --- a/CryptoExchange.Net.UnitTests/Implementations/TestSocketApiClient.cs +++ b/CryptoExchange.Net.UnitTests/Implementations/TestSocketApiClient.cs @@ -1,31 +1,44 @@ using CryptoExchange.Net.Clients; using CryptoExchange.Net.Converters.MessageParsing.DynamicConverters; +using CryptoExchange.Net.Converters.SystemTextJson; using CryptoExchange.Net.Interfaces; +using CryptoExchange.Net.Objects; using CryptoExchange.Net.Objects.Options; +using CryptoExchange.Net.Objects.Sockets; using CryptoExchange.Net.SharedApis; using Microsoft.Extensions.Logging; using System; -using System.Collections.Generic; using System.Net.Http; using System.Net.WebSockets; -using System.Text; +using System.Threading; +using System.Threading.Tasks; namespace CryptoExchange.Net.UnitTests.Implementations { internal class TestSocketApiClient : SocketApiClient { + public TestSocketApiClient(ILogger logger, TestSocketOptions options) + : base(logger, options.Environment.SocketClientAddress, options, options.ExchangeOptions) + { + } + public TestSocketApiClient(ILogger logger, HttpClient httpClient, string baseAddress, TestSocketOptions options, SocketApiOptions apiOptions) : base(logger, baseAddress, options, apiOptions) { } - public override ISocketMessageHandler CreateMessageConverter(WebSocketMessageType messageType) => throw new NotImplementedException(); - protected internal override IMessageSerializer CreateSerializer() => throw new NotImplementedException(); + public override ISocketMessageHandler CreateMessageConverter(WebSocketMessageType messageType) => new TestSocketMessageHandler(); + protected internal override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(SerializerOptions.WithConverters(new TestSerializerContext())); public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverDate = null) => baseAsset + quoteAsset; protected override TestAuthenticationProvider CreateAuthenticationProvider(TestCredentials credentials) => new TestAuthenticationProvider(credentials); + + public async Task> SubscribeToUpdatesAsync(Action> handler, CancellationToken ct) + { + return await base.SubscribeAsync(new TestSubscription(_logger, handler, false), ct); + } } } diff --git a/CryptoExchange.Net.UnitTests/Implementations/TestSocketClient.cs b/CryptoExchange.Net.UnitTests/Implementations/TestSocketClient.cs new file mode 100644 index 0000000..3b45729 --- /dev/null +++ b/CryptoExchange.Net.UnitTests/Implementations/TestSocketClient.cs @@ -0,0 +1,26 @@ +using CryptoExchange.Net.Clients; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System; + +namespace CryptoExchange.Net.UnitTests.Implementations +{ + internal class TestSocketClient : BaseSocketClient + { + public TestSocketApiClient ApiClient1 { get; set; } + public TestSocketApiClient ApiClient2 { get; set; } + + public TestSocketClient(Action? optionsDelegate = null) + : this(null, Options.Create(ApplyOptionsDelegate(optionsDelegate))) + { + } + + public TestSocketClient(ILoggerFactory? loggerFactory, IOptions options) : base(loggerFactory, "Test") + { + Initialize(options.Value); + + ApiClient1 = AddApiClient(new TestSocketApiClient(_logger, options.Value)); + ApiClient2 = AddApiClient(new TestSocketApiClient(_logger, options.Value)); + } + } +} diff --git a/CryptoExchange.Net.UnitTests/Implementations/TestSocketMessageHandler.cs b/CryptoExchange.Net.UnitTests/Implementations/TestSocketMessageHandler.cs new file mode 100644 index 0000000..201c053 --- /dev/null +++ b/CryptoExchange.Net.UnitTests/Implementations/TestSocketMessageHandler.cs @@ -0,0 +1,26 @@ +using CryptoExchange.Net.Converters.MessageParsing.DynamicConverters; +using CryptoExchange.Net.Converters.SystemTextJson; +using CryptoExchange.Net.Converters.SystemTextJson.MessageHandlers; +using System.Text.Json; + +namespace CryptoExchange.Net.UnitTests.Implementations +{ + internal class TestSocketMessageHandler : JsonSocketMessageHandler + { + public override JsonSerializerOptions Options { get; } = SerializerOptions.WithConverters(new TestSerializerContext()); + + public TestSocketMessageHandler() + { + } + + protected override MessageTypeDefinition[] TypeEvaluators { get; } = [ + + new MessageTypeDefinition { + ForceIfFound = true, + Fields = [ + ], + StaticIdentifier = "test" + }, + ]; + } +} diff --git a/CryptoExchange.Net.UnitTests/Implementations/TestSubscription.cs b/CryptoExchange.Net.UnitTests/Implementations/TestSubscription.cs new file mode 100644 index 0000000..a8cf1c5 --- /dev/null +++ b/CryptoExchange.Net.UnitTests/Implementations/TestSubscription.cs @@ -0,0 +1,34 @@ +using CryptoExchange.Net.Objects; +using CryptoExchange.Net.Objects.Sockets; +using CryptoExchange.Net.Sockets; +using CryptoExchange.Net.Sockets.Default; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Reflection.Metadata; +using System.Text; + +namespace CryptoExchange.Net.UnitTests.Implementations +{ + internal class TestSubscription : Subscription + { + private readonly Action> _handler; + + public TestSubscription(ILogger logger, Action> handler, bool authenticated) : base(logger, authenticated, true) + { + _handler = handler; + + MessageRouter = MessageRouter.CreateWithoutTopicFilter("test", HandleUpdate); + } + + protected override Query? GetSubQuery(SocketConnection connection) => null; + protected override Query? GetUnsubQuery(SocketConnection connection) => null; + + + private CallResult? HandleUpdate(SocketConnection connection, DateTime time, string? originalData, T data) + { + _handler(new DataEvent("Test", data, time, originalData)); + return CallResult.SuccessResult; + } + } +} diff --git a/CryptoExchange.Net.UnitTests/OptionsTests.cs b/CryptoExchange.Net.UnitTests/OptionsTests.cs index 3dd528e..823e121 100644 --- a/CryptoExchange.Net.UnitTests/OptionsTests.cs +++ b/CryptoExchange.Net.UnitTests/OptionsTests.cs @@ -2,7 +2,6 @@ using CryptoExchange.Net.Objects; using CryptoExchange.Net.Objects.Options; using CryptoExchange.Net.UnitTests.Implementations; -using CryptoExchange.Net.UnitTests.TestImplementations; using NUnit.Framework; using System; @@ -76,7 +75,7 @@ namespace CryptoExchange.Net.UnitTests public void TestSetOptionsRestWithCredentials() { var client = new TestRestClient(); - client.SetOptions(new UpdateOptions + client.SetOptions(new UpdateOptions { ApiCredentials = new TestCredentials("123", "456"), RequestTimeout = TimeSpan.FromSeconds(2), diff --git a/CryptoExchange.Net.UnitTests/SharedQuantityTests.cs b/CryptoExchange.Net.UnitTests/SharedQuantityTests.cs index ec65f97..79d9cea 100644 --- a/CryptoExchange.Net.UnitTests/SharedQuantityTests.cs +++ b/CryptoExchange.Net.UnitTests/SharedQuantityTests.cs @@ -1,6 +1,5 @@ using CryptoExchange.Net.SharedApis; using NUnit.Framework; -using System; namespace CryptoExchange.Net.UnitTests { diff --git a/CryptoExchange.Net.UnitTests/SocketClientTests.cs b/CryptoExchange.Net.UnitTests/SocketClientTests.cs deleted file mode 100644 index 97ce6a6..0000000 --- a/CryptoExchange.Net.UnitTests/SocketClientTests.cs +++ /dev/null @@ -1,234 +0,0 @@ -//using CryptoExchange.Net.Objects; -//using CryptoExchange.Net.Objects.Sockets; -//using CryptoExchange.Net.Sockets; -//using CryptoExchange.Net.Testing.Implementations; -//using CryptoExchange.Net.UnitTests.TestImplementations; -//using CryptoExchange.Net.UnitTests.TestImplementations.Sockets; -//using Microsoft.Extensions.Logging; -//using Moq; -//using NUnit.Framework; -//using NUnit.Framework.Legacy; -//using System; -//using System.Collections.Generic; -//using System.Net.Sockets; -//using System.Text.Json; -//using System.Threading; -//using System.Threading.Tasks; - -//namespace CryptoExchange.Net.UnitTests -//{ -// [TestFixture] -// public class SocketClientTests -// { -// [TestCase] -// public void SettingOptions_Should_ResultInOptionsSet() -// { -// //arrange -// //act -// var client = new TestSocketClient(options => -// { -// options.SubOptions.ApiCredentials = new Authentication.ApiCredentials("1", "2"); -// options.SubOptions.MaxSocketConnections = 1; -// }); - -// //assert -// ClassicAssert.NotNull(client.SubClient.ApiOptions.ApiCredentials); -// Assert.That(1 == client.SubClient.ApiOptions.MaxSocketConnections); -// } - -// [TestCase(true)] -// [TestCase(false)] -// public void ConnectSocket_Should_ReturnConnectionResult(bool canConnect) -// { -// //arrange -// var client = new TestSocketClient(); -// var socket = client.CreateSocket(); -// socket.CanConnect = canConnect; - -// //act -// var connectResult = client.SubClient.ConnectSocketSub( -// new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, "")); - -// //assert -// Assert.That(connectResult.Success == canConnect); -// } - -// [TestCase] -// public void SocketMessages_Should_BeProcessedInDataHandlers() -// { -// // arrange -// var client = new TestSocketClient(options => { -// options.ReconnectInterval = TimeSpan.Zero; -// }); -// var socket = client.CreateSocket(); -// socket.CanConnect = true; -// var sub = new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, ""); -// var rstEvent = new ManualResetEvent(false); -// Dictionary result = null; - -// client.SubClient.ConnectSocketSub(sub); - -// var subObj = new TestSubscription>(Mock.Of(), (messageEvent) => -// { -// result = messageEvent.Data; -// rstEvent.Set(); -// }); -// sub.AddSubscription(subObj); - -// // act -// socket.InvokeMessage("{\"property\": \"123\", \"action\": \"update\", \"topic\": \"topic\"}"); -// rstEvent.WaitOne(1000); - -// // assert -// Assert.That(result["property"] == "123"); -// } - -// [TestCase(false)] -// [TestCase(true)] -// public void SocketMessages_Should_ContainOriginalDataIfEnabled(bool enabled) -// { -// // arrange -// var client = new TestSocketClient(options => -// { -// options.ReconnectInterval = TimeSpan.Zero; -// options.SubOptions.OutputOriginalData = enabled; -// }); -// var socket = client.CreateSocket(); -// socket.CanConnect = true; -// var sub = new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, ""); -// var rstEvent = new ManualResetEvent(false); -// string original = null; - -// client.SubClient.ConnectSocketSub(sub); -// var subObj = new TestSubscription>(Mock.Of(), (messageEvent) => -// { -// original = messageEvent.OriginalData; -// rstEvent.Set(); -// }); -// sub.AddSubscription(subObj); -// var msgToSend = JsonSerializer.Serialize(new { topic = "topic", action = "update", property = "123" }); - -// // act -// socket.InvokeMessage(msgToSend); -// rstEvent.WaitOne(1000); - -// // assert -// Assert.That(original == (enabled ? msgToSend : null)); -// } - -// [TestCase()] -// public void UnsubscribingStream_Should_CloseTheSocket() -// { -// // arrange -// var client = new TestSocketClient(options => -// { -// options.ReconnectInterval = TimeSpan.Zero; -// }); -// var socket = client.CreateSocket(); -// socket.CanConnect = true; -// var sub = new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, ""); -// client.SubClient.ConnectSocketSub(sub); - -// var subscription = new TestSubscription>(Mock.Of(), (messageEvent) => { }); -// var ups = new UpdateSubscription(sub, subscription); -// sub.AddSubscription(subscription); - -// // act -// client.UnsubscribeAsync(ups).Wait(); - -// // assert -// Assert.That(socket.Connected == false); -// } - -// [TestCase()] -// public void UnsubscribingAll_Should_CloseAllSockets() -// { -// // arrange -// var client = new TestSocketClient(options => { options.ReconnectInterval = TimeSpan.Zero; }); -// var socket1 = client.CreateSocket(); -// var socket2 = client.CreateSocket(); -// socket1.CanConnect = true; -// socket2.CanConnect = true; -// var sub1 = new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket1), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, ""); -// var sub2 = new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket2), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, ""); -// client.SubClient.ConnectSocketSub(sub1); -// client.SubClient.ConnectSocketSub(sub2); -// var subscription1 = new TestSubscription>(Mock.Of(), (messageEvent) => { }); -// var subscription2 = new TestSubscription>(Mock.Of(), (messageEvent) => { }); - -// sub1.AddSubscription(subscription1); -// sub2.AddSubscription(subscription2); -// var ups1 = new UpdateSubscription(sub1, subscription1); -// var ups2 = new UpdateSubscription(sub2, subscription2); - -// // act -// client.UnsubscribeAllAsync().Wait(); - -// // assert -// Assert.That(socket1.Connected == false); -// Assert.That(socket2.Connected == false); -// } - -// [TestCase()] -// public void FailingToConnectSocket_Should_ReturnError() -// { -// // arrange -// var client = new TestSocketClient(options => { options.ReconnectInterval = TimeSpan.Zero; }); -// var socket = client.CreateSocket(); -// socket.CanConnect = false; -// var sub1 = new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, ""); - -// // act -// var connectResult = client.SubClient.ConnectSocketSub(sub1); - -// // assert -// ClassicAssert.IsFalse(connectResult.Success); -// } - -// [TestCase()] -// public async Task ErrorResponse_ShouldNot_ConfirmSubscription() -// { -// // arrange -// var channel = "trade_btcusd"; -// var client = new TestSocketClient(opt => -// { -// opt.OutputOriginalData = true; -// opt.SocketSubscriptionsCombineTarget = 1; -// }); -// var socket = client.CreateSocket(); -// socket.CanConnect = true; -// client.SubClient.ConnectSocketSub(new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, "")); - -// // act -// var sub = client.SubClient.SubscribeToSomethingAsync(channel, onUpdate => {}, ct: default); -// socket.InvokeMessage(JsonSerializer.Serialize(new { channel, action = "subscribe", status = "error" })); -// await sub; - -// // assert -// ClassicAssert.IsTrue(client.SubClient.TestSubscription.Status != SubscriptionStatus.Subscribed); -// } - -// [TestCase()] -// public async Task SuccessResponse_Should_ConfirmSubscription() -// { -// // arrange -// var channel = "trade_btcusd"; -// var client = new TestSocketClient(opt => -// { -// opt.OutputOriginalData = true; -// opt.SocketSubscriptionsCombineTarget = 1; -// }); -// var socket = client.CreateSocket(); -// socket.CanConnect = true; -// client.SubClient.ConnectSocketSub(new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, "")); - -// // act -// var sub = client.SubClient.SubscribeToSomethingAsync(channel, onUpdate => {}, ct: default); -// socket.InvokeMessage(JsonSerializer.Serialize(new { channel, action = "subscribe", status = "confirmed" })); -// await sub; - -// // assert -// Assert.That(client.SubClient.TestSubscription.Status == SubscriptionStatus.Subscribed); -// } -// } -//} diff --git a/CryptoExchange.Net.UnitTests/SystemTextJsonConverterTests.cs b/CryptoExchange.Net.UnitTests/SystemTextJsonConverterTests.cs deleted file mode 100644 index ea991ee..0000000 --- a/CryptoExchange.Net.UnitTests/SystemTextJsonConverterTests.cs +++ /dev/null @@ -1,490 +0,0 @@ -using CryptoExchange.Net.Attributes; -using CryptoExchange.Net.Converters; -using CryptoExchange.Net.Converters.SystemTextJson; -using CryptoExchange.Net.Objects; -using CryptoExchange.Net.SharedApis; -using CryptoExchange.Net.Testing; -using Newtonsoft.Json.Linq; -using NUnit.Framework; -using System; -using System.Diagnostics; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace CryptoExchange.Net.UnitTests -{ - [TestFixture()] - public class SystemTextJsonConverterTests - { - [TestCase("2021-05-12")] - [TestCase("20210512")] - [TestCase("210512")] - [TestCase("1620777600.000")] - [TestCase("1620777600000")] - [TestCase("2021-05-12T00:00:00.000Z")] - [TestCase("2021-05-12T00:00:00.000000000Z")] - [TestCase("0.000000", true)] - [TestCase("0", true)] - [TestCase("", true)] - [TestCase(" ", true)] - public void TestDateTimeConverterString(string input, bool expectNull = false) - { - var output = JsonSerializer.Deserialize($"{{ \"time\": \"{input}\" }}"); - Assert.That(output.Time == (expectNull ? null: new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc))); - } - - [TestCase(1620777600.000)] - [TestCase(1620777600000d)] - public void TestDateTimeConverterDouble(double input) - { - var output = JsonSerializer.Deserialize($"{{ \"time\": {input} }}"); - Assert.That(output.Time == new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); - } - - [TestCase(1620777600)] - [TestCase(1620777600000)] - [TestCase(1620777600000000)] - [TestCase(1620777600000000000)] - [TestCase(0, true)] - public void TestDateTimeConverterLong(long input, bool expectNull = false) - { - var output = JsonSerializer.Deserialize($"{{ \"time\": {input} }}"); - Assert.That(output.Time == (expectNull ? null : new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc))); - } - - [TestCase(1620777600)] - [TestCase(1620777600.000)] - public void TestDateTimeConverterFromSeconds(double input) - { - var output = DateTimeConverter.ConvertFromSeconds(input); - Assert.That(output == new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); - } - - [Test] - public void TestDateTimeConverterToSeconds() - { - var output = DateTimeConverter.ConvertToSeconds(new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); - Assert.That(output == 1620777600); - } - - [TestCase(1620777600000)] - [TestCase(1620777600000.000)] - public void TestDateTimeConverterFromMilliseconds(double input) - { - var output = DateTimeConverter.ConvertFromMilliseconds(input); - Assert.That(output == new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); - } - - [Test] - public void TestDateTimeConverterToMilliseconds() - { - var output = DateTimeConverter.ConvertToMilliseconds(new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); - Assert.That(output == 1620777600000); - } - - [TestCase(1620777600000000)] - public void TestDateTimeConverterFromMicroseconds(long input) - { - var output = DateTimeConverter.ConvertFromMicroseconds(input); - Assert.That(output == new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); - } - - [Test] - public void TestDateTimeConverterToMicroseconds() - { - var output = DateTimeConverter.ConvertToMicroseconds(new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); - Assert.That(output == 1620777600000000); - } - - [TestCase(1620777600000000000)] - public void TestDateTimeConverterFromNanoseconds(long input) - { - var output = DateTimeConverter.ConvertFromNanoseconds(input); - Assert.That(output == new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); - } - - [Test] - public void TestDateTimeConverterToNanoseconds() - { - var output = DateTimeConverter.ConvertToNanoseconds(new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); - Assert.That(output == 1620777600000000000); - } - - [TestCase()] - public void TestDateTimeConverterNull() - { - var output = JsonSerializer.Deserialize($"{{ \"time\": null }}"); - Assert.That(output.Time == null); - } - - [TestCase(TestEnum.One, "1")] - [TestCase(TestEnum.Two, "2")] - [TestCase(TestEnum.Three, "three")] - [TestCase(TestEnum.Four, "Four")] - [TestCase(null, null)] - public void TestEnumConverterNullableGetStringTests(TestEnum? value, string expected) - { - var output = EnumConverter.GetString(value); - Assert.That(output == expected); - } - - [TestCase(TestEnum.One, "1")] - [TestCase(TestEnum.Two, "2")] - [TestCase(TestEnum.Three, "three")] - [TestCase(TestEnum.Four, "Four")] - public void TestEnumConverterGetStringTests(TestEnum value, string expected) - { - var output = EnumConverter.GetString(value); - Assert.That(output == expected); - } - - [TestCase("1", TestEnum.One)] - [TestCase("2", TestEnum.Two)] - [TestCase("3", TestEnum.Three)] - [TestCase("three", TestEnum.Three)] - [TestCase("Four", TestEnum.Four)] - [TestCase("four", TestEnum.Four)] - [TestCase("Four1", null)] - [TestCase(null, null)] - public void TestEnumConverterNullableDeserializeTests(string value, TestEnum? expected) - { - var val = value == null ? "null" : $"\"{value}\""; - var output = JsonSerializer.Deserialize($"{{ \"Value\": {val} }}", SerializerOptions.WithConverters(new SerializationContext())); - Assert.That(output.Value == expected); - } - - [TestCase("1", TestEnum.One)] - [TestCase("2", TestEnum.Two)] - [TestCase("3", TestEnum.Three)] - [TestCase("three", TestEnum.Three)] - [TestCase("Four", TestEnum.Four)] - [TestCase("four", TestEnum.Four)] - [TestCase("Four1", (TestEnum)(-9))] - [TestCase(null, (TestEnum)(-9))] - public void TestEnumConverterNotNullableDeserializeTests(string value, TestEnum expected) - { - var val = value == null ? "null" : $"\"{value}\""; - var output = JsonSerializer.Deserialize($"{{ \"Value\": {val} }}"); - Assert.That(output.Value == expected); - } - - [Test] - public void TestEnumConverterMapsUndefinedValueCorrectlyIfDefaultIsDefined() - { - var output = JsonSerializer.Deserialize($"\"TestUndefined\""); - Assert.That((int)output == -99); - } - - [TestCase("1", TestEnum.One)] - [TestCase("2", TestEnum.Two)] - [TestCase("3", TestEnum.Three)] - [TestCase("three", TestEnum.Three)] - [TestCase("Four", TestEnum.Four)] - [TestCase("four", TestEnum.Four)] - [TestCase("Four1", null)] - [TestCase(null, null)] - public void TestEnumConverterParseStringTests(string value, TestEnum? expected) - { - var result = EnumConverter.ParseString(value); - Assert.That(result == expected); - } - - [Test] - public void TestEnumConverterParseNullOnNonNullableOnlyLogsOnce() - { - LibraryHelpers.StaticLogger = new TraceLogger(); - var listener = new EnumValueTraceListener(); - Trace.Listeners.Add(listener); - EnumConverter.Reset(); - try - { - Assert.Throws(() => - { - var result = JsonSerializer.Deserialize("{\"Value\": null}", SerializerOptions.WithConverters(new SerializationContext())); - }); - - Assert.DoesNotThrow(() => - { - var result2 = JsonSerializer.Deserialize("{\"Value\": null}", SerializerOptions.WithConverters(new SerializationContext())); - }); - } - finally - { - Trace.Listeners.Remove(listener); - } - } - - [TestCase("1", true)] - [TestCase("true", true)] - [TestCase("yes", true)] - [TestCase("y", true)] - [TestCase("on", true)] - [TestCase("-1", false)] - [TestCase("0", false)] - [TestCase("n", false)] - [TestCase("no", false)] - [TestCase("false", false)] - [TestCase("off", false)] - [TestCase("", null)] - public void TestBoolConverter(string value, bool? expected) - { - var val = value == null ? "null" : $"\"{value}\""; - var output = JsonSerializer.Deserialize($"{{ \"Value\": {val} }}", SerializerOptions.WithConverters(new SerializationContext())); - Assert.That(output.Value == expected); - } - - [TestCase("1", true)] - [TestCase("true", true)] - [TestCase("yes", true)] - [TestCase("y", true)] - [TestCase("on", true)] - [TestCase("-1", false)] - [TestCase("0", false)] - [TestCase("n", false)] - [TestCase("no", false)] - [TestCase("false", false)] - [TestCase("off", false)] - [TestCase("", false)] - public void TestBoolConverterNotNullable(string value, bool expected) - { - var val = value == null ? "null" : $"\"{value}\""; - var output = JsonSerializer.Deserialize($"{{ \"Value\": {val} }}", SerializerOptions.WithConverters(new SerializationContext())); - Assert.That(output.Value == expected); - } - - [TestCase("1", 1)] - [TestCase("1.1", 1.1)] - [TestCase("-1.1", -1.1)] - [TestCase(null, null)] - [TestCase("", null)] - [TestCase("null", null)] - [TestCase("nan", null)] - [TestCase("1E+2", 100)] - [TestCase("1E-2", 0.01)] - [TestCase("Infinity", 999)] // 999 is workaround for not being able to specify decimal.MinValue - [TestCase("-Infinity", -999)] // -999 is workaround for not being able to specify decimal.MaxValue - [TestCase("80228162514264337593543950335", 999)] // 999 is workaround for not being able to specify decimal.MaxValue - [TestCase("-80228162514264337593543950335", -999)] // -999 is workaround for not being able to specify decimal.MaxValue - public void TestDecimalConverterString(string value, decimal? expected) - { - var result = JsonSerializer.Deserialize("{ \"test\": \""+ value + "\"}"); - Assert.That(result.Test, Is.EqualTo(expected == -999 ? decimal.MinValue : expected == 999 ? decimal.MaxValue: expected)); - } - - [TestCase("1", 1)] - [TestCase("1.1", 1.1)] - [TestCase("-1.1", -1.1)] - [TestCase("null", null)] - [TestCase("1E+2", 100)] - [TestCase("1E-2", 0.01)] - [TestCase("80228162514264337593543950335", -999)] // -999 is workaround for not being able to specify decimal.MaxValue - public void TestDecimalConverterNumber(string value, decimal? expected) - { - var result = JsonSerializer.Deserialize("{ \"test\": " + value + "}"); - Assert.That(result.Test, Is.EqualTo(expected == -999 ? decimal.MaxValue : expected)); - } - - [Test()] - public void TestArrayConverter() - { - var data = new Test() - { - Prop1 = 2, - Prop2 = null, - Prop3 = "123", - Prop3Again = "123", - Prop4 = null, - Prop5 = new Test2 - { - Prop21 = 3, - Prop22 = "456" - }, - Prop6 = new Test3 - { - Prop31 = 4, - Prop32 = "789" - }, - Prop7 = TestEnum.Two, - TestInternal = new Test - { - Prop1 = 10 - }, - Prop8 = new Test3 - { - Prop31 = 5, - Prop32 = "101" - }, - }; - - var options = new JsonSerializerOptions() - { - TypeInfoResolver = new SerializationContext() - }; - var serialized = JsonSerializer.Serialize(data); - var deserialized = JsonSerializer.Deserialize(serialized); - - Assert.That(deserialized.Prop1, Is.EqualTo(2)); - Assert.That(deserialized.Prop2, Is.Null); - Assert.That(deserialized.Prop3, Is.EqualTo("123")); - Assert.That(deserialized.Prop3Again, Is.EqualTo("123")); - Assert.That(deserialized.Prop4, Is.Null); - Assert.That(deserialized.Prop5.Prop21, Is.EqualTo(3)); - Assert.That(deserialized.Prop5.Prop22, Is.EqualTo("456")); - Assert.That(deserialized.Prop6.Prop31, Is.EqualTo(4)); - Assert.That(deserialized.Prop6.Prop32, Is.EqualTo("789")); - Assert.That(deserialized.Prop7, Is.EqualTo(TestEnum.Two)); - Assert.That(deserialized.TestInternal.Prop1, Is.EqualTo(10)); - Assert.That(deserialized.Prop8.Prop31, Is.EqualTo(5)); - Assert.That(deserialized.Prop8.Prop32, Is.EqualTo("101")); - } - - [TestCase(TradingMode.Spot, "ETH", "USDT", null)] - [TestCase(TradingMode.PerpetualLinear, "ETH", "USDT", null)] - [TestCase(TradingMode.DeliveryLinear, "ETH", "USDT", 1748432430)] - public void TestSharedSymbolConversion(TradingMode tradingMode, string baseAsset, string quoteAsset, int? deliverTime) - { - DateTime? time = deliverTime == null ? null : DateTimeConverter.ParseFromDouble(deliverTime.Value); - var symbol = new SharedSymbol(tradingMode, baseAsset, quoteAsset, time); - - var serialized = JsonSerializer.Serialize(symbol); - var restored = JsonSerializer.Deserialize(serialized); - - Assert.That(restored.TradingMode, Is.EqualTo(symbol.TradingMode)); - Assert.That(restored.BaseAsset, Is.EqualTo(symbol.BaseAsset)); - Assert.That(restored.QuoteAsset, Is.EqualTo(symbol.QuoteAsset)); - Assert.That(restored.DeliverTime, Is.EqualTo(symbol.DeliverTime)); - } - - [TestCase(0.1, null, null)] - [TestCase(0.1, 0.1, null)] - [TestCase(0.1, 0.1, 0.1)] - [TestCase(null, 0.1, null)] - [TestCase(null, 0.1, 0.1)] - public void TestSharedQuantityConversion(double? baseQuantity, double? quoteQuantity, double? contractQuantity) - { - var symbol = new SharedOrderQuantity((decimal?)baseQuantity, (decimal?)quoteQuantity, (decimal?)contractQuantity); - - var serialized = JsonSerializer.Serialize(symbol); - var restored = JsonSerializer.Deserialize(serialized); - - Assert.That(restored.QuantityInBaseAsset, Is.EqualTo(symbol.QuantityInBaseAsset)); - Assert.That(restored.QuantityInQuoteAsset, Is.EqualTo(symbol.QuantityInQuoteAsset)); - Assert.That(restored.QuantityInContracts, Is.EqualTo(symbol.QuantityInContracts)); - } - } - - public class STJDecimalObject - { - [JsonConverter(typeof(DecimalConverter))] - [JsonPropertyName("test")] - public decimal? Test { get; set; } - } - - public class STJTimeObject - { - [JsonConverter(typeof(DateTimeConverter))] - [JsonPropertyName("time")] - public DateTime? Time { get; set; } - } - - public class STJEnumObject - { - public TestEnum? Value { get; set; } - } - - public class NotNullableSTJEnumObject - { - public TestEnum Value { get; set; } - } - - public class STJBoolObject - { - public bool? Value { get; set; } - } - - public class NotNullableSTJBoolObject - { - public bool Value { get; set; } - } - - [JsonConverter(typeof(ArrayConverter))] - record Test - { - [ArrayProperty(0)] - public int Prop1 { get; set; } - [ArrayProperty(1)] - public int? Prop2 { get; set; } - [ArrayProperty(2)] - public string Prop3 { get; set; } - [ArrayProperty(2)] - public string Prop3Again { get; set; } - [ArrayProperty(3)] - public string Prop4 { get; set; } - [ArrayProperty(4)] - public Test2 Prop5 { get; set; } - [ArrayProperty(5)] - public Test3 Prop6 { get; set; } - [ArrayProperty(6), JsonConverter(typeof(EnumConverter))] - public TestEnum? Prop7 { get; set; } - [ArrayProperty(7)] - public Test TestInternal { get; set; } - [ArrayProperty(8), JsonConversion] - public Test3 Prop8 { get; set; } - } - - [JsonConverter(typeof(ArrayConverter))] - record Test2 - { - [ArrayProperty(0)] - public int Prop21 { get; set; } - [ArrayProperty(1)] - public string Prop22 { get; set; } - } - - record Test3 - { - [JsonPropertyName("prop31")] - public int Prop31 { get; set; } - [JsonPropertyName("prop32")] - public string Prop32 { get; set; } - } - - [JsonConverter(typeof(EnumConverter))] - public enum TestEnum - { - [Map("1")] - One, - [Map("2")] - Two, - [Map("three", "3")] - Three, - Four - } - - [JsonConverter(typeof(EnumConverter))] - public enum TestEnum2 - { - [Map("-9")] - Minus9 = -9, - [Map("1")] - One, - [Map("2")] - Two, - [Map("three", "3")] - Three, - Four - } - - [JsonSerializable(typeof(Test))] - [JsonSerializable(typeof(Test2))] - [JsonSerializable(typeof(Test3))] - [JsonSerializable(typeof(NotNullableSTJBoolObject))] - [JsonSerializable(typeof(STJBoolObject))] - [JsonSerializable(typeof(NotNullableSTJEnumObject))] - [JsonSerializable(typeof(STJEnumObject))] - [JsonSerializable(typeof(STJDecimalObject))] - [JsonSerializable(typeof(STJTimeObject))] - internal partial class SerializationContext : JsonSerializerContext - { - } -} diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs b/CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs deleted file mode 100644 index 45afb53..0000000 --- a/CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs +++ /dev/null @@ -1,88 +0,0 @@ -//using System; -//using System.IO; -//using System.Text; -//using System.Text.Json; -//using System.Threading.Tasks; -//using CryptoExchange.Net.Authentication; -//using CryptoExchange.Net.Clients; -//using CryptoExchange.Net.Converters.MessageParsing.DynamicConverters; -//using CryptoExchange.Net.Converters.SystemTextJson; -//using CryptoExchange.Net.Interfaces; -//using CryptoExchange.Net.Objects; -//using CryptoExchange.Net.Objects.Errors; -//using CryptoExchange.Net.Objects.Options; -//using CryptoExchange.Net.SharedApis; -//using Microsoft.Extensions.Logging; -//using Microsoft.Extensions.Logging.Abstractions; - -//namespace CryptoExchange.Net.UnitTests -//{ -// public class TestBaseClient: BaseClient -// { -// public TestSubClient SubClient { get; } - -// public TestBaseClient(): base(null, "Test") -// { -// var options = new TestClientOptions(); -// _logger = NullLogger.Instance; -// Initialize(options); -// SubClient = AddApiClient(new TestSubClient(options, new RestApiOptions())); -// } - -// public TestBaseClient(TestClientOptions exchangeOptions) : base(null, "Test") -// { -// _logger = NullLogger.Instance; -// Initialize(exchangeOptions); -// SubClient = AddApiClient(new TestSubClient(exchangeOptions, new RestApiOptions())); -// } - -// public void Log(LogLevel verbosity, string data) -// { -// _logger.Log(verbosity, data); -// } -// } - -// public class TestSubClient : RestApiClient -// { -// protected override IRestMessageHandler MessageHandler => throw new NotImplementedException(); - -// public TestSubClient(RestExchangeOptions options, RestApiOptions apiOptions) : base(new TraceLogger(), null, "https://localhost:123", options, apiOptions) -// { -// } - -// public CallResult Deserialize(string data) -// { -// return new CallResult(JsonSerializer.Deserialize(data)); -// } - -// /// -// public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode futuresType, DateTime? deliverDate = null) => $"{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}"; -// protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(new System.Text.Json.JsonSerializerOptions()); -// protected override TestAuthProvider CreateAuthenticationProvider(HMACCredential credentials) => throw new NotImplementedException(); -// protected override Task> GetServerTimestampAsync() => throw new NotImplementedException(); -// } - -// public class TestAuthProvider : AuthenticationProvider -// { -// public TestAuthProvider(HMACCredential credentials) : base(credentials, credentials) -// { -// } - -// public override void ProcessRequest(RestApiClient apiClient, RestRequestConfiguration requestConfig) -// { -// } - -// public string GetKey() => Credential.Key; -// public string GetSecret() => Credential.Secret; -// } - -// public class TestEnvironment : TradeEnvironment -// { -// public string TestAddress { get; } - -// public TestEnvironment(string name, string url) : base(name) -// { -// TestAddress = url; -// } -// } -//} diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/TestHelpers.cs b/CryptoExchange.Net.UnitTests/TestImplementations/TestHelpers.cs deleted file mode 100644 index 9e95043..0000000 --- a/CryptoExchange.Net.UnitTests/TestImplementations/TestHelpers.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Reflection; - -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 deleted file mode 100644 index 3e19849..0000000 --- a/CryptoExchange.Net.UnitTests/TestImplementations/TestObjects.cs +++ /dev/null @@ -1,14 +0,0 @@ -//using System.Text.Json.Serialization; - -//namespace CryptoExchange.Net.UnitTests.TestImplementations -//{ -// public class TestObject -// { -// [JsonPropertyName("other")] -// public string StringData { get; set; } -// [JsonPropertyName("intData")] -// public int IntData { get; set; } -// [JsonPropertyName("decimalData")] -// public decimal DecimalData { get; set; } -// } -//} diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/TestRestClient.cs b/CryptoExchange.Net.UnitTests/TestImplementations/TestRestClient.cs deleted file mode 100644 index 7ac6742..0000000 --- a/CryptoExchange.Net.UnitTests/TestImplementations/TestRestClient.cs +++ /dev/null @@ -1,213 +0,0 @@ -//using CryptoExchange.Net.Interfaces; -//using CryptoExchange.Net.Objects; -//using Moq; -//using System; -//using System.IO; -//using System.Net; -//using System.Net.Http; -//using System.Reflection; -//using System.Text; -//using System.Threading; -//using System.Threading.Tasks; -//using CryptoExchange.Net.Authentication; -//using System.Collections.Generic; -//using Microsoft.Extensions.Logging; -//using CryptoExchange.Net.Clients; -//using Microsoft.Extensions.Options; -//using System.Linq; -//using CryptoExchange.Net.Converters.SystemTextJson; -//using System.Text.Json.Serialization; -//using System.Net.Http.Headers; -//using CryptoExchange.Net.SharedApis; -//using CryptoExchange.Net.Converters.MessageParsing.DynamicConverters; - -//namespace CryptoExchange.Net.UnitTests.TestImplementations -//{ -// public class TestRestClient: BaseRestClient -// { -// public TestRestApi1Client Api1 { get; } -// public TestRestApi2Client Api2 { get; } - -// public TestRestClient(Action optionsDelegate = null) -// : this(null, null, Options.Create(ApplyOptionsDelegate(optionsDelegate))) -// { -// } - -// public TestRestClient(HttpClient httpClient, ILoggerFactory loggerFactory, IOptions options) : base(loggerFactory, "Test") -// { -// Initialize(options.Value); - -// Api1 = AddApiClient(new TestRestApi1Client(options.Value)); -// Api2 = AddApiClient(new TestRestApi2Client(options.Value)); -// } - -// public void SetResponse(string responseData, out IRequest requestObj) -// { -// 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.IsSuccessStatusCode).Returns(true); -// response.Setup(c => c.GetResponseStreamAsync(It.IsAny())).Returns(Task.FromResult((Stream)responseStream)); - -// var headers = new HttpRequestMessage().Headers; -// var request = new Mock(); -// request.Setup(c => c.Uri).Returns(new Uri("http://www.test.com")); -// request.Setup(c => c.GetResponseAsync(It.IsAny())).Returns(Task.FromResult(response.Object)); -// request.Setup(c => c.SetContent(It.IsAny(), It.IsAny(), It.IsAny())).Callback(new Action((content, encoding, type) => { request.Setup(r => r.Content).Returns(content); })); -// request.Setup(c => c.AddHeader(It.IsAny(), It.IsAny())).Callback((key, val) => headers.Add(key, new string[] { val })); -// request.Setup(c => c.GetHeaders()).Returns(() => headers); - -// var factory = Mock.Get(Api1.RequestFactory); -// factory.Setup(c => c.Create(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) -// .Callback((version, method, uri, id) => -// { -// request.Setup(a => a.Uri).Returns(uri); -// request.Setup(a => a.Method).Returns(method); -// }) -// .Returns(request.Object); - -// factory = Mock.Get(Api2.RequestFactory); -// factory.Setup(c => c.Create(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) -// .Callback((version, method, uri, id) => -// { -// request.Setup(a => a.Uri).Returns(uri); -// request.Setup(a => a.Method).Returns(method); -// }) -// .Returns(request.Object); -// requestObj = request.Object; -// } - -// public void SetErrorWithoutResponse(HttpStatusCode code, string message) -// { -// var we = new HttpRequestException(); -// typeof(HttpRequestException).GetField("_message", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(we, message); - -// var request = new Mock(); -// request.Setup(c => c.Uri).Returns(new Uri("http://www.test.com")); -// request.Setup(c => c.GetHeaders()).Returns(new HttpRequestMessage().Headers); -// request.Setup(c => c.GetResponseAsync(It.IsAny())).Throws(we); - -// var factory = Mock.Get(Api1.RequestFactory); -// factory.Setup(c => c.Create(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) -// .Returns(request.Object); - - -// factory = Mock.Get(Api2.RequestFactory); -// factory.Setup(c => c.Create(It.IsAny(), It.IsAny(), It.IsAny(), 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 response = new Mock(); -// response.Setup(c => c.IsSuccessStatusCode).Returns(false); -// response.Setup(c => c.GetResponseStreamAsync(It.IsAny())).Returns(Task.FromResult((Stream)responseStream)); - -// var headers = new List>(); -// var request = new Mock(); -// request.Setup(c => c.Uri).Returns(new Uri("http://www.test.com")); -// request.Setup(c => c.GetResponseAsync(It.IsAny())).Returns(Task.FromResult(response.Object)); -// request.Setup(c => c.AddHeader(It.IsAny(), It.IsAny())).Callback((key, val) => headers.Add(new KeyValuePair(key, new string[] { val }))); -// request.Setup(c => c.GetHeaders()).Returns(new HttpRequestMessage().Headers); - -// var factory = Mock.Get(Api1.RequestFactory); -// factory.Setup(c => c.Create(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) -// .Callback((version, method, uri, id) => request.Setup(a => a.Uri).Returns(uri)) -// .Returns(request.Object); - -// factory = Mock.Get(Api2.RequestFactory); -// factory.Setup(c => c.Create(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) -// .Callback((version, method, uri, id) => request.Setup(a => a.Uri).Returns(uri)) -// .Returns(request.Object); -// } -// } - -// public class TestRestApi1Client : RestApiClient -// { -// protected override IRestMessageHandler MessageHandler { get; } = new TestRestMessageHandler(); - -// public TestRestApi1Client(TestClientOptions options) : base(new TraceLogger(), null, "https://localhost:123", options, options.Api1Options) -// { -// RequestFactory = new Mock().Object; -// } - -// /// -// public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode futuresType, DateTime? deliverDate = null) => $"{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}"; - -// protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(new System.Text.Json.JsonSerializerOptions()); - -// public async Task> Request(CancellationToken ct = default) where T : class -// { -// return await SendAsync("http://www.test.com", new RequestDefinition("/", HttpMethod.Get) { Weight = 0 }, null, ct); -// } - -// public async Task> RequestWithParams(HttpMethod method, ParameterCollection parameters, Dictionary headers) where T : class -// { -// return await SendAsync("http://www.test.com", new RequestDefinition("/", method) { Weight = 0 }, parameters, default, additionalHeaders: headers); -// } - -// public void SetParameterPosition(HttpMethod method, HttpMethodParameterPosition position) -// { -// ParameterPositions[method] = position; -// } - -// protected override TestAuthProvider CreateAuthenticationProvider(HMACCredential credentials) -// => new TestAuthProvider(credentials); - -// protected override Task> GetServerTimestampAsync() -// { -// throw new NotImplementedException(); -// } -// } - -// public class TestRestApi2Client : RestApiClient -// { -// protected override IRestMessageHandler MessageHandler { get; } = new TestRestMessageHandler(); - -// public TestRestApi2Client(TestClientOptions options) : base(new TraceLogger(), null, "https://localhost:123", options, options.Api2Options) -// { -// RequestFactory = new Mock().Object; -// } - -// protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer(new System.Text.Json.JsonSerializerOptions()); - -// /// -// public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode futuresType, DateTime? deliverDate = null) => $"{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}"; - -// public async Task> Request(CancellationToken ct = default) where T : class -// { -// return await SendAsync("http://www.test.com", new RequestDefinition("/", HttpMethod.Get) { Weight = 0 }, null, ct); -// } - -// protected override TestAuthProvider CreateAuthenticationProvider(HMACCredential credentials) -// => new TestAuthProvider(credentials); - -// protected override Task> GetServerTimestampAsync() -// { -// throw new NotImplementedException(); -// } - -// } - -// public class TestError -// { -// [JsonPropertyName("errorCode")] -// public int ErrorCode { get; set; } -// [JsonPropertyName("errorMessage")] -// public string ErrorMessage { get; set; } -// } - -// public class ParseErrorTestRestClient: TestRestClient -// { -// public ParseErrorTestRestClient() { } - -// } -//} diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/TestRestMessageHandler.cs b/CryptoExchange.Net.UnitTests/TestImplementations/TestRestMessageHandler.cs deleted file mode 100644 index 0ef8dc3..0000000 --- a/CryptoExchange.Net.UnitTests/TestImplementations/TestRestMessageHandler.cs +++ /dev/null @@ -1,32 +0,0 @@ -//using CryptoExchange.Net.Converters.MessageParsing.DynamicConverters; -//using CryptoExchange.Net.Converters.SystemTextJson.MessageHandlers; -//using CryptoExchange.Net.Objects; -//using CryptoExchange.Net.Objects.Errors; -//using System; -//using System.Collections.Generic; -//using System.IO; -//using System.Linq; -//using System.Net.Http.Headers; -//using System.Text; -//using System.Text.Json; -//using System.Threading; -//using System.Threading.Tasks; - -//namespace CryptoExchange.Net.UnitTests.TestImplementations -//{ -// internal class TestRestMessageHandler : JsonRestMessageHandler -// { -// private ErrorMapping _errorMapping = new ErrorMapping([]); -// public override JsonSerializerOptions Options => new JsonSerializerOptions(); - -// public override async ValueTask ParseErrorResponse(int httpStatusCode, HttpResponseHeaders responseHeaders, Stream responseStream) -// { -// var result = await GetJsonDocument(responseStream).ConfigureAwait(false); -// if (result.Item1 != null) -// return result.Item1; - -// var errorData = result.Item2.Deserialize(); -// return new ServerError(errorData.ErrorCode, _errorMapping.GetErrorInfo(errorData.ErrorCode.ToString(), errorData.ErrorMessage)); -// } -// } -//}