diff --git a/EchoTcpServer/Program.cs b/EchoTcpServer/Program.cs
index 5966c57..7116e7e 100644
--- a/EchoTcpServer/Program.cs
+++ b/EchoTcpServer/Program.cs
@@ -1,66 +1,91 @@
using System;
+using System.IO;
+using System.Linq;
using System.Net;
using System.Net.Sockets;
-using System.Text;
using System.Threading;
using System.Threading.Tasks;
-///
-/// This program was designed for test purposes only
-/// Not for a review
-///
+public interface ITcpListenerWrapper
+{
+ void Start();
+ void Stop();
+ Task AcceptTcpClientAsync();
+}
+
+public interface ITcpClientWrapper : IDisposable
+{
+ Stream GetStream();
+ void Close();
+}
+
+public class TcpListenerWrapper : ITcpListenerWrapper
+{
+ private readonly TcpListener _listener;
+ public TcpListenerWrapper(IPAddress localaddr, int port) { _listener = new TcpListener(localaddr, port); }
+ public void Start() => _listener.Start();
+ public void Stop() => _listener.Stop();
+ public async Task AcceptTcpClientAsync() => new TcpClientWrapper(await _listener.AcceptTcpClientAsync());
+}
+
+public class TcpClientWrapper : ITcpClientWrapper
+{
+ private readonly TcpClient _client;
+ public TcpClientWrapper(TcpClient client) { _client = client; }
+ public Stream GetStream() => _client.GetStream();
+ public void Close() => _client.Close();
+ public void Dispose() => _client.Dispose();
+}
+
public class EchoServer
{
- private readonly int _port;
- private TcpListener _listener;
+ private readonly ITcpListenerWrapper _listener;
private CancellationTokenSource _cancellationTokenSource;
-
- public EchoServer(int port)
+ public EchoServer(ITcpListenerWrapper listener)
{
- _port = port;
+ _listener = listener;
_cancellationTokenSource = new CancellationTokenSource();
}
public async Task StartAsync()
{
- _listener = new TcpListener(IPAddress.Any, _port);
_listener.Start();
- Console.WriteLine($"Server started on port {_port}.");
+ Console.WriteLine("Server started.");
while (!_cancellationTokenSource.Token.IsCancellationRequested)
{
try
{
- TcpClient client = await _listener.AcceptTcpClientAsync();
+ ITcpClientWrapper client = await _listener.AcceptTcpClientAsync();
Console.WriteLine("Client connected.");
_ = Task.Run(() => HandleClientAsync(client, _cancellationTokenSource.Token));
}
- catch (ObjectDisposedException)
+ catch (Exception ex) when (ex is ObjectDisposedException || ex is OperationCanceledException)
{
- // Listener has been closed
break;
}
}
-
Console.WriteLine("Server shutdown.");
}
- private async Task HandleClientAsync(TcpClient client, CancellationToken token)
+ public async Task HandleClientAsync(ITcpClientWrapper client, CancellationToken token)
{
- using (NetworkStream stream = client.GetStream())
+ using (client)
{
try
{
- byte[] buffer = new byte[8192];
- int bytesRead;
-
- while (!token.IsCancellationRequested && (bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token)) > 0)
+ using (Stream stream = client.GetStream())
{
- // Echo back the received message
- await stream.WriteAsync(buffer, 0, bytesRead, token);
- Console.WriteLine($"Echoed {bytesRead} bytes to the client.");
+ byte[] buffer = new byte[8192];
+ int bytesRead;
+
+ while (!token.IsCancellationRequested && (bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token)) > 0)
+ {
+ await stream.WriteAsync(buffer, 0, bytesRead, token);
+ Console.WriteLine($"Echoed {bytesRead} bytes to the client.");
+ }
}
}
catch (Exception ex) when (!(ex is OperationCanceledException))
@@ -82,17 +107,20 @@ public void Stop()
_cancellationTokenSource.Dispose();
Console.WriteLine("Server stopped.");
}
+}
+public class Program
+{
public static async Task Main(string[] args)
{
- EchoServer server = new EchoServer(5000);
+ var listener = new TcpListenerWrapper(IPAddress.Any, 5000);
+ EchoServer server = new EchoServer(listener);
- // Start the server in a separate task
_ = Task.Run(() => server.StartAsync());
- string host = "127.0.0.1"; // Target IP
- int port = 60000; // Target Port
- int intervalMilliseconds = 5000; // Send every 3 seconds
+ string host = "127.0.0.1";
+ int port = 60000;
+ int intervalMilliseconds = 5000;
using (var sender = new UdpTimedSender(host, port))
{
@@ -102,7 +130,6 @@ public static async Task Main(string[] args)
Console.WriteLine("Press 'q' to quit...");
while (Console.ReadKey(intercept: true).Key != ConsoleKey.Q)
{
- // Just wait until 'q' is pressed
}
sender.StopSending();
@@ -112,7 +139,6 @@ public static async Task Main(string[] args)
}
}
-
public class UdpTimedSender : IDisposable
{
private readonly string _host;
@@ -141,7 +167,6 @@ private void SendMessageCallback(object state)
{
try
{
- //dummy data
Random rnd = new Random();
byte[] samples = new byte[1024];
rnd.NextBytes(samples);
diff --git a/EchoTcpServerTests/EchoServerTests.cs b/EchoTcpServerTests/EchoServerTests.cs
new file mode 100644
index 0000000..ede370b
--- /dev/null
+++ b/EchoTcpServerTests/EchoServerTests.cs
@@ -0,0 +1,83 @@
+using System;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Moq;
+using NUnit.Framework;
+
+namespace EchoTcpServerTests
+{
+ public class EchoServerTests
+ {
+ private Mock _listenerMock;
+ private Mock _clientMock;
+ private EchoServer _server;
+
+ [SetUp]
+ public void Setup()
+ {
+ _listenerMock = new Mock();
+ _clientMock = new Mock();
+ _server = new EchoServer(_listenerMock.Object);
+ }
+
+ [Test]
+ public async Task HandleClientAsync_EchoesData_Correctly()
+ {
+ // Arrange
+ byte[] inputData = new byte[] { 1, 2, 3, 4, 5 };
+ var memoryStream = new MemoryStream();
+ memoryStream.Write(inputData, 0, inputData.Length);
+ memoryStream.Position = 0;
+
+ _clientMock.Setup(c => c.GetStream()).Returns(memoryStream);
+ var cts = new CancellationTokenSource();
+
+ // Act
+ await _server.HandleClientAsync(_clientMock.Object, cts.Token);
+
+ // Assert
+ _clientMock.Verify(c => c.GetStream(), Times.Once);
+ _clientMock.Verify(c => c.Close(), Times.Once);
+
+ Assert.That(memoryStream.Length, Is.EqualTo(inputData.Length * 2));
+
+ memoryStream.Position = inputData.Length;
+ byte[] echoedData = new byte[inputData.Length];
+ memoryStream.Read(echoedData, 0, echoedData.Length);
+
+ Assert.That(echoedData, Is.EqualTo(inputData));
+ }
+
+ [Test]
+ public void Stop_CancelsTokenAndStopsListener()
+ {
+ // Act
+ _server.Stop();
+
+ // Assert
+ _listenerMock.Verify(l => l.Stop(), Times.Once);
+ }
+
+ [Test]
+ public async Task StartAsync_AcceptsClients_UntilCancelled()
+ {
+ // Arrange
+ var tcs = new TaskCompletionSource();
+ _listenerMock.SetupSequence(l => l.AcceptTcpClientAsync())
+ .ReturnsAsync(_clientMock.Object)
+ .Returns(tcs.Task);
+
+ // Act
+ var startTask = _server.StartAsync();
+ await Task.Delay(50);
+
+ _server.Stop();
+ tcs.SetCanceled();
+
+ // Assert
+ _listenerMock.Verify(l => l.Start(), Times.Once);
+ _listenerMock.Verify(l => l.AcceptTcpClientAsync(), Times.AtLeastOnce);
+ }
+ }
+}
\ No newline at end of file
diff --git a/NetSdrClientApp/Messages/NetSdrMessageHelper.cs b/NetSdrClientApp/Messages/NetSdrMessageHelper.cs
index 0d69b4d..438dfaf 100644
--- a/NetSdrClientApp/Messages/NetSdrMessageHelper.cs
+++ b/NetSdrClientApp/Messages/NetSdrMessageHelper.cs
@@ -16,6 +16,8 @@ public static class NetSdrMessageHelper
private const short _msgControlItemLength = 2; //2 byte, 16 bit
private const short _msgSequenceNumberLength = 2; //2 byte, 16 bit
+
+
public enum MsgTypes
{
SetControlItem,
diff --git a/NetSdrClientAppTests/ArchitectureTests.cs b/NetSdrClientAppTests/ArchitectureTests.cs
new file mode 100644
index 0000000..dec06fc
--- /dev/null
+++ b/NetSdrClientAppTests/ArchitectureTests.cs
@@ -0,0 +1,24 @@
+using NetArchTest.Rules;
+using NUnit.Framework;
+using NetSdrClientApp.Networking;
+
+namespace NetSdrClientAppTests
+{
+ public class ArchitectureTests
+ {
+ [Test]
+ public void Messages_ShouldNotDependOn_Networking()
+ {
+ // Arrange
+ var result = Types.InAssembly(typeof(TcpClientWrapper).Assembly)
+ .That()
+ .ResideInNamespace("NetSdrClientApp.Messages")
+ .ShouldNot()
+ .HaveDependencyOn("NetSdrClientApp.Networking")
+ .GetResult();
+
+ // Assert
+ Assert.That(result.IsSuccessful, Is.True, "Messages namespace has a prohibited dependency on Networking.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/NetSdrClientAppTests/NetSdrClientAppTests.csproj b/NetSdrClientAppTests/NetSdrClientAppTests.csproj
index eb99533..728eebf 100644
--- a/NetSdrClientAppTests/NetSdrClientAppTests.csproj
+++ b/NetSdrClientAppTests/NetSdrClientAppTests.csproj
@@ -17,6 +17,7 @@
+
diff --git a/README.md b/README.md
index 63ef847..3b83954 100644
--- a/README.md
+++ b/README.md
@@ -28,9 +28,31 @@ https://github.com/friezze/ReengineeringCourse/commit/2534516c319a38d4aecd5d70a4
Може здатися дивним що їх стало більше але скоріше за все це тому що пофіксився білдер через зміни в які я лив в мейн і мерджив в гілку але сонар аналізував пуши в мейн а тік злиття. Але у будьякому випадку 8 фіксед.
# 3
+До а якщо бути точним одразу після включення ковередж
+
+Після(пушу тестів нових)
+
+
+# 4
До
+

-Після
+
+Після
+
+
+
+Важливо зауважити що завдяки зменьшенню дублікатів піднявся і тест коверед бо коду стало банально меньше
+
+
+
+# 5
+
+Це так виглядає після додання порушення прав архітектури і самого порушення.
+
+
+
+
diff --git a/image-10.png b/image-10.png
new file mode 100644
index 0000000..dd73204
Binary files /dev/null and b/image-10.png differ
diff --git a/image-11.png b/image-11.png
new file mode 100644
index 0000000..d0bc53d
Binary files /dev/null and b/image-11.png differ
diff --git a/image-4.png b/image-4.png
new file mode 100644
index 0000000..8bb1a03
Binary files /dev/null and b/image-4.png differ
diff --git a/image-7.png b/image-7.png
new file mode 100644
index 0000000..e21f162
Binary files /dev/null and b/image-7.png differ
diff --git a/image-8.png b/image-8.png
new file mode 100644
index 0000000..1b32640
Binary files /dev/null and b/image-8.png differ
diff --git a/image-9.png b/image-9.png
new file mode 100644
index 0000000..c41bc24
Binary files /dev/null and b/image-9.png differ