From 08e46776753d7db5005978c0e5251b474b956179 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Fri, 5 Dec 2025 10:14:38 +0200 Subject: [PATCH 01/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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/31] 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 6fdafe713970108dc3e4e1e22ac95e6e7b0adfd4 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Mon, 8 Dec 2025 20:44:20 +0200 Subject: [PATCH 28/31] 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 6ce77941290272e757e471be60d8ed8f2d3c00a4 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Mon, 8 Dec 2025 20:56:22 +0200 Subject: [PATCH 29/31] 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 c95e44f6b8153912f5963028ef00a8535930eb90 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Tue, 9 Dec 2025 00:10:28 +0200 Subject: [PATCH 30/31] Update README.md --- README.md | 290 ++---------------------------------------------------- 1 file changed, 10 insertions(+), 280 deletions(-) diff --git a/README.md b/README.md index e73d69a6..388f50ec 100644 --- a/README.md +++ b/README.md @@ -1,283 +1,13 @@ -# Лабораторні з реінжинірингу (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) - - - - -Цей репозиторій використовується для курсу **реінжиніринг ПЗ**. -Мета — провести комплексний реінжиніринг спадкового коду NetSdrClient, включаючи рефакторинг архітектури, покращення якості коду, впровадження сучасних практик розробки та автоматизацію процесів контролю якості через CI/CD пайплайни. - ---- - -## Структура 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”. + +Результат виправлення: + +Висновок: +У ході лабораторної роботи було виконано аналіз вихідного коду програмного проєкту за допомогою інструменту Sonar та виявлено низку дефектів типу code smells і потенційних помилок. На основі отриманих діагностичних звітів було здійснено комплексне уточнення та корекцію 5–10 зауважень без зміни функціональної поведінки програмного забезпечення. Застосовані правки охоплювали оптимізацію конструкцій коду, усунення дублювання, підвищення читабельності та покращення структурної узгодженості. +Порівняння початкових і кінцевих метрик показало покращення показників якості, зокрема зменшення кількості smells та зниження ризиків супроводу коду. Виконані зміни підтвердили ефективність підходу «gated merge», який забезпечує контроль якості на етапі інтеграції та унеможливлює потрапляння низькоякісного коду до основної гілки репозиторію. +Результати роботи демонструють важливість систематичного застосування засобів статичного аналізу та принципів реінжинірингу для підтримання високої якості програмного забезпечення, а також підтверджують доцільність використання контрольованих процесів внесення змін у рамках командної розробки. From ce9b7409ce07cab444a07d2e763188f5b9b22d45 Mon Sep 17 00:00:00 2001 From: olekca160406 Date: Tue, 9 Dec 2025 00:41:48 +0200 Subject: [PATCH 31/31] Update README.md --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 388f50ec..46c14f61 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,12 @@ Початкові метрики: +image Вношу незначні правки до коду: +image +image Результат виправлення: - -Висновок: -У ході лабораторної роботи було виконано аналіз вихідного коду програмного проєкту за допомогою інструменту Sonar та виявлено низку дефектів типу code smells і потенційних помилок. На основі отриманих діагностичних звітів було здійснено комплексне уточнення та корекцію 5–10 зауважень без зміни функціональної поведінки програмного забезпечення. Застосовані правки охоплювали оптимізацію конструкцій коду, усунення дублювання, підвищення читабельності та покращення структурної узгодженості. -Порівняння початкових і кінцевих метрик показало покращення показників якості, зокрема зменшення кількості smells та зниження ризиків супроводу коду. Виконані зміни підтвердили ефективність підходу «gated merge», який забезпечує контроль якості на етапі інтеграції та унеможливлює потрапляння низькоякісного коду до основної гілки репозиторію. -Результати роботи демонструють важливість систематичного застосування засобів статичного аналізу та принципів реінжинірингу для підтримання високої якості програмного забезпечення, а також підтверджують доцільність використання контрольованих процесів внесення змін у рамках командної розробки. + image