//+------------------------------------------------------------------+ //| UnitTests.mq5 | //| Unit Tests for Package sockets | //| Organization: douglasrechia | //+------------------------------------------------------------------+ #include "../knitpkg/build/BuildInfo.mqh" #property copyright "Douglas Rechia" #property link "https://knitpkg.dev" #property description "" #property description "Version: " + MANIFEST_VERSION #property description "" #property description "Description: Unit tests for package sockets" #property description "Organization: douglasrechia" #property description "Author: Douglas Rechia" #property description "License: MIT" #property description "" #property description "Powered by KnitPkg for MetaTrader" #property description "https://knitpkg.dev" // Include the headers under test #include "../knitpkg/include/douglasrechia/sockets/Sockets.mqh" //+------------------------------------------------------------------+ //| TestSocketBasicFunctionality | //| Tests basic socket functionality in single-threaded environment | //| Strategy: Create server, then client connects to it in same | //| thread using non-blocking sockets | //+------------------------------------------------------------------+ bool TestSocketBasicFunctionality() { const ushort TEST_PORT = 9999; const string TEST_MESSAGE = "Hello Socket"; const string MESSAGE_SEPARATOR = "\n"; // Step 1: Create server socket douglasrechia::ServerSocket* server = new douglasrechia::ServerSocket(TEST_PORT); if(!server.Created()) { Print("Failed to create server: ", server.GetLastError()); delete server; return false; } Print("Server created successfully on port ", TEST_PORT); // Step 2: Create client socket and connect to localhost douglasrechia::ClientSocket* client = new douglasrechia::ClientSocket("127.0.0.1", TEST_PORT); if(!client.IsSocketConnected()) { Print("Failed to connect client: ", client.GetLastError()); delete client; delete server; return false; } Print("Client connected successfully"); // Step 3: Server accepts the connection (non-blocking, may need retries) douglasrechia::ClientSocket* acceptedClient = NULL; int acceptRetries = 0; while(acceptedClient == NULL && acceptRetries < 100) { acceptedClient = server.Accept(); if(acceptedClient == NULL) { Sleep(10); acceptRetries++; } } if(acceptedClient == NULL) { Print("Server failed to accept connection: ", server.GetLastError()); delete client; delete server; return false; } Print("Server accepted client connection"); // Step 4: Client sends message string messageToSend = TEST_MESSAGE + MESSAGE_SEPARATOR; if(!client.Send(messageToSend)) { Print("Client failed to send message: ", client.GetLastError()); delete acceptedClient; delete client; delete server; return false; } Print("Client sent message: '", TEST_MESSAGE, "'"); // Step 5: Server receives message (non-blocking, may need retries) string receivedMessage = ""; int receiveRetries = 0; while(receivedMessage == "" && receiveRetries < 100) { receivedMessage = acceptedClient.Receive(MESSAGE_SEPARATOR); if(receivedMessage == "") { Sleep(10); receiveRetries++; } } if(receivedMessage == "") { Print("Server failed to receive message: ", acceptedClient.GetLastError()); delete acceptedClient; delete client; delete server; return false; } Print("Server received message: '", receivedMessage, "'"); // Step 6: Verify message content bool messageMatches = (receivedMessage == TEST_MESSAGE); if(!messageMatches) { Print("Message mismatch! Expected: '", TEST_MESSAGE, "', Got: '", receivedMessage, "'"); } // Step 7: Test echo back - server sends response string echoMessage = "Echo: " + receivedMessage + MESSAGE_SEPARATOR; if(!acceptedClient.Send(echoMessage)) { Print("Server failed to send echo: ", acceptedClient.GetLastError()); delete acceptedClient; delete client; delete server; return false; } Print("Server sent echo message"); // Step 8: Client receives echo string echoReceived = ""; receiveRetries = 0; while(echoReceived == "" && receiveRetries < 100) { echoReceived = client.Receive(MESSAGE_SEPARATOR); if(echoReceived == "") { Sleep(10); receiveRetries++; } } if(echoReceived == "") { Print("Client failed to receive echo: ", client.GetLastError()); delete acceptedClient; delete client; delete server; return false; } Print("Client received echo: '", echoReceived, "'"); string expectedEcho = "Echo: " + TEST_MESSAGE; bool echoMatches = (echoReceived == expectedEcho); if(!echoMatches) { Print("Echo mismatch! Expected: '", expectedEcho, "', Got: '", echoReceived, "'"); } // Cleanup delete acceptedClient; delete client; delete server; Print("Test completed successfully"); return messageMatches && echoMatches; } //+------------------------------------------------------------------+ //| DoTests | //+------------------------------------------------------------------+ void DoTests(int &testsPerformed,int &testsPassed) { string testName=""; //--- TestSocketBasicFunctionality testsPerformed++; testName="TestSocketBasicFunctionality"; if(TestSocketBasicFunctionality()) { testsPassed++; PrintFormat("%s pass",testName); } else PrintFormat("%s failed",testName); //--- // Add more tests here as needed } //+------------------------------------------------------------------+ //| UnitTests() | //+------------------------------------------------------------------+ void UnitTests(const string packageName) { PrintFormat("Unit tests for Package %s\n",packageName); //--- initial values int testsPerformed=0; int testsPassed=0; //--- test distributions DoTests(testsPerformed,testsPassed); //--- print statistics PrintFormat("\n%d of %d passed",testsPassed,testsPerformed); } //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { UnitTests("sockets"); } //+------------------------------------------------------------------+