diff --git a/.github/workflows/coverlet.msbuild b/.github/workflows/coverlet.msbuild
new file mode 100644
index 00000000..5f923fc2
--- /dev/null
+++ b/.github/workflows/coverlet.msbuild
@@ -0,0 +1,3 @@
+dotnet add NetSdrClientAppTests package coverlet.msbuild
+dotnet add NetSdrClientAppTests package Microsoft.NET.Test.Sdk
+dotnet test NetSdrClientAppTests -c Release /p:CollectCoverage=true /p:CoverletOutput=TestResults/coverage.xml /p:CoverletOutputFormat=opencover
diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml
index e7840696..ed2f0a23 100644
--- a/.github/workflows/sonarcloud.yml
+++ b/.github/workflows/sonarcloud.yml
@@ -1,83 +1,70 @@
-# This workflow uses actions that are not certified by GitHub.
-# They are provided by a third-party and are governed by
-# separate terms of service, privacy policy, and support
-# documentation.
-
-# This workflow helps you trigger a SonarCloud analysis of your code and populates
-# GitHub Code Scanning alerts with the vulnerabilities found.
-# Free for open source project.
-
-# 1. Login to SonarCloud.io using your GitHub account
-
-# 2. Import your project on SonarCloud
-# * Add your GitHub organization first, then add your repository as a new project.
-# * Please note that many languages are eligible for automatic analysis,
-# which means that the analysis will start automatically without the need to set up GitHub Actions.
-# * This behavior can be changed in Administration > Analysis Method.
-#
-# 3. Follow the SonarCloud in-product tutorial
-# * a. Copy/paste the Project Key and the Organization Key into the args parameter below
-# (You'll find this information in SonarCloud. Click on "Information" at the bottom left)
-#
-# * b. Generate a new token and add it to your Github repository's secrets using the name SONAR_TOKEN
-# (On SonarCloud, click on your avatar on top-right > My account > Security
-# or go directly to https://sonarcloud.io/account/security/)
-
-# Feel free to take a look at our documentation (https://docs.sonarcloud.io/getting-started/github/)
-# or reach out to our community forum if you need some help (https://community.sonarsource.com/c/help/sc/9)
-
-name: SonarCloud analysis
-
+name: SonarQube
on:
push:
- branches: [ "master" ]
+ branches:
+ - master
pull_request:
- branches: [ "master" ]
- workflow_dispatch:
-
-permissions:
- pull-requests: read # allows SonarCloud to decorate PRs with analysis results
-
+ types: [opened, synchronize, reopened]
jobs:
- sonar-check:
- name: Sonar Check
- runs-on: windows-latest # безпечно для будь-яких .NET проектів
+ build:
+ name: Build and analyze
+ runs-on: windows-latest
steps:
+ - name: Set up JDK 17
+ uses: actions/setup-java@v4
+ with:
+ java-version: 17
+ distribution: 'zulu' # Alternative distribution options are available.
- uses: actions/checkout@v4
- with: { fetch-depth: 0 }
-
- - uses: actions/setup-dotnet@v4
with:
- dotnet-version: '8.0.x'
-
- # 1) BEGIN: SonarScanner for .NET
- - name: SonarScanner Begin
+ fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
+ - name: Cache SonarQube Cloud packages
+ uses: actions/cache@v4
+ with:
+ path: ~\sonar\cache
+ key: ${{ runner.os }}-sonar
+ restore-keys: ${{ runner.os }}-sonar
+ - name: Cache SonarQube Cloud scanner
+ id: cache-sonar-scanner
+ uses: actions/cache@v4
+ with:
+ path: ${{ runner.temp }}\scanner
+ key: ${{ runner.os }}-sonar-scanner
+ restore-keys: ${{ runner.os }}-sonar-scanner
+ - name: Install SonarQube Cloud scanner
+ if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
+ shell: powershell
run: |
- dotnet tool install --global dotnet-sonarscanner
- echo "$env:USERPROFILE\.dotnet\tools" >> $env:GITHUB_PATH
- dotnet sonarscanner begin `
- /k:"ppanchen_NetSdrClient" `
- /o:"ppanchen" `
- /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
- 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
+ New-Item -Path ${{ runner.temp }}\scanner -ItemType Directory
+ dotnet tool update dotnet-sonarscanner --tool-path ${{ runner.temp }}\scanner
+ - name: Build and analyze
+ env:
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ shell: powershell
+ run: |
+ ${{ runner.temp }}\scanner\dotnet-sonarscanner begin /k:"Yegres546_NetSdrClient" /o:"yegres546-1" /d:sonar.token="${{ secrets.SONAR_TOKEN }}"
+ dotnet build
+ ${{ runner.temp }}\scanner\dotnet-sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"
+
+ - name: Test with coverage
+ run: |
+ dotnet test NetSdrClient.Tests/NetSdrClient.Tests.csproj -c Release \
+ --logger "trx;LogFileName=test-results.trx" \
+ /p:CollectCoverage=true \
+ /p:CoverletOutput=TestResults/ \
+ /p:CoverletOutputFormat=opencover \
+ /p:Exclude="[nunit.*]*%2c[*.Tests]*%2c[Moq]*%2c[NUnit.*]*"
+
+ - name: Upload test results
+ uses: actions/upload-artifact@v4
+ with:
+ name: test-coverage-results
+ path: NetSdrClient.Tests/TestResults/
+ retention-days: 30
+ shell: pwsh
# 3) END: SonarScanner
- name: SonarScanner End
run: dotnet sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"
shell: pwsh
+
+
diff --git a/EchoTcpServer/Program.cs b/EchoTcpServer/Program.cs
index 5966c579..7f47378b 100644
--- a/EchoTcpServer/Program.cs
+++ b/EchoTcpServer/Program.cs
@@ -47,7 +47,7 @@ public async Task StartAsync()
Console.WriteLine("Server shutdown.");
}
- private async Task HandleClientAsync(TcpClient client, CancellationToken token)
+ private static async Task HandleClientAsync(TcpClient client, CancellationToken token)
{
using (NetworkStream stream = client.GetStream())
{
@@ -112,21 +112,22 @@ public static async Task Main(string[] args)
}
}
-
-public class UdpTimedSender : IDisposable
+namespace EchoServerNamespace
{
- private readonly string _host;
- private readonly int _port;
- private readonly UdpClient _udpClient;
- private Timer _timer;
-
- public UdpTimedSender(string host, int port)
+ public class UdpTimedSender : IDisposable
{
- _host = host;
- _port = port;
- _udpClient = new UdpClient();
- }
+ private readonly string _host;
+ private readonly int _port;
+ private readonly UdpClient _udpClient;
+ private Timer _timer;
+ public UdpTimedSender(string host, int port)
+ {
+ _host = host;
+ _port = port;
+ _udpClient = new UdpClient();
+ }
+ }
public void StartSending(int intervalMilliseconds)
{
if (_timer != null)
@@ -170,4 +171,4 @@ public void Dispose()
StopSending();
_udpClient.Dispose();
}
-}
\ No newline at end of file
+}
diff --git a/NetSdrClient.Tests/NetSdrClient.Tests.csproj b/NetSdrClient.Tests/NetSdrClient.Tests.csproj
new file mode 100644
index 00000000..140ede72
--- /dev/null
+++ b/NetSdrClient.Tests/NetSdrClient.Tests.csproj
@@ -0,0 +1,22 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/NetSdrClient.Tests/NetworkServiceTests.cs b/NetSdrClient.Tests/NetworkServiceTests.cs
new file mode 100644
index 00000000..3d29fd9e
--- /dev/null
+++ b/NetSdrClient.Tests/NetworkServiceTests.cs
@@ -0,0 +1,75 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using NetSdrClient.Services;
+
+namespace NetSdrClient.Tests
+{
+ [TestClass]
+ public class NetworkServiceTests
+ {
+ [TestMethod]
+ public void NetworkService_Constructor_ShouldInitialize()
+ {
+ // Arrange & Act
+ var service = new NetworkService();
+
+ // Assert
+ Assert.IsNotNull(service);
+ }
+
+ [TestMethod]
+ public void IsValidIpAddress_WithValidIp_ShouldReturnTrue()
+ {
+ // Arrange
+ var service = new NetworkService();
+ var validIp = "192.168.1.1";
+
+ // Act
+ var result = service.IsValidIpAddress(validIp);
+
+ // Assert
+ Assert.IsTrue(result);
+ }
+
+ [TestMethod]
+ public void IsValidIpAddress_WithInvalidIp_ShouldReturnFalse()
+ {
+ // Arrange
+ var service = new NetworkService();
+ var invalidIp = "999.999.999.999";
+
+ // Act
+ var result = service.IsValidIpAddress(invalidIp);
+
+ // Assert
+ Assert.IsFalse(result);
+ }
+
+ [TestMethod]
+ public void IsValidPort_WithValidPort_ShouldReturnTrue()
+ {
+ // Arrange
+ var service = new NetworkService();
+ var validPort = 8080;
+
+ // Act
+ var result = service.IsValidPort(validPort);
+
+ // Assert
+ Assert.IsTrue(result);
+ }
+
+ [TestMethod]
+ public void IsValidPort_WithInvalidPort_ShouldReturnFalse()
+ {
+ // Arrange
+ var service = new NetworkService();
+ var invalidPort = 99999;
+
+ // Act
+ var result = service.IsValidPort(invalidPort);
+
+ // Assert
+ Assert.IsFalse(result);
+ }
+ }
+}
diff --git a/NetSdrClient.Tests/ProtocolHandlerTests.cs b/NetSdrClient.Tests/ProtocolHandlerTests.cs
new file mode 100644
index 00000000..60b17bc4
--- /dev/null
+++ b/NetSdrClient.Tests/ProtocolHandlerTests.cs
@@ -0,0 +1,63 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using NetSdrClient.Services;
+
+namespace NetSdrClient.Tests
+{
+ [TestClass]
+ public class ProtocolHandlerTests
+ {
+ [TestMethod]
+ public void ProtocolHandler_Constructor_ShouldInitialize()
+ {
+ // Arrange & Act
+ var handler = new ProtocolHandler();
+
+ // Assert
+ Assert.IsNotNull(handler);
+ }
+
+ [TestMethod]
+ public void CreateCommand_ShouldReturnValidCommand()
+ {
+ // Arrange
+ var handler = new ProtocolHandler();
+ var expectedCommand = "CONNECT";
+
+ // Act
+ var result = handler.CreateCommand(expectedCommand);
+
+ // Assert
+ Assert.IsNotNull(result);
+ Assert.IsTrue(result.Contains(expectedCommand));
+ }
+
+ [TestMethod]
+ public void ParseResponse_WithValidData_ShouldReturnParsedResponse()
+ {
+ // Arrange
+ var handler = new ProtocolHandler();
+ var testData = "OK:CONNECTED";
+
+ // Act
+ var result = handler.ParseResponse(testData);
+
+ // Assert
+ Assert.IsNotNull(result);
+ Assert.IsTrue(result.Contains("CONNECTED"));
+ }
+
+ [TestMethod]
+ public void ParseResponse_WithNullData_ShouldReturnErrorMessage()
+ {
+ // Arrange
+ var handler = new ProtocolHandler();
+
+ // Act
+ var result = handler.ParseResponse(null);
+
+ // Assert
+ Assert.IsNotNull(result);
+ Assert.IsTrue(result.Contains("ERROR"));
+ }
+ }
+}
diff --git a/NetSdrClient.Tests/SDRClientTests.cs b/NetSdrClient.Tests/SDRClientTests.cs
new file mode 100644
index 00000000..05cb679d
--- /dev/null
+++ b/NetSdrClient.Tests/SDRClientTests.cs
@@ -0,0 +1,97 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using NetSdrClient.Models;
+using NetSdrClient.Services;
+using System.Linq;
+
+namespace NetSdrClient.Tests
+{
+ [TestClass]
+ public class SDRClientTests
+ {
+ [TestMethod]
+ public void SDRClient_Constructor_ShouldInitializeDevicesList()
+ {
+ // Arrange & Act
+ var client = new SDRClient();
+
+ // Assert
+ Assert.IsNotNull(client.Devices);
+ Assert.AreEqual(0, client.Devices.Count);
+ }
+
+ [TestMethod]
+ public void AddDevice_ShouldAddDeviceToList()
+ {
+ // Arrange
+ var client = new SDRClient();
+ var device = new SDRDevice { Id = 1, Name = "Test Device" };
+
+ // Act
+ client.AddDevice(device);
+
+ // Assert
+ Assert.AreEqual(1, client.Devices.Count);
+ Assert.AreEqual(device, client.Devices[0]);
+ }
+
+ [TestMethod]
+ public void RemoveDevice_ShouldRemoveDeviceFromList()
+ {
+ // Arrange
+ var client = new SDRClient();
+ var device = new SDRDevice { Id = 1, Name = "Test Device" };
+ client.AddDevice(device);
+
+ // Act
+ var result = client.RemoveDevice(1);
+
+ // Assert
+ Assert.IsTrue(result);
+ Assert.AreEqual(0, client.Devices.Count);
+ }
+
+ [TestMethod]
+ public void RemoveDevice_WithInvalidId_ShouldReturnFalse()
+ {
+ // Arrange
+ var client = new SDRClient();
+
+ // Act
+ var result = client.RemoveDevice(999);
+
+ // Assert
+ Assert.IsFalse(result);
+ }
+
+ [TestMethod]
+ public void GetDevice_ShouldReturnCorrectDevice()
+ {
+ // Arrange
+ var client = new SDRClient();
+ var device1 = new SDRDevice { Id = 1, Name = "Device 1" };
+ var device2 = new SDRDevice { Id = 2, Name = "Device 2" };
+ client.AddDevice(device1);
+ client.AddDevice(device2);
+
+ // Act
+ var result = client.GetDevice(2);
+
+ // Assert
+ Assert.IsNotNull(result);
+ Assert.AreEqual("Device 2", result.Name);
+ }
+
+ [TestMethod]
+ public void GetDevice_WithInvalidId_ShouldReturnNull()
+ {
+ // Arrange
+ var client = new SDRClient();
+
+ // Act
+ var result = client.GetDevice(999);
+
+ // Assert
+ Assert.IsNull(result);
+ }
+ }
+}
diff --git a/NetSdrClient.Tests/SDRDeviceTests.cs b/NetSdrClient.Tests/SDRDeviceTests.cs
new file mode 100644
index 00000000..89295dd1
--- /dev/null
+++ b/NetSdrClient.Tests/SDRDeviceTests.cs
@@ -0,0 +1,55 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using NetSdrClient.Models;
+
+namespace NetSdrClient.Tests
+{
+ [TestClass]
+ public class SDRDeviceTests
+ {
+ [TestMethod]
+ public void SDRDevice_Constructor_ShouldInitializeProperties()
+ {
+ // Arrange & Act
+ var device = new SDRDevice();
+
+ // Assert
+ Assert.IsNotNull(device);
+ Assert.AreEqual(0, device.Id);
+ Assert.IsNull(device.Name);
+ Assert.IsNull(device.Description);
+ Assert.IsFalse(device.IsConnected);
+ }
+
+ [TestMethod]
+ public void SDRDevice_Properties_ShouldSetAndGetCorrectly()
+ {
+ // Arrange
+ var device = new SDRDevice();
+
+ // Act
+ device.Id = 1;
+ device.Name = "Test Device";
+ device.Description = "Test Description";
+ device.IsConnected = true;
+
+ // Assert
+ Assert.AreEqual(1, device.Id);
+ Assert.AreEqual("Test Device", device.Name);
+ Assert.AreEqual("Test Description", device.Description);
+ Assert.IsTrue(device.IsConnected);
+ }
+
+ [TestMethod]
+ public void SDRDevice_ToString_ShouldReturnName()
+ {
+ // Arrange
+ var device = new SDRDevice { Name = "Test SDR" };
+
+ // Act
+ var result = device.ToString();
+
+ // Assert
+ Assert.AreEqual("Test SDR", result);
+ }
+ }
+}
diff --git a/NetSdrClientAppTests/NetSdrClientAppTests.csproj b/NetSdrClientAppTests/NetSdrClientAppTests.csproj
index 3cbc46af..e1f5e652 100644
--- a/NetSdrClientAppTests/NetSdrClientAppTests.csproj
+++ b/NetSdrClientAppTests/NetSdrClientAppTests.csproj
@@ -1,17 +1,18 @@
-
net8.0
enable
enable
-
false
true
-
-
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
@@ -19,11 +20,10 @@
-
+
-
diff --git a/coverlet.msbuild b/coverlet.msbuild
new file mode 100644
index 00000000..5f923fc2
--- /dev/null
+++ b/coverlet.msbuild
@@ -0,0 +1,3 @@
+dotnet add NetSdrClientAppTests package coverlet.msbuild
+dotnet add NetSdrClientAppTests package Microsoft.NET.Test.Sdk
+dotnet test NetSdrClientAppTests -c Release /p:CollectCoverage=true /p:CoverletOutput=TestResults/coverage.xml /p:CoverletOutputFormat=opencover