1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2026-04-07 18:21:30 +00:00

Updated tests

This commit is contained in:
JKorf 2026-04-05 20:01:43 +02:00
parent 1de446493e
commit 8f2adaabe2
22 changed files with 733 additions and 234 deletions

View File

@ -96,7 +96,7 @@ namespace CryptoExchange.Net.UnitTests
waiters.Add(evnt.WaitAsync()); waiters.Add(evnt.WaitAsync());
} }
List<bool> results = null; List<bool>? results = null;
var resultsWaiter = Task.Run(async () => var resultsWaiter = Task.Run(async () =>
{ {
await Task.WhenAll(waiters); await Task.WhenAll(waiters);
@ -112,7 +112,7 @@ namespace CryptoExchange.Net.UnitTests
await resultsWaiter; await resultsWaiter;
Assert.That(10 == results.Count(r => r)); Assert.That(10 == results?.Count(r => r));
} }
[Test] [Test]

View File

@ -0,0 +1,43 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Text;
using CryptoExchange.Net;
using CryptoExchange.Net.Objects;
using CryptoExchange.Net.Converters.SystemTextJson;
namespace CryptoExchange.Net.UnitTests
{
internal class BodySerializationTests
{
[Test]
public void ToFormData_SerializesBasicValuesCorrectly()
{
var parameters = new Dictionary<string, object>()
{
{ "a", "1" },
{ "b", 2 },
{ "c", true }
};
var parameterString = parameters.ToFormData();
Assert.That(parameterString, Is.EqualTo("a=1&b=2&c=True"));
}
[Test]
public void JsonSerializer_SerializesBasicValuesCorrectly()
{
var serializer = new SystemTextJsonMessageSerializer(SerializerOptions.WithConverters(new TestSerializerContext()));
var parameters = new Dictionary<string, object>()
{
{ "a", "1" },
{ "b", 2 },
{ "c", true }
};
var parameterString = serializer.Serialize(parameters);
Assert.That(parameterString, Is.EqualTo("{\"a\":\"1\",\"b\":2,\"c\":true}"));
}
}
}

View File

@ -16,7 +16,7 @@ namespace CryptoExchange.Net.UnitTests
{ {
var result = new CallResult(new ServerError("TestError", ErrorInfo.Unknown)); var result = new CallResult(new ServerError("TestError", ErrorInfo.Unknown));
ClassicAssert.AreSame(result.Error.ErrorCode, "TestError"); ClassicAssert.AreSame(result.Error!.ErrorCode, "TestError");
ClassicAssert.IsFalse(result); ClassicAssert.IsFalse(result);
ClassicAssert.IsFalse(result.Success); ClassicAssert.IsFalse(result.Success);
} }
@ -36,7 +36,7 @@ namespace CryptoExchange.Net.UnitTests
{ {
var result = new CallResult<object>(new ServerError("TestError", ErrorInfo.Unknown)); var result = new CallResult<object>(new ServerError("TestError", ErrorInfo.Unknown));
ClassicAssert.AreSame(result.Error.ErrorCode, "TestError"); ClassicAssert.AreSame(result.Error!.ErrorCode, "TestError");
ClassicAssert.IsNull(result.Data); ClassicAssert.IsNull(result.Data);
ClassicAssert.IsFalse(result); ClassicAssert.IsFalse(result);
ClassicAssert.IsFalse(result.Success); ClassicAssert.IsFalse(result.Success);
@ -73,7 +73,7 @@ namespace CryptoExchange.Net.UnitTests
var asResult = result.As<TestObject2>(default); var asResult = result.As<TestObject2>(default);
ClassicAssert.IsNotNull(asResult.Error); ClassicAssert.IsNotNull(asResult.Error);
ClassicAssert.AreSame(asResult.Error.ErrorCode, "TestError"); ClassicAssert.AreSame(asResult.Error!.ErrorCode, "TestError");
ClassicAssert.IsNull(asResult.Data); ClassicAssert.IsNull(asResult.Data);
ClassicAssert.IsFalse(asResult); ClassicAssert.IsFalse(asResult);
ClassicAssert.IsFalse(asResult.Success); ClassicAssert.IsFalse(asResult.Success);
@ -86,7 +86,7 @@ namespace CryptoExchange.Net.UnitTests
var asResult = result.AsError<TestObject2>(new ServerError("TestError2", ErrorInfo.Unknown)); var asResult = result.AsError<TestObject2>(new ServerError("TestError2", ErrorInfo.Unknown));
ClassicAssert.IsNotNull(asResult.Error); ClassicAssert.IsNotNull(asResult.Error);
ClassicAssert.AreSame(asResult.Error.ErrorCode, "TestError2"); ClassicAssert.AreSame(asResult.Error!.ErrorCode, "TestError2");
ClassicAssert.IsNull(asResult.Data); ClassicAssert.IsNull(asResult.Data);
ClassicAssert.IsFalse(asResult); ClassicAssert.IsFalse(asResult);
ClassicAssert.IsFalse(asResult.Success); ClassicAssert.IsFalse(asResult.Success);
@ -99,7 +99,7 @@ namespace CryptoExchange.Net.UnitTests
var asResult = result.AsError<TestObject2>(new ServerError("TestError2", ErrorInfo.Unknown)); var asResult = result.AsError<TestObject2>(new ServerError("TestError2", ErrorInfo.Unknown));
ClassicAssert.IsNotNull(asResult.Error); ClassicAssert.IsNotNull(asResult.Error);
ClassicAssert.AreSame(asResult.Error.ErrorCode, "TestError2"); ClassicAssert.AreSame(asResult.Error!.ErrorCode, "TestError2");
ClassicAssert.IsNull(asResult.Data); ClassicAssert.IsNull(asResult.Data);
ClassicAssert.IsFalse(asResult); ClassicAssert.IsFalse(asResult);
ClassicAssert.IsFalse(asResult.Success); ClassicAssert.IsFalse(asResult.Success);
@ -126,7 +126,7 @@ namespace CryptoExchange.Net.UnitTests
var asResult = result.AsError<TestObject2>(new ServerError("TestError2", ErrorInfo.Unknown)); var asResult = result.AsError<TestObject2>(new ServerError("TestError2", ErrorInfo.Unknown));
ClassicAssert.IsNotNull(asResult.Error); ClassicAssert.IsNotNull(asResult.Error);
Assert.That(asResult.Error.ErrorCode == "TestError2"); Assert.That(asResult.Error!.ErrorCode == "TestError2");
Assert.That(asResult.ResponseStatusCode == System.Net.HttpStatusCode.OK); Assert.That(asResult.ResponseStatusCode == System.Net.HttpStatusCode.OK);
Assert.That(asResult.ResponseTime == TimeSpan.FromSeconds(1)); Assert.That(asResult.ResponseTime == TimeSpan.FromSeconds(1));
Assert.That(asResult.RequestUrl == "https://test.com/api"); Assert.That(asResult.RequestUrl == "https://test.com/api");

View File

@ -97,7 +97,7 @@ namespace CryptoExchange.Net.UnitTests.ClientTests
ClassicAssert.IsFalse(result.Success); ClassicAssert.IsFalse(result.Success);
Assert.That(result.Error != null); Assert.That(result.Error != null);
Assert.That(result.Error is DeserializeError); Assert.That(result.Error is DeserializeError);
Assert.That(result.Error.Message.Contains(response)); Assert.That(result.Error!.Message!.Contains(response));
} }
[TestCase] [TestCase]
@ -114,7 +114,7 @@ namespace CryptoExchange.Net.UnitTests.ClientTests
ClassicAssert.IsFalse(result.Success); ClassicAssert.IsFalse(result.Success);
Assert.That(result.Error != null); Assert.That(result.Error != null);
Assert.That(result.Error is ServerError); Assert.That(result.Error is ServerError);
Assert.That(result.Error.ErrorCode == "123"); Assert.That(result.Error!.ErrorCode == "123");
Assert.That(result.Error.Message == "Invalid request"); Assert.That(result.Error.Message == "Invalid request");
} }
@ -186,12 +186,12 @@ namespace CryptoExchange.Net.UnitTests.ClientTests
var requestDefinition = new RequestDefinition(endpoint, HttpMethod.Get); var requestDefinition = new RequestDefinition(endpoint, HttpMethod.Get);
RateLimitEvent evnt = null; RateLimitEvent? evnt = null;
rateLimiter.RateLimitTriggered += (x) => { evnt = x; }; rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
for (var i = 0; i < 2; i++) 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); 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); Assert.That(expected);
} }
} }
@ -208,7 +208,7 @@ namespace CryptoExchange.Net.UnitTests.ClientTests
var requestDefinition1 = new RequestDefinition(endpoint1, HttpMethod.Get); var requestDefinition1 = new RequestDefinition(endpoint1, HttpMethod.Get);
var requestDefinition2 = new RequestDefinition(endpoint2, HttpMethod.Get); var requestDefinition2 = new RequestDefinition(endpoint2, HttpMethod.Get);
RateLimitEvent evnt = null; RateLimitEvent? evnt = null;
rateLimiter.RateLimitTriggered += (x) => { evnt = x; }; rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition1, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default); var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition1, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default);
@ -251,12 +251,12 @@ namespace CryptoExchange.Net.UnitTests.ClientTests
var requestDefinition = new RequestDefinition(endpoint, HttpMethod.Get); var requestDefinition = new RequestDefinition(endpoint, HttpMethod.Get);
RateLimitEvent evnt = null; RateLimitEvent? evnt = null;
rateLimiter.RateLimitTriggered += (x) => { evnt = x; }; rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
for (var i = 0; i < 2; i++) 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); 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); Assert.That(expected);
} }
} }
@ -271,12 +271,12 @@ namespace CryptoExchange.Net.UnitTests.ClientTests
rateLimiter.AddGuard(new RateLimitGuard(RateLimitGuard.PerEndpoint, new ExactPathsFilter(new[] { "/sapi/test", "/sapi/test2" }), 1, TimeSpan.FromSeconds(0.1), RateLimitWindowType.Fixed)); rateLimiter.AddGuard(new RateLimitGuard(RateLimitGuard.PerEndpoint, new ExactPathsFilter(new[] { "/sapi/test", "/sapi/test2" }), 1, TimeSpan.FromSeconds(0.1), RateLimitWindowType.Fixed));
var requestDefinition = new RequestDefinition(endpoint, HttpMethod.Get); var requestDefinition = new RequestDefinition(endpoint, HttpMethod.Get);
RateLimitEvent evnt = null; RateLimitEvent? evnt = null;
rateLimiter.RateLimitTriggered += (x) => { evnt = x; }; rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
for (var i = 0; i < 2; i++) 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); 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); Assert.That(expected);
} }
} }
@ -295,7 +295,7 @@ namespace CryptoExchange.Net.UnitTests.ClientTests
var requestDefinition1 = new RequestDefinition(endpoint1, HttpMethod.Get) { Authenticated = key1 != null }; var requestDefinition1 = new RequestDefinition(endpoint1, HttpMethod.Get) { Authenticated = key1 != null };
var requestDefinition2 = new RequestDefinition(endpoint2, HttpMethod.Get) { Authenticated = key2 != null }; var requestDefinition2 = new RequestDefinition(endpoint2, HttpMethod.Get) { Authenticated = key2 != null };
RateLimitEvent evnt = null; RateLimitEvent? evnt = null;
rateLimiter.RateLimitTriggered += (x) => { evnt = x; }; rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition1, "https://test.com", key1, 1, RateLimitingBehaviour.Wait, null, default); var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition1, "https://test.com", key1, 1, RateLimitingBehaviour.Wait, null, default);
@ -314,7 +314,7 @@ namespace CryptoExchange.Net.UnitTests.ClientTests
var requestDefinition1 = new RequestDefinition(endpoint1, HttpMethod.Get); var requestDefinition1 = new RequestDefinition(endpoint1, HttpMethod.Get);
var requestDefinition2 = new RequestDefinition(endpoint2, HttpMethod.Get) { Authenticated = true }; var requestDefinition2 = new RequestDefinition(endpoint2, HttpMethod.Get) { Authenticated = true };
RateLimitEvent evnt = null; RateLimitEvent? evnt = null;
rateLimiter.RateLimitTriggered += (x) => { evnt = x; }; rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition1, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default); var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition1, "https://test.com", "123", 1, RateLimitingBehaviour.Wait, null, default);
@ -334,7 +334,7 @@ namespace CryptoExchange.Net.UnitTests.ClientTests
var requestDefinition1 = new RequestDefinition(endpoint1, HttpMethod.Get); var requestDefinition1 = new RequestDefinition(endpoint1, HttpMethod.Get);
var requestDefinition2 = new RequestDefinition(endpoint2, HttpMethod.Get) { Authenticated = true }; var requestDefinition2 = new RequestDefinition(endpoint2, HttpMethod.Get) { Authenticated = true };
RateLimitEvent evnt = null; RateLimitEvent? evnt = null;
rateLimiter.RateLimitTriggered += (x) => { evnt = x; }; rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition1, host1, "123", 1, RateLimitingBehaviour.Wait, null, default); var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Request, requestDefinition1, host1, "123", 1, RateLimitingBehaviour.Wait, null, default);
@ -351,7 +351,7 @@ namespace CryptoExchange.Net.UnitTests.ClientTests
var rateLimiter = new RateLimitGate("Test"); var rateLimiter = new RateLimitGate("Test");
rateLimiter.AddGuard(new RateLimitGuard(RateLimitGuard.PerHost, new LimitItemTypeFilter(RateLimitItemType.Connection), 1, TimeSpan.FromSeconds(0.1), RateLimitWindowType.Fixed)); rateLimiter.AddGuard(new RateLimitGuard(RateLimitGuard.PerHost, new LimitItemTypeFilter(RateLimitItemType.Connection), 1, TimeSpan.FromSeconds(0.1), RateLimitWindowType.Fixed));
RateLimitEvent evnt = null; RateLimitEvent? evnt = null;
rateLimiter.RateLimitTriggered += (x) => { evnt = x; }; rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Connection, new RequestDefinition("1", HttpMethod.Get), host1, "123", 1, RateLimitingBehaviour.Wait, null, default); var result1 = await rateLimiter.ProcessAsync(new TraceLogger(), 1, RateLimitItemType.Connection, new RequestDefinition("1", HttpMethod.Get), host1, "123", 1, RateLimitingBehaviour.Wait, null, default);
@ -366,7 +366,7 @@ namespace CryptoExchange.Net.UnitTests.ClientTests
var rateLimiter = new RateLimitGate("Test"); var rateLimiter = new RateLimitGate("Test");
rateLimiter.AddGuard(new RateLimitGuard(RateLimitGuard.PerHost, new LimitItemTypeFilter(RateLimitItemType.Connection), 1, TimeSpan.FromSeconds(10), RateLimitWindowType.Fixed)); rateLimiter.AddGuard(new RateLimitGuard(RateLimitGuard.PerHost, new LimitItemTypeFilter(RateLimitItemType.Connection), 1, TimeSpan.FromSeconds(10), RateLimitWindowType.Fixed));
RateLimitEvent evnt = null; RateLimitEvent? evnt = null;
rateLimiter.RateLimitTriggered += (x) => { evnt = x; }; rateLimiter.RateLimitTriggered += (x) => { evnt = x; };
var ct = new CancellationTokenSource(TimeSpan.FromSeconds(0.2)); var ct = new CancellationTokenSource(TimeSpan.FromSeconds(0.2));

View File

@ -4,6 +4,7 @@ using CryptoExchange.Net.UnitTests.Implementations;
using CryptoExchange.Net.UnitTests.TestImplementations; using CryptoExchange.Net.UnitTests.TestImplementations;
using NUnit.Framework; using NUnit.Framework;
using System; using System;
using System.Linq;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -27,8 +28,24 @@ namespace CryptoExchange.Net.UnitTests
Assert.That(1 == client.ApiClient1.ApiOptions.MaxSocketConnections); Assert.That(1 == client.ApiClient1.ApiOptions.MaxSocketConnections);
} }
[TestCase(true)]
[TestCase(false)]
public async Task ConnectSocket_Should_ReturnConnectionResult(bool canConnect)
{
//arrange
var client = new TestSocketClient();
var socket = TestHelpers.ConfigureSocketClient(client, "wss://localhost");
socket.CanConnect = canConnect;
//act
var connectResult = await client.ApiClient1.SubscribeToUpdatesAsync<TestObject>(x => { }, false, default);
//assert
Assert.That(connectResult.Success == canConnect);
}
[TestCase] [TestCase]
public async Task Test() public async Task SocketMessages_Should_BeProcessedInDataHandlers()
{ {
var client = new TestSocketClient(); var client = new TestSocketClient();
var socket = TestHelpers.ConfigureSocketClient(client, "wss://localhost"); var socket = TestHelpers.ConfigureSocketClient(client, "wss://localhost");
@ -43,209 +60,119 @@ namespace CryptoExchange.Net.UnitTests
{ {
received = x.Data; received = x.Data;
resetEvent.Set(); resetEvent.Set();
}, default); }, false, default);
socket.InvokeMessage(strData); socket.InvokeMessage(strData);
await resetEvent.WaitAsync(TimeSpan.FromSeconds(1)); await resetEvent.WaitAsync(TimeSpan.FromSeconds(1));
Assert.That(received != null); Assert.That(received != null);
} }
//[TestCase(true)] [TestCase(false)]
//[TestCase(false)] [TestCase(true)]
//public void ConnectSocket_Should_ReturnConnectionResult(bool canConnect) public async Task SocketMessages_Should_ContainOriginalDataIfEnabled(bool enabled)
//{ {
// //arrange // arrange
// var client = new TestSocketClient(); var client = new TestSocketClient(options =>
// var socket = client.CreateSocket(); {
// socket.CanConnect = canConnect; options.ReconnectInterval = TimeSpan.Zero;
options.ExchangeOptions.OutputOriginalData = enabled;
});
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() });
// //act string? originalData = null;
// var connectResult = client.SubClient.ConnectSocketSub( var resetEvent = new AsyncResetEvent(false);
// new SocketConnection(new TraceLogger(), new TestWebsocketFactory(socket), new WebSocketParameters(new Uri("https://localhost/"), ReconnectPolicy.Disabled), client.SubClient, ""));
// //assert await client.ApiClient1.SubscribeToUpdatesAsync<TestObject>(x =>
// Assert.That(connectResult.Success == canConnect); {
//} originalData = x.OriginalData;
resetEvent.Set();
}, false, default);
//[TestCase] socket.InvokeMessage(strData);
//public void SocketMessages_Should_BeProcessedInDataHandlers() await resetEvent.WaitAsync(TimeSpan.FromSeconds(1));
//{
// // 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<string, string> result = null;
// client.SubClient.ConnectSocketSub(sub); // assert
Assert.That(originalData == (enabled ? strData : null));
}
// var subObj = new TestSubscription<Dictionary<string, string>>(Mock.Of<ILogger>(), (messageEvent) => [TestCase()]
// { public async Task UnsubscribingStream_Should_CloseTheSocket()
// result = messageEvent.Data; {
// rstEvent.Set(); // arrange
// }); var client = new TestSocketClient(options =>
// sub.AddSubscription(subObj); {
options.ReconnectInterval = TimeSpan.Zero;
});
var socket = TestHelpers.ConfigureSocketClient(client, "wss://localhost");
// // act var result = await client.ApiClient1.SubscribeToUpdatesAsync<TestObject>(x => {}, false, default);
// socket.InvokeMessage("{\"property\": \"123\", \"action\": \"update\", \"topic\": \"topic\"}");
// rstEvent.WaitOne(1000);
// // assert // act
// Assert.That(result["property"] == "123"); await client.UnsubscribeAsync(result.Data);
//}
//[TestCase(false)] // assert
//[TestCase(true)] Assert.That(socket.Connected == false);
//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); [TestCase()]
// var subObj = new TestSubscription<Dictionary<string, string>>(Mock.Of<ILogger>(), (messageEvent) => public async Task UnsubscribingAll_Should_CloseAllSockets()
// { {
// original = messageEvent.OriginalData; // arrange
// rstEvent.Set(); var client = new TestSocketClient(options =>
// }); {
// sub.AddSubscription(subObj); options.ReconnectInterval = TimeSpan.Zero;
// var msgToSend = JsonSerializer.Serialize(new { topic = "topic", action = "update", property = "123" }); });
var socket = TestHelpers.ConfigureSocketClient(client, "wss://localhost");
var result = await client.ApiClient1.SubscribeToUpdatesAsync<TestObject>(x => { }, false, default);
// // act var socket2 = TestHelpers.ConfigureSocketClient(client, "wss://localhost");
// socket.InvokeMessage(msgToSend); var result2 = await client.ApiClient1.SubscribeToUpdatesAsync<TestObject>(x => { }, false, default);
// rstEvent.WaitOne(1000);
// // assert // act
// Assert.That(original == (enabled ? msgToSend : null)); await client.UnsubscribeAllAsync();
//}
//[TestCase()] // assert
//public void UnsubscribingStream_Should_CloseTheSocket() Assert.That(socket.Connected == false);
//{ Assert.That(socket2.Connected == false);
// // 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<Dictionary<string, string>>(Mock.Of<ILogger>(), (messageEvent) => { }); [TestCase()]
// var ups = new UpdateSubscription(sub, subscription); public async Task ErrorResponse_ShouldNot_ConfirmSubscription()
// sub.AddSubscription(subscription); {
// arrange
var client = new TestSocketClient(opt =>
{
opt.OutputOriginalData = true;
});
// // act var socket = TestHelpers.ConfigureSocketClient(client, "wss://localhost");
// client.UnsubscribeAsync(ups).Wait(); var subTask = client.ApiClient1.SubscribeToUpdatesAsync<TestObject>(x => { }, true, default);
// // assert socket.InvokeMessage(JsonSerializer.Serialize(new TestSocketMessage { Id = 1, Data = "ErrorWithSub" }));
// Assert.That(socket.Connected == false);
//}
//[TestCase()] var result = await subTask;
//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<Dictionary<string, string>>(Mock.Of<ILogger>(), (messageEvent) => { });
// var subscription2 = new TestSubscription<Dictionary<string, string>>(Mock.Of<ILogger>(), (messageEvent) => { });
// sub1.AddSubscription(subscription1); // assert
// sub2.AddSubscription(subscription2); Assert.That(result.Success == false);
// var ups1 = new UpdateSubscription(sub1, subscription1); Assert.That(result.Error!.Message!.Contains("ErrorWithSub"));
// var ups2 = new UpdateSubscription(sub2, subscription2); }
// // act [TestCase()]
// client.UnsubscribeAllAsync().Wait(); public async Task SuccessResponse_Should_ConfirmSubscription()
{
var client = new TestSocketClient();
var socket = TestHelpers.ConfigureSocketClient(client, "wss://localhost");
var subTask = client.ApiClient1.SubscribeToUpdatesAsync<TestObject>(x => { }, true, default);
// // assert socket.InvokeMessage(JsonSerializer.Serialize(new TestSocketMessage { Id = 1, Data = "OK" }));
// Assert.That(socket1.Connected == false);
// Assert.That(socket2.Connected == false);
//}
//[TestCase()] var result = await subTask;
//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 subscription = client.ApiClient1._socketConnections.Single().Value.Subscriptions.Single();
// var connectResult = client.SubClient.ConnectSocketSub(sub1); Assert.That(subscription.Status == SubscriptionStatus.Subscribed);
}
// // 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);
//}
} }
} }

View File

@ -48,18 +48,18 @@ namespace CryptoExchange.Net.UnitTests.ConverterTests
var serialized = JsonSerializer.Serialize(data); var serialized = JsonSerializer.Serialize(data);
var deserialized = JsonSerializer.Deserialize<Test>(serialized); var deserialized = JsonSerializer.Deserialize<Test>(serialized);
Assert.That(deserialized.Prop1, Is.EqualTo(2)); Assert.That(deserialized!.Prop1, Is.EqualTo(2));
Assert.That(deserialized.Prop2, Is.Null); Assert.That(deserialized.Prop2, Is.Null);
Assert.That(deserialized.Prop3, Is.EqualTo("123")); Assert.That(deserialized.Prop3, Is.EqualTo("123"));
Assert.That(deserialized.Prop3Again, Is.EqualTo("123")); Assert.That(deserialized.Prop3Again, Is.EqualTo("123"));
Assert.That(deserialized.Prop4, Is.Null); Assert.That(deserialized.Prop4, Is.Null);
Assert.That(deserialized.Prop5.Prop21, Is.EqualTo(3)); Assert.That(deserialized.Prop5!.Prop21, Is.EqualTo(3));
Assert.That(deserialized.Prop5.Prop22, Is.EqualTo("456")); Assert.That(deserialized.Prop5!.Prop22, Is.EqualTo("456"));
Assert.That(deserialized.Prop6.Prop31, Is.EqualTo(4)); Assert.That(deserialized.Prop6!.Prop31, Is.EqualTo(4));
Assert.That(deserialized.Prop6.Prop32, Is.EqualTo("789")); Assert.That(deserialized.Prop6.Prop32, Is.EqualTo("789"));
Assert.That(deserialized.Prop7, Is.EqualTo(TestEnum.Two)); Assert.That(deserialized.Prop7, Is.EqualTo(TestEnum.Two));
Assert.That(deserialized.TestInternal.Prop1, Is.EqualTo(10)); Assert.That(deserialized.TestInternal!.Prop1, Is.EqualTo(10));
Assert.That(deserialized.Prop8.Prop31, Is.EqualTo(5)); Assert.That(deserialized.Prop8!.Prop31, Is.EqualTo(5));
Assert.That(deserialized.Prop8.Prop32, Is.EqualTo("101")); Assert.That(deserialized.Prop8.Prop32, Is.EqualTo("101"));
} }
} }
@ -72,21 +72,21 @@ namespace CryptoExchange.Net.UnitTests.ConverterTests
[ArrayProperty(1)] [ArrayProperty(1)]
public int? Prop2 { get; set; } public int? Prop2 { get; set; }
[ArrayProperty(2)] [ArrayProperty(2)]
public string Prop3 { get; set; } public string? Prop3 { get; set; }
[ArrayProperty(2)] [ArrayProperty(2)]
public string Prop3Again { get; set; } public string? Prop3Again { get; set; }
[ArrayProperty(3)] [ArrayProperty(3)]
public string Prop4 { get; set; } public string? Prop4 { get; set; }
[ArrayProperty(4)] [ArrayProperty(4)]
public Test2 Prop5 { get; set; } public Test2? Prop5 { get; set; }
[ArrayProperty(5)] [ArrayProperty(5)]
public Test3 Prop6 { get; set; } public Test3? Prop6 { get; set; }
[ArrayProperty(6), JsonConverter(typeof(EnumConverter<TestEnum>))] [ArrayProperty(6), JsonConverter(typeof(EnumConverter<TestEnum>))]
public TestEnum? Prop7 { get; set; } public TestEnum? Prop7 { get; set; }
[ArrayProperty(7)] [ArrayProperty(7)]
public Test TestInternal { get; set; } public Test? TestInternal { get; set; }
[ArrayProperty(8), JsonConversion] [ArrayProperty(8), JsonConversion]
public Test3 Prop8 { get; set; } public Test3? Prop8 { get; set; }
} }
[JsonConverter(typeof(ArrayConverter<Test2>))] [JsonConverter(typeof(ArrayConverter<Test2>))]
@ -95,7 +95,7 @@ namespace CryptoExchange.Net.UnitTests.ConverterTests
[ArrayProperty(0)] [ArrayProperty(0)]
public int Prop21 { get; set; } public int Prop21 { get; set; }
[ArrayProperty(1)] [ArrayProperty(1)]
public string Prop22 { get; set; } public string? Prop22 { get; set; }
} }
public record Test3 public record Test3
@ -103,7 +103,7 @@ namespace CryptoExchange.Net.UnitTests.ConverterTests
[JsonPropertyName("prop31")] [JsonPropertyName("prop31")]
public int Prop31 { get; set; } public int Prop31 { get; set; }
[JsonPropertyName("prop32")] [JsonPropertyName("prop32")]
public string Prop32 { get; set; } public string? Prop32 { get; set; }
} }
} }

View File

@ -22,7 +22,7 @@ namespace CryptoExchange.Net.UnitTests.ConverterTests
{ {
var val = value == null ? "null" : $"\"{value}\""; var val = value == null ? "null" : $"\"{value}\"";
var output = JsonSerializer.Deserialize<STJBoolObject>($"{{ \"Value\": {val} }}", SerializerOptions.WithConverters(new TestSerializerContext())); var output = JsonSerializer.Deserialize<STJBoolObject>($"{{ \"Value\": {val} }}", SerializerOptions.WithConverters(new TestSerializerContext()));
Assert.That(output.Value == expected); Assert.That(output!.Value == expected);
} }
[TestCase("1", true)] [TestCase("1", true)]
@ -41,7 +41,7 @@ namespace CryptoExchange.Net.UnitTests.ConverterTests
{ {
var val = value == null ? "null" : $"\"{value}\""; var val = value == null ? "null" : $"\"{value}\"";
var output = JsonSerializer.Deserialize<NotNullableSTJBoolObject>($"{{ \"Value\": {val} }}", SerializerOptions.WithConverters(new TestSerializerContext())); var output = JsonSerializer.Deserialize<NotNullableSTJBoolObject>($"{{ \"Value\": {val} }}", SerializerOptions.WithConverters(new TestSerializerContext()));
Assert.That(output.Value == expected); Assert.That(output!.Value == expected);
} }
} }

View File

@ -22,7 +22,7 @@ namespace CryptoExchange.Net.UnitTests.ConverterTests
public void TestDateTimeConverterString(string input, bool expectNull = false) public void TestDateTimeConverterString(string input, bool expectNull = false)
{ {
var output = JsonSerializer.Deserialize<STJTimeObject>($"{{ \"time\": \"{input}\" }}"); var output = JsonSerializer.Deserialize<STJTimeObject>($"{{ \"time\": \"{input}\" }}");
Assert.That(output.Time == (expectNull ? null : new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc))); Assert.That(output!.Time == (expectNull ? null : new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)));
} }
[TestCase(1620777600.000)] [TestCase(1620777600.000)]
@ -30,7 +30,7 @@ namespace CryptoExchange.Net.UnitTests.ConverterTests
public void TestDateTimeConverterDouble(double input) public void TestDateTimeConverterDouble(double input)
{ {
var output = JsonSerializer.Deserialize<STJTimeObject>($"{{ \"time\": {input} }}"); var output = JsonSerializer.Deserialize<STJTimeObject>($"{{ \"time\": {input} }}");
Assert.That(output.Time == new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)); Assert.That(output!.Time == new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc));
} }
[TestCase(1620777600)] [TestCase(1620777600)]
@ -41,7 +41,7 @@ namespace CryptoExchange.Net.UnitTests.ConverterTests
public void TestDateTimeConverterLong(long input, bool expectNull = false) public void TestDateTimeConverterLong(long input, bool expectNull = false)
{ {
var output = JsonSerializer.Deserialize<STJTimeObject>($"{{ \"time\": {input} }}"); var output = JsonSerializer.Deserialize<STJTimeObject>($"{{ \"time\": {input} }}");
Assert.That(output.Time == (expectNull ? null : new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc))); Assert.That(output!.Time == (expectNull ? null : new DateTime(2021, 05, 12, 0, 0, 0, DateTimeKind.Utc)));
} }
[TestCase(1620777600)] [TestCase(1620777600)]
@ -106,7 +106,7 @@ namespace CryptoExchange.Net.UnitTests.ConverterTests
public void TestDateTimeConverterNull() public void TestDateTimeConverterNull()
{ {
var output = JsonSerializer.Deserialize<STJTimeObject>($"{{ \"time\": null }}"); var output = JsonSerializer.Deserialize<STJTimeObject>($"{{ \"time\": null }}");
Assert.That(output.Time == null); Assert.That(output!.Time == null);
} }
} }

View File

@ -23,7 +23,7 @@ namespace CryptoExchange.Net.UnitTests.ConverterTests
public void TestDecimalConverterString(string value, decimal? expected) public void TestDecimalConverterString(string value, decimal? expected)
{ {
var result = JsonSerializer.Deserialize<STJDecimalObject>("{ \"test\": \"" + value + "\"}"); var result = JsonSerializer.Deserialize<STJDecimalObject>("{ \"test\": \"" + value + "\"}");
Assert.That(result.Test, Is.EqualTo(expected == -999 ? decimal.MinValue : expected == 999 ? decimal.MaxValue : expected)); Assert.That(result!.Test, Is.EqualTo(expected == -999 ? decimal.MinValue : expected == 999 ? decimal.MaxValue : expected));
} }
[TestCase("1", 1)] [TestCase("1", 1)]
@ -36,7 +36,7 @@ namespace CryptoExchange.Net.UnitTests.ConverterTests
public void TestDecimalConverterNumber(string value, decimal? expected) public void TestDecimalConverterNumber(string value, decimal? expected)
{ {
var result = JsonSerializer.Deserialize<STJDecimalObject>("{ \"test\": " + value + "}"); var result = JsonSerializer.Deserialize<STJDecimalObject>("{ \"test\": " + value + "}");
Assert.That(result.Test, Is.EqualTo(expected == -999 ? decimal.MaxValue : expected)); Assert.That(result!.Test, Is.EqualTo(expected == -999 ? decimal.MaxValue : expected));
} }
} }

View File

@ -45,7 +45,7 @@ namespace CryptoExchange.Net.UnitTests.ConverterTests
{ {
var val = value == null ? "null" : $"\"{value}\""; var val = value == null ? "null" : $"\"{value}\"";
var output = JsonSerializer.Deserialize<STJEnumObject>($"{{ \"Value\": {val} }}", SerializerOptions.WithConverters(new TestSerializerContext())); var output = JsonSerializer.Deserialize<STJEnumObject>($"{{ \"Value\": {val} }}", SerializerOptions.WithConverters(new TestSerializerContext()));
Assert.That(output.Value == expected); Assert.That(output!.Value == expected);
} }
[TestCase("1", TestEnum.One)] [TestCase("1", TestEnum.One)]
@ -60,7 +60,7 @@ namespace CryptoExchange.Net.UnitTests.ConverterTests
{ {
var val = value == null ? "null" : $"\"{value}\""; var val = value == null ? "null" : $"\"{value}\"";
var output = JsonSerializer.Deserialize<NotNullableSTJEnumObject>($"{{ \"Value\": {val} }}"); var output = JsonSerializer.Deserialize<NotNullableSTJEnumObject>($"{{ \"Value\": {val} }}");
Assert.That(output.Value == expected); Assert.That(output!.Value == expected);
} }
[Test] [Test]

View File

@ -20,7 +20,7 @@ namespace CryptoExchange.Net.UnitTests
var serialized = JsonSerializer.Serialize(symbol); var serialized = JsonSerializer.Serialize(symbol);
var restored = JsonSerializer.Deserialize<SharedSymbol>(serialized); var restored = JsonSerializer.Deserialize<SharedSymbol>(serialized);
Assert.That(restored.TradingMode, Is.EqualTo(symbol.TradingMode)); Assert.That(restored!.TradingMode, Is.EqualTo(symbol.TradingMode));
Assert.That(restored.BaseAsset, Is.EqualTo(symbol.BaseAsset)); Assert.That(restored.BaseAsset, Is.EqualTo(symbol.BaseAsset));
Assert.That(restored.QuoteAsset, Is.EqualTo(symbol.QuoteAsset)); Assert.That(restored.QuoteAsset, Is.EqualTo(symbol.QuoteAsset));
Assert.That(restored.DeliverTime, Is.EqualTo(symbol.DeliverTime)); Assert.That(restored.DeliverTime, Is.EqualTo(symbol.DeliverTime));
@ -38,7 +38,7 @@ namespace CryptoExchange.Net.UnitTests
var serialized = JsonSerializer.Serialize(symbol); var serialized = JsonSerializer.Serialize(symbol);
var restored = JsonSerializer.Deserialize<SharedOrderQuantity>(serialized); var restored = JsonSerializer.Deserialize<SharedOrderQuantity>(serialized);
Assert.That(restored.QuantityInBaseAsset, Is.EqualTo(symbol.QuantityInBaseAsset)); Assert.That(restored!.QuantityInBaseAsset, Is.EqualTo(symbol.QuantityInBaseAsset));
Assert.That(restored.QuantityInQuoteAsset, Is.EqualTo(symbol.QuantityInQuoteAsset)); Assert.That(restored.QuantityInQuoteAsset, Is.EqualTo(symbol.QuantityInQuoteAsset));
Assert.That(restored.QuantityInContracts, Is.EqualTo(symbol.QuantityInContracts)); Assert.That(restored.QuantityInContracts, Is.EqualTo(symbol.QuantityInContracts));
} }

View File

@ -326,7 +326,7 @@ namespace CryptoExchange.Net.UnitTests
// assert // assert
Assert.That(result, Is.Not.Null); Assert.That(result, Is.Not.Null);
Assert.That(result.BaseAsset, Is.EqualTo("BTC")); Assert.That(result!.BaseAsset, Is.EqualTo("BTC"));
Assert.That(result.QuoteAsset, Is.EqualTo("USDT")); Assert.That(result.QuoteAsset, Is.EqualTo("USDT"));
Assert.That(result.TradingMode, Is.EqualTo(TradingMode.Spot)); Assert.That(result.TradingMode, Is.EqualTo(TradingMode.Spot));
Assert.That(result.SymbolName, Is.EqualTo("BTCUSDT")); Assert.That(result.SymbolName, Is.EqualTo("BTCUSDT"));

View File

@ -0,0 +1,24 @@
using CryptoExchange.Net.Objects;
using CryptoExchange.Net.Objects.Errors;
using CryptoExchange.Net.Sockets;
using CryptoExchange.Net.Sockets.Default;
using System;
namespace CryptoExchange.Net.UnitTests.Implementations
{
internal class TestQuery : Query<TestSocketMessage>
{
public TestQuery(TestSocketMessage request, bool authenticated) : base(request, authenticated, 1)
{
MessageRouter = MessageRouter.CreateWithoutTopicFilter<TestSocketMessage>(request.Id.ToString(), HandleMessage);
}
private CallResult? HandleMessage(SocketConnection connection, DateTime time, string? arg3, TestSocketMessage message)
{
if (message.Data != "OK")
return new CallResult(new ServerError(ErrorInfo.Unknown with { Message = message.Data }));
return CallResult.SuccessResult;
}
}
}

View File

@ -1,4 +1,5 @@
using CryptoExchange.Net.UnitTests.ConverterTests; using CryptoExchange.Net.UnitTests.ConverterTests;
using CryptoExchange.Net.UnitTests.Implementations;
using CryptoExchange.Net.UnitTests.TestImplementations; using CryptoExchange.Net.UnitTests.TestImplementations;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
@ -13,6 +14,7 @@ namespace CryptoExchange.Net.UnitTests
[JsonSerializable(typeof(IDictionary<string, object>))] [JsonSerializable(typeof(IDictionary<string, object>))]
[JsonSerializable(typeof(TestObject))] [JsonSerializable(typeof(TestObject))]
[JsonSerializable(typeof(TestSocketMessage))]
[JsonSerializable(typeof(Test))] [JsonSerializable(typeof(Test))]
[JsonSerializable(typeof(Test2))] [JsonSerializable(typeof(Test2))]
[JsonSerializable(typeof(Test3))] [JsonSerializable(typeof(Test3))]

View File

@ -36,9 +36,9 @@ namespace CryptoExchange.Net.UnitTests.Implementations
protected override TestAuthenticationProvider CreateAuthenticationProvider(TestCredentials credentials) => protected override TestAuthenticationProvider CreateAuthenticationProvider(TestCredentials credentials) =>
new TestAuthenticationProvider(credentials); new TestAuthenticationProvider(credentials);
public async Task<CallResult<UpdateSubscription>> SubscribeToUpdatesAsync<T>(Action<DataEvent<T>> handler, CancellationToken ct) public async Task<CallResult<UpdateSubscription>> SubscribeToUpdatesAsync<T>(Action<DataEvent<T>> handler, bool subQuery, CancellationToken ct)
{ {
return await base.SubscribeAsync(new TestSubscription<T>(_logger, handler, false), ct); return await base.SubscribeAsync(new TestSubscription<T>(_logger, handler, subQuery, false), ct);
} }
} }
} }

View File

@ -0,0 +1,16 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json.Serialization;
namespace CryptoExchange.Net.UnitTests.Implementations
{
internal record TestSocketMessage
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("data")]
public string Data { get; set; } = string.Empty;
}
}

View File

@ -17,6 +17,13 @@ namespace CryptoExchange.Net.UnitTests.Implementations
new MessageTypeDefinition { new MessageTypeDefinition {
ForceIfFound = true, ForceIfFound = true,
Fields = [
new PropertyFieldReference("id")
],
TypeIdentifierCallback = (doc) => doc.FieldValue("id")!
},
new MessageTypeDefinition {
Fields = [ Fields = [
], ],
StaticIdentifier = "test" StaticIdentifier = "test"

View File

@ -13,16 +13,31 @@ namespace CryptoExchange.Net.UnitTests.Implementations
internal class TestSubscription<T> : Subscription internal class TestSubscription<T> : Subscription
{ {
private readonly Action<DataEvent<T>> _handler; private readonly Action<DataEvent<T>> _handler;
private bool _subQuery;
public TestSubscription(ILogger logger, Action<DataEvent<T>> handler, bool authenticated) : base(logger, authenticated, true) public TestSubscription(ILogger logger, Action<DataEvent<T>> handler, bool subQuery, bool authenticated) : base(logger, authenticated, true)
{ {
_handler = handler; _handler = handler;
_subQuery = subQuery;
MessageRouter = MessageRouter.CreateWithoutTopicFilter<T>("test", HandleUpdate); MessageRouter = MessageRouter.CreateWithoutTopicFilter<T>("test", HandleUpdate);
} }
protected override Query? GetSubQuery(SocketConnection connection) => null; protected override Query? GetSubQuery(SocketConnection connection)
protected override Query? GetUnsubQuery(SocketConnection connection) => null; {
if (!_subQuery)
return null;
return new TestQuery(new TestSocketMessage { Id = 1, Data = "Sub" }, false);
}
protected override Query? GetUnsubQuery(SocketConnection connection)
{
if (!_subQuery)
return null;
return new TestQuery(new TestSocketMessage { Id = 2, Data = "Unsub" }, false);
}
private CallResult? HandleUpdate(SocketConnection connection, DateTime time, string? originalData, T data) private CallResult? HandleUpdate(SocketConnection connection, DateTime time, string? originalData, T data)

View File

@ -0,0 +1,331 @@
using CryptoExchange.Net.Objects;
using CryptoExchange.Net.UnitTests.ConverterTests;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Text;
namespace CryptoExchange.Net.UnitTests
{
internal class ParameterCollectionTests
{
[Test]
public void AddingBasicValue_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.Add("test", "value");
Assert.That(parameters["test"], Is.EqualTo("value"));
}
[Test]
public void AddingBasicNullValue_ThrowExecption()
{
var parameters = new ParameterCollection();
Assert.Throws<ArgumentNullException>(() => parameters.Add("test", null!));
}
[Test]
public void AddingOptionalBasicValue_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddOptional("test", "value");
Assert.That(parameters["test"], Is.EqualTo("value"));
}
[Test]
public void AddingOptionalBasicNullValue_DoesntSetValue()
{
var parameters = new ParameterCollection();
parameters.AddOptional("test", null);
Assert.That(parameters.ContainsKey("test"), Is.False);
}
[Test]
public void AddingDecimalValueAsString_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddString("test", 0.1m);
Assert.That(parameters["test"], Is.EqualTo("0.1"));
}
[Test]
public void AddingOptionalDecimalValueAsString_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddOptionalString("test", 0.1m);
Assert.That(parameters["test"], Is.EqualTo("0.1"));
}
[Test]
public void AddingOptionalDecimalNullValueAsString_DoesntSetValue()
{
var parameters = new ParameterCollection();
parameters.AddOptionalString("test", (decimal?)null);
Assert.That(parameters.ContainsKey("test"), Is.False);
}
[Test]
public void AddingIntValueAsString_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddString("test", 1);
Assert.That(parameters["test"], Is.EqualTo("1"));
}
[Test]
public void AddingOptionalIntValueAsString_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddOptionalString("test", 1);
Assert.That(parameters["test"], Is.EqualTo("1"));
}
[Test]
public void AddingOptionalIntNullValueAsString_DoesntSetValue()
{
var parameters = new ParameterCollection();
parameters.AddOptionalString("test", (int?)null);
Assert.That(parameters.ContainsKey("test"), Is.False);
}
[Test]
public void AddingLongValueAsString_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddString("test", 1L);
Assert.That(parameters["test"], Is.EqualTo("1"));
}
[Test]
public void AddingOptionalLongValueAsString_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddOptionalString("test", 1L);
Assert.That(parameters["test"], Is.EqualTo("1"));
}
[Test]
public void AddingOptionalLongNullValueAsString_DoesntSetValue()
{
var parameters = new ParameterCollection();
parameters.AddOptionalString("test", (long?)null);
Assert.That(parameters.ContainsKey("test"), Is.False);
}
[Test]
public void AddingMillisecondTimestamp_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddMilliseconds("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
Assert.That(parameters["test"], Is.EqualTo(1735689600000));
}
[Test]
public void AddingOptionalMillisecondTimestamp_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddOptionalMilliseconds("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
Assert.That(parameters["test"], Is.EqualTo(1735689600000));
}
[Test]
public void AddingOptionalMillisecondNullValue_DoesntSetValue()
{
var parameters = new ParameterCollection();
parameters.AddOptionalMilliseconds("test", null);
Assert.That(parameters.ContainsKey("test"), Is.False);
}
[Test]
public void AddingMillisecondTimestampString_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddMillisecondsString("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
Assert.That(parameters["test"], Is.EqualTo("1735689600000"));
}
[Test]
public void AddingOptionalMillisecondTimestampString_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddOptionalMillisecondsString("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
Assert.That(parameters["test"], Is.EqualTo("1735689600000"));
}
[Test]
public void AddingOptionalMillisecondStringNullValue_DoesntSetValue()
{
var parameters = new ParameterCollection();
parameters.AddOptionalMillisecondsString("test", null);
Assert.That(parameters.ContainsKey("test"), Is.False);
}
[Test]
public void AddingSecondTimestamp_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddSeconds("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
Assert.That(parameters["test"], Is.EqualTo(1735689600));
}
[Test]
public void AddingOptionalSecondTimestamp_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddOptionalSeconds("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
Assert.That(parameters["test"], Is.EqualTo(1735689600));
}
[Test]
public void AddingSecondNullValue_DoesntSetValue()
{
var parameters = new ParameterCollection();
parameters.AddOptionalSeconds("test", null);
Assert.That(parameters.ContainsKey("test"), Is.False);
}
[Test]
public void AddingSecondTimestampString_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddSecondsString("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
Assert.That(parameters["test"], Is.EqualTo("1735689600"));
}
[Test]
public void AddingOptionalSecondTimestampString_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddOptionalSecondsString("test", new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc));
Assert.That(parameters["test"], Is.EqualTo("1735689600"));
}
[Test]
public void AddingSecondStringNullValue_DoesntSetValue()
{
var parameters = new ParameterCollection();
parameters.AddOptionalSecondsString("test", null);
Assert.That(parameters.ContainsKey("test"), Is.False);
}
[Test]
public void AddingEnum_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddEnum("test", TestEnum.Two);
Assert.That(parameters["test"], Is.EqualTo("2"));
}
[Test]
public void AddingOptionalEnum_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddOptionalEnum("test", (TestEnum?)TestEnum.Two);
Assert.That(parameters["test"], Is.EqualTo("2"));
}
[Test]
public void AddingOptionalEnumNullValue_DoesntSetValue()
{
var parameters = new ParameterCollection();
parameters.AddOptionalEnum("test", (TestEnum?)null);
Assert.That(parameters.ContainsKey("test"), Is.False);
}
[Test]
public void AddingEnumAsInt_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddEnumAsInt("test", TestEnum.Two);
Assert.That(parameters["test"], Is.EqualTo(2));
}
[Test]
public void AddingOptionalEnumAsInt_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddOptionalEnumAsInt("test", (TestEnum?)TestEnum.Two);
Assert.That(parameters["test"], Is.EqualTo(2));
}
[Test]
public void AddingOptionalEnumAsIntNullValue_DoesntSetValue()
{
var parameters = new ParameterCollection();
parameters.AddOptionalEnumAsInt("test", (TestEnum?)null);
Assert.That(parameters.ContainsKey("test"), Is.False);
}
[Test]
public void AddingCommaSeparated_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddCommaSeparated("test", ["1", "2"]);
Assert.That(parameters["test"], Is.EqualTo("1,2"));
}
[Test]
public void AddingOptionalCommaSeparated_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddOptionalCommaSeparated("test", ["1", "2"]);
Assert.That(parameters["test"], Is.EqualTo("1,2"));
}
[Test]
public void AddingOptionalCommaSeparatedNullValue_DoesntSetValue()
{
var parameters = new ParameterCollection();
parameters.AddOptionalCommaSeparated("test", (string[]?)null);
Assert.That(parameters.ContainsKey("test"), Is.False);
}
[Test]
public void AddingCommaSeparatedEnum_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddCommaSeparated("test", [TestEnum.Two, TestEnum.One]);
Assert.That(parameters["test"], Is.EqualTo("2,1"));
}
[Test]
public void AddingOptionalCommaSeparatedEnum_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddOptionalCommaSeparated("test", [TestEnum.Two, TestEnum.One]);
Assert.That(parameters["test"], Is.EqualTo("2,1"));
}
[Test]
public void AddingOptionalCommaSeparatedEnumNullValue_DoesntSetValue()
{
var parameters = new ParameterCollection();
parameters.AddOptionalCommaSeparated("test", (TestEnum[]?)null);
Assert.That(parameters.ContainsKey("test"), Is.False);
}
[Test]
public void AddingBoolString_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddBoolString("test", true);
Assert.That(parameters["test"], Is.EqualTo("true"));
}
[Test]
public void AddingOptionalBoolString_SetValueCorrectly()
{
var parameters = new ParameterCollection();
parameters.AddOptionalBoolString("test", true);
Assert.That(parameters["test"], Is.EqualTo("true"));
}
[Test]
public void AddingOptionalBoolStringNullValue_DoesntSetValue()
{
var parameters = new ParameterCollection();
parameters.AddOptionalBoolString("test", null);
Assert.That(parameters.ContainsKey("test"), Is.False);
}
}
}

View File

@ -0,0 +1,105 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Text;
using CryptoExchange.Net;
using CryptoExchange.Net.Objects;
namespace CryptoExchange.Net.UnitTests
{
internal class UriSerializationTests
{
[Test]
public void CreateParamString_SerializesBasicValuesCorrectly()
{
var parameters = new Dictionary<string, object>()
{
{ "a", "1" },
{ "b", 2 },
{ "c", true }
};
var parameterString = parameters.CreateParamString(false, ArrayParametersSerialization.Array);
Assert.That(parameterString, Is.EqualTo("a=1&b=2&c=True"));
}
[Test]
public void CreateParamString_SerializesArrayValuesCorrectly()
{
var parameters = new Dictionary<string, object>()
{
{ "a", new [] { "1", "2" } },
};
var parameterString = parameters.CreateParamString(false, ArrayParametersSerialization.Array);
Assert.That(parameterString, Is.EqualTo("a[]=1&a[]=2"));
}
[Test]
public void CreateParamStringEncoded_SerializesArrayValuesCorrectly()
{
var parameters = new Dictionary<string, object>()
{
{ "a", new [] { "1+2", "2+3" } },
};
var parameterString = parameters.CreateParamString(true, ArrayParametersSerialization.Array);
Assert.That(parameterString, Is.EqualTo("a[]=1%2B2&a[]=2%2B3"));
}
[Test]
public void CreateParamString_SerializesJsonArrayValuesCorrectly()
{
var parameters = new Dictionary<string, object>()
{
{ "a", new [] { "1", "2" } },
};
var parameterString = parameters.CreateParamString(false, ArrayParametersSerialization.JsonArray);
Assert.That(parameterString, Is.EqualTo("a=[1,2]"));
}
[Test]
public void CreateParamStringEncoded_SerializesJsonArrayValuesCorrectly()
{
var parameters = new Dictionary<string, object>()
{
{ "a", new [] { "1+2", "2+3" } },
};
var parameterString = parameters.CreateParamString(true, ArrayParametersSerialization.JsonArray);
Assert.That(parameterString, Is.EqualTo("a=[1%2B2,2%2B3]"));
}
[Test]
public void CreateParamString_SerializesMultipleValuesArrayCorrectly()
{
var parameters = new Dictionary<string, object>()
{
{ "a", new [] { "1", "2" } },
};
var parameterString = parameters.CreateParamString(false, ArrayParametersSerialization.MultipleValues);
Assert.That(parameterString, Is.EqualTo("a=1&a=2"));
}
[Test]
public void CreateParamStringEncoded_SerializesMultipleValuesArrayCorrectly()
{
var parameters = new Dictionary<string, object>()
{
{ "a", new [] { "1+2", "2+3" } },
};
var parameterString = parameters.CreateParamString(true, ArrayParametersSerialization.MultipleValues);
Assert.That(parameterString, Is.EqualTo("a=1%2B2&a=2%2B3"));
}
}
}

View File

@ -107,7 +107,7 @@ namespace CryptoExchange.Net
} }
else else
{ {
uriString.Append('['); uriString.Append($"{parameter.Key}=[");
var firstArrayEntry = true; var firstArrayEntry = true;
foreach (var entry in (Array)parameter.Value) foreach (var entry in (Array)parameter.Value)
{ {

View File

@ -278,6 +278,35 @@ namespace CryptoExchange.Net.Objects
base.Add(key, string.Join(",", values)); base.Add(key, string.Join(",", values));
} }
/// <summary>
/// Add key as comma separated values
/// </summary>
#if NET5_0_OR_GREATER
public void AddCommaSeparated<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T>(string key, IEnumerable<T> values)
#else
public void AddCommaSeparated<T>(string key, IEnumerable<T> values)
#endif
where T : struct, Enum
{
base.Add(key, string.Join(",", values.Select(x => EnumConverter.GetString(x))));
}
/// <summary>
/// Add key as comma separated values if there are values provided
/// </summary>
#if NET5_0_OR_GREATER
public void AddOptionalCommaSeparated<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor | DynamicallyAccessedMemberTypes.PublicFields)] T>(string key, IEnumerable<T>? values)
#else
public void AddOptionalCommaSeparated<T>(string key, IEnumerable<T>? values)
#endif
where T : struct, Enum
{
if (values == null || !values.Any())
return;
base.Add(key, string.Join(",", values.Select(x => EnumConverter.GetString(x))));
}
/// <summary> /// <summary>
/// Add key as boolean lower case value /// Add key as boolean lower case value
/// </summary> /// </summary>