Skip to content

Commit

Permalink
Merge pull request #3 from JKorf/feature/System.Text.Json
Browse files Browse the repository at this point in the history
CryptoExchange.Net V7.1.0
  • Loading branch information
JKorf authored Mar 16, 2024
2 parents db79a3d + b8f19b8 commit eea35af
Show file tree
Hide file tree
Showing 17 changed files with 132 additions and 71 deletions.
16 changes: 11 additions & 5 deletions Mexc.Net.UnitTests/Helpers/JsonToObjectComparer.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using CryptoExchange.Net.Converters;
using CryptoExchange.Net.Converters.JsonNet;
using CryptoExchange.Net.Objects;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NUnit.Framework;
using NUnit.Framework.Legacy;
using System;
using System.Collections;
using System.Collections.Generic;
Expand Down Expand Up @@ -76,7 +78,7 @@ public async Task ProcessSubject<K>(
CallResult result = (CallResult)await TestHelpers.InvokeAsync(method, getSubject(client), input.ToArray());

// asset
Assert.Null(result.Error, method.Name);
ClassicAssert.Null(result.Error, method.Name);

var resultData = result.GetType().GetProperty("Data", BindingFlags.Public | BindingFlags.Instance).GetValue(result);
ProcessData(method.Name + (i == 0 ? "" : i.ToString()), resultData, json, parametersToSetNull, useNestedJsonPropertyForCompare, ignoreProperties);
Expand Down Expand Up @@ -199,10 +201,8 @@ private static void CheckObject(string method, JProperty prop, object obj, Dicti

// Property has a value
var property = resultProperties.SingleOrDefault(p => p.Item2?.PropertyName == prop.Name).p;
if (property is null)
property = resultProperties.SingleOrDefault(p => p.p.Name == prop.Name).p;
if (property is null)
property = resultProperties.SingleOrDefault(p => p.p.Name.ToUpperInvariant() == prop.Name.ToUpperInvariant()).p;
property ??= resultProperties.SingleOrDefault(p => p.p.Name == prop.Name).p;
property ??= resultProperties.SingleOrDefault(p => p.p.Name.ToUpperInvariant() == prop.Name.ToUpperInvariant()).p;

if (property is null)
{
Expand Down Expand Up @@ -327,7 +327,9 @@ private static void CheckPropertyValue(string method, JToken propValue, object p
if (info.GetCustomAttribute<JsonConverterAttribute>(true) == null
&& info.GetCustomAttribute<JsonPropertyAttribute>(true)?.ItemConverterType == null
&& !info.PropertyType.IsEnum && Nullable.GetUnderlyingType(info.PropertyType)?.IsEnum != true)
{
CheckValues(method, propertyName, (JValue)propValue, propertyValue);
}
}
}
}
Expand All @@ -346,7 +348,9 @@ private static void CheckValues(string method, string property, JValue jsonValue
// timestamp, hard to check..
}
else if (jsonValue.Value<string>().ToLowerInvariant() != objectValue.ToString().ToLowerInvariant())
{
throw new Exception($"{method}: {property} not equal: {jsonValue.Value<string>()} vs {objectValue.ToString()}");
}
}
else if (jsonValue.Type == JTokenType.Integer)
{
Expand All @@ -355,7 +359,9 @@ private static void CheckValues(string method, string property, JValue jsonValue
// timestamp, hard to check..
}
else if (jsonValue.Value<long>() != Convert.ToInt64(objectValue))
{
throw new Exception($"{method}: {property} not equal: {jsonValue.Value<long>()} vs {Convert.ToInt64(objectValue)}");
}
}
else if (jsonValue.Type == JTokenType.Boolean)
{
Expand Down
26 changes: 3 additions & 23 deletions Mexc.Net.UnitTests/Helpers/TestHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,36 +78,16 @@ public static IMexcRestClient CreateResponseClient<T>(T response, Action<MexcRes
return client;
}

public static void SetResponse(MexcRestClient client, string responseData)
public static void SetResponse(MexcRestClient client, string responseData, HttpStatusCode statusCode = HttpStatusCode.OK)
{
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<IResponse>();
response.Setup(c => c.IsSuccessStatusCode).Returns(true);
response.Setup(c => c.GetResponseStreamAsync()).Returns(Task.FromResult((Stream)responseStream));

var request = new Mock<IRequest>();
request.Setup(c => c.Uri).Returns(new Uri("http://www.test.com"));
request.Setup(c => c.GetHeaders()).Returns(new Dictionary<string, IEnumerable<string>>());
request.Setup(c => c.GetResponseAsync(It.IsAny<CancellationToken>())).Returns(Task.FromResult(response.Object));

var factory = Mock.Get(client.SpotApi.RequestFactory);
factory.Setup(c => c.Create(It.IsAny<HttpMethod>(), It.IsAny<Uri>(), It.IsAny<int>()))
.Returns(request.Object);
}

public static void SetErrorWithResponse(IMexcRestClient client, 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<IResponse>();
response.Setup(c => c.IsSuccessStatusCode).Returns(false);
response.Setup(c => c.StatusCode).Returns(statusCode);
response.Setup(c => c.IsSuccessStatusCode).Returns(statusCode == HttpStatusCode.OK);
response.Setup(c => c.GetResponseStreamAsync()).Returns(Task.FromResult((Stream)responseStream));

var request = new Mock<IRequest>();
Expand Down
10 changes: 4 additions & 6 deletions Mexc.Net.UnitTests/Mexc.Net.UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.4.2" />
<PackageReference Include="NUnit.Analyzers" Version="3.6.1" />
<PackageReference Include="coverlet.collector" Version="3.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="Moq" Version="4.20.70" />
<PackageReference Include="NUnit" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
</ItemGroup>

<ItemGroup>
Expand Down
49 changes: 43 additions & 6 deletions Mexc.Net.UnitTests/MexcClientTests.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
using Mexc.Net.Clients;
using System;
using System.Collections.Generic;
using Mexc.Net.Objects.Models;
using Mexc.Net.UnitTests.Helpers;
using Newtonsoft.Json;
using NUnit.Framework.Legacy;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Mexc.Net.UnitTests
{
Expand All @@ -26,11 +25,49 @@ public void CheckRestInterfaces()
foreach (var method in implementation.GetMethods().Where(m => m.ReturnType.IsAssignableTo(typeof(Task))))
{
var interfaceMethod = clientInterface.GetMethod(method.Name, method.GetParameters().Select(p => p.ParameterType).ToArray());
Assert.NotNull(interfaceMethod, $"Missing interface for method {method.Name} in {implementation.Name} implementing interface {clientInterface.Name}");
ClassicAssert.NotNull(interfaceMethod, $"Missing interface for method {method.Name} in {implementation.Name} implementing interface {clientInterface.Name}");
methods++;
}
Debug.WriteLine($"{clientInterface.Name} {methods} methods validated");
}
}

[TestCase()]
public async Task ReceivingHttpErrorWithNoJson_Should_ReturnErrorAndNotSuccess()
{
// arrange
var client = TestHelpers.CreateClient();
TestHelpers.SetResponse((MexcRestClient)client, "", System.Net.HttpStatusCode.BadRequest);

// act
var result = await client.SpotApi.ExchangeData.GetTickersAsync();

// assert
ClassicAssert.IsFalse(result.Success);
ClassicAssert.IsNotNull(result.Error);
}

[TestCase()]
public async Task ReceivingHttpErrorWithJsonError_Should_ReturnErrorAndNotSuccess()
{
// arrange
var client = TestHelpers.CreateClient();
var resultObj = new MexcResult()
{
Code = 400001,
Message = "Error occured"
};

TestHelpers.SetResponse((MexcRestClient)client, JsonConvert.SerializeObject(resultObj), System.Net.HttpStatusCode.BadRequest);

// act
var result = await client.SpotApi.ExchangeData.GetTickersAsync();

// assert
ClassicAssert.IsFalse(result.Success);
ClassicAssert.IsNotNull(result.Error);
Assert.That(result.Error!.Code == 400001);
Assert.That(result.Error.Message == "Error occured");
}
}
}
1 change: 1 addition & 0 deletions Mexc.Net/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("Mexc.Net.UnitTests")]
2 changes: 1 addition & 1 deletion Mexc.Net/Clients/MexcRestClient.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using CryptoExchange.Net;
using CryptoExchange.Net.Clients;
using Mexc.Net.Clients.SpotApi;
using Mexc.Net.Interfaces.Clients;
using Mexc.Net.Interfaces.Clients.SpotApi;
Expand Down
4 changes: 2 additions & 2 deletions Mexc.Net/Clients/MexcSocketClient.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using CryptoExchange.Net;
using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.Clients;
using Mexc.Net.Clients.SpotApi;
using Mexc.Net.Interfaces.Clients;
using Mexc.Net.Interfaces.Clients.SpotApi;
Expand Down
30 changes: 23 additions & 7 deletions Mexc.Net/Clients/SpotApi/MexcRestClientSpotApi.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using CryptoExchange.Net;
using System;
using System;
using System.Collections.Generic;
using CryptoExchange.Net.Objects;
using Microsoft.Extensions.Logging;
Expand All @@ -16,6 +15,8 @@
using CryptoExchange.Net.CommonObjects;
using System.Linq;
using Mexc.Net.Enums;
using CryptoExchange.Net.Clients;
using CryptoExchange.Net.Converters.MessageParsing;

namespace Mexc.Net.Clients.SpotApi
{
Expand Down Expand Up @@ -56,11 +57,9 @@ internal MexcRestClientSpotApi(ILogger logger, HttpClient? httpClient, MexcRestO
ExchangeData = new MexcRestClientSpotApiExchangeData(logger, this);
Trading = new MexcRestClientSpotApiTrading(logger, this);

DefaultSerializer = JsonSerializer.Create(SerializerOptions.WithConverters);

requestBodyEmptyContent = "";
requestBodyFormat = RequestBodyFormat.FormData;
arraySerialization = ArrayParametersSerialization.MultipleValues;
RequestBodyEmptyContent = "";
RequestBodyFormat = RequestBodyFormat.FormData;
ArraySerialization = ArrayParametersSerialization.MultipleValues;

ParameterPositions[HttpMethod.Post] = HttpMethodParameterPosition.InUri;
ParameterPositions[HttpMethod.Delete] = HttpMethodParameterPosition.InUri;
Expand Down Expand Up @@ -91,6 +90,23 @@ internal async Task<WebCallResult<T>> SendRequestInternal<T>(string path, HttpMe
return result;
}

/// <inheritdoc />
protected override Error ParseErrorResponse(int httpStatusCode, IEnumerable<KeyValuePair<string, IEnumerable<string>>> responseHeaders, IMessageAccessor accessor)
{
if (!accessor.IsJson)
return new ServerError(accessor.GetOriginalString());

var code = accessor.GetValue<int?>(MessagePath.Get().Property("code"));
var msg = accessor.GetValue<string>(MessagePath.Get().Property("msg"));
if (msg == null)
return new ServerError(accessor.GetOriginalString());

if (code == null)
return new ServerError(msg);

return new ServerError(code.Value, msg);
}

/// <inheritdoc />
protected override Task<WebCallResult<DateTime>> GetServerTimestampAsync()
=> ExchangeData.GetServerTimeAsync();
Expand Down
7 changes: 3 additions & 4 deletions Mexc.Net/Clients/SpotApi/MexcSocketClientSpotApi.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
using CryptoExchange.Net;
using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.Clients;
using CryptoExchange.Net.Converters;
using CryptoExchange.Net.Converters.MessageParsing;
using CryptoExchange.Net.Objects;
using CryptoExchange.Net.Objects.Sockets;
using CryptoExchange.Net.Sockets;
using CryptoExchange.Net.Sockets.MessageParsing;
using CryptoExchange.Net.Sockets.MessageParsing.Interfaces;
using Mexc.Net.Enums;
using Mexc.Net.Interfaces.Clients.SpotApi;
using Mexc.Net.Objects.Models.Spot;
Expand Down
10 changes: 5 additions & 5 deletions Mexc.Net/Mexc.Net.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
<PropertyGroup>
<PackageId>JK.Mexc.Net</PackageId>
<Authors>JKorf</Authors>
<PackageVersion>1.0.1</PackageVersion>
<AssemblyVersion>1.0.1</AssemblyVersion>
<FileVersion>1.0.1</FileVersion>
<PackageVersion>1.1.0</PackageVersion>
<AssemblyVersion>1.1.0</AssemblyVersion>
<FileVersion>1.1.0</FileVersion>
<Description>JK.Mexc.Net is a client library for accessing the Mexc REST and Websocket API. All data is mapped to readable models and enum values. Additional features include an implementation for maintaining a client side order book, easy integration with other exchange client libraries and more.</Description>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<PackageTags>Mexc;Mexc.Net;Mexc Client;Mexc API;CryptoCurrency;CryptoCurrency Exchange</PackageTags>
Expand Down Expand Up @@ -44,14 +44,14 @@
<None Include="..\README.md" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ConfigureAwaitChecker.Analyzer" Version="5.0.0">
<PackageReference Include="ConfigureAwaitChecker.Analyzer" Version="5.0.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="CryptoExchange.Net" Version="7.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="CryptoExchange.Net" Version="7.1.0" />
</ItemGroup>
</Project>
5 changes: 4 additions & 1 deletion Mexc.Net/Mexc.Net.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Mexc.Net/MexcAuthenticationProvider.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using CryptoExchange.Net;
using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.Clients;
using CryptoExchange.Net.Objects;
using System;
using System.Collections.Generic;
Expand All @@ -16,7 +16,7 @@ public MexcAuthenticationProvider(ApiCredentials credentials) : base(credentials
{
}

public override void AuthenticateRequest(RestApiClient apiClient, Uri uri, HttpMethod method, Dictionary<string, object> providedParameters, bool auth, ArrayParametersSerialization arraySerialization, HttpMethodParameterPosition parameterPosition, out SortedDictionary<string, object> uriParameters, out SortedDictionary<string, object> bodyParameters, out Dictionary<string, string> headers)
public override void AuthenticateRequest(RestApiClient apiClient, Uri uri, HttpMethod method, Dictionary<string, object> providedParameters, bool auth, ArrayParametersSerialization arraySerialization, HttpMethodParameterPosition parameterPosition, RequestBodyFormat bodyFormat, out SortedDictionary<string, object> uriParameters, out SortedDictionary<string, object> bodyParameters, out Dictionary<string, string> headers)
{
uriParameters = parameterPosition == HttpMethodParameterPosition.InUri ? new SortedDictionary<string, object>(providedParameters) : new SortedDictionary<string, object>();
bodyParameters = parameterPosition == HttpMethodParameterPosition.InBody ? new SortedDictionary<string, object>(providedParameters) : new SortedDictionary<string, object>();
Expand Down
6 changes: 3 additions & 3 deletions Mexc.Net/Objects/Sockets/Queries/MexcQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ public MexcQuery(string method, IEnumerable<string> parameters, bool authenticat
ListenerIdentifiers = new HashSet<string> { ((MexcRequest)Request).Id.ToString() };
}

public override Task<CallResult<MexcResponse>> HandleMessageAsync(SocketConnection connection, DataEvent<MexcResponse> message)
public override CallResult<MexcResponse> HandleMessage(SocketConnection connection, DataEvent<MexcResponse> message)
{
var topics = message.Data.Message.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
if (!topics.All(t => _expectedTopics.Contains(t)))
return Task.FromResult(new CallResult<MexcResponse>(new ServerError(message.Data.Message)));
return new CallResult<MexcResponse>(new ServerError(message.Data.Message));

return base.HandleMessageAsync(connection, message);
return base.HandleMessage(connection, message);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ public MexcErrorSubscription(ILogger logger) : base(logger, false)
{
}

public override Task<CallResult> HandleMessageAsync(SocketConnection connection, DataEvent<MexcResponse> message)
public override CallResult HandleMessage(SocketConnection connection, DataEvent<MexcResponse> message)
{
_logger.LogError("Server Error: {Error}", message.Data.Message);
return Task.FromResult(new CallResult(null));
return new CallResult(null);
}
}
}
5 changes: 2 additions & 3 deletions Mexc.Net/Objects/Sockets/Subscriptions/MexcSubscription.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using CryptoExchange.Net.Objects;
using CryptoExchange.Net.Objects.Sockets;
using CryptoExchange.Net.Sockets;
using CryptoExchange.Net.Sockets.MessageParsing.Interfaces;
using Mexc.Net.Objects.Sockets.Models;
using Mexc.Net.Objects.Sockets.Queries;
using Microsoft.Extensions.Logging;
Expand All @@ -26,11 +25,11 @@ public MexcSubscription(ILogger logger, IEnumerable<string> topics, Action<DataE
ListenerIdentifiers = new HashSet<string>(_topics);
}

public override Task<CallResult> DoHandleMessageAsync(SocketConnection connection, DataEvent<object> message)
public override CallResult DoHandleMessage(SocketConnection connection, DataEvent<object> message)
{
var data = (MexcUpdate<T>)message.Data;
_handler.Invoke(message.As(data.Data, data.Symbol, SocketUpdateType.Update));
return Task.FromResult(new CallResult(null));
return new CallResult(null);
}

public override Type? GetMessageType(IMessageAccessor message) => typeof(MexcUpdate<T>);
Expand Down
Loading

0 comments on commit eea35af

Please sign in to comment.