diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml
index e784069..db9518c 100644
--- a/.github/workflows/sonarcloud.yml
+++ b/.github/workflows/sonarcloud.yml
@@ -44,6 +44,8 @@ jobs:
runs-on: windows-latest # безпечно для будь-яких .NET проектів
steps:
- uses: actions/checkout@v4
+ env:
+ FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
with: { fetch-depth: 0 }
- uses: actions/setup-dotnet@v4
@@ -56,27 +58,27 @@ jobs:
dotnet tool install --global dotnet-sonarscanner
echo "$env:USERPROFILE\.dotnet\tools" >> $env:GITHUB_PATH
dotnet sonarscanner begin `
- /k:"ppanchen_NetSdrClient" `
- /o:"ppanchen" `
+ /k:"MinTins_ReengineeringCourse" `
+ /o:"roman-flakei" `
/d:sonar.token="${{ secrets.SONAR_TOKEN }}" `
/d:sonar.cs.opencover.reportsPaths="**/coverage.xml" `
/d:sonar.cpd.cs.minimumTokens=40 `
/d:sonar.cpd.cs.minimumLines=5 `
/d:sonar.exclusions=**/bin/**,**/obj/**,**/sonarcloud.yml `
- /d:sonar.qualitygate.wait=true
+ /d:sonar.qualitygate.wait=false
shell: pwsh
# 2) BUILD & TEST
- name: Restore
run: dotnet restore NetSdrClient.sln
- name: Build
run: dotnet build NetSdrClient.sln -c Release --no-restore
- #- name: Tests with coverage (OpenCover)
- # run: |
- # dotnet test NetSdrClientAppTests/NetSdrClientAppTests.csproj -c Release --no-build `
- # /p:CollectCoverage=true `
- # /p:CoverletOutput=TestResults/coverage.xml `
- # /p:CoverletOutputFormat=opencover
- # shell: pwsh
+ - name: Tests with coverage (OpenCover)
+ run: |
+ dotnet test NetSdrClientAppTests/NetSdrClientAppTests.csproj -c Release --no-build `
+ /p:CollectCoverage=true `
+ /p:CoverletOutput=TestResults/coverage.xml `
+ /p:CoverletOutputFormat=opencover
+ shell: pwsh
# 3) END: SonarScanner
- name: SonarScanner End
run: dotnet sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"
diff --git a/EchoTcpServer/EchoServer.csproj b/EchoTcpServer/EchoServer.csproj
index 2150e37..ed9781c 100644
--- a/EchoTcpServer/EchoServer.csproj
+++ b/EchoTcpServer/EchoServer.csproj
@@ -2,7 +2,7 @@
Exe
- net8.0
+ net10.0
enable
enable
diff --git a/EchoTcpServer/Program.cs b/EchoTcpServer/Program.cs
index 5966c57..fab6e1f 100644
--- a/EchoTcpServer/Program.cs
+++ b/EchoTcpServer/Program.cs
@@ -13,7 +13,7 @@ public class EchoServer
{
private readonly int _port;
private TcpListener _listener;
- private CancellationTokenSource _cancellationTokenSource;
+ private readonly CancellationTokenSource _cancellationTokenSource;
public EchoServer(int port)
diff --git a/NetSdrClientApp/Messages/NetSdrMessageHelper.cs b/NetSdrClientApp/Messages/NetSdrMessageHelper.cs
index 0d69b4d..1fb0248 100644
--- a/NetSdrClientApp/Messages/NetSdrMessageHelper.cs
+++ b/NetSdrClientApp/Messages/NetSdrMessageHelper.cs
@@ -83,7 +83,7 @@ public static bool TranslateMessage(byte[] msg, out MsgTypes type, out ControlIt
msgEnumarable = msgEnumarable.Skip(_msgControlItemLength);
msgLength -= _msgControlItemLength;
- if (Enum.IsDefined(typeof(ControlItemCodes), value))
+ if (Enum.IsDefined(typeof(ControlItemCodes), (int)value))
{
itemCode = (ControlItemCodes)value;
}
diff --git a/NetSdrClientApp/NetSdrClient.cs b/NetSdrClientApp/NetSdrClient.cs
index b0a7c05..fac1c6a 100644
--- a/NetSdrClientApp/NetSdrClient.cs
+++ b/NetSdrClientApp/NetSdrClient.cs
@@ -14,8 +14,8 @@ namespace NetSdrClientApp
{
public class NetSdrClient
{
- private ITcpClient _tcpClient;
- private IUdpClient _udpClient;
+ private readonly ITcpClient _tcpClient;
+ private readonly IUdpClient _udpClient;
public bool IQStarted { get; set; }
@@ -66,7 +66,7 @@ public async Task StartIQAsync()
return;
}
-; var iqDataMode = (byte)0x80;
+ var iqDataMode = (byte)0x80;
var start = (byte)0x02;
var fifo16bitCaptureMode = (byte)0x01;
var n = (byte)1;
@@ -116,7 +116,7 @@ public async Task ChangeFrequencyAsync(long hz, int channel)
private void _udpClient_MessageReceived(object? sender, byte[] e)
{
- NetSdrMessageHelper.TranslateMessage(e, out MsgTypes type, out ControlItemCodes code, out ushort sequenceNum, out byte[] body);
+ NetSdrMessageHelper.TranslateMessage(e, out _, out _, out _, out byte[] body);
var samples = NetSdrMessageHelper.GetSamples(16, body);
Console.WriteLine($"Samples recieved: " + body.Select(b => Convert.ToString(b, toBase: 16)).Aggregate((l, r) => $"{l} {r}"));
diff --git a/NetSdrClientApp/NetSdrClientApp.csproj b/NetSdrClientApp/NetSdrClientApp.csproj
index 2ac9100..9cebf4e 100644
--- a/NetSdrClientApp/NetSdrClientApp.csproj
+++ b/NetSdrClientApp/NetSdrClientApp.csproj
@@ -2,7 +2,7 @@
Exe
- net8.0
+ net10.0
enable
enable
diff --git a/NetSdrClientApp/Networking/TcpClientWrapper.cs b/NetSdrClientApp/Networking/TcpClientWrapper.cs
index 1f37e2e..df06f2e 100644
--- a/NetSdrClientApp/Networking/TcpClientWrapper.cs
+++ b/NetSdrClientApp/Networking/TcpClientWrapper.cs
@@ -7,13 +7,15 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using System.Diagnostics.CodeAnalysis;
namespace NetSdrClientApp.Networking
{
+ [ExcludeFromCodeCoverage]
public class TcpClientWrapper : ITcpClient
{
- private string _host;
- private int _port;
+ private readonly string _host;
+ private readonly int _port;
private TcpClient? _tcpClient;
private NetworkStream? _stream;
private CancellationTokenSource _cts;
@@ -117,7 +119,7 @@ private async Task StartListeningAsync()
}
}
}
- catch (OperationCanceledException ex)
+ catch (OperationCanceledException)
{
//empty
}
diff --git a/NetSdrClientApp/Networking/UdpClientWrapper.cs b/NetSdrClientApp/Networking/UdpClientWrapper.cs
index 31e0b79..9cbd66b 100644
--- a/NetSdrClientApp/Networking/UdpClientWrapper.cs
+++ b/NetSdrClientApp/Networking/UdpClientWrapper.cs
@@ -5,7 +5,9 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using System.Diagnostics.CodeAnalysis;
+[ExcludeFromCodeCoverage]
public class UdpClientWrapper : IUdpClient
{
private readonly IPEndPoint _localEndPoint;
diff --git a/NetSdrClientApp/Program.cs b/NetSdrClientApp/Program.cs
index fda2e69..9577a7d 100644
--- a/NetSdrClientApp/Program.cs
+++ b/NetSdrClientApp/Program.cs
@@ -1,4 +1,7 @@
-using NetSdrClientApp;
+//
+// Excluded from coverage - entry point only
+
+using NetSdrClientApp;
using NetSdrClientApp.Networking;
Console.WriteLine(@"Usage:
diff --git a/NetSdrClientAppTests/NetSdrClientAppTests.csproj b/NetSdrClientAppTests/NetSdrClientAppTests.csproj
index 3cbc46a..e0b6e01 100644
--- a/NetSdrClientAppTests/NetSdrClientAppTests.csproj
+++ b/NetSdrClientAppTests/NetSdrClientAppTests.csproj
@@ -1,7 +1,7 @@
- net8.0
+ net10.0
enable
enable
@@ -11,7 +11,11 @@
-
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
diff --git a/NetSdrClientAppTests/NetSdrClientTests.cs b/NetSdrClientAppTests/NetSdrClientTests.cs
index ad00c4f..936a525 100644
--- a/NetSdrClientAppTests/NetSdrClientTests.cs
+++ b/NetSdrClientAppTests/NetSdrClientTests.cs
@@ -115,5 +115,64 @@ public async Task StopIQTest()
Assert.That(_client.IQStarted, Is.False);
}
- //TODO: cover the rest of the NetSdrClient code here
+ [Test]
+ public async Task StopIQNoConnectionTest()
+ {
+ // act
+ await _client.StopIQAsync();
+
+ // assert — без з'єднання StopListening не викликається
+ _updMock.Verify(udp => udp.StopListening(), Times.Never);
+ Assert.That(_client.IQStarted, Is.False);
+ }
+
+ [Test]
+ public async Task ChangeFrequencyAsyncTest()
+ {
+ // Arrange
+ await ConnectAsyncTest();
+
+ // Act
+ await _client.ChangeFrequencyAsync(20000000, 1);
+
+ // Assert
+ _tcpMock.Verify(tcp => tcp.SendMessageAsync(It.IsAny()), Times.Exactly(4)); // 3 з connect + 1
+ }
+
+ [Test]
+ public async Task ChangeFrequencyNoConnectionTest()
+ {
+ // Act
+ await _client.ChangeFrequencyAsync(20000000, 1);
+
+ // Assert
+ _tcpMock.Verify(tcp => tcp.SendMessageAsync(It.IsAny()), Times.Never);
+ }
+
+ [Test]
+ public async Task StartIQSetsIQStartedTrueTest()
+ {
+ // Arrange
+ await ConnectAsyncTest();
+
+ // Act
+ await _client.StartIQAsync();
+
+ // Assert
+ Assert.That(_client.IQStarted, Is.True);
+ }
+
+ [Test]
+ public async Task StopIQSetsIQStartedFalseTest()
+ {
+ // Arrange
+ await ConnectAsyncTest();
+ await _client.StartIQAsync();
+
+ // Act
+ await _client.StopIQAsync();
+
+ // Assert
+ Assert.That(_client.IQStarted, Is.False);
+ }
}
diff --git a/NetSdrClientAppTests/NetSdrMessageHelperTests.cs b/NetSdrClientAppTests/NetSdrMessageHelperTests.cs
index b40fff7..dfc34ce 100644
--- a/NetSdrClientAppTests/NetSdrMessageHelperTests.cs
+++ b/NetSdrClientAppTests/NetSdrMessageHelperTests.cs
@@ -64,6 +64,190 @@ public void GetDataItemMessageTest()
Assert.That(parametersBytes.Count(), Is.EqualTo(parametersLength));
}
- //TODO: add more NetSdrMessageHelper tests
+ [Test]
+ public void GetControlItemMessage_LengthIsCorrect()
+ {
+ var msg = NetSdrMessageHelper.GetControlItemMessage(
+ NetSdrMessageHelper.MsgTypes.SetControlItem,
+ NetSdrMessageHelper.ControlItemCodes.ReceiverFrequency,
+ new byte[6]);
+
+ Assert.That(msg.Length, Is.EqualTo(10)); // 2 header + 2 code + 6 params
+ }
+
+ [Test]
+ public void GetControlItemMessage_TypeIsEncodedCorrectly()
+ {
+ var type = NetSdrMessageHelper.MsgTypes.SetControlItem;
+ var msg = NetSdrMessageHelper.GetControlItemMessage(
+ type,
+ NetSdrMessageHelper.ControlItemCodes.ReceiverState,
+ new byte[4]);
+
+ var num = BitConverter.ToUInt16(msg.Take(2).ToArray());
+ var actualType = (NetSdrMessageHelper.MsgTypes)(num >> 13);
+
+ Assert.That(actualType, Is.EqualTo(type));
+ }
+
+ [Test]
+ public void GetDataItemMessage_EmptyParams_ReturnsHeaderOnly()
+ {
+ var msg = NetSdrMessageHelper.GetDataItemMessage(
+ NetSdrMessageHelper.MsgTypes.DataItem0,
+ new byte[0]);
+
+ Assert.That(msg.Length, Is.EqualTo(2)); // тільки header
+ }
+
+ [Test]
+ public void GetDataItemMessage_TypeEncodedCorrectly()
+ {
+ var type = NetSdrMessageHelper.MsgTypes.DataItem0;
+ var msg = NetSdrMessageHelper.GetDataItemMessage(type, new byte[100]);
+
+ var num = BitConverter.ToUInt16(msg.Take(2).ToArray());
+ var actualType = (NetSdrMessageHelper.MsgTypes)(num >> 13);
+
+ Assert.That(actualType, Is.EqualTo(type));
+ }
+
+ [Test]
+ public void TranslateMessage_ControlItem_ReturnsCorrectTypeAndCode()
+ {
+ // Arrange — побудувати повідомлення і одразу розібрати
+ var type = NetSdrMessageHelper.MsgTypes.SetControlItem;
+ var code = NetSdrMessageHelper.ControlItemCodes.ReceiverFrequency;
+ var parameters = new byte[] { 0x01, 0x02, 0x03 };
+ var msg = NetSdrMessageHelper.GetControlItemMessage(type, code, parameters);
+
+ // Act
+ var success = NetSdrMessageHelper.TranslateMessage(msg, out var outType, out var outCode, out var outSeq, out var body);
+
+ // Assert
+ Assert.That(success, Is.True);
+ Assert.That(outType, Is.EqualTo(type));
+ Assert.That(outCode, Is.EqualTo(code));
+ Assert.That(outSeq, Is.EqualTo(0));
+ Assert.That(body, Is.EqualTo(parameters));
+ }
+
+ [Test]
+ public void TranslateMessage_DataItem_ReturnsCorrectTypeAndSequence()
+ {
+ // Arrange
+ var type = NetSdrMessageHelper.MsgTypes.DataItem0;
+ var parameters = new byte[] { 0x10, 0x20, 0x30, 0x40 };
+ var msg = NetSdrMessageHelper.GetDataItemMessage(type, parameters);
+
+ // Act
+ var success = NetSdrMessageHelper.TranslateMessage(msg, out var outType, out _, out var outSeq, out var body);
+
+ // Assert
+ Assert.That(success, Is.True);
+ Assert.That(outType, Is.EqualTo(type));
+ Assert.That(body.Length, Is.GreaterThan(0));
+ }
+
+ [Test]
+ public void TranslateMessage_AckType_ParsedCorrectly()
+ {
+ var type = NetSdrMessageHelper.MsgTypes.Ack;
+ var code = NetSdrMessageHelper.ControlItemCodes.ReceiverState;
+ var msg = NetSdrMessageHelper.GetControlItemMessage(type, code, new byte[2]);
+
+ var success = NetSdrMessageHelper.TranslateMessage(msg, out var outType, out var outCode, out _, out _);
+
+ Assert.That(success, Is.True);
+ Assert.That(outType, Is.EqualTo(type));
+ Assert.That(outCode, Is.EqualTo(code));
+ }
+
+ [Test]
+ public void GetSamples_16bit_ReturnsCorrectCount()
+ {
+ // Arrange — 8 байт = 4 семпли по 16 біт
+ var body = new byte[] { 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00 };
+
+ // Act
+ var samples = NetSdrMessageHelper.GetSamples(16, body).ToList();
+
+ // Assert
+ Assert.That(samples.Count, Is.EqualTo(4));
+ }
+
+ [Test]
+ public void GetSamples_16bit_ReturnsCorrectValues()
+ {
+ var body = new byte[] { 0x05, 0x00, 0x0A, 0x00 };
+
+ var samples = NetSdrMessageHelper.GetSamples(16, body).ToList();
+
+ Assert.That(samples[0], Is.EqualTo(5));
+ Assert.That(samples[1], Is.EqualTo(10));
+ }
+
+ [Test]
+ public void GetSamples_8bit_ReturnsCorrectCount()
+ {
+ var body = new byte[] { 0x01, 0x02, 0x03, 0x04 };
+
+ var samples = NetSdrMessageHelper.GetSamples(8, body).ToList();
+
+ Assert.That(samples.Count, Is.EqualTo(4));
+ }
+
+ [Test]
+ public void GetSamples_EmptyBody_ReturnsNoSamples()
+ {
+ var samples = NetSdrMessageHelper.GetSamples(16, new byte[0]).ToList();
+
+ Assert.That(samples.Count, Is.EqualTo(0));
+ }
+
+ [Test]
+ public void GetSamples_InvalidSampleSize_ThrowsException()
+ {
+ // sampleSize > 32 біти (4 байти) — має кинути виняток
+ Assert.Throws(() =>
+ NetSdrMessageHelper.GetSamples(64, new byte[] { 0x01 }).ToList());
+ }
+
+ [Test]
+ public void GetHeader_MessageTooLong_ThrowsArgumentException()
+ {
+ // параметри довжиною більше ніж maxMessageLength
+ var hugeParams = new byte[9000];
+
+ Assert.Throws(() =>
+ NetSdrMessageHelper.GetControlItemMessage(
+ NetSdrMessageHelper.MsgTypes.SetControlItem,
+ NetSdrMessageHelper.ControlItemCodes.ReceiverState,
+ hugeParams));
+ }
+
+ [Test]
+ public void GetControlItemMessage_ZeroParams_LengthIsHeaderPlusCode()
+ {
+ var msg = NetSdrMessageHelper.GetControlItemMessage(
+ NetSdrMessageHelper.MsgTypes.CurrentControlItem,
+ NetSdrMessageHelper.ControlItemCodes.ADModes,
+ new byte[0]);
+
+ // 2 байти header + 2 байти code = 4
+ Assert.That(msg.Length, Is.EqualTo(4));
+ }
+
+ [Test]
+ public void GetDataItemMessage_NoneCode_NoCodeBytesInMessage()
+ {
+ var parameters = new byte[] { 0xAA, 0xBB };
+ var msg = NetSdrMessageHelper.GetDataItemMessage(
+ NetSdrMessageHelper.MsgTypes.DataItem1,
+ parameters);
+
+ // 2 байти header + 2 байти parameters = 4 (без code)
+ Assert.That(msg.Length, Is.EqualTo(4));
+ }
}
}
\ No newline at end of file