mirror of
https://github.com/JKorf/CryptoExchange.Net
synced 2026-02-16 14:13:46 +00:00
Merge branch 'master' of https://github.com/JKorf/CryptoExchange.Net
This commit is contained in:
commit
be2eb01353
465
CryptoExchange.Net.UnitTests/ExchangeSymbolCacheTests.cs
Normal file
465
CryptoExchange.Net.UnitTests/ExchangeSymbolCacheTests.cs
Normal file
@ -0,0 +1,465 @@
|
|||||||
|
using CryptoExchange.Net.SharedApis;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace CryptoExchange.Net.UnitTests
|
||||||
|
{
|
||||||
|
[TestFixture()]
|
||||||
|
public class ExchangeSymbolCacheTests
|
||||||
|
{
|
||||||
|
private SharedSpotSymbol[] CreateTestSymbols()
|
||||||
|
{
|
||||||
|
return new[]
|
||||||
|
{
|
||||||
|
new SharedSpotSymbol("BTC", "USDT", "BTCUSDT", true, TradingMode.Spot),
|
||||||
|
new SharedSpotSymbol("ETH", "USDT", "ETHUSDT", true, TradingMode.Spot),
|
||||||
|
new SharedSpotSymbol("BTC", "EUR", "BTCEUR", true, TradingMode.Spot),
|
||||||
|
new SharedSpotSymbol("ETH", "BTC", "ETHBTC", true, TradingMode.Spot),
|
||||||
|
new SharedSpotSymbol("XRP", "USDT", "XRPUSDT", false, TradingMode.Spot)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private SharedSpotSymbol[] CreateFuturesSymbols()
|
||||||
|
{
|
||||||
|
return new[]
|
||||||
|
{
|
||||||
|
new SharedSpotSymbol("BTC", "USDT", "BTCUSDT-PERP", true, TradingMode.PerpetualLinear),
|
||||||
|
new SharedSpotSymbol("ETH", "USDT", "ETHUSDT-PERP", true, TradingMode.PerpetualLinear)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void UpdateSymbolInfo_NewTopic_Should_AddToCache()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "NewExchange";
|
||||||
|
var symbols = CreateTestSymbols();
|
||||||
|
|
||||||
|
// act
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||||
|
var hasCached = ExchangeSymbolCache.HasCached(topicId);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(hasCached, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void UpdateSymbolInfo_Should_StoreAllSymbols()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "ExchangeWithSymbols";
|
||||||
|
var symbols = CreateTestSymbols();
|
||||||
|
|
||||||
|
// act
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "BTCUSDT"), Is.True);
|
||||||
|
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "ETHUSDT"), Is.True);
|
||||||
|
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "BTCEUR"), Is.True);
|
||||||
|
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "ETHBTC"), Is.True);
|
||||||
|
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "XRPUSDT"), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void UpdateSymbolInfo_CalledTwiceWithinAnHour_Should_NotUpdate()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "ExchangeNoUpdate";
|
||||||
|
var initialSymbols = new[]
|
||||||
|
{
|
||||||
|
new SharedSpotSymbol("BTC", "USDT", "BTCUSDT", true, TradingMode.Spot)
|
||||||
|
};
|
||||||
|
var updatedSymbols = new[]
|
||||||
|
{
|
||||||
|
new SharedSpotSymbol("BTC", "USDT", "BTCUSDT", true, TradingMode.Spot),
|
||||||
|
new SharedSpotSymbol("ETH", "USDT", "ETHUSDT", true, TradingMode.Spot)
|
||||||
|
};
|
||||||
|
|
||||||
|
// act
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, initialSymbols);
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, updatedSymbols);
|
||||||
|
|
||||||
|
// assert - should still have only the initial symbol since less than 60 minutes passed
|
||||||
|
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "BTCUSDT"), Is.True);
|
||||||
|
// The second update should not have been applied
|
||||||
|
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, "ETHUSDT"), Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void UpdateSymbolInfo_WithEmptyArray_Should_CreateEmptyCache()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "EmptyExchange";
|
||||||
|
var symbols = Array.Empty<SharedSpotSymbol>();
|
||||||
|
|
||||||
|
// act
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||||
|
var hasCached = ExchangeSymbolCache.HasCached(topicId);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(hasCached, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void HasCached_NonExistentTopic_Should_ReturnFalse()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var nonExistentTopic = "NonExistent_" + Guid.NewGuid();
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.HasCached(nonExistentTopic);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void HasCached_ExistingTopicWithSymbols_Should_ReturnTrue()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "ExchangeWithData";
|
||||||
|
var symbols = CreateTestSymbols();
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.HasCached(topicId);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void HasCached_ExistingTopicWithNoSymbols_Should_ReturnFalse()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "ExchangeNoData";
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, Array.Empty<SharedSpotSymbol>());
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.HasCached(topicId);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SupportsSymbol_ByName_ExistingSymbol_Should_ReturnTrue()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "ExchangeSupports";
|
||||||
|
var symbols = CreateTestSymbols();
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.SupportsSymbol(topicId, "BTCUSDT");
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SupportsSymbol_ByName_NonExistingSymbol_Should_ReturnFalse()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "ExchangeNoSupport";
|
||||||
|
var symbols = CreateTestSymbols();
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.SupportsSymbol(topicId, "LINKUSDT");
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SupportsSymbol_ByName_NonExistentTopic_Should_ReturnFalse()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var nonExistentTopic = "NonExistent_" + Guid.NewGuid();
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.SupportsSymbol(nonExistentTopic, "BTCUSDT");
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SupportsSymbol_BySharedSymbol_ExistingSymbol_Should_ReturnTrue()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "ExchangeSharedSymbol";
|
||||||
|
var symbols = CreateTestSymbols();
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||||
|
var sharedSymbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.SupportsSymbol(topicId, sharedSymbol);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SupportsSymbol_BySharedSymbol_NonExistingSymbol_Should_ReturnFalse()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "ExchangeNoSharedSymbol";
|
||||||
|
var symbols = CreateTestSymbols();
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||||
|
var sharedSymbol = new SharedSymbol(TradingMode.Spot, "LINK", "USDT");
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.SupportsSymbol(topicId, sharedSymbol);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SupportsSymbol_BySharedSymbol_DifferentTradingMode_Should_ReturnFalse()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "ExchangeDifferentMode";
|
||||||
|
var symbols = CreateTestSymbols();
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||||
|
var sharedSymbol = new SharedSymbol(TradingMode.PerpetualLinear, "BTC", "USDT");
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.SupportsSymbol(topicId, sharedSymbol);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SupportsSymbol_BySharedSymbol_NonExistentTopic_Should_ReturnFalse()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var nonExistentTopic = "NonExistent_" + Guid.NewGuid();
|
||||||
|
var sharedSymbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.SupportsSymbol(nonExistentTopic, sharedSymbol);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSymbolsForBaseAsset_ExistingBaseAsset_Should_ReturnMatchingSymbols()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "ExchangeBaseAsset";
|
||||||
|
var symbols = CreateTestSymbols();
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "BTC");
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.Not.Null);
|
||||||
|
Assert.That(result.Length, Is.EqualTo(2));
|
||||||
|
Assert.That(result.Any(x => x.QuoteAsset == "USDT"), Is.True);
|
||||||
|
Assert.That(result.Any(x => x.QuoteAsset == "EUR"), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSymbolsForBaseAsset_CaseInsensitive_Should_ReturnMatchingSymbols()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "ExchangeCaseInsensitive";
|
||||||
|
var symbols = CreateTestSymbols();
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "btc");
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.Not.Null);
|
||||||
|
Assert.That(result.Length, Is.EqualTo(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSymbolsForBaseAsset_NonExistingBaseAsset_Should_ReturnEmptyArray()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "ExchangeNoBaseAsset";
|
||||||
|
var symbols = CreateTestSymbols();
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "LINK");
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.Not.Null);
|
||||||
|
Assert.That(result.Length, Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSymbolsForBaseAsset_NonExistentTopic_Should_ReturnEmptyArray()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var nonExistentTopic = "NonExistent_" + Guid.NewGuid();
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(nonExistentTopic, "BTC");
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.Not.Null);
|
||||||
|
Assert.That(result.Length, Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ParseSymbol_ExistingSymbol_Should_ReturnSharedSymbol()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "ExchangeParse";
|
||||||
|
var symbols = CreateTestSymbols();
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.ParseSymbol(topicId, "BTCUSDT");
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.Not.Null);
|
||||||
|
Assert.That(result.BaseAsset, Is.EqualTo("BTC"));
|
||||||
|
Assert.That(result.QuoteAsset, Is.EqualTo("USDT"));
|
||||||
|
Assert.That(result.TradingMode, Is.EqualTo(TradingMode.Spot));
|
||||||
|
Assert.That(result.SymbolName, Is.EqualTo("BTCUSDT"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ParseSymbol_NonExistingSymbol_Should_ReturnNull()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "ExchangeNoParse";
|
||||||
|
var symbols = CreateTestSymbols();
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.ParseSymbol(topicId, "LINKUSDT");
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ParseSymbol_NullSymbolName_Should_ReturnNull()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "ExchangeNullSymbol";
|
||||||
|
var symbols = CreateTestSymbols();
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.ParseSymbol(topicId, null);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ParseSymbol_NonExistentTopic_Should_ReturnNull()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var nonExistentTopic = "NonExistent_" + Guid.NewGuid();
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.ParseSymbol(nonExistentTopic, "BTCUSDT");
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void MultipleTopics_Should_MaintainSeparateData()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topic1 = "Exchange1";
|
||||||
|
var topic2 = "Exchange2";
|
||||||
|
var symbols1 = new[]
|
||||||
|
{
|
||||||
|
new SharedSpotSymbol("BTC", "USDT", "BTCUSDT", true, TradingMode.Spot)
|
||||||
|
};
|
||||||
|
var symbols2 = new[]
|
||||||
|
{
|
||||||
|
new SharedSpotSymbol("ETH", "USDT", "ETHUSDT", true, TradingMode.Spot)
|
||||||
|
};
|
||||||
|
|
||||||
|
// act
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topic1, symbols1);
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topic2, symbols2);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(ExchangeSymbolCache.SupportsSymbol(topic1, "BTCUSDT"), Is.True);
|
||||||
|
Assert.That(ExchangeSymbolCache.SupportsSymbol(topic1, "ETHUSDT"), Is.False);
|
||||||
|
Assert.That(ExchangeSymbolCache.SupportsSymbol(topic2, "ETHUSDT"), Is.True);
|
||||||
|
Assert.That(ExchangeSymbolCache.SupportsSymbol(topic2, "BTCUSDT"), Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void UpdateSymbolInfo_WithDifferentTradingModes_Should_StoreCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "ExchangeMixedModes";
|
||||||
|
var spotSymbols = CreateTestSymbols();
|
||||||
|
var futuresSymbols = CreateFuturesSymbols();
|
||||||
|
var allSymbols = spotSymbols.Concat(futuresSymbols).ToArray();
|
||||||
|
|
||||||
|
// act
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, allSymbols);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
var spotSymbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
|
||||||
|
var futuresSymbol = new SharedSymbol(TradingMode.PerpetualLinear, "BTC", "USDT");
|
||||||
|
|
||||||
|
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, spotSymbol), Is.True);
|
||||||
|
Assert.That(ExchangeSymbolCache.SupportsSymbol(topicId, futuresSymbol), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSymbolsForBaseAsset_Should_ReturnAllTradingModes()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "ExchangeAllModes";
|
||||||
|
var spotSymbols = CreateTestSymbols();
|
||||||
|
var futuresSymbols = CreateFuturesSymbols();
|
||||||
|
var allSymbols = spotSymbols.Concat(futuresSymbols).ToArray();
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, allSymbols);
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "BTC");
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result.Length, Is.GreaterThanOrEqualTo(2));
|
||||||
|
Assert.That(result.Any(x => x.TradingMode == TradingMode.Spot), Is.True);
|
||||||
|
Assert.That(result.Any(x => x.TradingMode == TradingMode.PerpetualLinear), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSymbolsForBaseAsset_WithMultipleMatchingSymbols_Should_ReturnAll()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var topicId = "ExchangeMultiple";
|
||||||
|
var symbols = new[]
|
||||||
|
{
|
||||||
|
new SharedSpotSymbol("ETH", "USDT", "ETHUSDT", true, TradingMode.Spot),
|
||||||
|
new SharedSpotSymbol("ETH", "BTC", "ETHBTC", true, TradingMode.Spot),
|
||||||
|
new SharedSpotSymbol("ETH", "EUR", "ETHEUR", true, TradingMode.Spot)
|
||||||
|
};
|
||||||
|
ExchangeSymbolCache.UpdateSymbolInfo(topicId, symbols);
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = ExchangeSymbolCache.GetSymbolsForBaseAsset(topicId, "ETH");
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result.Length, Is.EqualTo(3));
|
||||||
|
Assert.That(result.All(x => x.BaseAsset == "ETH"), Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
633
CryptoExchange.Net.UnitTests/SharedQuantityTests.cs
Normal file
633
CryptoExchange.Net.UnitTests/SharedQuantityTests.cs
Normal file
@ -0,0 +1,633 @@
|
|||||||
|
using CryptoExchange.Net.SharedApis;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace CryptoExchange.Net.UnitTests
|
||||||
|
{
|
||||||
|
[TestFixture()]
|
||||||
|
public class SharedQuantityTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantityReference_IsZero_AllNull_Should_ReturnTrue()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quantity = new SharedOrderQuantity(null, null, null);
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
Assert.That(quantity.IsZero, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantityReference_IsZero_AllZero_Should_ReturnTrue()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quantity = new SharedOrderQuantity(0, 0, 0);
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
Assert.That(quantity.IsZero, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantityReference_IsZero_BaseAssetSet_Should_ReturnFalse()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quantity = new SharedOrderQuantity(1.5m, null, null);
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
Assert.That(quantity.IsZero, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantityReference_IsZero_QuoteAssetSet_Should_ReturnFalse()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quantity = new SharedOrderQuantity(null, 100m, null);
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
Assert.That(quantity.IsZero, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantityReference_IsZero_ContractsSet_Should_ReturnFalse()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quantity = new SharedOrderQuantity(null, null, 10m);
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
Assert.That(quantity.IsZero, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantityReference_IsZero_NegativeValue_Should_ReturnTrue()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quantity = new SharedOrderQuantity(-1m, 0, 0);
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
Assert.That(quantity.IsZero, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_DefaultConstructor_Should_SetAllPropertiesToNull()
|
||||||
|
{
|
||||||
|
// arrange & act
|
||||||
|
var quantity = new SharedQuantity();
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.Null);
|
||||||
|
Assert.That(quantity.QuantityInQuoteAsset, Is.Null);
|
||||||
|
Assert.That(quantity.QuantityInContracts, Is.Null);
|
||||||
|
Assert.That(quantity.IsZero, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_Base_Should_SetBaseAssetQuantity()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var expectedQuantity = 1.5m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.Base(expectedQuantity);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(expectedQuantity));
|
||||||
|
Assert.That(quantity.QuantityInQuoteAsset, Is.Null);
|
||||||
|
Assert.That(quantity.QuantityInContracts, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_Base_WithZero_Should_SetZeroQuantity()
|
||||||
|
{
|
||||||
|
// arrange & act
|
||||||
|
var quantity = SharedQuantity.Base(0m);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(0m));
|
||||||
|
Assert.That(quantity.IsZero, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_Base_WithLargeValue_Should_SetCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var largeValue = 999999.123456789m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.Base(largeValue);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(largeValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_Quote_Should_SetQuoteAssetQuantity()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var expectedQuantity = 100m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.Quote(expectedQuantity);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.Null);
|
||||||
|
Assert.That(quantity.QuantityInQuoteAsset, Is.EqualTo(expectedQuantity));
|
||||||
|
Assert.That(quantity.QuantityInContracts, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_Quote_WithDecimal_Should_PreserveDecimals()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var expectedQuantity = 50.123456m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.Quote(expectedQuantity);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInQuoteAsset, Is.EqualTo(expectedQuantity));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_Contracts_Should_SetContractQuantity()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var expectedQuantity = 10m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.Contracts(expectedQuantity);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.Null);
|
||||||
|
Assert.That(quantity.QuantityInQuoteAsset, Is.Null);
|
||||||
|
Assert.That(quantity.QuantityInContracts, Is.EqualTo(expectedQuantity));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_Contracts_WithFractionalValue_Should_SetCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var expectedQuantity = 2.5m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.Contracts(expectedQuantity);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInContracts, Is.EqualTo(expectedQuantity));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_BaseFromQuote_Should_CalculateCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quoteQuantity = 100m;
|
||||||
|
var price = 50m;
|
||||||
|
var expectedBase = 2m; // 100 / 50 = 2
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.BaseFromQuote(quoteQuantity, price);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(expectedBase));
|
||||||
|
Assert.That(quantity.QuantityInQuoteAsset, Is.Null);
|
||||||
|
Assert.That(quantity.QuantityInContracts, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_BaseFromQuote_WithCustomDecimals_Should_RoundCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quoteQuantity = 100m;
|
||||||
|
var price = 3m;
|
||||||
|
var decimalPlaces = 2;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.BaseFromQuote(quoteQuantity, price, decimalPlaces);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
// 100 / 3 = 33.333... should round to 33.33
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(33.33m));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_BaseFromQuote_WithLotSize_Should_AdjustToLotSize()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quoteQuantity = 100m;
|
||||||
|
var price = 7m;
|
||||||
|
var lotSize = 0.1m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.BaseFromQuote(quoteQuantity, price, 8, lotSize);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
// 100 / 7 = 14.285714... should adjust to nearest 0.1 = 14.3
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(14.3m));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_BaseFromQuote_WithHighPrecision_Should_HandleCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quoteQuantity = 1000m;
|
||||||
|
var price = 0.00001m;
|
||||||
|
var decimalPlaces = 8;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.BaseFromQuote(quoteQuantity, price, decimalPlaces);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.GreaterThan(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_QuoteFromBase_Should_CalculateCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var baseQuantity = 2m;
|
||||||
|
var price = 50m;
|
||||||
|
var expectedQuote = 100m; // 2 * 50 = 100
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.QuoteFromBase(baseQuantity, price);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(expectedQuote));
|
||||||
|
Assert.That(quantity.QuantityInQuoteAsset, Is.Null);
|
||||||
|
Assert.That(quantity.QuantityInContracts, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_QuoteFromBase_WithCustomDecimals_Should_RoundCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var baseQuantity = 1.234567m;
|
||||||
|
var price = 10m;
|
||||||
|
var decimalPlaces = 2;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.QuoteFromBase(baseQuantity, price, decimalPlaces);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
// 1.234567 * 10 = 12.34567 should round to 12.35
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(12.35m));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_QuoteFromBase_WithLotSize_Should_AdjustToLotSize()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var baseQuantity = 3.456m;
|
||||||
|
var price = 10m;
|
||||||
|
var lotSize = 1m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.QuoteFromBase(baseQuantity, price, 8, lotSize);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
// 3.456 * 10 = 34.56 should adjust to nearest 1 = 35
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(35m));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_QuoteFromBase_WithSmallValues_Should_HandleCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var baseQuantity = 0.001m;
|
||||||
|
var price = 0.1m;
|
||||||
|
var decimalPlaces = 8;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.QuoteFromBase(baseQuantity, price, decimalPlaces);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(0.0001m));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_ContractsFromBase_Should_CalculateCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var baseQuantity = 100m;
|
||||||
|
var contractSize = 10m;
|
||||||
|
var expectedContracts = 10m; // 100 / 10 = 10
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.ContractsFromBase(baseQuantity, contractSize);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(expectedContracts));
|
||||||
|
Assert.That(quantity.QuantityInQuoteAsset, Is.Null);
|
||||||
|
Assert.That(quantity.QuantityInContracts, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_ContractsFromBase_WithCustomDecimals_Should_RoundCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var baseQuantity = 100m;
|
||||||
|
var contractSize = 3m;
|
||||||
|
var decimalPlaces = 2;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.ContractsFromBase(baseQuantity, contractSize, decimalPlaces);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
// 100 / 3 = 33.333... should round to 33.33
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(33.33m));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_ContractsFromBase_WithLotSize_Should_AdjustToLotSize()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var baseQuantity = 100m;
|
||||||
|
var contractSize = 7m;
|
||||||
|
var lotSize = 0.5m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.ContractsFromBase(baseQuantity, contractSize, 8, lotSize);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
// 100 / 7 = 14.285714... should adjust to nearest 0.5 = 14.5
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(14.5m));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_ContractsFromBase_WithFractionalContract_Should_HandleCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var baseQuantity = 1m;
|
||||||
|
var contractSize = 0.1m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.ContractsFromBase(baseQuantity, contractSize);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(10m));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_ContractsFromQuote_Should_CalculateCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quoteQuantity = 1000m;
|
||||||
|
var contractSize = 10m;
|
||||||
|
var price = 50m;
|
||||||
|
var expectedContracts = 2m; // 1000 / 50 / 10 = 2
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.ContractsFromQuote(quoteQuantity, contractSize, price);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(expectedContracts));
|
||||||
|
Assert.That(quantity.QuantityInQuoteAsset, Is.Null);
|
||||||
|
Assert.That(quantity.QuantityInContracts, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_ContractsFromQuote_WithCustomDecimals_Should_RoundCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quoteQuantity = 100m;
|
||||||
|
var contractSize = 3m;
|
||||||
|
var price = 7m;
|
||||||
|
var decimalPlaces = 2;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.ContractsFromQuote(quoteQuantity, contractSize, price, decimalPlaces);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
// 100 / 7 / 3 = 4.761904... should round to 4.76
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(4.76m));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_ContractsFromQuote_WithLotSize_Should_AdjustToLotSize()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quoteQuantity = 1000m;
|
||||||
|
var contractSize = 7m;
|
||||||
|
var price = 13m;
|
||||||
|
var lotSize = 0.5m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.ContractsFromQuote(quoteQuantity, contractSize, price, 8, lotSize);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
// 1000 / 13 / 7 = 10.989... should adjust to nearest 0.5 = 11.0
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(11.0m));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_ContractsFromQuote_WithComplexValues_Should_CalculateCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quoteQuantity = 5000m;
|
||||||
|
var contractSize = 0.01m;
|
||||||
|
var price = 25000m;
|
||||||
|
var decimalPlaces = 4;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.ContractsFromQuote(quoteQuantity, contractSize, price, decimalPlaces);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
// 5000 / 25000 / 0.01 = 20
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(20m));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedOrderQuantity_DefaultConstructor_Should_SetAllPropertiesToNull()
|
||||||
|
{
|
||||||
|
// arrange & act
|
||||||
|
var quantity = new SharedOrderQuantity();
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.Null);
|
||||||
|
Assert.That(quantity.QuantityInQuoteAsset, Is.Null);
|
||||||
|
Assert.That(quantity.QuantityInContracts, Is.Null);
|
||||||
|
Assert.That(quantity.IsZero, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedOrderQuantity_ParameterizedConstructor_Should_SetBaseAsset()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var baseAsset = 5m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = new SharedOrderQuantity(baseAssetQuantity: baseAsset);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(baseAsset));
|
||||||
|
Assert.That(quantity.QuantityInQuoteAsset, Is.Null);
|
||||||
|
Assert.That(quantity.QuantityInContracts, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedOrderQuantity_ParameterizedConstructor_Should_SetQuoteAsset()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quoteAsset = 100m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = new SharedOrderQuantity(quoteAssetQuantity: quoteAsset);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.Null);
|
||||||
|
Assert.That(quantity.QuantityInQuoteAsset, Is.EqualTo(quoteAsset));
|
||||||
|
Assert.That(quantity.QuantityInContracts, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedOrderQuantity_ParameterizedConstructor_Should_SetContracts()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var contracts = 10m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = new SharedOrderQuantity(contractQuantity: contracts);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.Null);
|
||||||
|
Assert.That(quantity.QuantityInQuoteAsset, Is.Null);
|
||||||
|
Assert.That(quantity.QuantityInContracts, Is.EqualTo(contracts));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedOrderQuantity_ParameterizedConstructor_Should_SetAllValues()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var baseAsset = 1m;
|
||||||
|
var quoteAsset = 50m;
|
||||||
|
var contracts = 5m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = new SharedOrderQuantity(baseAsset, quoteAsset, contracts);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.EqualTo(baseAsset));
|
||||||
|
Assert.That(quantity.QuantityInQuoteAsset, Is.EqualTo(quoteAsset));
|
||||||
|
Assert.That(quantity.QuantityInContracts, Is.EqualTo(contracts));
|
||||||
|
Assert.That(quantity.IsZero, Is.False);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedOrderQuantity_ParameterizedConstructor_WithNullValues_Should_HandleCorrectly()
|
||||||
|
{
|
||||||
|
// arrange & act
|
||||||
|
var quantity = new SharedOrderQuantity(null, null, null);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.Null);
|
||||||
|
Assert.That(quantity.QuantityInQuoteAsset, Is.Null);
|
||||||
|
Assert.That(quantity.QuantityInContracts, Is.Null);
|
||||||
|
Assert.That(quantity.IsZero, Is.True);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_RecordEquality_SameValues_Should_BeEqual()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quantity1 = SharedQuantity.Base(10m);
|
||||||
|
var quantity2 = SharedQuantity.Base(10m);
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
Assert.That(quantity1, Is.EqualTo(quantity2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_RecordEquality_DifferentValues_Should_NotBeEqual()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quantity1 = SharedQuantity.Base(10m);
|
||||||
|
var quantity2 = SharedQuantity.Base(20m);
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
Assert.That(quantity1, Is.Not.EqualTo(quantity2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_RecordEquality_DifferentTypes_Should_NotBeEqual()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quantity1 = SharedQuantity.Base(10m);
|
||||||
|
var quantity2 = SharedQuantity.Quote(10m);
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
Assert.That(quantity1, Is.Not.EqualTo(quantity2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedOrderQuantity_RecordEquality_SameValues_Should_BeEqual()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quantity1 = new SharedOrderQuantity(5m, 100m, 2m);
|
||||||
|
var quantity2 = new SharedOrderQuantity(5m, 100m, 2m);
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
Assert.That(quantity1, Is.EqualTo(quantity2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_BaseFromQuote_WithDefaultParameters_Should_UseDefaults()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quoteQuantity = 100m;
|
||||||
|
var price = 3m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.BaseFromQuote(quoteQuantity, price);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
// Default decimalPlaces = 8, default lotSize = 0.00000001
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.Not.Null);
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.GreaterThan(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_QuoteFromBase_WithDefaultParameters_Should_UseDefaults()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var baseQuantity = 1.234567m;
|
||||||
|
var price = 10m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.QuoteFromBase(baseQuantity, price);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.Not.Null);
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.GreaterThan(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_ContractsFromBase_WithDefaultParameters_Should_UseDefaults()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var baseQuantity = 100m;
|
||||||
|
var contractSize = 3m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.ContractsFromBase(baseQuantity, contractSize);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.Not.Null);
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.GreaterThan(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedQuantity_ContractsFromQuote_WithDefaultParameters_Should_UseDefaults()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var quoteQuantity = 1000m;
|
||||||
|
var contractSize = 10m;
|
||||||
|
var price = 50m;
|
||||||
|
|
||||||
|
// act
|
||||||
|
var quantity = SharedQuantity.ContractsFromQuote(quoteQuantity, contractSize, price);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.Not.Null);
|
||||||
|
Assert.That(quantity.QuantityInBaseAsset, Is.GreaterThan(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
400
CryptoExchange.Net.UnitTests/SharedSymbolTests.cs
Normal file
400
CryptoExchange.Net.UnitTests/SharedSymbolTests.cs
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
using CryptoExchange.Net.SharedApis;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace CryptoExchange.Net.UnitTests
|
||||||
|
{
|
||||||
|
[TestFixture()]
|
||||||
|
public class SharedSymbolTests
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void SharedSymbol_Constructor_Should_SetAllProperties()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var tradingMode = TradingMode.Spot;
|
||||||
|
var baseAsset = "BTC";
|
||||||
|
var quoteAsset = "USDT";
|
||||||
|
|
||||||
|
// act
|
||||||
|
var symbol = new SharedSymbol(tradingMode, baseAsset, quoteAsset);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(symbol.TradingMode, Is.EqualTo(tradingMode));
|
||||||
|
Assert.That(symbol.BaseAsset, Is.EqualTo(baseAsset));
|
||||||
|
Assert.That(symbol.QuoteAsset, Is.EqualTo(quoteAsset));
|
||||||
|
Assert.That(symbol.DeliverTime, Is.Null);
|
||||||
|
Assert.That(symbol.SymbolName, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedSymbol_Constructor_WithDeliveryTime_Should_SetDeliveryTime()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var tradingMode = TradingMode.DeliveryLinear;
|
||||||
|
var baseAsset = "BTC";
|
||||||
|
var quoteAsset = "USDT";
|
||||||
|
var deliveryTime = new DateTime(2026, 6, 25, 0, 0, 0, DateTimeKind.Utc);
|
||||||
|
|
||||||
|
// act
|
||||||
|
var symbol = new SharedSymbol(tradingMode, baseAsset, quoteAsset, deliveryTime);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(symbol.TradingMode, Is.EqualTo(tradingMode));
|
||||||
|
Assert.That(symbol.BaseAsset, Is.EqualTo(baseAsset));
|
||||||
|
Assert.That(symbol.QuoteAsset, Is.EqualTo(quoteAsset));
|
||||||
|
Assert.That(symbol.DeliverTime, Is.EqualTo(deliveryTime));
|
||||||
|
Assert.That(symbol.SymbolName, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedSymbol_Constructor_WithNullDeliveryTime_Should_SetToNull()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var tradingMode = TradingMode.Spot;
|
||||||
|
var baseAsset = "ETH";
|
||||||
|
var quoteAsset = "BTC";
|
||||||
|
|
||||||
|
// act
|
||||||
|
var symbol = new SharedSymbol(tradingMode, baseAsset, quoteAsset, deliverTime: null);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(symbol.DeliverTime, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase(TradingMode.Spot)]
|
||||||
|
[TestCase(TradingMode.PerpetualLinear)]
|
||||||
|
[TestCase(TradingMode.PerpetualInverse)]
|
||||||
|
[TestCase(TradingMode.DeliveryLinear)]
|
||||||
|
[TestCase(TradingMode.DeliveryInverse)]
|
||||||
|
public void SharedSymbol_Constructor_WithDifferentTradingModes_Should_SetCorrectly(TradingMode tradingMode)
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var baseAsset = "BTC";
|
||||||
|
var quoteAsset = "USDT";
|
||||||
|
|
||||||
|
// act
|
||||||
|
var symbol = new SharedSymbol(tradingMode, baseAsset, quoteAsset);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(symbol.TradingMode, Is.EqualTo(tradingMode));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedSymbol_ConstructorWithSymbolName_Should_SetSymbolName()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var tradingMode = TradingMode.Spot;
|
||||||
|
var baseAsset = "BTC";
|
||||||
|
var quoteAsset = "USDT";
|
||||||
|
var symbolName = "BTC-USDT";
|
||||||
|
|
||||||
|
// act
|
||||||
|
var symbol = new SharedSymbol(tradingMode, baseAsset, quoteAsset, symbolName);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(symbol.TradingMode, Is.EqualTo(tradingMode));
|
||||||
|
Assert.That(symbol.BaseAsset, Is.EqualTo(baseAsset));
|
||||||
|
Assert.That(symbol.QuoteAsset, Is.EqualTo(quoteAsset));
|
||||||
|
Assert.That(symbol.SymbolName, Is.EqualTo(symbolName));
|
||||||
|
Assert.That(symbol.DeliverTime, Is.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedSymbol_ConstructorWithSymbolName_WithCustomFormat_Should_SetCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var tradingMode = TradingMode.PerpetualLinear;
|
||||||
|
var baseAsset = "ETH";
|
||||||
|
var quoteAsset = "USDT";
|
||||||
|
var symbolName = "ETHUSDT-PERP";
|
||||||
|
|
||||||
|
// act
|
||||||
|
var symbol = new SharedSymbol(tradingMode, baseAsset, quoteAsset, symbolName);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(symbol.SymbolName, Is.EqualTo(symbolName));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedSymbol_ConstructorWithSymbolName_WithEmptyString_Should_SetEmptyString()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var tradingMode = TradingMode.Spot;
|
||||||
|
var baseAsset = "BTC";
|
||||||
|
var quoteAsset = "USDT";
|
||||||
|
var symbolName = "";
|
||||||
|
|
||||||
|
// act
|
||||||
|
var symbol = new SharedSymbol(tradingMode, baseAsset, quoteAsset, symbolName);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(symbol.SymbolName, Is.EqualTo(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSymbol_WithSymbolNameSet_Should_ReturnSymbolName()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var symbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT", "CUSTOM-BTC-USDT");
|
||||||
|
var formatFunc = new Func<string, string, TradingMode, DateTime?, string>(
|
||||||
|
(b, q, t, d) => $"{b}{q}");
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = symbol.GetSymbol(formatFunc);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.EqualTo("CUSTOM-BTC-USDT"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSymbol_WithSymbolNameNull_Should_UseFormatFunction()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var symbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
|
||||||
|
var formatFunc = new Func<string, string, TradingMode, DateTime?, string>(
|
||||||
|
(b, q, t, d) => $"{b}/{q}");
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = symbol.GetSymbol(formatFunc);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.EqualTo("BTC/USDT"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSymbol_WithComplexFormatFunction_Should_ApplyCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var symbol = new SharedSymbol(TradingMode.PerpetualLinear, "ETH", "USDT");
|
||||||
|
var formatFunc = new Func<string, string, TradingMode, DateTime?, string>(
|
||||||
|
(b, q, t, d) => t == TradingMode.PerpetualLinear ? $"{b}{q}-PERP" : $"{b}{q}");
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = symbol.GetSymbol(formatFunc);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.EqualTo("ETHUSDT-PERP"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSymbol_WithDeliveryTime_Should_PassDeliveryTimeToFormatter()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var deliveryTime = new DateTime(2026, 6, 25);
|
||||||
|
var symbol = new SharedSymbol(TradingMode.DeliveryLinear, "BTC", "USDT", deliveryTime);
|
||||||
|
var formatFunc = new Func<string, string, TradingMode, DateTime?, string>(
|
||||||
|
(b, q, t, d) => d.HasValue ? $"{b}{q}_{d.Value:yyyyMMdd}" : $"{b}{q}");
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = symbol.GetSymbol(formatFunc);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.EqualTo("BTCUSDT_20260625"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSymbol_WithTradingMode_Should_PassTradingModeToFormatter()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var symbol = new SharedSymbol(TradingMode.PerpetualInverse, "BTC", "USD");
|
||||||
|
var formatFunc = new Func<string, string, TradingMode, DateTime?, string>(
|
||||||
|
(b, q, t, d) =>
|
||||||
|
{
|
||||||
|
return t switch
|
||||||
|
{
|
||||||
|
TradingMode.Spot => $"{b}{q}",
|
||||||
|
TradingMode.PerpetualLinear => $"{b}{q}-PERP",
|
||||||
|
TradingMode.PerpetualInverse => $"{b}{q}I-PERP",
|
||||||
|
_ => $"{b}{q}"
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = symbol.GetSymbol(formatFunc);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.EqualTo("BTCUSDI-PERP"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSymbol_WithEmptySymbolName_Should_UseFormatFunction()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var symbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT", "");
|
||||||
|
var formatFunc = new Func<string, string, TradingMode, DateTime?, string>(
|
||||||
|
(b, q, t, d) => $"{b}-{q}");
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = symbol.GetSymbol(formatFunc);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.EqualTo("BTC-USDT"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void GetSymbol_WithWhitespaceSymbolName_Should_ReturnWhitespace()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var symbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT", " ");
|
||||||
|
var formatFunc = new Func<string, string, TradingMode, DateTime?, string>(
|
||||||
|
(b, q, t, d) => $"{b}-{q}");
|
||||||
|
|
||||||
|
// act
|
||||||
|
var result = symbol.GetSymbol(formatFunc);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(result, Is.EqualTo(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedSymbol_RecordEquality_SameValues_Should_BeEqual()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var symbol1 = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
|
||||||
|
var symbol2 = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
Assert.That(symbol1, Is.EqualTo(symbol2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedSymbol_RecordEquality_DifferentBaseAsset_Should_NotBeEqual()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var symbol1 = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
|
||||||
|
var symbol2 = new SharedSymbol(TradingMode.Spot, "ETH", "USDT");
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
Assert.That(symbol1, Is.Not.EqualTo(symbol2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedSymbol_RecordEquality_DifferentQuoteAsset_Should_NotBeEqual()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var symbol1 = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
|
||||||
|
var symbol2 = new SharedSymbol(TradingMode.Spot, "BTC", "EUR");
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
Assert.That(symbol1, Is.Not.EqualTo(symbol2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedSymbol_RecordEquality_DifferentTradingMode_Should_NotBeEqual()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var symbol1 = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
|
||||||
|
var symbol2 = new SharedSymbol(TradingMode.PerpetualLinear, "BTC", "USDT");
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
Assert.That(symbol1, Is.Not.EqualTo(symbol2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedSymbol_RecordEquality_DifferentDeliveryTime_Should_NotBeEqual()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var deliveryTime1 = new DateTime(2026, 6, 25);
|
||||||
|
var deliveryTime2 = new DateTime(2026, 9, 25);
|
||||||
|
var symbol1 = new SharedSymbol(TradingMode.DeliveryLinear, "BTC", "USDT", deliveryTime1);
|
||||||
|
var symbol2 = new SharedSymbol(TradingMode.DeliveryLinear, "BTC", "USDT", deliveryTime2);
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
Assert.That(symbol1, Is.Not.EqualTo(symbol2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedSymbol_RecordEquality_DifferentSymbolName_Should_NotBeEqual()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var symbol1 = new SharedSymbol(TradingMode.Spot, "BTC", "USDT", "BTCUSDT");
|
||||||
|
var symbol2 = new SharedSymbol(TradingMode.Spot, "BTC", "USDT", "BTC-USDT");
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
Assert.That(symbol1, Is.Not.EqualTo(symbol2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedSymbol_RecordEquality_OneWithSymbolNameOneWithout_Should_NotBeEqual()
|
||||||
|
{
|
||||||
|
// NOTE; although this should probably be equal it's considered not because the SymbolName property isn't equal
|
||||||
|
// Overridding equality to ignore SymbolName would be possible but would break the default record equality behavior and cause confusion
|
||||||
|
|
||||||
|
// arrange
|
||||||
|
var symbol1 = new SharedSymbol(TradingMode.Spot, "BTC", "USDT", "BTCUSDT");
|
||||||
|
var symbol2 = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
Assert.That(symbol1, Is.Not.EqualTo(symbol2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedSymbol_RecordEquality_WithAllPropertiesSet_Should_BeEqual()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var deliveryTime = new DateTime(2026, 6, 25);
|
||||||
|
var symbol1 = new SharedSymbol(TradingMode.DeliveryLinear, "BTC", "USDT", deliveryTime)
|
||||||
|
{
|
||||||
|
SymbolName = "BTCUSDT-0625"
|
||||||
|
};
|
||||||
|
var symbol2 = new SharedSymbol(TradingMode.DeliveryLinear, "BTC", "USDT", deliveryTime)
|
||||||
|
{
|
||||||
|
SymbolName = "BTCUSDT-0625"
|
||||||
|
};
|
||||||
|
|
||||||
|
// act & assert
|
||||||
|
Assert.That(symbol1, Is.EqualTo(symbol2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedSymbol_Properties_Should_BeSettable()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var symbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
|
||||||
|
|
||||||
|
// act
|
||||||
|
symbol.BaseAsset = "ETH";
|
||||||
|
symbol.QuoteAsset = "EUR";
|
||||||
|
symbol.TradingMode = TradingMode.PerpetualLinear;
|
||||||
|
symbol.SymbolName = "CUSTOM";
|
||||||
|
symbol.DeliverTime = DateTime.UtcNow;
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(symbol.BaseAsset, Is.EqualTo("ETH"));
|
||||||
|
Assert.That(symbol.QuoteAsset, Is.EqualTo("EUR"));
|
||||||
|
Assert.That(symbol.TradingMode, Is.EqualTo(TradingMode.PerpetualLinear));
|
||||||
|
Assert.That(symbol.SymbolName, Is.EqualTo("CUSTOM"));
|
||||||
|
Assert.That(symbol.DeliverTime, Is.Not.Null);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedSymbol_WithSpecialCharactersInAssets_Should_HandleCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var baseAsset = "BTC-123";
|
||||||
|
var quoteAsset = "USDT_2.0";
|
||||||
|
|
||||||
|
// act
|
||||||
|
var symbol = new SharedSymbol(TradingMode.Spot, baseAsset, quoteAsset);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(symbol.BaseAsset, Is.EqualTo(baseAsset));
|
||||||
|
Assert.That(symbol.QuoteAsset, Is.EqualTo(quoteAsset));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SharedSymbol_WithLongAssetNames_Should_HandleCorrectly()
|
||||||
|
{
|
||||||
|
// arrange
|
||||||
|
var baseAsset = "VERYLONGASSETNAMEFORTESTING";
|
||||||
|
var quoteAsset = "ANOTHERVERYLONGASSETNAME";
|
||||||
|
|
||||||
|
// act
|
||||||
|
var symbol = new SharedSymbol(TradingMode.Spot, baseAsset, quoteAsset);
|
||||||
|
|
||||||
|
// assert
|
||||||
|
Assert.That(symbol.BaseAsset, Is.EqualTo(baseAsset));
|
||||||
|
Assert.That(symbol.QuoteAsset, Is.EqualTo(quoteAsset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -87,7 +87,8 @@ namespace CryptoExchange.Net.Sockets.Default
|
|||||||
get
|
get
|
||||||
{
|
{
|
||||||
UpdateReceivedMessages();
|
UpdateReceivedMessages();
|
||||||
return Math.Round(_prevSlotBytesReceived * (_lastBytesReceivedUpdate - _prevSlotBytesReceivedUpdate).TotalSeconds / 1000);
|
var seconds = (_lastBytesReceivedUpdate - _prevSlotBytesReceivedUpdate).TotalSeconds;
|
||||||
|
return seconds > 0 ? Math.Round(_prevSlotBytesReceived / seconds / 1000) : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -948,7 +948,7 @@ namespace CryptoExchange.Net.Sockets.Default
|
|||||||
return SendStringAsync(requestId, str, weight);
|
return SendStringAsync(requestId, str, weight);
|
||||||
|
|
||||||
str = stringSerializer.Serialize(obj);
|
str = stringSerializer.Serialize(obj);
|
||||||
return SendAsync(requestId, str, weight);
|
return SendStringAsync(requestId, str, weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Exception("Unknown serializer when sending message");
|
throw new Exception("Unknown serializer when sending message");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user