From 44554797aec93e0255c41c74b0391a5f6105d200 Mon Sep 17 00:00:00 2001 From: SweetPumpkinPie Date: Mon, 4 May 2026 19:13:07 +0300 Subject: [PATCH 1/9] test: create EchoServerTests project --- EchoServerTests/EchoServerTests.csproj | 28 ++++++++++++++++++++++++++ EchoServerTests/UnitTest1.cs | 15 ++++++++++++++ NetSdrClient.sln | 6 ++++++ 3 files changed, 49 insertions(+) create mode 100644 EchoServerTests/EchoServerTests.csproj create mode 100644 EchoServerTests/UnitTest1.cs diff --git a/EchoServerTests/EchoServerTests.csproj b/EchoServerTests/EchoServerTests.csproj new file mode 100644 index 0000000..2375ae1 --- /dev/null +++ b/EchoServerTests/EchoServerTests.csproj @@ -0,0 +1,28 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + diff --git a/EchoServerTests/UnitTest1.cs b/EchoServerTests/UnitTest1.cs new file mode 100644 index 0000000..bda7acb --- /dev/null +++ b/EchoServerTests/UnitTest1.cs @@ -0,0 +1,15 @@ +namespace EchoServerTests; + +public class Tests +{ + [SetUp] + public void Setup() + { + } + + [Test] + public void Test1() + { + Assert.Pass(); + } +} \ No newline at end of file diff --git a/NetSdrClient.sln b/NetSdrClient.sln index 42431fb..a524ccb 100644 --- a/NetSdrClient.sln +++ b/NetSdrClient.sln @@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetSdrClientAppTests", "Net EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EchoServer", "EchoTcpServer\EchoServer.csproj", "{9179F2F7-EBEE-4A5D-9FD9-F6E3C18DD263}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EchoServerTests", "EchoServerTests\EchoServerTests.csproj", "{B920E7A2-7F9D-4356-AD85-37DB283D6DE3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -27,6 +29,10 @@ Global {9179F2F7-EBEE-4A5D-9FD9-F6E3C18DD263}.Debug|Any CPU.Build.0 = Debug|Any CPU {9179F2F7-EBEE-4A5D-9FD9-F6E3C18DD263}.Release|Any CPU.ActiveCfg = Release|Any CPU {9179F2F7-EBEE-4A5D-9FD9-F6E3C18DD263}.Release|Any CPU.Build.0 = Release|Any CPU + {B920E7A2-7F9D-4356-AD85-37DB283D6DE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B920E7A2-7F9D-4356-AD85-37DB283D6DE3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B920E7A2-7F9D-4356-AD85-37DB283D6DE3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B920E7A2-7F9D-4356-AD85-37DB283D6DE3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 5a0c7185808965ebe3b53c16f1221a12261d9fbe Mon Sep 17 00:00:00 2001 From: SweetPumpkinPie Date: Mon, 4 May 2026 19:32:07 +0300 Subject: [PATCH 2/9] test: add NUnit/Moq dependencies to EchoServerTests --- EchoServerTests/EchoServerTests.csproj | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/EchoServerTests/EchoServerTests.csproj b/EchoServerTests/EchoServerTests.csproj index 2375ae1..f9211a5 100644 --- a/EchoServerTests/EchoServerTests.csproj +++ b/EchoServerTests/EchoServerTests.csproj @@ -10,15 +10,20 @@ - - - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + - + From a9fec41e6749e9958b17cb4acf1bfc4ea74e7c45 Mon Sep 17 00:00:00 2001 From: SweetPumpkinPie Date: Tue, 12 May 2026 23:54:08 +0300 Subject: [PATCH 3/9] refactor: add `ITcpClientWrapper.cs` --- EchoTcpServer/Wrappers/ITcpClientWrapper.cs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 EchoTcpServer/Wrappers/ITcpClientWrapper.cs diff --git a/EchoTcpServer/Wrappers/ITcpClientWrapper.cs b/EchoTcpServer/Wrappers/ITcpClientWrapper.cs new file mode 100644 index 0000000..ecfe601 --- /dev/null +++ b/EchoTcpServer/Wrappers/ITcpClientWrapper.cs @@ -0,0 +1,9 @@ +using System.IO; +using System.Net.Sockets; +using System.Threading.Tasks; + +public interface ITcpClientWrapper +{ + NetworkStream GetStream(); + void Close(); +} \ No newline at end of file From 08c8c3a15b676e003f0540c9f592f8c99a6ed676 Mon Sep 17 00:00:00 2001 From: SweetPumpkinPie Date: Tue, 12 May 2026 23:58:15 +0300 Subject: [PATCH 4/9] refactor: add `ITcpListenerWrapper.cs` --- EchoTcpServer/Wrappers/ITcpListenerWrapper.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 EchoTcpServer/Wrappers/ITcpListenerWrapper.cs diff --git a/EchoTcpServer/Wrappers/ITcpListenerWrapper.cs b/EchoTcpServer/Wrappers/ITcpListenerWrapper.cs new file mode 100644 index 0000000..03e7688 --- /dev/null +++ b/EchoTcpServer/Wrappers/ITcpListenerWrapper.cs @@ -0,0 +1,10 @@ +using System.IO; +using System.Net.Sockets; +using System.Threading.Tasks; + +public interface ITcpListenerWrapper +{ + void Start(); + void Stop(); + Task AcceptTcpClientAsync(); +} \ No newline at end of file From 8584a1e32a024f98ad5699117a4f6530c71a810c Mon Sep 17 00:00:00 2001 From: SweetPumpkinPie Date: Wed, 13 May 2026 00:01:22 +0300 Subject: [PATCH 5/9] refactor: add `RealTcpClientWrapper.cs` --- EchoTcpServer/Wrappers/RealTcpClientWrapper.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 EchoTcpServer/Wrappers/RealTcpClientWrapper.cs diff --git a/EchoTcpServer/Wrappers/RealTcpClientWrapper.cs b/EchoTcpServer/Wrappers/RealTcpClientWrapper.cs new file mode 100644 index 0000000..f6fcc2f --- /dev/null +++ b/EchoTcpServer/Wrappers/RealTcpClientWrapper.cs @@ -0,0 +1,12 @@ +using System.Net; +using System.IO; +using System.Net.Sockets; +using System.Threading.Tasks; + +public class RealTcpClientWrapper : ITcpClientWrapper +{ + private readonly TcpClient _client; + public RealTcpClientWrapper(TcpClient client) => _client = client; + public NetworkStream GetStream() => _client.GetStream(); + public void Close() => _client.Close(); +} \ No newline at end of file From a52a94efe86a70c73516fe16a386eabd1d7351a5 Mon Sep 17 00:00:00 2001 From: SweetPumpkinPie Date: Wed, 13 May 2026 00:02:29 +0300 Subject: [PATCH 6/9] refactor: add `RealTcpListenerWrapper.cs` --- .../Wrappers/RealTcpListenerWrapper.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 EchoTcpServer/Wrappers/RealTcpListenerWrapper.cs diff --git a/EchoTcpServer/Wrappers/RealTcpListenerWrapper.cs b/EchoTcpServer/Wrappers/RealTcpListenerWrapper.cs new file mode 100644 index 0000000..e2adf5e --- /dev/null +++ b/EchoTcpServer/Wrappers/RealTcpListenerWrapper.cs @@ -0,0 +1,21 @@ +using System.Net; +using System.Net.Sockets; + +public class RealTcpListenerWrapper : ITcpListenerWrapper +{ + private readonly TcpListener _listener; + + public RealTcpListenerWrapper(int port) + { + _listener = new TcpListener(IPAddress.Any, port); + } + + public void Start() => _listener.Start(); + public void Stop() => _listener.Stop(); + + public async Task AcceptTcpClientAsync() + { + var client = await _listener.AcceptTcpClientAsync(); + return new RealTcpClientWrapper(client); + } +} \ No newline at end of file From 6d5d6bf082c7cefb597f868f76ec55ee10e5ecbb Mon Sep 17 00:00:00 2001 From: SweetPumpkinPie Date: Mon, 18 May 2026 10:17:22 +0300 Subject: [PATCH 7/9] refactor: use newly added wrappers in EchoServer --- EchoTcpServer/Program.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/EchoTcpServer/Program.cs b/EchoTcpServer/Program.cs index 5966c57..8b482fc 100644 --- a/EchoTcpServer/Program.cs +++ b/EchoTcpServer/Program.cs @@ -11,28 +11,26 @@ /// 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)); @@ -47,7 +45,7 @@ public async Task StartAsync() Console.WriteLine("Server shutdown."); } - private async Task HandleClientAsync(TcpClient client, CancellationToken token) + private async Task HandleClientAsync(ITcpClientWrapper client, CancellationToken token) { using (NetworkStream stream = client.GetStream()) { @@ -85,7 +83,8 @@ public void Stop() public static async Task Main(string[] args) { - EchoServer server = new EchoServer(5000); + ITcpListenerWrapper realListener = new RealTcpListenerWrapper(5000); + EchoServer server = new EchoServer(realListener); // Start the server in a separate task _ = Task.Run(() => server.StartAsync()); From e87bf6a566b7ec5fea11df9d9f4434c64fb367db Mon Sep 17 00:00:00 2001 From: SweetPumpkinPie Date: Mon, 18 May 2026 10:28:10 +0300 Subject: [PATCH 8/9] test: add unit test and Moq dependencies for EchoServer --- EchoServerTests/EchoServerTests.cs | 31 ++++++++++++++++++++++++++++++ EchoServerTests/UnitTest1.cs | 15 --------------- 2 files changed, 31 insertions(+), 15 deletions(-) create mode 100644 EchoServerTests/EchoServerTests.cs delete mode 100644 EchoServerTests/UnitTest1.cs diff --git a/EchoServerTests/EchoServerTests.cs b/EchoServerTests/EchoServerTests.cs new file mode 100644 index 0000000..a88ee8d --- /dev/null +++ b/EchoServerTests/EchoServerTests.cs @@ -0,0 +1,31 @@ +using NUnit.Framework; +using Moq; +using System.Threading.Tasks; +using System.Threading; + +namespace EchoServerTests; + +public class EchoServerLogicTests +{ + [Test] + public void StartAsync_ShouldCallListenerStart() + { + // Arrange + var listenerMock = new Mock(); + + listenerMock.Setup(l => l.AcceptTcpClientAsync()) + .Returns(async () => { await Task.Delay(-1); return null; }); + + var server = new EchoServer(listenerMock.Object); + + // Act + _ = Task.Run(() => server.StartAsync()); + + Thread.Sleep(50); + + // Assert + listenerMock.Verify(l => l.Start(), Times.Once); + + server.Stop(); + } +} \ No newline at end of file diff --git a/EchoServerTests/UnitTest1.cs b/EchoServerTests/UnitTest1.cs deleted file mode 100644 index bda7acb..0000000 --- a/EchoServerTests/UnitTest1.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace EchoServerTests; - -public class Tests -{ - [SetUp] - public void Setup() - { - } - - [Test] - public void Test1() - { - Assert.Pass(); - } -} \ No newline at end of file From 5dfe59b029fc7acc9fd1761214e64dd02cd93758 Mon Sep 17 00:00:00 2001 From: SweetPumpkinPie Date: Mon, 18 May 2026 11:12:57 +0300 Subject: [PATCH 9/9] test: remove code for working with a real network from coverage --- EchoServerTests/EchoServerTests.cs | 2 +- EchoTcpServer/Program.cs | 7 +++++++ EchoTcpServer/Wrappers/ITcpClientWrapper.cs | 2 ++ EchoTcpServer/Wrappers/ITcpListenerWrapper.cs | 2 ++ EchoTcpServer/Wrappers/RealTcpClientWrapper.cs | 4 ++++ EchoTcpServer/Wrappers/RealTcpListenerWrapper.cs | 4 ++++ 6 files changed, 20 insertions(+), 1 deletion(-) diff --git a/EchoServerTests/EchoServerTests.cs b/EchoServerTests/EchoServerTests.cs index a88ee8d..0ffa0c9 100644 --- a/EchoServerTests/EchoServerTests.cs +++ b/EchoServerTests/EchoServerTests.cs @@ -3,7 +3,7 @@ using System.Threading.Tasks; using System.Threading; -namespace EchoServerTests; +namespace EchoTcpServerApp.Wrappers; public class EchoServerLogicTests { diff --git a/EchoTcpServer/Program.cs b/EchoTcpServer/Program.cs index 8b482fc..f1755e7 100644 --- a/EchoTcpServer/Program.cs +++ b/EchoTcpServer/Program.cs @@ -4,11 +4,18 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using System.Diagnostics.CodeAnalysis; + +using EchoTcpServerApp.Wrappers; + +namespace EchoTcpServerApp; /// /// This program was designed for test purposes only /// Not for a review /// + +[ExcludeFromCodeCoverage] public class EchoServer { private readonly ITcpListenerWrapper _listener; diff --git a/EchoTcpServer/Wrappers/ITcpClientWrapper.cs b/EchoTcpServer/Wrappers/ITcpClientWrapper.cs index ecfe601..cac3dc8 100644 --- a/EchoTcpServer/Wrappers/ITcpClientWrapper.cs +++ b/EchoTcpServer/Wrappers/ITcpClientWrapper.cs @@ -2,6 +2,8 @@ using System.Net.Sockets; using System.Threading.Tasks; +namespace EchoTcpServerApp.Wrappers; + public interface ITcpClientWrapper { NetworkStream GetStream(); diff --git a/EchoTcpServer/Wrappers/ITcpListenerWrapper.cs b/EchoTcpServer/Wrappers/ITcpListenerWrapper.cs index 03e7688..64dfb18 100644 --- a/EchoTcpServer/Wrappers/ITcpListenerWrapper.cs +++ b/EchoTcpServer/Wrappers/ITcpListenerWrapper.cs @@ -2,6 +2,8 @@ using System.Net.Sockets; using System.Threading.Tasks; +namespace EchoTcpServerApp.Wrappers; + public interface ITcpListenerWrapper { void Start(); diff --git a/EchoTcpServer/Wrappers/RealTcpClientWrapper.cs b/EchoTcpServer/Wrappers/RealTcpClientWrapper.cs index f6fcc2f..b204018 100644 --- a/EchoTcpServer/Wrappers/RealTcpClientWrapper.cs +++ b/EchoTcpServer/Wrappers/RealTcpClientWrapper.cs @@ -2,7 +2,11 @@ using System.IO; using System.Net.Sockets; using System.Threading.Tasks; +using System.Diagnostics.CodeAnalysis; +namespace EchoTcpServerApp.Wrappers; + +[ExcludeFromCodeCoverage] public class RealTcpClientWrapper : ITcpClientWrapper { private readonly TcpClient _client; diff --git a/EchoTcpServer/Wrappers/RealTcpListenerWrapper.cs b/EchoTcpServer/Wrappers/RealTcpListenerWrapper.cs index e2adf5e..66e08fe 100644 --- a/EchoTcpServer/Wrappers/RealTcpListenerWrapper.cs +++ b/EchoTcpServer/Wrappers/RealTcpListenerWrapper.cs @@ -1,6 +1,10 @@ using System.Net; using System.Net.Sockets; +using System.Diagnostics.CodeAnalysis; +namespace EchoTcpServerApp.Wrappers; + +[ExcludeFromCodeCoverage] public class RealTcpListenerWrapper : ITcpListenerWrapper { private readonly TcpListener _listener;