From fc08735caeed622fee9deb6b32cb7491d686e857 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 00:36:41 +0200
Subject: [PATCH 01/29] Update sonarcloud.yml
---
.github/workflows/sonarcloud.yml | 53 ++++++--------------------------
1 file changed, 9 insertions(+), 44 deletions(-)
diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml
index e7840696..72940bfd 100644
--- a/.github/workflows/sonarcloud.yml
+++ b/.github/workflows/sonarcloud.yml
@@ -1,31 +1,3 @@
-# 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
on:
@@ -36,28 +8,27 @@ on:
workflow_dispatch:
permissions:
- pull-requests: read # allows SonarCloud to decorate PRs with analysis results
+ pull-requests: read
jobs:
sonar-check:
name: Sonar Check
- runs-on: windows-latest # безпечно для будь-яких .NET проектів
+ runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- with: { fetch-depth: 0 }
+ with:
+ fetch-depth: 0
- uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'
- # 1) BEGIN: SonarScanner for .NET
- name: SonarScanner Begin
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.projectKey="ppanchen_NetSdrClient" `
+ /d:sonar.organization="ppanchen-org" `
/d:sonar.token="${{ secrets.SONAR_TOKEN }}" `
/d:sonar.cs.opencover.reportsPaths="**/coverage.xml" `
/d:sonar.cpd.cs.minimumTokens=40 `
@@ -65,19 +36,13 @@ jobs:
/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
- # 3) END: SonarScanner
+
- name: SonarScanner End
run: dotnet sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"
shell: pwsh
From 1bb56023910d41ae0af7b34249c9e9a25db3f7e1 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 01:03:01 +0200
Subject: [PATCH 02/29] Move 'UdpTimedSender' into a named namespace.Program.cs
---
EchoTcpServer/Program.cs | 27 ++++++++++++++-------------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/EchoTcpServer/Program.cs b/EchoTcpServer/Program.cs
index 5966c579..7a6f595a 100644
--- a/EchoTcpServer/Program.cs
+++ b/EchoTcpServer/Program.cs
@@ -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
+}
From 165f3ac7bedfbe0521344f85036a33856ee08c2a Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 01:11:05 +0200
Subject: [PATCH 03/29] static handle Program.cs
---
EchoTcpServer/Program.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/EchoTcpServer/Program.cs b/EchoTcpServer/Program.cs
index 7a6f595a..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())
{
From 3b5c4e45a7f9beabb44406e34c787f9e5236797b Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 01:22:40 +0200
Subject: [PATCH 04/29] coverlet.msbuild sonarcloud.yml
---
.github/workflows/sonarcloud.yml | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml
index e7840696..c90de044 100644
--- a/.github/workflows/sonarcloud.yml
+++ b/.github/workflows/sonarcloud.yml
@@ -70,14 +70,16 @@ jobs:
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
- # 3) END: SonarScanner
+ 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 }}"
shell: pwsh
+
+
From 0b1b87bdbf6901a0460b3bedd63cd2b79702e69d Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 01:24:00 +0200
Subject: [PATCH 05/29] coverage sonarcloud.yml
---
.github/workflows/sonarcloud.yml | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml
index c90de044..1236c4cc 100644
--- a/.github/workflows/sonarcloud.yml
+++ b/.github/workflows/sonarcloud.yml
@@ -70,14 +70,14 @@ jobs:
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
- 3) END: SonarScanner
+ - 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 }}"
shell: pwsh
From 6e8bc311ba070e8c50937217d1f8ddf485efee8f Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 01:37:34 +0200
Subject: [PATCH 06/29] coverage sonarcloud.yml
---
.github/workflows/sonarcloud.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml
index 1236c4cc..a083dd99 100644
--- a/.github/workflows/sonarcloud.yml
+++ b/.github/workflows/sonarcloud.yml
@@ -70,7 +70,7 @@ jobs:
run: dotnet restore NetSdrClient.sln
- name: Build
run: dotnet build NetSdrClient.sln -c Release --no-restore
- - name: Tests with coverage (OpenCover)
+ - name: Tests with coverage (OpenCover)
run: |
dotnet test NetSdrClientAppTests/NetSdrClientAppTests.csproj -c Release --no-build `
/p:CollectCoverage=true `
From 2f7289c20a20db2e677bbcfd1a5b9c7845698d75 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 01:38:03 +0200
Subject: [PATCH 07/29] coverage sonarcloud.yml
---
.github/workflows/sonarcloud.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml
index 1236c4cc..a083dd99 100644
--- a/.github/workflows/sonarcloud.yml
+++ b/.github/workflows/sonarcloud.yml
@@ -70,7 +70,7 @@ jobs:
run: dotnet restore NetSdrClient.sln
- name: Build
run: dotnet build NetSdrClient.sln -c Release --no-restore
- - name: Tests with coverage (OpenCover)
+ - name: Tests with coverage (OpenCover)
run: |
dotnet test NetSdrClientAppTests/NetSdrClientAppTests.csproj -c Release --no-build `
/p:CollectCoverage=true `
From 9d333e20121c06745551cb5b59d13a89f5dce5ef Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 01:43:46 +0200
Subject: [PATCH 08/29] Update NetSdrClientAppTests.csproj
---
NetSdrClientAppTests/NetSdrClientAppTests.csproj | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
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 @@
-
+
-
From a8c55e879fa9a9f0986f5f4dcbc14c4cb0f38b1b Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 01:44:07 +0200
Subject: [PATCH 09/29] Update NetSdrClientAppTests.csproj
---
NetSdrClientAppTests/NetSdrClientAppTests.csproj | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
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 @@
-
+
-
From 77a217eea9bbe5a50686a24de1cd3ffbf9987ac1 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 01:47:37 +0200
Subject: [PATCH 10/29] Update sonarcloud.yml
---
.github/workflows/sonarcloud.yml | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml
index a083dd99..14308d2f 100644
--- a/.github/workflows/sonarcloud.yml
+++ b/.github/workflows/sonarcloud.yml
@@ -66,17 +66,26 @@ jobs:
/d:sonar.qualitygate.wait=true
shell: pwsh
# 2) BUILD & TEST
- - name: Restore
+ - 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
+ #coverage
+ - 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
# 3) END: SonarScanner
- name: SonarScanner End
run: dotnet sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"
From 0574e6652cde8b0f19f7d7d7e3065f32fc504abf Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 02:00:26 +0200
Subject: [PATCH 11/29] Update sonarcloud.yml
---
.github/workflows/sonarcloud.yml | 125 ++++++++++++++-----------------
1 file changed, 55 insertions(+), 70 deletions(-)
diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml
index a083dd99..ed2f0a23 100644
--- a/.github/workflows/sonarcloud.yml
+++ b/.github/workflows/sonarcloud.yml
@@ -1,81 +1,66 @@
-# 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
+ 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
From a9464dc9ca1ecf7209e0eaa0550cae1896d0da55 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 11:37:59 +0200
Subject: [PATCH 12/29] ref sonarcloud.yml
---
.github/workflows/sonarcloud.yml | 127 +++++++++++++++++--------------
1 file changed, 70 insertions(+), 57 deletions(-)
diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml
index ed2f0a23..aca8b48d 100644
--- a/.github/workflows/sonarcloud.yml
+++ b/.github/workflows/sonarcloud.yml
@@ -1,70 +1,83 @@
-name: SonarQube
+# 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
+
on:
push:
- branches:
- - master
+ branches: [ "master" ]
pull_request:
- types: [opened, synchronize, reopened]
+ branches: [ "master" ]
+ workflow_dispatch:
+
+permissions:
+ pull-requests: read # allows SonarCloud to decorate PRs with analysis results
+
jobs:
- build:
- name: Build and analyze
- runs-on: windows-latest
+ sonar-check:
+ name: Sonar Check
+ runs-on: windows-latest # безпечно для будь-яких .NET проектів
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:
- 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
+ dotnet-version: '8.0.x'
+
+ # 1) BEGIN: SonarScanner for .NET
+ - name: SonarScanner Begin
run: |
- 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
+ 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: |
- ${{ 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
+ 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 }}"
shell: pwsh
-
-
From 49bdb5caad8d2a5bd144b17d4565224f8243f943 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 11:39:15 +0200
Subject: [PATCH 13/29] Create coverlet.msbuild
---
coverlet.msbuild | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 coverlet.msbuild
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
From 9d4bea6dfbd8b2d6218cce2a4657144d7183e68a Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 11:46:18 +0200
Subject: [PATCH 14/29] Create SDRDeviceTests.cs
---
NetSdrClient.Tests/SDRDeviceTests.cs | 55 ++++++++++++++++++++++++++++
1 file changed, 55 insertions(+)
create mode 100644 NetSdrClient.Tests/SDRDeviceTests.cs
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);
+ }
+ }
+}
From d0da030c4292c8ef1f0a624edc442203896cf2d0 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 11:46:37 +0200
Subject: [PATCH 15/29] Create SDRClientTests.cs
---
NetSdrClient.Tests/SDRClientTests.cs | 97 ++++++++++++++++++++++++++++
1 file changed, 97 insertions(+)
create mode 100644 NetSdrClient.Tests/SDRClientTests.cs
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);
+ }
+ }
+}
From e9bfced7d57689589c6e83e03b55bfcd583b07e1 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 11:49:10 +0200
Subject: [PATCH 16/29] Create ProtocolHandlerTests.cs
---
NetSdrClient.Tests/ProtocolHandlerTests.cs | 63 ++++++++++++++++++++++
1 file changed, 63 insertions(+)
create mode 100644 NetSdrClient.Tests/ProtocolHandlerTests.cs
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"));
+ }
+ }
+}
From e4531ee91514e78bf0c3925be7448ff94216389e Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 11:49:28 +0200
Subject: [PATCH 17/29] Create NetworkServiceTests.cs
---
NetSdrClient.Tests/NetworkServiceTests.cs | 75 +++++++++++++++++++++++
1 file changed, 75 insertions(+)
create mode 100644 NetSdrClient.Tests/NetworkServiceTests.cs
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);
+ }
+ }
+}
From ba9bceeab537e96dbe95c3e2ce9898257003f308 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 11:49:55 +0200
Subject: [PATCH 18/29] Create NetSdrClient.Tests.csproj
---
NetSdrClient.Tests/NetSdrClient.Tests.csproj | 22 ++++++++++++++++++++
1 file changed, 22 insertions(+)
create mode 100644 NetSdrClient.Tests/NetSdrClient.Tests.csproj
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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
From 84c9c4279e1a4c9cc10883575abd68503f234ee6 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 11:52:33 +0200
Subject: [PATCH 19/29] Create coverlet.msbuild
---
.github/workflows/coverlet.msbuild | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 .github/workflows/coverlet.msbuild
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
From 64e97d4e2f88ddbcb30d7ad75102aeff2d5f0e50 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 12:05:37 +0200
Subject: [PATCH 20/29] Update sonarcloud.yml
---
.github/workflows/sonarcloud.yml | 118 ++++++++++++-------------------
1 file changed, 47 insertions(+), 71 deletions(-)
diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml
index aca8b48d..bfb501f2 100644
--- a/.github/workflows/sonarcloud.yml
+++ b/.github/workflows/sonarcloud.yml
@@ -1,83 +1,59 @@
-# 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: SonarCloud Analysis
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
- workflow_dispatch:
-
-permissions:
- pull-requests: read # allows SonarCloud to decorate PRs with analysis results
jobs:
- sonar-check:
- name: Sonar Check
- runs-on: windows-latest # безпечно для будь-яких .NET проектів
+ build-and-analyze:
+ name: Build and Analyze
+ runs-on: windows-latest
+
steps:
- - 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
- 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" `
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: '6.0.x'
+
+ - name: Install SonarScanner
+ run: |
+ dotnet tool install --global dotnet-sonarscanner
+ echo "$env:USERPROFILE\.dotnet\tools" >> $env:GITHUB_PATH
+
+ - name: Install Coverlet
+ run: dotnet tool install --global coverlet.console
+
+ - name: Build and test with SonarCloud
+ env:
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ run: |
+ # Start SonarScanner
+ dotnet sonarscanner begin `
+ /k:"Yegres546_NetSdrClient" `
+ /o:"yegres546" `
+ /d:sonar.token="$env:SONAR_TOKEN" `
+ /d:sonar.cs.opencover.reportsPaths="**/coverage.opencover.xml" `
/d:sonar.cpd.cs.minimumTokens=40 `
/d:sonar.cpd.cs.minimumLines=5 `
- /d:sonar.exclusions=**/bin/**,**/obj/**,**/sonarcloud.yml `
+ /d:sonar.exclusions="**/bin/**,**/obj/**,**/TestResults/**,**/*.Tests.cs" `
+ /d:sonar.coverage.exclusions="**Test*.cs" `
/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
- # 3) END: SonarScanner
- - name: SonarScanner End
- run: dotnet sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"
- shell: pwsh
+
+ # Build the solution
+ dotnet build --configuration Release
+
+ # Run tests with coverage
+ dotnet test --configuration Release `
+ --no-build `
+ --verbosity normal `
+ --collect:"XPlat Code Coverage" `
+ --results-directory ./TestResults `
+ -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover
+
+ # End SonarScanner
+ dotnet sonarscanner end /d:sonar.token="$env:SONAR_TOKEN"
From 71b909b510e6b28f084cf950903acc42f7048da1 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 12:14:42 +0200
Subject: [PATCH 21/29] Create coverlet.runsettings
---
coverlet.runsettings | 14 ++++++++++++++
1 file changed, 14 insertions(+)
create mode 100644 coverlet.runsettings
diff --git a/coverlet.runsettings b/coverlet.runsettings
new file mode 100644
index 00000000..9815d295
--- /dev/null
+++ b/coverlet.runsettings
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+ opencover
+ [NetSdrClient]*
+ [NetSdrClient.Tests]*
+
+
+
+
+
From d799a0852ba9d263071a9ff406f6614830fbb6f7 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 12:43:19 +0200
Subject: [PATCH 22/29] Create ArchitectureTests.cs
---
NetSdrClient.Tests/ArchitectureTests.cs | 148 ++++++++++++++++++++++++
1 file changed, 148 insertions(+)
create mode 100644 NetSdrClient.Tests/ArchitectureTests.cs
diff --git a/NetSdrClient.Tests/ArchitectureTests.cs b/NetSdrClient.Tests/ArchitectureTests.cs
new file mode 100644
index 00000000..a664fae4
--- /dev/null
+++ b/NetSdrClient.Tests/ArchitectureTests.cs
@@ -0,0 +1,148 @@
+using NetArchTest.Rules;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace NetSdrClient.Tests
+{
+ [TestClass]
+ public class ArchitectureTests
+ {
+ private const string ApplicationNamespace = "NetSdrClient";
+ private const string ModelsNamespace = "NetSdrClient.Models";
+ private const string ServicesNamespace = "NetSdrClient.Services";
+ private const string InterfacesNamespace = "NetSdrClient.Interfaces";
+ private const string InfrastructureNamespace = "NetSdrClient.Infrastructure";
+ private const string UINamespace = "NetSdrClient.UI";
+
+ [TestMethod]
+ public void ServicesLayer_ShouldNotDependOnUI()
+ {
+ // Arrange
+ var assembly = typeof(Services.SDRClient).Assembly;
+
+ // Act
+ var result = Types
+ .InAssembly(assembly)
+ .That()
+ .ResideInNamespace(ServicesNamespace)
+ .ShouldNot()
+ .HaveDependencyOn(UINamespace)
+ .GetResult();
+
+ // Assert
+ Assert.IsTrue(result.IsSuccessful,
+ $"Services layer should not depend on UI: {string.Join(", ", result.FailingTypes)}");
+ }
+
+ [TestMethod]
+ public void Models_ShouldNotReferenceServices()
+ {
+ // Arrange
+ var assembly = typeof(Models.SDRDevice).Assembly;
+
+ // Act
+ var result = Types
+ .InAssembly(assembly)
+ .That()
+ .ResideInNamespace(ModelsNamespace)
+ .ShouldNot()
+ .HaveDependencyOn(ServicesNamespace)
+ .GetResult();
+
+ // Assert
+ Assert.IsTrue(result.IsSuccessful,
+ $"Models should not depend on Services: {string.Join(", ", result.FailingTypes)}");
+ }
+
+ [TestMethod]
+ public void Interfaces_ShouldNotHaveDependencies()
+ {
+ // Arrange
+ var assembly = typeof(Services.SDRClient).Assembly;
+
+ // Act
+ var result = Types
+ .InAssembly(assembly)
+ .That()
+ .ResideInNamespace(InterfacesNamespace)
+ .Should()
+ .NotHaveDependencyOnAny(
+ ServicesNamespace,
+ ModelsNamespace,
+ InfrastructureNamespace,
+ UINamespace)
+ .GetResult();
+
+ // Assert
+ Assert.IsTrue(result.IsSuccessful,
+ $"Interfaces should not have dependencies: {string.Join(", ", result.FailingTypes)}");
+ }
+
+ [TestMethod]
+ public void AllClasses_ShouldHaveNamesEndingWithService_IfInServicesNamespace()
+ {
+ // Arrange
+ var assembly = typeof(Services.SDRClient).Assembly;
+
+ // Act
+ var result = Types
+ .InAssembly(assembly)
+ .That()
+ .ResideInNamespace(ServicesNamespace)
+ .And()
+ .AreClasses()
+ .Should()
+ .HaveNameEndingWith("Service")
+ .Or()
+ .HaveNameEndingWith("Client")
+ .Or()
+ .HaveNameEndingWith("Handler")
+ .GetResult();
+
+ // Assert
+ Assert.IsTrue(result.IsSuccessful,
+ $"Services should have proper naming: {string.Join(", ", result.FailingTypes)}");
+ }
+
+ [TestMethod]
+ public void Models_ShouldBeSealed()
+ {
+ // Arrange
+ var assembly = typeof(Models.SDRDevice).Assembly;
+
+ // Act
+ var result = Types
+ .InAssembly(assembly)
+ .That()
+ .ResideInNamespace(ModelsNamespace)
+ .And()
+ .AreClasses()
+ .Should()
+ .BeSealed()
+ .GetResult();
+
+ // Assert
+ Assert.IsTrue(result.IsSuccessful,
+ $"Models should be sealed: {string.Join(", ", result.FailingTypes)}");
+ }
+
+ [TestMethod]
+ public void Services_ShouldNotDependOnInfrastructureDirectly()
+ {
+ // Arrange
+ var assembly = typeof(Services.SDRClient).Assembly;
+
+ // Act
+ var result = Types
+ .InAssembly(assembly)
+ .That()
+ .ResideInNamespace(ServicesNamespace)
+ .ShouldNot()
+ .HaveDependencyOn(InfrastructureNamespace)
+ .GetResult();
+
+ // Assert
+ Assert.IsTrue(result.IsSuccessful,
+ $"Services should not depend directly on Infrastructure: {string.Join(", ", result.FailingTypes)}");
+ }
+ }
+}
From d01b5554b7db4a3b753771ca2f1d81591f692f04 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 12:43:42 +0200
Subject: [PATCH 23/29] Update NetSdrClient.Tests.csproj
---
NetSdrClient.Tests/NetSdrClient.Tests.csproj | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/NetSdrClient.Tests/NetSdrClient.Tests.csproj b/NetSdrClient.Tests/NetSdrClient.Tests.csproj
index 140ede72..7697a375 100644
--- a/NetSdrClient.Tests/NetSdrClient.Tests.csproj
+++ b/NetSdrClient.Tests/NetSdrClient.Tests.csproj
@@ -4,7 +4,6 @@
net6.0
enable
enable
-
false
@@ -13,6 +12,7 @@
+
From 8e1e35ebb132cd99c7bedb0182d5352ee5551687 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 12:45:07 +0200
Subject: [PATCH 24/29] Create BadService.cs
---
NetSdrClient/Services/BadService.cs | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
create mode 100644 NetSdrClient/Services/BadService.cs
diff --git a/NetSdrClient/Services/BadService.cs b/NetSdrClient/Services/BadService.cs
new file mode 100644
index 00000000..51da3ba7
--- /dev/null
+++ b/NetSdrClient/Services/BadService.cs
@@ -0,0 +1,20 @@
+using NetSdrClient.Models;
+using NetSdrClient.UI; // Навмисне порушення - Services залежить від UI
+
+namespace NetSdrClient.Services
+{
+ public class BadService
+ {
+ private readonly UIComponent _uiComponent; // Порушення!
+
+ public BadService()
+ {
+ _uiComponent = new UIComponent();
+ }
+
+ public void DoSomething()
+ {
+ _uiComponent.ShowMessage("This violates architecture rules!");
+ }
+ }
+}
From 178b8eaceeb7b06eebb8e747592be374cb636815 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 12:45:57 +0200
Subject: [PATCH 25/29] Create UIComponent.cs
---
UI/UIComponent.cs | 10 ++++++++++
1 file changed, 10 insertions(+)
create mode 100644 UI/UIComponent.cs
diff --git a/UI/UIComponent.cs b/UI/UIComponent.cs
new file mode 100644
index 00000000..347ef573
--- /dev/null
+++ b/UI/UIComponent.cs
@@ -0,0 +1,10 @@
+namespace NetSdrClient.UI
+{
+ public class UIComponent
+ {
+ public void ShowMessage(string message)
+ {
+ // UI logic here - this should not be called from Services
+ }
+ }
+}
From cd16e6d50c8e2c4b88256d8eb3aaf0d83ff79683 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 12:46:49 +0200
Subject: [PATCH 26/29] Create DatabaseService.cs
---
Infrastructure/DatabaseService.cs | 10 ++++++++++
1 file changed, 10 insertions(+)
create mode 100644 Infrastructure/DatabaseService.cs
diff --git a/Infrastructure/DatabaseService.cs b/Infrastructure/DatabaseService.cs
new file mode 100644
index 00000000..2fcf4980
--- /dev/null
+++ b/Infrastructure/DatabaseService.cs
@@ -0,0 +1,10 @@
+namespace NetSdrClient.Infrastructure
+{
+ public class DatabaseService
+ {
+ public void SaveData(object data)
+ {
+ // Database operations
+ }
+ }
+}
From 1031a89aee84a3c921651b34bd1c069f6a150d58 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 12:47:19 +0200
Subject: [PATCH 27/29] Create IDeviceService.cs
---
Interfaces/IDeviceService.cs | 8 ++++++++
1 file changed, 8 insertions(+)
create mode 100644 Interfaces/IDeviceService.cs
diff --git a/Interfaces/IDeviceService.cs b/Interfaces/IDeviceService.cs
new file mode 100644
index 00000000..b19adbd7
--- /dev/null
+++ b/Interfaces/IDeviceService.cs
@@ -0,0 +1,8 @@
+namespace NetSdrClient.Interfaces
+{
+ public interface IDeviceService
+ {
+ void Connect();
+ void Disconnect();
+ }
+}
From 1d6ed29f5cdb1f09781f22be44b7ab9360771a41 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 12:53:52 +0200
Subject: [PATCH 28/29] Update NetSdrClient.cs
---
NetSdrClientApp/NetSdrClient.cs | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/NetSdrClientApp/NetSdrClient.cs b/NetSdrClientApp/NetSdrClient.cs
index b0a7c058..d4466ac5 100644
--- a/NetSdrClientApp/NetSdrClient.cs
+++ b/NetSdrClientApp/NetSdrClient.cs
@@ -9,7 +9,29 @@
using System.Threading.Tasks;
using static NetSdrClientApp.Messages.NetSdrMessageHelper;
using static System.Runtime.InteropServices.JavaScript.JSType;
+using NetSdrClient.Models;
+using NetSdrClient.Interfaces;
+namespace NetSdrClient.Services
+{
+ public class SDRClient : IDeviceService
+ {
+ public List Devices { get; private set; }
+
+ // Реалізація інтерфейсу
+ public void Connect()
+ {
+ // Connection logic
+ }
+
+ public void Disconnect()
+ {
+ // Disconnection logic
+ }
+
+ // Інші методи...
+ }
+}
namespace NetSdrClientApp
{
public class NetSdrClient
From 0eac29fe625eb3305f82650fe88e1e90e6762dd0 Mon Sep 17 00:00:00 2001
From: Yegres546 <126583849+Yegres546@users.noreply.github.com>
Date: Wed, 26 Nov 2025 12:55:23 +0200
Subject: [PATCH 29/29] Update sonarcloud.yml
---
.github/workflows/sonarcloud.yml | 33 ++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml
index bfb501f2..d23eba70 100644
--- a/.github/workflows/sonarcloud.yml
+++ b/.github/workflows/sonarcloud.yml
@@ -57,3 +57,36 @@ jobs:
# End SonarScanner
dotnet sonarscanner end /d:sonar.token="$env:SONAR_TOKEN"
+name: Architecture Rules Validation
+
+on:
+ push:
+ branches: [ "lab5" ]
+ pull_request:
+ branches: [ "lab5" ]
+
+jobs:
+ architecture-tests:
+ name: Architecture Rules Validation
+ runs-on: windows-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v3
+ with:
+ dotnet-version: '6.0.x'
+
+ - name: Install dependencies
+ run: dotnet restore
+
+ - name: Build
+ run: dotnet build --no-restore --configuration Release
+
+ - name: Run Architecture Tests
+ run: dotnet test --configuration Release --no-build --verbosity normal --filter "Category=Architecture"
+
+ - name: Run All Tests
+ run: dotnet test --configuration Release --no-build --verbosity normal