From 08e46776753d7db5005978c0e5251b474b956179 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 10:14:38 +0200 Subject: [PATCH 01/36] Update README.md --- README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index b3a90294..aba5cb0f 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,13 @@ # Лабораторні з реінжинірингу (8×) -[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=ppanchen_NetSdrClient&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=ppanchen_NetSdrClient) -[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=ppanchen_NetSdrClient&metric=coverage)](https://sonarcloud.io/summary/new_code?id=ppanchen_NetSdrClient) -[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=ppanchen_NetSdrClient&metric=bugs)](https://sonarcloud.io/summary/new_code?id=ppanchen_NetSdrClient) -[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=ppanchen_NetSdrClient&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=ppanchen_NetSdrClient) -[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=ppanchen_NetSdrClient&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=ppanchen_NetSdrClient) -[![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=ppanchen_NetSdrClient&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=ppanchen_NetSdrClient) -[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=ppanchen_NetSdrClient&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=ppanchen_NetSdrClient) -[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=ppanchen_NetSdrClient&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=ppanchen_NetSdrClient) + + +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=bugs)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +[![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) + + Цей репозиторій використовується для курсу **реінжиніринг ПЗ**. From 792dc804b1faa5b9a51ab2c64a58987db3176936 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 10:37:50 +0200 Subject: [PATCH 02/36] Update Program.cs --- EchoTcpServer/Program.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/EchoTcpServer/Program.cs b/EchoTcpServer/Program.cs index 5966c579..ec5fe335 100644 --- a/EchoTcpServer/Program.cs +++ b/EchoTcpServer/Program.cs @@ -1,4 +1,5 @@ -using System; +namespace NetSdrClientApp.EchoServer; +using System; using System.Net; using System.Net.Sockets; using System.Text; @@ -170,4 +171,4 @@ public void Dispose() StopSending(); _udpClient.Dispose(); } -} \ No newline at end of file +} From 125b26cce86969992a428e2912f36913b541a6f7 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 10:42:52 +0200 Subject: [PATCH 03/36] Update Program.cs --- EchoTcpServer/Program.cs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/EchoTcpServer/Program.cs b/EchoTcpServer/Program.cs index ec5fe335..83bff14c 100644 --- a/EchoTcpServer/Program.cs +++ b/EchoTcpServer/Program.cs @@ -14,7 +14,8 @@ public class EchoServer { private readonly int _port; private TcpListener _listener; - private CancellationTokenSource _cancellationTokenSource; + private readonly CancellationTokenSource _cancellationTokenSource; + public EchoServer(int port) @@ -48,7 +49,8 @@ public async Task StartAsync() Console.WriteLine("Server shutdown."); } - private async Task HandleClientAsync(TcpClient client, CancellationToken token) + private static async Task HandleClientAsync(TcpClient client) + { using (NetworkStream stream = client.GetStream()) { @@ -166,9 +168,10 @@ public void StopSending() _timer = null; } - public void Dispose() - { - StopSending(); - _udpClient.Dispose(); - } + public void Dispose() +{ + _listener?.Stop(); + _cancellationTokenSource?.Dispose(); +} + } From d0b32c9889d5561ff8e43b91bee04111e7872e40 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 10:58:50 +0200 Subject: [PATCH 04/36] Update Program.cs --- EchoTcpServer/Program.cs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/EchoTcpServer/Program.cs b/EchoTcpServer/Program.cs index 83bff14c..8957c784 100644 --- a/EchoTcpServer/Program.cs +++ b/EchoTcpServer/Program.cs @@ -1,5 +1,4 @@ -namespace NetSdrClientApp.EchoServer; -using System; +using System; using System.Net; using System.Net.Sockets; using System.Text; @@ -14,8 +13,7 @@ public class EchoServer { private readonly int _port; private TcpListener _listener; - private readonly CancellationTokenSource _cancellationTokenSource; - + private CancellationTokenSource _cancellationTokenSource; public EchoServer(int port) @@ -49,8 +47,7 @@ public async Task StartAsync() Console.WriteLine("Server shutdown."); } - private static async Task HandleClientAsync(TcpClient client) - + private async Task HandleClientAsync(TcpClient client, CancellationToken token) { using (NetworkStream stream = client.GetStream()) { @@ -168,10 +165,9 @@ public void StopSending() _timer = null; } - public void Dispose() -{ - _listener?.Stop(); - _cancellationTokenSource?.Dispose(); -} - + public void Dispose() + { + StopSending(); + _udpClient.Dispose(); + } } From 8dfcb5aedc6de7f1541ba35b4d1b4c8fe4534784 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 11:15:01 +0200 Subject: [PATCH 05/36] Update sonarcloud.yml --- .github/workflows/sonarcloud.yml | 69 +++++++++----------------------- 1 file changed, 19 insertions(+), 50 deletions(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index e7840696..4f8f8bcf 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,48 +8,45 @@ 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 + - name: Install SonarScanner run: | dotnet tool install --global dotnet-sonarscanner echo "$env:USERPROFILE\.dotnet\tools" >> $env:GITHUB_PATH + shell: pwsh + + - name: SonarScanner Begin + run: | 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 + /k:"olekca160406_NetSdrClient" ` + /o:"olekca160406" ` + /d:sonar.token="${{ secrets.SONAR_TOKEN }}" ` + /d:sonar.cs.opencover.reportsPaths="**/coverage.xml" ` + /d:sonar.exclusions=**/bin/**,**/obj/** ` + /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 22c34b7e507dc7665f5645bcb6091862d4a567f3 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 11:59:51 +0200 Subject: [PATCH 06/36] Update sonarcloud.yml --- .github/workflows/sonarcloud.yml | 80 ++++++++++---------------------- 1 file changed, 25 insertions(+), 55 deletions(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index e7840696..fdf6bc3f 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: @@ -33,51 +5,49 @@ on: branches: [ "master" ] pull_request: branches: [ "master" ] - workflow_dispatch: permissions: - pull-requests: read # allows SonarCloud to decorate PRs with analysis results + contents: read + pull-requests: read jobs: - sonar-check: - name: Sonar Check - runs-on: windows-latest # безпечно для будь-яких .NET проектів + sonarcloud: + name: SonarCloud + runs-on: windows-latest + steps: - - uses: actions/checkout@v4 - with: { fetch-depth: 0 } + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 - - uses: actions/setup-dotnet@v4 + - name: Setup .NET + uses: actions/setup-dotnet@v4 with: dotnet-version: '8.0.x' - # 1) BEGIN: SonarScanner for .NET - - name: SonarScanner Begin + - name: Install SonarScanner run: | dotnet tool install --global dotnet-sonarscanner echo "$env:USERPROFILE\.dotnet\tools" >> $env:GITHUB_PATH + shell: pwsh + + - name: SonarScanner Begin + run: | 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 + /k:"olekca160406_NetSdrClient" ` + /o:"olekca160406" ` + /d:sonar.token="${{ secrets.SONAR_TOKEN }}" ` + /d:sonar.cs.opencover.reportsPaths="**/coverage.xml" ` + /d:sonar.exclusions=**/bin/**,**/obj/** 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 c3eb03a10a2dbdcfb1d53ed9924c352337941d77 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 12:39:11 +0200 Subject: [PATCH 07/36] Update sonarcloud.yml --- .github/workflows/sonarcloud.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 4f8f8bcf..12a39d3a 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -8,11 +8,12 @@ on: workflow_dispatch: permissions: + contents: read pull-requests: read jobs: - sonar-check: - name: Sonar Check + sonar: + name: SonarCloud Analysis runs-on: windows-latest steps: @@ -37,7 +38,7 @@ jobs: /o:"olekca160406" ` /d:sonar.token="${{ secrets.SONAR_TOKEN }}" ` /d:sonar.cs.opencover.reportsPaths="**/coverage.xml" ` - /d:sonar.exclusions=**/bin/**,**/obj/** ` + /d:sonar.exclusions="**/bin/**,**/obj/**" ` /d:sonar.qualitygate.wait=true shell: pwsh From e515677f6566c3380cb0f3e20f2359a92316355f Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 12:49:17 +0200 Subject: [PATCH 08/36] Update sonarcloud.yml --- .github/workflows/sonarcloud.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index fdf6bc3f..273364ef 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -5,24 +5,22 @@ on: branches: [ "master" ] pull_request: branches: [ "master" ] + workflow_dispatch: permissions: contents: read pull-requests: read jobs: - sonarcloud: - name: SonarCloud + sonar: runs-on: windows-latest steps: - - name: Checkout - uses: actions/checkout@v4 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Setup .NET - uses: actions/setup-dotnet@v4 + - uses: actions/setup-dotnet@v4 with: dotnet-version: '8.0.x' @@ -38,8 +36,7 @@ jobs: /k:"olekca160406_NetSdrClient" ` /o:"olekca160406" ` /d:sonar.token="${{ secrets.SONAR_TOKEN }}" ` - /d:sonar.cs.opencover.reportsPaths="**/coverage.xml" ` - /d:sonar.exclusions=**/bin/**,**/obj/** + /d:sonar.cs.opencover.reportsPaths="**/coverage.xml" shell: pwsh - name: Restore From aed126ba501cf54765f2bacd4818a97a8d35c5fc Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 13:29:58 +0200 Subject: [PATCH 09/36] Update sonarcloud.yml --- .github/workflows/sonarcloud.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 273364ef..eda5445f 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -45,6 +45,17 @@ jobs: - name: Build run: dotnet build NetSdrClient.sln -c Release --no-restore + - name: Run Tests with Coverage + run: dotnet test NetSdrClient.sln --collect:"XPlat Code Coverage" + + - name: Convert coverage to Sonar format + run: | + reportgenerator ` + -reports:**/coverage.cobertura.xml ` + -targetdir:coverage ` + -reporttypes:opencover + shell: pwsh + - name: SonarScanner End run: dotnet sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" shell: pwsh From a29cdb9b45773c1a1f414be40cbf445e205a70c9 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 13:45:35 +0200 Subject: [PATCH 10/36] Update 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 12a39d3a..53799570 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -39,7 +39,7 @@ jobs: /d:sonar.token="${{ secrets.SONAR_TOKEN }}" ` /d:sonar.cs.opencover.reportsPaths="**/coverage.xml" ` /d:sonar.exclusions="**/bin/**,**/obj/**" ` - /d:sonar.qualitygate.wait=true + shell: pwsh - name: Restore From a3041805b97b2ba93d89f2f6590d9d5e36b5ff7a Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 13:58:07 +0200 Subject: [PATCH 11/36] Update IUdpClient.cs --- NetSdrClientApp/Networking/IUdpClient.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/NetSdrClientApp/Networking/IUdpClient.cs b/NetSdrClientApp/Networking/IUdpClient.cs index 1b9f9311..fb296806 100644 --- a/NetSdrClientApp/Networking/IUdpClient.cs +++ b/NetSdrClientApp/Networking/IUdpClient.cs @@ -1,10 +1,10 @@ - -public interface IUdpClient +namespace NetSdrClientApp.Networking { - event EventHandler? MessageReceived; - - Task StartListeningAsync(); - - void StopListening(); - void Exit(); -} \ No newline at end of file + public interface IUdpClient + { + event EventHandler? MessageReceived; + Task StartListeningAsync(); + void StopListening(); + void Exit(); + } +} From 4102906ae257d4325b1c654a57567cb7cfc25729 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 14:01:35 +0200 Subject: [PATCH 12/36] Update Program.cs --- EchoTcpServer/Program.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/EchoTcpServer/Program.cs b/EchoTcpServer/Program.cs index 5966c579..0d9f5fd9 100644 --- a/EchoTcpServer/Program.cs +++ b/EchoTcpServer/Program.cs @@ -9,6 +9,7 @@ /// This program was designed for test purposes only /// Not for a review /// +namespace NetSdrClientApp.EchoServer public class EchoServer { private readonly int _port; @@ -170,4 +171,4 @@ public void Dispose() StopSending(); _udpClient.Dispose(); } -} \ No newline at end of file +} From 665d925027b8b3d351f3a76e18f9bb6dc9bd6e81 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 14:03:58 +0200 Subject: [PATCH 13/36] Update IUdpClient.cs --- NetSdrClientApp/Networking/IUdpClient.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NetSdrClientApp/Networking/IUdpClient.cs b/NetSdrClientApp/Networking/IUdpClient.cs index 1b9f9311..b17bc5b6 100644 --- a/NetSdrClientApp/Networking/IUdpClient.cs +++ b/NetSdrClientApp/Networking/IUdpClient.cs @@ -1,3 +1,4 @@ +using NetSdrClientApp.Networking;  public interface IUdpClient { @@ -7,4 +8,4 @@ public interface IUdpClient void StopListening(); void Exit(); -} \ No newline at end of file +} From 02d50ff20a0979daf301b696b7235a8c4e3eead2 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 14:18:47 +0200 Subject: [PATCH 14/36] Update Program.cs --- EchoTcpServer/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/EchoTcpServer/Program.cs b/EchoTcpServer/Program.cs index 0d9f5fd9..bed810b4 100644 --- a/EchoTcpServer/Program.cs +++ b/EchoTcpServer/Program.cs @@ -9,7 +9,7 @@ /// This program was designed for test purposes only /// Not for a review /// -namespace NetSdrClientApp.EchoServer +namespace NetSdrClientApp.EchoServer; public class EchoServer { private readonly int _port; From a125d2bcacfe2d7f8bc89c0fd98fd2063263a43f Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 14:19:31 +0200 Subject: [PATCH 15/36] Update Program.cs --- EchoTcpServer/Program.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/EchoTcpServer/Program.cs b/EchoTcpServer/Program.cs index 8957c784..27309c3b 100644 --- a/EchoTcpServer/Program.cs +++ b/EchoTcpServer/Program.cs @@ -9,6 +9,8 @@ /// This program was designed for test purposes only /// Not for a review /// +namespace NetSdrClientApp.EchoServer +{ public class EchoServer { private readonly int _port; @@ -171,3 +173,4 @@ public void Dispose() _udpClient.Dispose(); } } +} From fb467d24ac5c42725f7eb2e78074e10ae14baabf Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 14:28:00 +0200 Subject: [PATCH 16/36] Update Program.cs --- EchoTcpServer/Program.cs | 230 +++++++++++++++++++-------------------- 1 file changed, 115 insertions(+), 115 deletions(-) diff --git a/EchoTcpServer/Program.cs b/EchoTcpServer/Program.cs index bed810b4..9affa28f 100644 --- a/EchoTcpServer/Program.cs +++ b/EchoTcpServer/Program.cs @@ -1,109 +1,107 @@ -using System; +using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; + /// /// This program was designed for test purposes only /// Not for a review /// -namespace NetSdrClientApp.EchoServer; -public class EchoServer +namespace NetSdrClientApp.EchoServer { - private readonly int _port; - private TcpListener _listener; - private CancellationTokenSource _cancellationTokenSource; - - - public EchoServer(int port) + public class EchoServer { - _port = port; - _cancellationTokenSource = new CancellationTokenSource(); - } + private readonly int _port; + private TcpListener _listener; + private readonly CancellationTokenSource _cancellationTokenSource; - public async Task StartAsync() - { - _listener = new TcpListener(IPAddress.Any, _port); - _listener.Start(); - Console.WriteLine($"Server started on port {_port}."); + public EchoServer(int port) + { + _port = port; + _cancellationTokenSource = new CancellationTokenSource(); + } - while (!_cancellationTokenSource.Token.IsCancellationRequested) + public async Task StartAsync() { - try - { - TcpClient client = await _listener.AcceptTcpClientAsync(); - Console.WriteLine("Client connected."); + _listener = new TcpListener(IPAddress.Any, _port); + _listener.Start(); + Console.WriteLine($"Server started on port {_port}."); - _ = Task.Run(() => HandleClientAsync(client, _cancellationTokenSource.Token)); - } - catch (ObjectDisposedException) + while (!_cancellationTokenSource.Token.IsCancellationRequested) { - // Listener has been closed - break; + try + { + TcpClient client = await _listener.AcceptTcpClientAsync(); + Console.WriteLine("Client connected."); + + _ = Task.Run(() => HandleClientAsync(client, _cancellationTokenSource.Token)); + } + catch (ObjectDisposedException) + { + // Listener has been closed + break; + } } - } - Console.WriteLine("Server shutdown."); - } + Console.WriteLine("Server shutdown."); + } - private async Task HandleClientAsync(TcpClient client, CancellationToken token) - { - using (NetworkStream stream = client.GetStream()) + private async Task HandleClientAsync(TcpClient client, CancellationToken token) { - try + using (NetworkStream stream = client.GetStream()) { - byte[] buffer = new byte[8192]; - int bytesRead; - - while (!token.IsCancellationRequested && (bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token)) > 0) + try { - // Echo back the received message - await stream.WriteAsync(buffer, 0, bytesRead, token); - Console.WriteLine($"Echoed {bytesRead} bytes to the client."); + byte[] buffer = new byte[8192]; + int bytesRead; + + while (!token.IsCancellationRequested && + (bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token)) > 0) + { + await stream.WriteAsync(buffer, 0, bytesRead, token); + Console.WriteLine($"Echoed {bytesRead} bytes to the client."); + } + } + catch (Exception ex) when (ex is not OperationCanceledException) + { + Console.WriteLine($"Error: {ex.Message}"); + } + finally + { + client.Close(); + Console.WriteLine("Client disconnected."); } - } - catch (Exception ex) when (!(ex is OperationCanceledException)) - { - Console.WriteLine($"Error: {ex.Message}"); - } - finally - { - client.Close(); - Console.WriteLine("Client disconnected."); } } - } - public void Stop() - { - _cancellationTokenSource.Cancel(); - _listener.Stop(); - _cancellationTokenSource.Dispose(); - Console.WriteLine("Server stopped."); - } + public void Stop() + { + _cancellationTokenSource.Cancel(); + _listener.Stop(); + _cancellationTokenSource.Dispose(); + Console.WriteLine("Server stopped."); + } - public static async Task Main(string[] args) - { - EchoServer server = new EchoServer(5000); + public static async Task Main(string[] args) + { + EchoServer server = new EchoServer(5000); - // Start the server in a separate task - _ = Task.Run(() => server.StartAsync()); + _ = Task.Run(() => server.StartAsync()); - string host = "127.0.0.1"; // Target IP - int port = 60000; // Target Port - int intervalMilliseconds = 5000; // Send every 3 seconds + string host = "127.0.0.1"; + int port = 60000; + int intervalMilliseconds = 5000; - using (var sender = new UdpTimedSender(host, port)) - { + using var sender = new UdpTimedSender(host, port); Console.WriteLine("Press any key to stop sending..."); sender.StartSending(intervalMilliseconds); Console.WriteLine("Press 'q' to quit..."); while (Console.ReadKey(intercept: true).Key != ConsoleKey.Q) { - // Just wait until 'q' is pressed } sender.StopSending(); @@ -111,64 +109,66 @@ public static async Task Main(string[] args) Console.WriteLine("Sender stopped."); } } -} - - -public class UdpTimedSender : IDisposable -{ - 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 void StartSending(int intervalMilliseconds) - { - if (_timer != null) - throw new InvalidOperationException("Sender is already running."); + private ushort _counter; - _timer = new Timer(SendMessageCallback, null, 0, intervalMilliseconds); - } + public UdpTimedSender(string host, int port) + { + _host = host; + _port = port; + _udpClient = new UdpClient(); + } - ushort i = 0; + public void StartSending(int intervalMilliseconds) + { + if (_timer != null) + throw new InvalidOperationException("Sender is already running."); - private void SendMessageCallback(object state) - { - try + _timer = new Timer(SendMessageCallback, null, 0, intervalMilliseconds); + } + + private void SendMessageCallback(object? state) { - //dummy data - Random rnd = new Random(); - byte[] samples = new byte[1024]; - rnd.NextBytes(samples); - i++; + try + { + var rnd = new Random(); + byte[] samples = new byte[1024]; + rnd.NextBytes(samples); + _counter++; - byte[] msg = (new byte[] { 0x04, 0x84 }).Concat(BitConverter.GetBytes(i)).Concat(samples).ToArray(); - var endpoint = new IPEndPoint(IPAddress.Parse(_host), _port); + byte[] msg = new byte[] { 0x04, 0x84 } + .Concat(BitConverter.GetBytes(_counter)) + .Concat(samples) + .ToArray(); - _udpClient.Send(msg, msg.Length, endpoint); - Console.WriteLine($"Message sent to {_host}:{_port} "); + var endpoint = new IPEndPoint(IPAddress.Parse(_host), _port); + + _udpClient.Send(msg, msg.Length, endpoint); + Console.WriteLine($"Message sent to {_host}:{_port} "); + } + catch (Exception ex) + { + Console.WriteLine($"Error sending message: {ex.Message}"); + } } - catch (Exception ex) + + public void StopSending() { - Console.WriteLine($"Error sending message: {ex.Message}"); + _timer?.Dispose(); + _timer = null; } - } - - public void StopSending() - { - _timer?.Dispose(); - _timer = null; - } - public void Dispose() - { - StopSending(); - _udpClient.Dispose(); + public void Dispose() + { + StopSending(); + _udpClient.Dispose(); + } } } From 6bec1524b82f2e1b26ee1403753d6cadfc0eced3 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 14:28:21 +0200 Subject: [PATCH 17/36] Update Program.cs --- EchoTcpServer/Program.cs | 230 +++++++++++++++++++-------------------- 1 file changed, 114 insertions(+), 116 deletions(-) diff --git a/EchoTcpServer/Program.cs b/EchoTcpServer/Program.cs index 27309c3b..9affa28f 100644 --- a/EchoTcpServer/Program.cs +++ b/EchoTcpServer/Program.cs @@ -1,110 +1,107 @@ -using System; +using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; + /// /// This program was designed for test purposes only /// Not for a review /// namespace NetSdrClientApp.EchoServer { -public class EchoServer -{ - private readonly int _port; - private TcpListener _listener; - private CancellationTokenSource _cancellationTokenSource; - - - public EchoServer(int port) + public class EchoServer { - _port = port; - _cancellationTokenSource = new CancellationTokenSource(); - } + private readonly int _port; + private TcpListener _listener; + private readonly CancellationTokenSource _cancellationTokenSource; - public async Task StartAsync() - { - _listener = new TcpListener(IPAddress.Any, _port); - _listener.Start(); - Console.WriteLine($"Server started on port {_port}."); + public EchoServer(int port) + { + _port = port; + _cancellationTokenSource = new CancellationTokenSource(); + } - while (!_cancellationTokenSource.Token.IsCancellationRequested) + public async Task StartAsync() { - try - { - TcpClient client = await _listener.AcceptTcpClientAsync(); - Console.WriteLine("Client connected."); + _listener = new TcpListener(IPAddress.Any, _port); + _listener.Start(); + Console.WriteLine($"Server started on port {_port}."); - _ = Task.Run(() => HandleClientAsync(client, _cancellationTokenSource.Token)); - } - catch (ObjectDisposedException) + while (!_cancellationTokenSource.Token.IsCancellationRequested) { - // Listener has been closed - break; + try + { + TcpClient client = await _listener.AcceptTcpClientAsync(); + Console.WriteLine("Client connected."); + + _ = Task.Run(() => HandleClientAsync(client, _cancellationTokenSource.Token)); + } + catch (ObjectDisposedException) + { + // Listener has been closed + break; + } } - } - Console.WriteLine("Server shutdown."); - } + Console.WriteLine("Server shutdown."); + } - private async Task HandleClientAsync(TcpClient client, CancellationToken token) - { - using (NetworkStream stream = client.GetStream()) + private async Task HandleClientAsync(TcpClient client, CancellationToken token) { - try + using (NetworkStream stream = client.GetStream()) { - byte[] buffer = new byte[8192]; - int bytesRead; - - while (!token.IsCancellationRequested && (bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token)) > 0) + try { - // Echo back the received message - await stream.WriteAsync(buffer, 0, bytesRead, token); - Console.WriteLine($"Echoed {bytesRead} bytes to the client."); + byte[] buffer = new byte[8192]; + int bytesRead; + + while (!token.IsCancellationRequested && + (bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token)) > 0) + { + await stream.WriteAsync(buffer, 0, bytesRead, token); + Console.WriteLine($"Echoed {bytesRead} bytes to the client."); + } + } + catch (Exception ex) when (ex is not OperationCanceledException) + { + Console.WriteLine($"Error: {ex.Message}"); + } + finally + { + client.Close(); + Console.WriteLine("Client disconnected."); } - } - catch (Exception ex) when (!(ex is OperationCanceledException)) - { - Console.WriteLine($"Error: {ex.Message}"); - } - finally - { - client.Close(); - Console.WriteLine("Client disconnected."); } } - } - public void Stop() - { - _cancellationTokenSource.Cancel(); - _listener.Stop(); - _cancellationTokenSource.Dispose(); - Console.WriteLine("Server stopped."); - } + public void Stop() + { + _cancellationTokenSource.Cancel(); + _listener.Stop(); + _cancellationTokenSource.Dispose(); + Console.WriteLine("Server stopped."); + } - public static async Task Main(string[] args) - { - EchoServer server = new EchoServer(5000); + public static async Task Main(string[] args) + { + EchoServer server = new EchoServer(5000); - // Start the server in a separate task - _ = Task.Run(() => server.StartAsync()); + _ = Task.Run(() => server.StartAsync()); - string host = "127.0.0.1"; // Target IP - int port = 60000; // Target Port - int intervalMilliseconds = 5000; // Send every 3 seconds + string host = "127.0.0.1"; + int port = 60000; + int intervalMilliseconds = 5000; - using (var sender = new UdpTimedSender(host, port)) - { + using var sender = new UdpTimedSender(host, port); Console.WriteLine("Press any key to stop sending..."); sender.StartSending(intervalMilliseconds); Console.WriteLine("Press 'q' to quit..."); while (Console.ReadKey(intercept: true).Key != ConsoleKey.Q) { - // Just wait until 'q' is pressed } sender.StopSending(); @@ -112,65 +109,66 @@ public static async Task Main(string[] args) Console.WriteLine("Sender stopped."); } } -} - - -public class UdpTimedSender : IDisposable -{ - 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 void StartSending(int intervalMilliseconds) - { - if (_timer != null) - throw new InvalidOperationException("Sender is already running."); + private ushort _counter; - _timer = new Timer(SendMessageCallback, null, 0, intervalMilliseconds); - } + public UdpTimedSender(string host, int port) + { + _host = host; + _port = port; + _udpClient = new UdpClient(); + } - ushort i = 0; + public void StartSending(int intervalMilliseconds) + { + if (_timer != null) + throw new InvalidOperationException("Sender is already running."); - private void SendMessageCallback(object state) - { - try + _timer = new Timer(SendMessageCallback, null, 0, intervalMilliseconds); + } + + private void SendMessageCallback(object? state) { - //dummy data - Random rnd = new Random(); - byte[] samples = new byte[1024]; - rnd.NextBytes(samples); - i++; + try + { + var rnd = new Random(); + byte[] samples = new byte[1024]; + rnd.NextBytes(samples); + _counter++; + + byte[] msg = new byte[] { 0x04, 0x84 } + .Concat(BitConverter.GetBytes(_counter)) + .Concat(samples) + .ToArray(); - byte[] msg = (new byte[] { 0x04, 0x84 }).Concat(BitConverter.GetBytes(i)).Concat(samples).ToArray(); - var endpoint = new IPEndPoint(IPAddress.Parse(_host), _port); + var endpoint = new IPEndPoint(IPAddress.Parse(_host), _port); - _udpClient.Send(msg, msg.Length, endpoint); - Console.WriteLine($"Message sent to {_host}:{_port} "); + _udpClient.Send(msg, msg.Length, endpoint); + Console.WriteLine($"Message sent to {_host}:{_port} "); + } + catch (Exception ex) + { + Console.WriteLine($"Error sending message: {ex.Message}"); + } } - catch (Exception ex) + + public void StopSending() { - Console.WriteLine($"Error sending message: {ex.Message}"); + _timer?.Dispose(); + _timer = null; } - } - - public void StopSending() - { - _timer?.Dispose(); - _timer = null; - } - public void Dispose() - { - StopSending(); - _udpClient.Dispose(); + public void Dispose() + { + StopSending(); + _udpClient.Dispose(); + } } } -} From e9981ff6949fb7e04c35f8305fe062514468c195 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 14:31:42 +0200 Subject: [PATCH 18/36] Update IUdpClient.cs --- NetSdrClientApp/Networking/IUdpClient.cs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/NetSdrClientApp/Networking/IUdpClient.cs b/NetSdrClientApp/Networking/IUdpClient.cs index b17bc5b6..fb296806 100644 --- a/NetSdrClientApp/Networking/IUdpClient.cs +++ b/NetSdrClientApp/Networking/IUdpClient.cs @@ -1,11 +1,10 @@ -using NetSdrClientApp.Networking; - -public interface IUdpClient +namespace NetSdrClientApp.Networking { - event EventHandler? MessageReceived; - - Task StartListeningAsync(); - - void StopListening(); - void Exit(); + public interface IUdpClient + { + event EventHandler? MessageReceived; + Task StartListeningAsync(); + void StopListening(); + void Exit(); + } } From 890982bc9ae8a2ea2a9d4ae43162691b55afef4f Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 22:20:28 +0200 Subject: [PATCH 19/36] Update IUdpClient.cs --- NetSdrClientApp/Networking/IUdpClient.cs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/NetSdrClientApp/Networking/IUdpClient.cs b/NetSdrClientApp/Networking/IUdpClient.cs index fb296806..26c5dc9d 100644 --- a/NetSdrClientApp/Networking/IUdpClient.cs +++ b/NetSdrClientApp/Networking/IUdpClient.cs @@ -1,10 +1,9 @@ -namespace NetSdrClientApp.Networking +public interface IUdpClient { - public interface IUdpClient - { - event EventHandler? MessageReceived; - Task StartListeningAsync(); - void StopListening(); - void Exit(); - } + event EventHandler? MessageReceived; + + Task StartListeningAsync(); + + void StopListening(); + void Exit(); } From a7fffca2139edb0437967767665b00ff0ffe9e29 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 22:21:43 +0200 Subject: [PATCH 20/36] Update Program.cs --- EchoTcpServer/Program.cs | 229 +++++++++++++++++++-------------------- 1 file changed, 114 insertions(+), 115 deletions(-) diff --git a/EchoTcpServer/Program.cs b/EchoTcpServer/Program.cs index 9affa28f..8957c784 100644 --- a/EchoTcpServer/Program.cs +++ b/EchoTcpServer/Program.cs @@ -1,107 +1,108 @@ -using System; +using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; - /// /// This program was designed for test purposes only /// Not for a review /// -namespace NetSdrClientApp.EchoServer +public class EchoServer { - public class EchoServer + private readonly int _port; + private TcpListener _listener; + private CancellationTokenSource _cancellationTokenSource; + + + public EchoServer(int port) { - private readonly int _port; - private TcpListener _listener; - private readonly CancellationTokenSource _cancellationTokenSource; + _port = port; + _cancellationTokenSource = new CancellationTokenSource(); + } - public EchoServer(int port) - { - _port = port; - _cancellationTokenSource = new CancellationTokenSource(); - } + public async Task StartAsync() + { + _listener = new TcpListener(IPAddress.Any, _port); + _listener.Start(); + Console.WriteLine($"Server started on port {_port}."); - public async Task StartAsync() + while (!_cancellationTokenSource.Token.IsCancellationRequested) { - _listener = new TcpListener(IPAddress.Any, _port); - _listener.Start(); - Console.WriteLine($"Server started on port {_port}."); - - while (!_cancellationTokenSource.Token.IsCancellationRequested) + try { - try - { - TcpClient client = await _listener.AcceptTcpClientAsync(); - Console.WriteLine("Client connected."); + TcpClient client = await _listener.AcceptTcpClientAsync(); + Console.WriteLine("Client connected."); - _ = Task.Run(() => HandleClientAsync(client, _cancellationTokenSource.Token)); - } - catch (ObjectDisposedException) - { - // Listener has been closed - break; - } + _ = Task.Run(() => HandleClientAsync(client, _cancellationTokenSource.Token)); + } + catch (ObjectDisposedException) + { + // Listener has been closed + break; } - - Console.WriteLine("Server shutdown."); } - private async Task HandleClientAsync(TcpClient client, CancellationToken token) + Console.WriteLine("Server shutdown."); + } + + private async Task HandleClientAsync(TcpClient client, CancellationToken token) + { + using (NetworkStream stream = client.GetStream()) { - using (NetworkStream stream = client.GetStream()) + try { - try - { - byte[] buffer = new byte[8192]; - int bytesRead; - - while (!token.IsCancellationRequested && - (bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token)) > 0) - { - await stream.WriteAsync(buffer, 0, bytesRead, token); - Console.WriteLine($"Echoed {bytesRead} bytes to the client."); - } - } - catch (Exception ex) when (ex is not OperationCanceledException) - { - Console.WriteLine($"Error: {ex.Message}"); - } - finally + byte[] buffer = new byte[8192]; + int bytesRead; + + while (!token.IsCancellationRequested && (bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token)) > 0) { - client.Close(); - Console.WriteLine("Client disconnected."); + // Echo back the received message + await stream.WriteAsync(buffer, 0, bytesRead, token); + Console.WriteLine($"Echoed {bytesRead} bytes to the client."); } } + catch (Exception ex) when (!(ex is OperationCanceledException)) + { + Console.WriteLine($"Error: {ex.Message}"); + } + finally + { + client.Close(); + Console.WriteLine("Client disconnected."); + } } + } - public void Stop() - { - _cancellationTokenSource.Cancel(); - _listener.Stop(); - _cancellationTokenSource.Dispose(); - Console.WriteLine("Server stopped."); - } + public void Stop() + { + _cancellationTokenSource.Cancel(); + _listener.Stop(); + _cancellationTokenSource.Dispose(); + Console.WriteLine("Server stopped."); + } - public static async Task Main(string[] args) - { - EchoServer server = new EchoServer(5000); + public static async Task Main(string[] args) + { + EchoServer server = new EchoServer(5000); - _ = Task.Run(() => server.StartAsync()); + // Start the server in a separate task + _ = Task.Run(() => server.StartAsync()); - string host = "127.0.0.1"; - int port = 60000; - int intervalMilliseconds = 5000; + string host = "127.0.0.1"; // Target IP + int port = 60000; // Target Port + int intervalMilliseconds = 5000; // Send every 3 seconds - using var sender = new UdpTimedSender(host, port); + using (var sender = new UdpTimedSender(host, port)) + { Console.WriteLine("Press any key to stop sending..."); sender.StartSending(intervalMilliseconds); Console.WriteLine("Press 'q' to quit..."); while (Console.ReadKey(intercept: true).Key != ConsoleKey.Q) { + // Just wait until 'q' is pressed } sender.StopSending(); @@ -109,66 +110,64 @@ public static async Task Main(string[] args) Console.WriteLine("Sender stopped."); } } +} - public class UdpTimedSender : IDisposable - { - private readonly string _host; - private readonly int _port; - private readonly UdpClient _udpClient; - private Timer? _timer; - private ushort _counter; +public class UdpTimedSender : IDisposable +{ + 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 UdpTimedSender(string host, int port) + { + _host = host; + _port = port; + _udpClient = new UdpClient(); + } - public void StartSending(int intervalMilliseconds) - { - if (_timer != null) - throw new InvalidOperationException("Sender is already running."); + public void StartSending(int intervalMilliseconds) + { + if (_timer != null) + throw new InvalidOperationException("Sender is already running."); - _timer = new Timer(SendMessageCallback, null, 0, intervalMilliseconds); - } + _timer = new Timer(SendMessageCallback, null, 0, intervalMilliseconds); + } - private void SendMessageCallback(object? state) - { - try - { - var rnd = new Random(); - byte[] samples = new byte[1024]; - rnd.NextBytes(samples); - _counter++; + ushort i = 0; - byte[] msg = new byte[] { 0x04, 0x84 } - .Concat(BitConverter.GetBytes(_counter)) - .Concat(samples) - .ToArray(); + private void SendMessageCallback(object state) + { + try + { + //dummy data + Random rnd = new Random(); + byte[] samples = new byte[1024]; + rnd.NextBytes(samples); + i++; - var endpoint = new IPEndPoint(IPAddress.Parse(_host), _port); + byte[] msg = (new byte[] { 0x04, 0x84 }).Concat(BitConverter.GetBytes(i)).Concat(samples).ToArray(); + var endpoint = new IPEndPoint(IPAddress.Parse(_host), _port); - _udpClient.Send(msg, msg.Length, endpoint); - Console.WriteLine($"Message sent to {_host}:{_port} "); - } - catch (Exception ex) - { - Console.WriteLine($"Error sending message: {ex.Message}"); - } + _udpClient.Send(msg, msg.Length, endpoint); + Console.WriteLine($"Message sent to {_host}:{_port} "); } - - public void StopSending() + catch (Exception ex) { - _timer?.Dispose(); - _timer = null; + Console.WriteLine($"Error sending message: {ex.Message}"); } + } - public void Dispose() - { - StopSending(); - _udpClient.Dispose(); - } + public void StopSending() + { + _timer?.Dispose(); + _timer = null; + } + + public void Dispose() + { + StopSending(); + _udpClient.Dispose(); } } From 0dd39da430912941e7a016a8910c22d843684112 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Mon, 8 Dec 2025 11:55:30 +0200 Subject: [PATCH 21/36] Update README.md --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index aba5cb0f..e73d69a6 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,15 @@ # Лабораторні з реінжинірингу (8×) - [![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) [![Bugs](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=bugs)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) [![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) [![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=coverage)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) [![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +[![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) From 14844de1e6b6724062a90b4be3fde951e974d85a Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Mon, 8 Dec 2025 12:16:50 +0200 Subject: [PATCH 22/36] Update UdpClientWrapper.cs --- .../Networking/UdpClientWrapper.cs | 117 ++++++++++-------- 1 file changed, 65 insertions(+), 52 deletions(-) diff --git a/NetSdrClientApp/Networking/UdpClientWrapper.cs b/NetSdrClientApp/Networking/UdpClientWrapper.cs index 31e0b798..20bf1db3 100644 --- a/NetSdrClientApp/Networking/UdpClientWrapper.cs +++ b/NetSdrClientApp/Networking/UdpClientWrapper.cs @@ -1,85 +1,98 @@ -using System; +using System; using System.Net; using System.Net.Sockets; using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; +using NetSdrClientApp.Networking; -public class UdpClientWrapper : IUdpClient +namespace NetSdrClientApp.Networking { - private readonly IPEndPoint _localEndPoint; - private CancellationTokenSource? _cts; - private UdpClient? _udpClient; - - public event EventHandler? MessageReceived; - - public UdpClientWrapper(int port) + public class UdpClientWrapper : IUdpClient, IDisposable { - _localEndPoint = new IPEndPoint(IPAddress.Any, port); - } + private readonly IPEndPoint _localEndPoint; + private CancellationTokenSource? _cts; + private UdpClient? _udpClient; + private bool _disposed; - public async Task StartListeningAsync() - { - _cts = new CancellationTokenSource(); - Console.WriteLine("Start listening for UDP messages..."); + public event EventHandler? MessageReceived; - try + public UdpClientWrapper(int port) { - _udpClient = new UdpClient(_localEndPoint); - while (!_cts.Token.IsCancellationRequested) + _localEndPoint = new IPEndPoint(IPAddress.Any, port); + } + + public async Task StartListeningAsync() + { + _cts = new CancellationTokenSource(); + Console.WriteLine("Start listening for UDP messages..."); + + try { - UdpReceiveResult result = await _udpClient.ReceiveAsync(_cts.Token); - MessageReceived?.Invoke(this, result.Buffer); + _udpClient = new UdpClient(_localEndPoint); + + while (!_cts.Token.IsCancellationRequested) + { + UdpReceiveResult result = await _udpClient.ReceiveAsync(_cts.Token); + MessageReceived?.Invoke(this, result.Buffer); - Console.WriteLine($"Received from {result.RemoteEndPoint}"); + Console.WriteLine($"Received from {result.RemoteEndPoint}"); + } + } + catch (OperationCanceledException) + { + Console.WriteLine("Listening cancelled."); + } + catch (Exception ex) + { + Console.WriteLine($"Error receiving message: {ex.Message}"); } } - catch (OperationCanceledException ex) - { - //empty - } - catch (Exception ex) - { - Console.WriteLine($"Error receiving message: {ex.Message}"); - } - } - public void StopListening() - { - try + public void StopListening() { _cts?.Cancel(); _udpClient?.Close(); Console.WriteLine("Stopped listening for UDP messages."); } - catch (Exception ex) + + public void Exit() { - Console.WriteLine($"Error while stopping: {ex.Message}"); + StopListening(); } - } - public void Exit() - { - try + public override bool Equals(object? obj) { - _cts?.Cancel(); - _udpClient?.Close(); - Console.WriteLine("Stopped listening for UDP messages."); + if (obj is not UdpClientWrapper other) return false; + + return _localEndPoint.Port == other._localEndPoint.Port && + _localEndPoint.Address.Equals(other._localEndPoint.Address); + } + + public override int GetHashCode() + { + return HashCode.Combine(_localEndPoint.Address, _localEndPoint.Port); } - catch (Exception ex) + + public void Dispose() { - Console.WriteLine($"Error while stopping: {ex.Message}"); + Dispose(true); + GC.SuppressFinalize(this); } - } - public override int GetHashCode() - { - var payload = $"{nameof(UdpClientWrapper)}|{_localEndPoint.Address}|{_localEndPoint.Port}"; + protected virtual void Dispose(bool disposing) + { + if (_disposed) return; - using var md5 = MD5.Create(); - var hash = md5.ComputeHash(Encoding.UTF8.GetBytes(payload)); + if (disposing) + { + _cts?.Cancel(); + _cts?.Dispose(); + _udpClient?.Dispose(); + } - return BitConverter.ToInt32(hash, 0); + _disposed = true; + } } -} \ No newline at end of file +} From 07de388e63586204a0e7757ce0696047928dad41 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Mon, 8 Dec 2025 12:17:53 +0200 Subject: [PATCH 23/36] Update UdpClientWrapper.cs --- NetSdrClientApp/Networking/UdpClientWrapper.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/NetSdrClientApp/Networking/UdpClientWrapper.cs b/NetSdrClientApp/Networking/UdpClientWrapper.cs index 20bf1db3..1402b3be 100644 --- a/NetSdrClientApp/Networking/UdpClientWrapper.cs +++ b/NetSdrClientApp/Networking/UdpClientWrapper.cs @@ -62,6 +62,7 @@ public void Exit() StopListening(); } + public override bool Equals(object? obj) { if (obj is not UdpClientWrapper other) return false; From a23b99015bdeee09ac6741d7740efaad889e2362 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Mon, 8 Dec 2025 12:19:12 +0200 Subject: [PATCH 24/36] Update UdpClientWrapper.cs --- NetSdrClientApp/Networking/UdpClientWrapper.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/NetSdrClientApp/Networking/UdpClientWrapper.cs b/NetSdrClientApp/Networking/UdpClientWrapper.cs index 1402b3be..20bf1db3 100644 --- a/NetSdrClientApp/Networking/UdpClientWrapper.cs +++ b/NetSdrClientApp/Networking/UdpClientWrapper.cs @@ -62,7 +62,6 @@ public void Exit() StopListening(); } - public override bool Equals(object? obj) { if (obj is not UdpClientWrapper other) return false; From bc96014f869bf601e2b5367759cd27993b864be4 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Mon, 8 Dec 2025 12:44:31 +0200 Subject: [PATCH 25/36] Update sonarcloud.yml --- .github/workflows/sonarcloud.yml | 56 +++++++++++++------------------- 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 53799570..9d20f1bf 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -1,19 +1,15 @@ -name: SonarCloud analysis +name: SonarCloud Analysis on: push: - branches: [ "master" ] + branches: + - master pull_request: - branches: [ "master" ] - workflow_dispatch: - -permissions: - contents: read - pull-requests: read + branches: + - master jobs: - sonar: - name: SonarCloud Analysis + build: runs-on: windows-latest steps: @@ -21,33 +17,25 @@ jobs: with: fetch-depth: 0 - - uses: actions/setup-dotnet@v4 + - name: Setup .NET + uses: actions/setup-dotnet@v4 with: dotnet-version: '8.0.x' - - name: Install SonarScanner - run: | - dotnet tool install --global dotnet-sonarscanner - echo "$env:USERPROFILE\.dotnet\tools" >> $env:GITHUB_PATH - shell: pwsh - - - name: SonarScanner Begin - run: | - dotnet sonarscanner begin ` - /k:"olekca160406_NetSdrClient" ` - /o:"olekca160406" ` - /d:sonar.token="${{ secrets.SONAR_TOKEN }}" ` - /d:sonar.cs.opencover.reportsPaths="**/coverage.xml" ` - /d:sonar.exclusions="**/bin/**,**/obj/**" ` - - shell: pwsh - - - name: Restore - run: dotnet restore NetSdrClient.sln + - name: Restore dependencies + run: dotnet restore - name: Build - run: dotnet build NetSdrClient.sln -c Release --no-restore + run: dotnet build --no-restore + + - name: Test + run: dotnet test --no-build --verbosity normal - - name: SonarScanner End - run: dotnet sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" - shell: pwsh + - name: SonarCloud Scan + uses: SonarSource/sonarcloud-github-action@v2 + env: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + with: + args: > + -Dsonar.projectKey=olekca160406_NetSdrClient + -Dsonar.organization=olekca160406 From e1ea4f46be07e72b6885e43c714f245782ed9998 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Mon, 8 Dec 2025 13:27:32 +0200 Subject: [PATCH 26/36] Create DummyTests.cs --- NetSdrClientAppTests/DummyTests.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 NetSdrClientAppTests/DummyTests.cs diff --git a/NetSdrClientAppTests/DummyTests.cs b/NetSdrClientAppTests/DummyTests.cs new file mode 100644 index 00000000..da1eaf5e --- /dev/null +++ b/NetSdrClientAppTests/DummyTests.cs @@ -0,0 +1,10 @@ +using Xunit; + +public class DummyTests +{ + [Fact] + public void AlwaysPass() + { + Assert.True(true); + } +} From 802f142d241e29a8239e122f12c472daff01a779 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Mon, 8 Dec 2025 13:28:27 +0200 Subject: [PATCH 27/36] Update DummyTests.cs --- NetSdrClientAppTests/DummyTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NetSdrClientAppTests/DummyTests.cs b/NetSdrClientAppTests/DummyTests.cs index da1eaf5e..0e7de07b 100644 --- a/NetSdrClientAppTests/DummyTests.cs +++ b/NetSdrClientAppTests/DummyTests.cs @@ -3,7 +3,7 @@ public class DummyTests { [Fact] - public void AlwaysPass() + public void AlwaysPass() { Assert.True(true); } From 05979fcf8114a369c42c020269516947c7777e16 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Mon, 8 Dec 2025 14:44:05 +0200 Subject: [PATCH 28/36] Update sonarcloud.yml --- .github/workflows/sonarcloud.yml | 49 +++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 14 deletions(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 9d20f1bf..afe256d2 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -22,20 +22,41 @@ jobs: with: dotnet-version: '8.0.x' + # ----------------------------- + # Install test coverage tools + # ----------------------------- + - name: Install coverlet + test sdk + run: | + dotnet add NetSdrClientAppTests package coverlet.msbuild + dotnet add NetSdrClientAppTests package Microsoft.NET.Test.Sdk + - name: Restore dependencies - run: dotnet restore + run: dotnet restore NetSdrClient.sln - name: Build - run: dotnet build --no-restore - - - name: Test - run: dotnet test --no-build --verbosity normal - - - name: SonarCloud Scan - uses: SonarSource/sonarcloud-github-action@v2 - env: - SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - with: - args: > - -Dsonar.projectKey=olekca160406_NetSdrClient - -Dsonar.organization=olekca160406 + run: dotnet build NetSdrClient.sln --no-restore -c Release + + - name: Tests with coverage (OpenCover) + run: | + dotnet test NetSdrClientAppTests/NetSdrClientAppTests.csproj ` + -c Release --no-build ` + /p:CollectCoverage=true ` + /p:CoverletOutput=TestResults/coverage.xml ` + /p:CoverletOutputFormat=opencover + shell: pwsh + + - name: SonarScanner Begin + run: | + dotnet tool install --global dotnet-sonarscanner + echo "$env:USERPROFILE\.dotnet\tools" >> $env:GITHUB_PATH + dotnet sonarscanner begin ` + /k:"olekca160406_NetSdrClient" ` + /o:"olekca160406" ` + /d:sonar.token="${{ secrets.SONAR_TOKEN }}" ` + /d:sonar.cs.opencover.reportsPaths="**/coverage.xml" ` + /d:sonar.qualitygate.wait=true + shell: pwsh + + - name: SonarScanner End + run: dotnet sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" + shell: pwsh From 173c07614b18ab0e65775ade6e25fbcf6abbae3d Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Mon, 8 Dec 2025 14:47:12 +0200 Subject: [PATCH 29/36] Update sonarcloud.yml --- .github/workflows/sonarcloud.yml | 35 ++++++++++++-------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index afe256d2..bdd86f6c 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -2,44 +2,33 @@ name: SonarCloud Analysis on: push: - branches: - - master + branches: [ "master" ] pull_request: - branches: - - master + branches: [ "master" ] jobs: - build: + sonar: runs-on: windows-latest - steps: + - uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Setup .NET + - name: Setup .NET 8 uses: actions/setup-dotnet@v4 with: dotnet-version: '8.0.x' - # ----------------------------- - # Install test coverage tools - # ----------------------------- - - name: Install coverlet + test sdk - run: | - dotnet add NetSdrClientAppTests package coverlet.msbuild - dotnet add NetSdrClientAppTests package Microsoft.NET.Test.Sdk - - - name: Restore dependencies + - name: Restore run: dotnet restore NetSdrClient.sln - name: Build - run: dotnet build NetSdrClient.sln --no-restore -c Release + run: dotnet build NetSdrClient.sln -c Release --no-restore - - name: Tests with coverage (OpenCover) + - name: Run tests with coverage run: | - dotnet test NetSdrClientAppTests/NetSdrClientAppTests.csproj ` - -c Release --no-build ` + dotnet test NetSdrClientAppTests/NetSdrClientAppTests.csproj -c Release ` /p:CollectCoverage=true ` /p:CoverletOutput=TestResults/coverage.xml ` /p:CoverletOutputFormat=opencover @@ -53,10 +42,12 @@ jobs: /k:"olekca160406_NetSdrClient" ` /o:"olekca160406" ` /d:sonar.token="${{ secrets.SONAR_TOKEN }}" ` - /d:sonar.cs.opencover.reportsPaths="**/coverage.xml" ` - /d:sonar.qualitygate.wait=true + /d:sonar.cs.opencover.reportsPaths="**/coverage.xml" shell: pwsh + - name: Rebuild for Sonar + run: dotnet build NetSdrClient.sln -c Release + - name: SonarScanner End run: dotnet sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" shell: pwsh From d894e4cd6bb3bc293ae21c867168757089794f37 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Mon, 8 Dec 2025 14:51:28 +0200 Subject: [PATCH 30/36] Update NetSdrClientTests.cs --- NetSdrClientAppTests/NetSdrClientTests.cs | 57 +++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/NetSdrClientAppTests/NetSdrClientTests.cs b/NetSdrClientAppTests/NetSdrClientTests.cs index ad00c4f8..1eddaecf 100644 --- a/NetSdrClientAppTests/NetSdrClientTests.cs +++ b/NetSdrClientAppTests/NetSdrClientTests.cs @@ -116,4 +116,61 @@ public async Task StopIQTest() } //TODO: cover the rest of the NetSdrClient code here + [Test] + public void GetControlItemMessage_CreatesValidMessage() + { + var msg = NetSdrMessageHelper.GetControlItemMessage( + NetSdrMessageHelper.MsgTypes.SetControlItem, + NetSdrMessageHelper.ControlItemCodes.ReceiverFrequency, + new byte[] { 0x01, 0x02 }); + + Assert.That(msg.Length, Is.GreaterThan(4)); + Assert.That(msg[2], Is.EqualTo(0x20)); // low byte of ReceiverFrequency + } + + [Test] + public void TranslateMessage_ControlItem_WorksCorrectly() + { + var raw = NetSdrMessageHelper.GetControlItemMessage( + NetSdrMessageHelper.MsgTypes.SetControlItem, + NetSdrMessageHelper.ControlItemCodes.RFFilter, + new byte[] { 0xAA }); + + bool ok = NetSdrMessageHelper.TranslateMessage( + raw, out var type, out var code, out var seq, out var body); + + Assert.IsTrue(ok); + Assert.That(type, Is.EqualTo(NetSdrMessageHelper.MsgTypes.SetControlItem)); + Assert.That(code, Is.EqualTo(NetSdrMessageHelper.ControlItemCodes.RFFilter)); + Assert.That(body[0], Is.EqualTo(0xAA)); + } + [Test] + public void TranslateMessage_DataItem_WorksCorrectly() + { + var raw = NetSdrMessageHelper.GetDataItemMessage( + NetSdrMessageHelper.MsgTypes.DataItem1, + new byte[] { 0x10, 0x20 }); + + bool ok = NetSdrMessageHelper.TranslateMessage( + raw, out var type, out var code, out var seq, out var body); + + Assert.IsTrue(ok); + Assert.That(type, Is.EqualTo(NetSdrMessageHelper.MsgTypes.DataItem1)); + Assert.That(code, Is.EqualTo(NetSdrMessageHelper.ControlItemCodes.None)); + Assert.That(seq, Is.GreaterThanOrEqualTo(0)); // some sequence number + Assert.That(body.Length, Is.EqualTo(2)); + } + + [Test] + public void GetSamples_ParsesSignedIntegers() + { + byte[] body = { 0x01, 0x00, 0xFF, 0xFF }; // 16-bit samples: 1 and -1 + + var result = NetSdrMessageHelper.GetSamples(16, body).ToArray(); + + Assert.That(result.Length, Is.EqualTo(2)); + Assert.That(result[0], Is.EqualTo(1)); + Assert.That(result[1], Is.EqualTo(-1)); + } +} } From dd2ea4a72ff11e3247781e00fad2c118955ea1e8 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Mon, 8 Dec 2025 14:56:53 +0200 Subject: [PATCH 31/36] Update NetSdrClientAppTests.csproj --- NetSdrClientAppTests/NetSdrClientAppTests.csproj | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/NetSdrClientAppTests/NetSdrClientAppTests.csproj b/NetSdrClientAppTests/NetSdrClientAppTests.csproj index 3cbc46af..a2d1c386 100644 --- a/NetSdrClientAppTests/NetSdrClientAppTests.csproj +++ b/NetSdrClientAppTests/NetSdrClientAppTests.csproj @@ -25,5 +25,12 @@ + + + + + + + From 8fa80d1561e5dae8f149656b85cdc9feb5489eee Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Mon, 8 Dec 2025 14:58:14 +0200 Subject: [PATCH 32/36] Update DummyTests.cs --- NetSdrClientAppTests/DummyTests.cs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/NetSdrClientAppTests/DummyTests.cs b/NetSdrClientAppTests/DummyTests.cs index 0e7de07b..8b137891 100644 --- a/NetSdrClientAppTests/DummyTests.cs +++ b/NetSdrClientAppTests/DummyTests.cs @@ -1,10 +1 @@ -using Xunit; -public class DummyTests -{ - [Fact] - public void AlwaysPass() - { - Assert.True(true); - } -} From 3c3f466f9b6c9f18b410df40d086a63778eca872 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Mon, 8 Dec 2025 15:01:32 +0200 Subject: [PATCH 33/36] Delete NetSdrClientAppTests/DummyTests.cs --- NetSdrClientAppTests/DummyTests.cs | 1 - 1 file changed, 1 deletion(-) delete mode 100644 NetSdrClientAppTests/DummyTests.cs diff --git a/NetSdrClientAppTests/DummyTests.cs b/NetSdrClientAppTests/DummyTests.cs deleted file mode 100644 index 8b137891..00000000 --- a/NetSdrClientAppTests/DummyTests.cs +++ /dev/null @@ -1 +0,0 @@ - From 2dd810f6892208b19bcb6a95e1e31edac31b67a3 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Mon, 8 Dec 2025 20:49:28 +0200 Subject: [PATCH 34/36] Update NetSdrClientAppTests.csproj --- NetSdrClientAppTests/NetSdrClientAppTests.csproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/NetSdrClientAppTests/NetSdrClientAppTests.csproj b/NetSdrClientAppTests/NetSdrClientAppTests.csproj index a2d1c386..4ee4be0c 100644 --- a/NetSdrClientAppTests/NetSdrClientAppTests.csproj +++ b/NetSdrClientAppTests/NetSdrClientAppTests.csproj @@ -32,5 +32,11 @@ + + + + + + From 14501bd9b63095c13217f0eaddc70ab09c7a2034 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Mon, 8 Dec 2025 21:21:44 +0200 Subject: [PATCH 35/36] Update NetSdrMessageHelperTests.cs --- .../NetSdrMessageHelperTests.cs | 66 ++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/NetSdrClientAppTests/NetSdrMessageHelperTests.cs b/NetSdrClientAppTests/NetSdrMessageHelperTests.cs index b40fff79..613f4b94 100644 --- a/NetSdrClientAppTests/NetSdrMessageHelperTests.cs +++ b/NetSdrClientAppTests/NetSdrMessageHelperTests.cs @@ -65,5 +65,69 @@ public void GetDataItemMessageTest() } //TODO: add more NetSdrMessageHelper tests + [Test] + public void GetSamples_ParsesSignedIntegers() + { + byte[] body = { 0x01, 0x00, 0xFF, 0xFF }; + + var result = NetSdrMessageHelper.GetSamples(16, body).ToArray(); + + Assert.That(result.Length, Is.EqualTo(2)); + Assert.That(result[0], Is.EqualTo(1)); + Assert.That(result[1], Is.EqualTo(-1)); + } +} + + } + + [Test] + public void TranslateMessage_DataItem_WorksCorrectly() + { + var raw = NetSdrMessageHelper.GetDataItemMessage( + NetSdrMessageHelper.MsgTypes.DataItem1, + new byte[] { 0x10, 0x20 }); + + bool ok = NetSdrMessageHelper.TranslateMessage( + raw, out var type, out var code, out var seq, out var body); + + Assert.IsTrue(ok); + Assert.That(type, Is.EqualTo(NetSdrMessageHelper.MsgTypes.DataItem1)); + Assert.That(code, Is.EqualTo(NetSdrMessageHelper.ControlItemCodes.None)); + Assert.That(seq, Is.GreaterThanOrEqualTo(0)); + Assert.That(body.Length, Is.EqualTo(2)); + } + [Test] + public void TranslateMessage_ControlItem_WorksCorrectly() + { + var raw = NetSdrMessageHelper.GetControlItemMessage( + NetSdrMessageHelper.MsgTypes.SetControlItem, + NetSdrMessageHelper.ControlItemCodes.RFFilter, + new byte[] { 0xAA }); + + bool ok = NetSdrMessageHelper.TranslateMessage( + raw, out var type, out var code, out var seq, out var body); + + Assert.IsTrue(ok); + Assert.That(type, Is.EqualTo(NetSdrMessageHelper.MsgTypes.SetControlItem)); + Assert.That(code, Is.EqualTo(NetSdrMessageHelper.ControlItemCodes.RFFilter)); + Assert.That(body[0], Is.EqualTo(0xAA)); } -} \ No newline at end of file +using NetSdrClientApp.Messages; + +namespace NetSdrClientAppTests; + +public class NetSdrMessageHelperTests +{ + [Test] + public void GetControlItemMessage_CreatesValidMessage() + { + var msg = NetSdrMessageHelper.GetControlItemMessage( + NetSdrMessageHelper.MsgTypes.SetControlItem, + NetSdrMessageHelper.ControlItemCodes.ReceiverFrequency, + new byte[] { 0x01, 0x02 }); + + Assert.That(msg.Length, Is.GreaterThan(4)); + Assert.That(msg[2], Is.EqualTo(0x20)); + } + +} From d9254a2c21851c80a20b5efc3ee2fb9b43428a3b Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Tue, 9 Dec 2025 00:43:29 +0200 Subject: [PATCH 36/36] Update README.md --- README.md | 285 ++---------------------------------------------------- 1 file changed, 10 insertions(+), 275 deletions(-) diff --git a/README.md b/README.md index e73d69a6..effa99f8 100644 --- a/README.md +++ b/README.md @@ -1,283 +1,18 @@ -# Лабораторні з реінжинірингу (8×) +Для початку необхідно встановити пакети coverlet.msbuild та Microsoft.NET.Test.Sdk, оскільки саме вони виконують функцію інструментів, що забезпечують збирання даних про покриття тестами. Зазначені пакети інтегруються у тестовий проєкт (NetSdrClientAppTests) та уможливлюють отримання показників тестового покриття в SonarCloud під час виконання лабораторної роботи. За їх відсутності отримання будь-яких числових значень щодо покриття тестами було б неможливим. +Втсановленння пакетів: + image -[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) -[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=bugs)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) -[![Code Smells](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=code_smells)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) -[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) -[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) -[![Maintainability Rating](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=sqale_rating)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) -[![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=reliability_rating)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) -[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=coverage)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) -[![Duplicated Lines (%)](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=duplicated_lines_density)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) -[![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=olekca160406_NetSdrClient&metric=sqale_index)](https://sonarcloud.io/summary/new_code?id=olekca160406_NetSdrClient) +Підключення тестів + image +Додаємо тести: + image -Цей репозиторій використовується для курсу **реінжиніринг ПЗ**. -Мета — провести комплексний реінжиніринг спадкового коду NetSdrClient, включаючи рефакторинг архітектури, покращення якості коду, впровадження сучасних практик розробки та автоматизацію процесів контролю якості через CI/CD пайплайни. +PR із новими тестами + image + image ---- -## Структура 8 лабораторних - - Кожна робота — **через Pull Request або окремий commit**. Додати короткий опис: *що змінено / як перевірити* + звіт про хід виконання в Classroom. - -### Лаба 1 — Підключення SonarCloud і CI - -**Мета:** створити проект у SonarCloud, підключити GitHub Actions, запустити перший аналіз. - -**Необхідно:** -- .NET 8 SDK -- Публічний GitHub-репозиторій -- Обліковка SonarCloud (організація прив’язана до GitHub) - -**1) Підключити SonarCloud** -- На SonarCloud створити проект з цього репозиторію (*Analyze new project*). -- Згенерувати **user token** і додати в репозиторій як секрет **`SONAR_TOKEN`** (*Settings → Secrets and variables → Actions*). -- Додати/перевірити `.github/workflows/sonarcloud.yml` з тригерами на PR і push у основну гілку. - `sonarcloud.yml`: -```yml -# 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" ] - 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 проектів - 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 ` - /d:sonar.projectKey="" ` - /d:sonar.organization="" ` - /d:sonar.token="${{ secrets.SONAR_TOKEN }}" ` - /d:sonar.cs.opencover.reportsPaths="**/coverage.xml" ` - /d:sonar.cpd.cs.minimumTokens=40 ` - /d:sonar.cpd.cs.minimumLines=5 ` - /d:sonar.exclusions=**/bin/**,**/obj/**,**/sonarcloud.yml ` - /d:sonar.qualitygate.wait=true - shell: pwsh - # 2) BUILD & TEST - - name: Restore - run: dotnet restore NetSdrClient.sln - - name: Build - run: dotnet build NetSdrClient.sln -c Release --no-restore - #- name: Tests with coverage (OpenCover) - # run: | - # dotnet test NetSdrClientAppTests/NetSdrClientAppTests.csproj -c Release --no-build ` - # /p:CollectCoverage=true ` - # /p:CoverletOutput=TestResults/coverage.xml ` - # /p:CoverletOutputFormat=opencover - # shell: pwsh - # 3) END: SonarScanner - - name: SonarScanner End - run: dotnet sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}" - shell: pwsh -``` - -- **Вимкнути Automatic Analysis** в проєкті. -- Перевірити **PR-декорацію** (вкладка *Checks* у PR). - -**Здати:** посилання на PR чи commit, скрін Quality Gate, скрін бейджів у README. - ---- - -### Лаба 2 — Code Smells через PR + “gated merge” - -**Мета:** виправити **5–10** зауважень Sonar (bugs/smells) без зміни поведінки. - -**Кроки:** -- Дрібними комітами виправити знайдені Sonar-проблеми у `NetSdrClientApp`. - -**Здати:** скріни змін метрик у Sonar. - ---- - -### Лаба 3 — Тести та покриття - -**Мета:** підняти покриття коду юніт-тестами в модулі. - -**Кроки:** -- Підключити генерацію покриття: - - `coverlet.msbuild`: - ```bash - 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 - ``` -- У Sonar додати крок запуску тестів: - ``` - - 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 - ``` -- додати 4–6 юніт-тестів - -**Здати:** PR із новими тестами, скрін Coverage у Sonar. - ---- - -### Лаба 4 — Дублікати через SonarCloud - -**Мета:** зменшити дублікати коду. - -**Кроки:** -- Переглянути **Measures → Duplications** у Sonar і **Checks → SonarCloud** у PR. -- Прибрати **1–2** найбільші дубльовані фрагменти (рефакторинг/винесення спільного коду). -- Перезапустити CI, перевірити, що *Duplications on New Code* ≤ порога (типово 3%). - -**Здати:** PR з скрінами “до/після”. - ---- - -### Лаба 5 — Архітектурні правила (NetArchTest) - -**Мета:** дослідження архітектурних правила залежностей - -**Кроки:** -- Додати кілька архітектурних правил залежностей (наприклад, `*.UI` не має залежати від `*.Infrastructure` напряму). -- Переконатися, що порушення **ламає збірку** (червоний PR), а фікс — зеленить. - -**Здати:** PR із тестами правил, скрін невдалого прогону (до фіксу) і зеленого (після). - ---- - -### Лаба 6 — Безпечний рефакторинг під тести - -**Мета:** рефакторинг коду - -**Кроки:** -- Додати проект з юніт тестами для `EchoServer` -- Реалізувати необхідні зміни в `EchoServer` для покращення його придатності до тестування -- Покрити код юніт-тестами - -**Здати:** PR + коротка таблиця метрик “до/після”. - ---- - -### Лаба 7 — Оновлення залежностей - -**Мета:**навчитись виявляти й виправляти уразливі залежності, користуватись інструментами GitHub Security (Dependency graph, Dependabot alerts/updates). - -**Кроки:** -- `dotnet list NetSdrClient.sln package --outdated --include-transitive` -- Увімкнути GitHub Security - - Repo → Settings → Code security and analysis → включи Dependency graph + Dependabot alerts. - - Через кілька хвилин GitHub має показати алерт про Newtonsoft.Json. - -- Налаштувати Dependabot - - Додай у корінь .github/dependabot.yml: -``` -version: 2 -updates: - - package-ecosystem: "nuget" - directory: "/" - schedule: - interval: "weekly" -``` - - Оновити обрані пакети, прогнати тест/сонар. Dependabot створить PR на оновлення до безпечної версії (13.0.1+). - -**Здати:** PR з оновленням, скрін push-рану після мерджу, нотатки про ризики. - ---- - -### Лаба 8 — Чистий проєкт і gated build - -**Мета:** Домогтися зеленого Quality Gate у SonarCloud. Увімкнути gated merge у GitHub - -**Кроки:** -- Довести SonarCloud до “зеленого” - - Пройти всі умови Quality Gate (типово “Sonar way”), зокрема на New Code: - - Bugs/Vulnerabilities = 0 (на новому коді). - - Coverage on New Code ≥ 80% (підняти тести). - - Duplications on New Code ≤ 3% (або твій суворіший поріг). - - Code Smells: критичні — виправити; інші — зменшити. - - Security Hotspots: переглянути й закрити/виправити. -- Увімкнути gated merge у GitHub - - Repo → Settings → Branches → Add rule для main: - - Require a pull request before merging - - Require status checks to pass → відміть: - - твій CI-джоб (наприклад, CI / Tests & Sonar) - - SonarCloud Code Analysis / SonarCloud Quality Gateimage - - (Опц.) Require approvals (1–2) - - (Опц.) Require branches to be up to date (щоб ребейзилися перед мерджем) -- Після застосування останніх змін, перевірити що Pull Request не дозволяється залити, допоки Sonar не закінчить переврку -image - -**Здати:** скрін *Branches → main* з зеленим Gate - ---- - -## Норми здачі та оцінювання (єдині для всіх лаб) - -**Подання:** через **Pull Request** чи **commit**. -**Опис:** що зроблено, як перевірити, ризики/зворотна сумісність. -**Артефакти:** скріни/посилання на Sonar, логи CI. - ---- - -## Типові граблі → що робити - -- **“You are running CI analysis while Automatic Analysis is enabled”** - Вимкнути *Automatic Analysis* у SonarCloud (використовуємо CI). -- **“Project not found”** - Перевірити `sonar.organization`/`sonar.projectKey` **точно як у UI**; токен має доступ до org. -- **Покриття не генерується** - Додати `coverlet.msbuild` або `coverlet.collector`; використовувати формат **opencover**; у Sonar — `sonar.cs.opencover.reportsPaths`. -- **Подвійний аналіз (PR + push)** - Обмежити умову запуску Sonar: тільки PR **або** `refs/heads/master`. -- **PR зелений, push червоний** - Перевірити **New Code Definition** (Number of days або Previous version) і довести покриття/дублікації на “new code”.