using System; using System.Collections.Generic; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.VisualStudio.TestTools.UnitTesting; using NT8.Core.OMS; using NT8.Core.Tests.Mocks; namespace NT8.Core.Tests.OMS { [TestClass] public class BasicOrderManagerTests { private MockLogger _mockLogger; private MockNT8OrderAdapter _mockAdapter; private BasicOrderManager _orderManager; [TestInitialize] public void Setup() { _mockLogger = new MockLogger(); _mockAdapter = new MockNT8OrderAdapter(); _orderManager = new BasicOrderManager(_mockLogger, _mockAdapter); } [TestCleanup] public void Cleanup() { if (_orderManager != null) { _orderManager.Dispose(); } } [TestMethod] public async Task SubmitOrderAsync_ValidRequest_ReturnsSuccessResult() { // Arrange var request = new OrderRequest { Symbol = "ES", Side = OrderSide.Buy, Type = OrderType.Market, Quantity = 1, ClientOrderId = "TEST123" }; // Act var result = await _orderManager.SubmitOrderAsync(request); // Assert Assert.IsTrue(result.Success); Assert.IsNotNull(result.OrderId); Assert.AreEqual(request, result.Request); Assert.AreEqual("Order submitted successfully", result.Message); } [TestMethod] public async Task SubmitOrderAsync_NullRequest_ThrowsArgumentNullException() { // Arrange OrderRequest request = null; // Act & Assert await Assert.ThrowsExceptionAsync( () => _orderManager.SubmitOrderAsync(request)); } [TestMethod] public async Task SubmitOrderAsync_InvalidRequest_ReturnsFailureResult() { // Arrange var request = new OrderRequest { Symbol = "", // Invalid symbol Side = OrderSide.Buy, Type = OrderType.Market, Quantity = 1 }; // Act var result = await _orderManager.SubmitOrderAsync(request); // Assert Assert.IsFalse(result.Success); Assert.IsNull(result.OrderId); } [TestMethod] public async Task SubmitOrderAsync_Nt8SubmissionFails_ReturnsFailureResult() { // Arrange _mockAdapter.ShouldSucceed = false; _mockAdapter.ShouldFail = true; var request = new OrderRequest { Symbol = "ES", Side = OrderSide.Buy, Type = OrderType.Market, Quantity = 1, ClientOrderId = "TEST123" }; // Act var result = await _orderManager.SubmitOrderAsync(request); // Assert Assert.IsFalse(result.Success); Assert.IsNotNull(result.OrderId); // Order ID is generated before NT8 submission Assert.AreEqual("Order submission failed at NT8 level", result.Message); } [TestMethod] public async Task ModifyOrderAsync_ValidRequest_ReturnsTrue() { // Arrange var request = new OrderRequest { Symbol = "ES", Side = OrderSide.Buy, Type = OrderType.Limit, Quantity = 1, LimitPrice = 4000m, ClientOrderId = "TEST123" }; var submitResult = await _orderManager.SubmitOrderAsync(request); var modification = new OrderModification(submitResult.OrderId) { NewQuantity = 2 }; // Act var result = await _orderManager.ModifyOrderAsync(modification); // Assert Assert.IsTrue(result); } [TestMethod] public async Task ModifyOrderAsync_NullRequest_ThrowsArgumentNullException() { // Arrange OrderModification modification = null; // Act & Assert await Assert.ThrowsExceptionAsync( () => _orderManager.ModifyOrderAsync(modification)); } [TestMethod] public async Task CancelOrderAsync_ValidRequest_ReturnsTrue() { // Arrange var request = new OrderRequest { Symbol = "ES", Side = OrderSide.Buy, Type = OrderType.Market, Quantity = 1, ClientOrderId = "TEST123" }; var submitResult = await _orderManager.SubmitOrderAsync(request); var cancellation = new OrderCancellation(submitResult.OrderId, "Test cancellation"); // Act var result = await _orderManager.CancelOrderAsync(cancellation); // Assert Assert.IsTrue(result); } [TestMethod] public async Task CancelOrderAsync_NullRequest_ThrowsArgumentNullException() { // Arrange OrderCancellation cancellation = null; // Act & Assert await Assert.ThrowsExceptionAsync( () => _orderManager.CancelOrderAsync(cancellation)); } [TestMethod] public async Task GetOrderStatusAsync_ExistingOrder_ReturnsOrderStatus() { // Arrange var request = new OrderRequest { Symbol = "ES", Side = OrderSide.Buy, Type = OrderType.Market, Quantity = 1, ClientOrderId = "TEST123" }; var submitResult = await _orderManager.SubmitOrderAsync(request); // Act var status = await _orderManager.GetOrderStatusAsync(submitResult.OrderId); // Assert Assert.IsNotNull(status); Assert.AreEqual(submitResult.OrderId, status.OrderId); Assert.AreEqual("ES", status.Symbol); } [TestMethod] public async Task GetOrderStatusAsync_NonExistentOrder_ReturnsNull() { // Act var status = await _orderManager.GetOrderStatusAsync("NONEXISTENT"); // Assert Assert.IsNull(status); } [TestMethod] public async Task GetOrderStatusAsync_NullOrderId_ThrowsArgumentNullException() { // Act & Assert await Assert.ThrowsExceptionAsync( () => _orderManager.GetOrderStatusAsync(null)); } [TestMethod] public async Task GetActiveOrdersAsync_HasActiveOrders_ReturnsList() { // Arrange var request1 = new OrderRequest { Symbol = "ES", Side = OrderSide.Buy, Type = OrderType.Market, Quantity = 1, ClientOrderId = "TEST123" }; var request2 = new OrderRequest { Symbol = "NQ", Side = OrderSide.Sell, Type = OrderType.Market, Quantity = 2, ClientOrderId = "TEST124" }; await _orderManager.SubmitOrderAsync(request1); await _orderManager.SubmitOrderAsync(request2); // Act var activeOrders = await _orderManager.GetActiveOrdersAsync(); // Assert Assert.IsNotNull(activeOrders); Assert.IsTrue(activeOrders.Count >= 2); } [TestMethod] public async Task GetOrdersBySymbolAsync_ValidSymbol_ReturnsFilteredOrders() { // Arrange var request1 = new OrderRequest { Symbol = "ES", Side = OrderSide.Buy, Type = OrderType.Market, Quantity = 1, ClientOrderId = "TEST123" }; var request2 = new OrderRequest { Symbol = "NQ", Side = OrderSide.Sell, Type = OrderType.Market, Quantity = 2, ClientOrderId = "TEST124" }; await _orderManager.SubmitOrderAsync(request1); await _orderManager.SubmitOrderAsync(request2); // Act var esOrders = await _orderManager.GetOrdersBySymbolAsync("ES"); // Assert Assert.IsNotNull(esOrders); foreach (var order in esOrders) { Assert.AreEqual("ES", order.Symbol, true); // Case insensitive comparison } } [TestMethod] public async Task GetOrdersBySymbolAsync_NullSymbol_ThrowsArgumentNullException() { // Act & Assert await Assert.ThrowsExceptionAsync( () => _orderManager.GetOrdersBySymbolAsync(null)); } [TestMethod] public async Task FlattenSymbolAsync_ValidSymbol_CancelsOrders() { // Arrange var request1 = new OrderRequest { Symbol = "ES", Side = OrderSide.Buy, Type = OrderType.Market, Quantity = 1, ClientOrderId = "TEST123" }; var request2 = new OrderRequest { Symbol = "ES", // Same symbol Side = OrderSide.Sell, Type = OrderType.Market, Quantity = 2, ClientOrderId = "TEST124" }; await _orderManager.SubmitOrderAsync(request1); await _orderManager.SubmitOrderAsync(request2); // Act var result = await _orderManager.FlattenSymbolAsync("ES"); // Assert Assert.IsTrue(result); } [TestMethod] public async Task FlattenAllAsync_CancelsAllOrders() { // Arrange var request1 = new OrderRequest { Symbol = "ES", Side = OrderSide.Buy, Type = OrderType.Market, Quantity = 1, ClientOrderId = "TEST123" }; var request2 = new OrderRequest { Symbol = "NQ", Side = OrderSide.Sell, Type = OrderType.Market, Quantity = 2, ClientOrderId = "TEST124" }; await _orderManager.SubmitOrderAsync(request1); await _orderManager.SubmitOrderAsync(request2); // Act var result = await _orderManager.FlattenAllAsync(); // Assert Assert.IsTrue(result); } [TestMethod] public void SubscribeAndUnsubscribeToOrderUpdates_WorksCorrectly() { // Arrange - First create an order so the manager knows about it var request = new OrderRequest { Symbol = "ES", Side = OrderSide.Buy, Type = OrderType.Market, Quantity = 1, ClientOrderId = "TEST_CLIENT_ORDER" }; var submitResult = _orderManager.SubmitOrderAsync(request).Result; Assert.IsTrue(submitResult.Success); string orderId = submitResult.OrderId; Assert.IsNotNull(orderId); bool callbackCalled = false; Action callback = delegate(OrderStatus statusParam) { callbackCalled = true; }; // Act - subscribe _orderManager.SubscribeToOrderUpdates(callback); // Simulate an order update via the mock adapter for the known order var statusUpdate = new OrderStatus { OrderId = orderId, // Use the actual order ID from the created order Symbol = "ES", State = OrderState.Filled }; _mockAdapter.FireOrderUpdate(statusUpdate); // Assert that callback was called Assert.IsTrue(callbackCalled, "Callback should have been called after subscription and order update"); // Reset flag callbackCalled = false; // Act - unsubscribe _orderManager.UnsubscribeFromOrderUpdates(callback); // Simulate another order update for the same order var statusUpdate2 = new OrderStatus { OrderId = orderId, // Use the same order ID Symbol = "ES", State = OrderState.Cancelled }; _mockAdapter.FireOrderUpdate(statusUpdate2); // Assert that callback was NOT called after unsubscribe Assert.IsFalse(callbackCalled, "Callback should NOT have been called after unsubscription"); } [TestMethod] public void SubscribeToOrderUpdates_NullCallback_ThrowsArgumentNullException() { // Act & Assert Assert.ThrowsException( () => _orderManager.SubscribeToOrderUpdates(null)); } [TestMethod] public void UnsubscribeFromOrderUpdates_NullCallback_ThrowsArgumentNullException() { // Act & Assert Assert.ThrowsException( () => _orderManager.UnsubscribeFromOrderUpdates(null)); } [TestMethod] public async Task OrderStateTransition_ValidTransitions_AreAllowed() { // Arrange - create an order and submit it var request = new OrderRequest { Symbol = "ES", Side = OrderSide.Buy, Type = OrderType.Market, Quantity = 1, ClientOrderId = "TEST123" }; var submitResult = await _orderManager.SubmitOrderAsync(request); Assert.IsNotNull(submitResult.OrderId); // Act - simulate state updates through the mock adapter var pendingStatus = new OrderStatus { OrderId = submitResult.OrderId, Symbol = "ES", State = OrderState.Pending }; var submittedStatus = new OrderStatus { OrderId = submitResult.OrderId, Symbol = "ES", State = OrderState.Submitted }; var acceptedStatus = new OrderStatus { OrderId = submitResult.OrderId, Symbol = "ES", State = OrderState.Accepted }; var workingStatus = new OrderStatus { OrderId = submitResult.OrderId, Symbol = "ES", State = OrderState.Working }; // Simulate the state transitions _mockAdapter.FireOrderUpdate(pendingStatus); _mockAdapter.FireOrderUpdate(submittedStatus); _mockAdapter.FireOrderUpdate(acceptedStatus); _mockAdapter.FireOrderUpdate(workingStatus); // Assert - get the final status and verify it's in working state var finalStatus = await _orderManager.GetOrderStatusAsync(submitResult.OrderId); Assert.AreEqual(OrderState.Working, finalStatus.State); } [TestMethod] public async Task Dispose_DisposesResources() { // Arrange var orderManager = new BasicOrderManager(_mockLogger, _mockAdapter); // Act orderManager.Dispose(); // Assert - no exception should be thrown // Additional assertions could check if resources were properly cleaned up } } }