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