1
0

3 Commits

Author SHA1 Message Date
3740c87528 Updated to .NET 10
All checks were successful
Branch Build / build-test-deploy (push) Successful in 53s
2026-01-12 21:34:11 +01:00
09199753e4 Updated to VS 2026 2026-01-12 21:33:27 +01:00
e7d1b3a2d3 Migrated CI from Gitlab to Gitea
All checks were successful
Branch Build / build-test-deploy (push) Successful in 1m36s
2026-01-12 21:12:01 +01:00
16 changed files with 261 additions and 159 deletions

View File

@@ -0,0 +1,62 @@
name: Branch Build
on:
push:
branches:
- '**'
env:
TZ: 'Europe/Berlin'
LANG: 'de'
CONFIGURATION: 'Debug'
GITEA_SERVER_URL: ${{ gitea.server_url }}
jobs:
build-test-deploy:
runs-on: ubuntu
defaults:
run:
shell: bash
steps:
- name: Checkout repository code
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup dotnet
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.x
cache: false
- name: Restore dependencies
run: |
set -ex
dotnet restore -v q
echo "CI_SERVER_HOST=${GITEA_SERVER_URL#https://}" >> "$GITEA_ENV"
- name: Setup tools
run: |
set -ex
dotnet tool install dotnet-reportgenerator-globaltool --tool-path /dotnet-tools
- name: Build solution
run: |
set -ex
shopt -s globstar
mkdir /artifacts
dotnet build -c ${CONFIGURATION} --no-restore --nologo
mv ./**/*.nupkg /artifacts/
mv ./**/*.snupkg /artifacts/
- name: Test solution
run: |
set -ex
dotnet test -c ${CONFIGURATION} --no-build --nologo /p:CoverletOutputFormat=Cobertura
/dotnet-tools/reportgenerator "-reports:${{ gitea.workspace }}/**/coverage.cobertura.xml" "-targetdir:/reports" "-reportType:TextSummary"
cat /reports/Summary.txt
- name: Publish packages
run: |
set -ex
dotnet nuget push -k "${{ secrets.BAGET_APIKEY }}" -s "https://nuget.am-wd.de/v3/index.json" --skip-duplicate /artifacts/*.nupkg

View File

@@ -0,0 +1,79 @@
name: Release Build
on:
push:
tags:
- 'v*'
env:
TZ: 'Europe/Berlin'
LANG: 'de'
CONFIGURATION: 'Release'
GITEA_SERVER_URL: ${{ gitea.server_url }}
jobs:
build-test-deploy:
runs-on: ubuntu
defaults:
run:
shell: bash
steps:
- name: Checkout repository code
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Setup dotnet
uses: actions/setup-dotnet@v5
with:
dotnet-version: 10.x
cache: false
- name: Restore dependencies
run: |
set -ex
dotnet restore -v q
echo "CI_SERVER_HOST=${GITEA_SERVER_URL#https://}" >> "$GITEA_ENV"
- name: Setup tools
run: |
set -ex
dotnet tool install dotnet-reportgenerator-globaltool --tool-path /dotnet-tools
- name: Build solution
run: |
set -ex
shopt -s globstar
mkdir /artifacts
dotnet build -c ${CONFIGURATION} --no-restore --nologo
mv ./**/*.nupkg /artifacts/
mv ./**/*.snupkg /artifacts/
- name: Test solution
run: |
set -ex
dotnet test -c ${CONFIGURATION} --no-build --nologo /p:CoverletOutputFormat=Cobertura
/dotnet-tools/reportgenerator "-reports:${{ gitea.workspace }}/**/coverage.cobertura.xml" "-targetdir:/reports" "-reportType:TextSummary"
- name: Publish packages
run: |
set -ex
dotnet nuget push -k "${{ secrets.NUGET_APIKEY }}" -s "https://api.nuget.org/v3/index.json" --skip-duplicate /artifacts/*.nupkg
- name: Publish documentation
env:
DOCFX_SOURCE_REPOSITORY_URL: 'https://github.com/AM-WD/FritzCallMonitor'
run: |
set -ex
/dotnet-tools/docfx metadata docs/docfx.json
/dotnet-tools/docfx build docs/docfx.json
tar -C "${{ gitea.workspace }}/docs/_site" -czf "/artifacts/docs.tar.gz" .
curl -sSL --no-progress-meter --user "${{ secrets.DOCS_DEPLOY_USER }}:${{ secrets.DOCS_DEPLOY_PASS }}" -F docs=fritzcallmonitor -F dump=@/artifacts/docs.tar.gz "${{ vars.DOCS_DEPLOY_URL }}"
- name: Upload artifacts
uses: actions/upload-artifact@v3
with:
name: artifacts
path: |
/artifacts/*
/reports/Summary.txt

View File

@@ -2,12 +2,16 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased] ## [Unreleased]
_No changes_ ### Changed
- Migrated main repository from Gitlab to Gitea (CI/CD)
- Updated to VS 2026
- Updated to .NET 10
## [v0.1.2] - 2025-11-08 ## [v0.1.2] - 2025-11-08

View File

@@ -1,6 +1,6 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<LangVersion>12.0</LangVersion> <LangVersion>14.0</LangVersion>
<PublicKey>0024000004800000940000000602000000240000525341310004000001000100d9b40f5db1670c563c2e8be5dfd24ed66ad811b3ebba8a0ca0df9cbad3a115ca361b3de4b4d4ed990bf9874d2651e62565f56adb33af33819687021e263b02d6bf5b3cdacde4f09650cafe97467de4b9e4e9cc1d6c2d500a08759697bbe80940916c05533d172ca7e55e10434f9cc46fd189f26cefc100781a20e57f1bad65d5</PublicKey> <PublicKey>0024000004800000940000000602000000240000525341310004000001000100d9b40f5db1670c563c2e8be5dfd24ed66ad811b3ebba8a0ca0df9cbad3a115ca361b3de4b4d4ed990bf9874d2651e62565f56adb33af33819687021e263b02d6bf5b3cdacde4f09650cafe97467de4b9e4e9cc1d6c2d500a08759697bbe80940916c05533d172ca7e55e10434f9cc46fd189f26cefc100781a20e57f1bad65d5</PublicKey>

View File

@@ -1,78 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36414.22
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FritzCallMonitor", "src\FritzCallMonitor\FritzCallMonitor.csproj", "{9951D44E-9511-40D0-84C1-6A7344389A05}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{C386CB98-2D60-4E40-B869-73053972BD28}"
ProjectSection(SolutionItems) = preProject
src\Directory.Build.props = src\Directory.Build.props
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{DC8CE4B0-4CDD-4162-9CCD-FE711BC86EAB}"
ProjectSection(SolutionItems) = preProject
test\Directory.Build.props = test\Directory.Build.props
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FritzCallMonitor.Tests", "test\FritzCallMonitor.Tests\FritzCallMonitor.Tests.csproj", "{7C5920EA-F4A8-4446-9645-3484DB13BCBD}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{3DF1F30A-77F3-4F24-8739-CB89EE07BB8B}"
ProjectSection(SolutionItems) = preProject
.gitlab-ci.yml = .gitlab-ci.yml
Directory.Build.props = Directory.Build.props
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "config", "config", "{6FA27A08-FCE1-405E-A4A4-3A89FF4579F3}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
CodeMaid.config = CodeMaid.config
nuget.config = nuget.config
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{B5851E79-416B-40CA-959C-ADCAFCC8BADB}"
ProjectSection(SolutionItems) = preProject
CHANGELOG.md = CHANGELOG.md
LICENSE.txt = LICENSE.txt
README.md = README.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FritzCallMonitor.Demo", "src\FritzCallMonitor.Demo\FritzCallMonitor.Demo.csproj", "{6D718239-B477-4517-B8A5-9FBFCF3F3F2D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9951D44E-9511-40D0-84C1-6A7344389A05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9951D44E-9511-40D0-84C1-6A7344389A05}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9951D44E-9511-40D0-84C1-6A7344389A05}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9951D44E-9511-40D0-84C1-6A7344389A05}.Release|Any CPU.Build.0 = Release|Any CPU
{7C5920EA-F4A8-4446-9645-3484DB13BCBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C5920EA-F4A8-4446-9645-3484DB13BCBD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C5920EA-F4A8-4446-9645-3484DB13BCBD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C5920EA-F4A8-4446-9645-3484DB13BCBD}.Release|Any CPU.Build.0 = Release|Any CPU
{6D718239-B477-4517-B8A5-9FBFCF3F3F2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6D718239-B477-4517-B8A5-9FBFCF3F3F2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6D718239-B477-4517-B8A5-9FBFCF3F3F2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6D718239-B477-4517-B8A5-9FBFCF3F3F2D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{9951D44E-9511-40D0-84C1-6A7344389A05} = {C386CB98-2D60-4E40-B869-73053972BD28}
{7C5920EA-F4A8-4446-9645-3484DB13BCBD} = {DC8CE4B0-4CDD-4162-9CCD-FE711BC86EAB}
{3DF1F30A-77F3-4F24-8739-CB89EE07BB8B} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{6FA27A08-FCE1-405E-A4A4-3A89FF4579F3} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{B5851E79-416B-40CA-959C-ADCAFCC8BADB} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{6D718239-B477-4517-B8A5-9FBFCF3F3F2D} = {C386CB98-2D60-4E40-B869-73053972BD28}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {68E37BBB-3CC2-4B0B-8093-7F2F56345EF3}
EndGlobalSection
EndGlobal

32
FritzCallMonitor.slnx Normal file
View File

@@ -0,0 +1,32 @@
<Solution>
<Folder Name="/Solution Items/" />
<Folder Name="/Solution Items/build/">
<File Path="Directory.Build.props" />
</Folder>
<Folder Name="/Solution Items/build/workflows/">
<File Path=".gitea/workflows/branch-build.yml" />
<File Path=".gitea/workflows/release-build.yml" />
</Folder>
<Folder Name="/Solution Items/config/">
<File Path=".editorconfig" />
<File Path=".gitignore" />
<File Path="CodeMaid.config" />
<File Path="nuget.config" />
</Folder>
<Folder Name="/Solution Items/docs/">
<File Path="CHANGELOG.md" />
<File Path="LICENSE.txt" />
<File Path="README.md" />
<File Path="package-icon.png" />
</Folder>
<Folder Name="/src/">
<Project Path="src/FritzCallMonitor/FritzCallMonitor.csproj" />
<Project Path="src/FritzCallMonitor.Demo/FritzCallMonitor.Demo.csproj" />
<File Path="src/Directory.Build.props" />
</Folder>
<Folder Name="/test/">
<File Path="test/MSTestSettings.cs" />
<Project Path="test/FritzCallMonitor.Tests/FritzCallMonitor.Tests.csproj" />
<File Path="test/Directory.Build.props" />
</Folder>
</Solution>

View File

@@ -18,7 +18,6 @@ To disable the call monitor, dial: `#96*4*`.
Published under [MIT License] (see [choose a license]). Published under [MIT License] (see [choose a license]).
[![Buy me a Coffee](https://shields.io/badge/PayPal-Buy_me_a_Coffee-yellow?style=flat&logo=paypal)](https://link.am-wd.de/donate)
[MIT License]: LICENSE.txt [MIT License]: LICENSE.txt

View File

@@ -2,6 +2,7 @@
<PropertyGroup> <PropertyGroup>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<NrtRevisionFormat>{semvertag:main}{!:-dev}</NrtRevisionFormat> <NrtRevisionFormat>{semvertag:main}{!:-dev}</NrtRevisionFormat>
<NrtContinuousIntegrationBuild>$(ContinuousIntegrationBuild)</NrtContinuousIntegrationBuild>
<AssemblyOriginatorKeyFile>../../FritzCallMonitor.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>../../FritzCallMonitor.snk</AssemblyOriginatorKeyFile>
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath> <AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
@@ -18,7 +19,6 @@
<IncludeSymbols>true</IncludeSymbols> <IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat> <SymbolPackageFormat>snupkg</SymbolPackageFormat>
<EmbedUntrackedSources>false</EmbedUntrackedSources>
<Title>CallMonitor implementation for FRITZ!Box</Title> <Title>CallMonitor implementation for FRITZ!Box</Title>
<Company>AM.WD</Company> <Company>AM.WD</Company>
@@ -26,13 +26,14 @@
<Copyright>© {copyright:2025-} AM.WD</Copyright> <Copyright>© {copyright:2025-} AM.WD</Copyright>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(GITLAB_CI)' == 'true'"> <PropertyGroup Condition="'$(CI)' == 'true'">
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild> <ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
</PropertyGroup> </PropertyGroup>
<ItemGroup Condition="'$(GITLAB_CI)' == 'true'"> <ItemGroup Condition="'$(CI)' == 'true'">
<SourceLinkGitLabHost Include="$(CI_SERVER_HOST)" Version="$(CI_SERVER_VERSION)" /> <SourceLinkGiteaHost Include="$(CI_SERVER_HOST)" />
<PackageReference Include="Microsoft.SourceLink.GitLab" Version="8.0.0"> <PackageReference Include="Microsoft.SourceLink.Gitea" Version="8.0.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
@@ -44,7 +45,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AMWD.NetRevisionTask" Version="1.3.0"> <PackageReference Include="AMWD.NetRevisionTask" Version="1.4.0">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@@ -46,6 +46,5 @@ using (var client = new CallMonitorClient(host, port))
Published under MIT License (see [choose a license]). Published under MIT License (see [choose a license]).
[![Buy me a Coffee](https://shields.io/badge/PayPal-Buy_me_a_Coffee-yellow?style=flat&logo=paypal)](https://link.am-wd.de/donate)
[choose a license]: https://choosealicense.com/licenses/mit/ [choose a license]: https://choosealicense.com/licenses/mit/

View File

@@ -1,5 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject> <IsTestProject>true</IsTestProject>
<CollectCoverage>true</CollectCoverage> <CollectCoverage>true</CollectCoverage>
@@ -13,14 +15,16 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="Moq" Version="4.20.72" /> <PackageReference Include="Moq" Version="4.20.72" />
<PackageReference Include="MSTest.TestAdapter" Version="3.10.0" /> <PackageReference Include="MSTest.TestAdapter" Version="4.0.2" />
<PackageReference Include="MSTest.TestFramework" Version="3.10.0" /> <PackageReference Include="MSTest.TestFramework" Version="4.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Using Include="AMWD.Net.Api.Fritz.CallMonitor" />
<Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" /> <Using Include="Microsoft.VisualStudio.TestTools.UnitTesting" />
<Using Include="Moq" />
</ItemGroup> </ItemGroup>
<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)\..'))" /> <Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)\..'))" />

View File

@@ -4,11 +4,9 @@ using System.Reflection;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using AMWD.Net.Api.Fritz.CallMonitor;
using AMWD.Net.Api.Fritz.CallMonitor.Utils; using AMWD.Net.Api.Fritz.CallMonitor.Utils;
using AMWD.Net.Api.Fritz.CallMonitor.Wrappers; using AMWD.Net.Api.Fritz.CallMonitor.Wrappers;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Moq;
namespace FritzCallMonitor.Tests namespace FritzCallMonitor.Tests
{ {
@@ -21,11 +19,10 @@ namespace FritzCallMonitor.Tests
private const string HOST = "localhost"; private const string HOST = "localhost";
private const int PORT = 1012; private const int PORT = 1012;
private readonly DateTime NOW = new(2025, 8, 25, 20, 15, 30, DateTimeKind.Local); private readonly DateTime _now = new(2025, 8, 25, 20, 15, 30, DateTimeKind.Local);
private string _dateOffset; private string _dateOffset;
private Mock<ReconnectTcpClient> _tcpClientMock; private Mock<ReconnectTcpClient> _tcpClientMock;
private Mock<NetworkStreamWrapper> _networkStreamMock; private Mock<NetworkStreamWrapper> _networkStreamMock;
@@ -35,7 +32,7 @@ namespace FritzCallMonitor.Tests
[TestInitialize] [TestInitialize]
public void Initialize() public void Initialize()
{ {
var offset = TimeZoneInfo.Local.GetUtcOffset(NOW); var offset = TimeZoneInfo.Local.GetUtcOffset(_now);
_dateOffset = offset < TimeSpan.Zero _dateOffset = offset < TimeSpan.Zero
? "-" + offset.ToString("hh\\:mm") ? "-" + offset.ToString("hh\\:mm")
: "+" + offset.ToString("hh\\:mm"); : "+" + offset.ToString("hh\\:mm");
@@ -44,7 +41,7 @@ namespace FritzCallMonitor.Tests
_readAsyncResponses = new Queue<(int, byte[])>(); _readAsyncResponses = new Queue<(int, byte[])>();
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes($"{NOW:dd.MM.yy HH:mm:ss};RING;2;012345678901;9876543;SIP0;\r\n"))); _readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes($"{_now:dd.MM.yy HH:mm:ss};RING;2;012345678901;9876543;SIP0;\r\n")));
_readAsyncResponses.Enqueue((Timeout.Infinite, Array.Empty<byte>())); _readAsyncResponses.Enqueue((Timeout.Infinite, Array.Empty<byte>()));
} }
@@ -83,7 +80,7 @@ namespace FritzCallMonitor.Tests
// Arrange // Arrange
var loggerMock = new Mock<ILogger>(); var loggerMock = new Mock<ILogger>();
var client = GetClient(); var client = GetClient();
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
// Act // Act
client.Logger = loggerMock.Object; client.Logger = loggerMock.Object;
@@ -107,7 +104,7 @@ namespace FritzCallMonitor.Tests
{ {
// Arrange // Arrange
var client = GetClient(); var client = GetClient();
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
// Act // Act
client.Dispose(); client.Dispose();
@@ -131,7 +128,7 @@ namespace FritzCallMonitor.Tests
_tcpClientMock.Setup(m => m.GetStream()).Returns((NetworkStreamWrapper)null); _tcpClientMock.Setup(m => m.GetStream()).Returns((NetworkStreamWrapper)null);
// Act // Act
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
client.Dispose(); client.Dispose();
// Assert // Assert
@@ -156,7 +153,7 @@ namespace FritzCallMonitor.Tests
}; };
// Act // Act
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
client.Dispose(); client.Dispose();
// Assert // Assert
@@ -185,7 +182,7 @@ namespace FritzCallMonitor.Tests
{ {
// Arrange // Arrange
_readAsyncResponses.Clear(); _readAsyncResponses.Clear();
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes($"{NOW:dd.MM.yy HH:mm:ss};RING;"))); _readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes($"{_now:dd.MM.yy HH:mm:ss};RING;")));
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes("2;012345678901;9876543;SIP0;\n"))); _readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes("2;012345678901;9876543;SIP0;\n")));
_readAsyncResponses.Enqueue((Timeout.Infinite, Array.Empty<byte>())); _readAsyncResponses.Enqueue((Timeout.Infinite, Array.Empty<byte>()));
@@ -199,7 +196,7 @@ namespace FritzCallMonitor.Tests
}; };
// Act // Act
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
client.Dispose(); client.Dispose();
// Assert // Assert
@@ -228,7 +225,7 @@ namespace FritzCallMonitor.Tests
{ {
// Arrange // Arrange
_readAsyncResponses.Clear(); _readAsyncResponses.Clear();
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes($"{NOW:dd.MM.yy HH:mm:ss};RING;2;012345678901;9876543;SIP0;\n{NOW:dd.MM.yy HH:mm:ss}"))); _readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes($"{_now:dd.MM.yy HH:mm:ss};RING;2;012345678901;9876543;SIP0;\n{_now:dd.MM.yy HH:mm:ss}")));
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes(";RING;2;012345678901;9876543;SIP0;\r\n"))); _readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes(";RING;2;012345678901;9876543;SIP0;\r\n")));
_readAsyncResponses.Enqueue((Timeout.Infinite, Array.Empty<byte>())); _readAsyncResponses.Enqueue((Timeout.Infinite, Array.Empty<byte>()));
@@ -240,7 +237,7 @@ namespace FritzCallMonitor.Tests
}; };
// Act // Act
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
client.Dispose(); client.Dispose();
// Assert // Assert
@@ -260,7 +257,7 @@ namespace FritzCallMonitor.Tests
{ {
// Arrange // Arrange
_readAsyncResponses.Clear(); _readAsyncResponses.Clear();
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes($"{NOW:dd.MM.yy HH:mm:ss};TEST;2;012345678901;9876543;SIP0;\n{NOW:dd.MM.yy HH:mm:ss}"))); _readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes($"{_now:dd.MM.yy HH:mm:ss};TEST;2;012345678901;9876543;SIP0;\n{_now:dd.MM.yy HH:mm:ss}")));
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes(";RING;2;012345678901;9876543;SIP0;\r\n"))); _readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes(";RING;2;012345678901;9876543;SIP0;\r\n")));
_readAsyncResponses.Enqueue((Timeout.Infinite, Array.Empty<byte>())); _readAsyncResponses.Enqueue((Timeout.Infinite, Array.Empty<byte>()));
@@ -272,7 +269,7 @@ namespace FritzCallMonitor.Tests
}; };
// Act // Act
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
client.Dispose(); client.Dispose();
// Assert // Assert
@@ -328,9 +325,9 @@ namespace FritzCallMonitor.Tests
tcpClientField.SetValue(client, _tcpClientMock.Object); tcpClientField.SetValue(client, _tcpClientMock.Object);
var onConnectedMethodInfo = client.GetType().GetMethod("OnConnected", BindingFlags.NonPublic | BindingFlags.Instance); var onConnectedMethodInfo = client.GetType().GetMethod("OnConnected", BindingFlags.NonPublic | BindingFlags.Instance);
_tcpClientMock.SetupGet(c => c.OnConnected).Returns((Func<ReconnectTcpClient, Task>)onConnectedMethodInfo.CreateDelegate(typeof(Func<ReconnectTcpClient, Task>), client)); _tcpClientMock.SetupGet(c => c.OnConnected).Returns(onConnectedMethodInfo.CreateDelegate<Func<ReconnectTcpClient, Task>>(client));
_tcpClientMock.Object.OnConnected(_tcpClientMock.Object).Wait(); _tcpClientMock.Object.OnConnected(_tcpClientMock.Object).Wait(TestContext.CancellationToken);
return client; return client;
} }
} }

View File

@@ -1,5 +1,4 @@
using System; using System;
using AMWD.Net.Api.Fritz.CallMonitor;
namespace FritzCallMonitor.Tests namespace FritzCallMonitor.Tests
{ {
@@ -8,12 +7,12 @@ namespace FritzCallMonitor.Tests
{ {
private string _dateOffset; private string _dateOffset;
private readonly DateTime NOW = new(2025, 8, 25, 20, 15, 30, DateTimeKind.Local); private readonly DateTime _now = new(2025, 8, 25, 20, 15, 30, DateTimeKind.Local);
[TestInitialize] [TestInitialize]
public void Initialize() public void Initialize()
{ {
var offset = TimeZoneInfo.Local.GetUtcOffset(NOW); var offset = TimeZoneInfo.Local.GetUtcOffset(_now);
_dateOffset = offset < TimeSpan.Zero _dateOffset = offset < TimeSpan.Zero
? "-" + offset.ToString("hh\\:mm") ? "-" + offset.ToString("hh\\:mm")
: "+" + offset.ToString("hh\\:mm"); : "+" + offset.ToString("hh\\:mm");
@@ -23,7 +22,7 @@ namespace FritzCallMonitor.Tests
public void ShouldParseRingEvent() public void ShouldParseRingEvent()
{ {
// Arrange // Arrange
string line = $"{NOW:dd.MM.yy HH:mm:ss};RING;2;012345678901;9876543;SIP0;"; string line = $"{_now:dd.MM.yy HH:mm:ss};RING;2;012345678901;9876543;SIP0;";
var result = CallMonitorEventArgs.Parse(line); var result = CallMonitorEventArgs.Parse(line);
Assert.IsNotNull(result); Assert.IsNotNull(result);
@@ -39,7 +38,7 @@ namespace FritzCallMonitor.Tests
[TestMethod] [TestMethod]
public void ShouldParseConnectEvent() public void ShouldParseConnectEvent()
{ {
string line = $"{NOW:dd.MM.yy HH:mm:ss};CONNECT;1;3;012345678901;"; string line = $"{_now:dd.MM.yy HH:mm:ss};CONNECT;1;3;012345678901;";
var result = CallMonitorEventArgs.Parse(line); var result = CallMonitorEventArgs.Parse(line);
Assert.IsNotNull(result); Assert.IsNotNull(result);
@@ -55,7 +54,7 @@ namespace FritzCallMonitor.Tests
[TestMethod] [TestMethod]
public void ShouldParseDisconnectEvent() public void ShouldParseDisconnectEvent()
{ {
string line = $"{NOW:dd.MM.yy HH:mm:ss};DISCONNECT;2;42;"; string line = $"{_now:dd.MM.yy HH:mm:ss};DISCONNECT;2;42;";
var result = CallMonitorEventArgs.Parse(line); var result = CallMonitorEventArgs.Parse(line);
Assert.IsNotNull(result); Assert.IsNotNull(result);
@@ -71,7 +70,7 @@ namespace FritzCallMonitor.Tests
[TestMethod] [TestMethod]
public void ShouldParseCallEvent() public void ShouldParseCallEvent()
{ {
string line = $"{NOW:dd.MM.yy HH:mm:ss};CALL;4;7;9876543;012345678901;SIP0;"; string line = $"{_now:dd.MM.yy HH:mm:ss};CALL;4;7;9876543;012345678901;SIP0;";
var result = CallMonitorEventArgs.Parse(line); var result = CallMonitorEventArgs.Parse(line);
Assert.IsNotNull(result); Assert.IsNotNull(result);
@@ -95,7 +94,7 @@ namespace FritzCallMonitor.Tests
[TestMethod] [TestMethod]
public void ShouldReturnNullOnUnknownEventType() public void ShouldReturnNullOnUnknownEventType()
{ {
string line = $"{NOW:dd.MM.yy HH:mm:ss};UNKNOWN;2;012345678901;9876543;SIP0;"; string line = $"{_now:dd.MM.yy HH:mm:ss};UNKNOWN;2;012345678901;9876543;SIP0;";
var result = CallMonitorEventArgs.Parse(line); var result = CallMonitorEventArgs.Parse(line);
Assert.IsNull(result); Assert.IsNull(result);
} }
@@ -103,7 +102,7 @@ namespace FritzCallMonitor.Tests
[TestMethod] [TestMethod]
public void ShouldReturnNullOnInvalidConnectionId() public void ShouldReturnNullOnInvalidConnectionId()
{ {
string line = $"{NOW:dd.MM.yy HH:mm:ss};RING;abc;012345678901;9876543;SIP0;"; string line = $"{_now:dd.MM.yy HH:mm:ss};RING;abc;012345678901;9876543;SIP0;";
var result = CallMonitorEventArgs.Parse(line); var result = CallMonitorEventArgs.Parse(line);
Assert.IsNull(result); Assert.IsNull(result);
} }
@@ -111,7 +110,7 @@ namespace FritzCallMonitor.Tests
[TestMethod] [TestMethod]
public void ShouldHandleInvalidLinePortInConnect() public void ShouldHandleInvalidLinePortInConnect()
{ {
string line = $"{NOW:dd.MM.yy HH:mm:ss};CONNECT;1;abc;012345678901;"; string line = $"{_now:dd.MM.yy HH:mm:ss};CONNECT;1;abc;012345678901;";
var result = CallMonitorEventArgs.Parse(line); var result = CallMonitorEventArgs.Parse(line);
Assert.IsNotNull(result); Assert.IsNotNull(result);
Assert.IsNull(result.LinePort); Assert.IsNull(result.LinePort);
@@ -120,7 +119,7 @@ namespace FritzCallMonitor.Tests
[TestMethod] [TestMethod]
public void ShouldHandleInvalidLinePortInCall() public void ShouldHandleInvalidLinePortInCall()
{ {
string line = $"{NOW:dd.MM.yy HH:mm:ss};CALL;4;abc;9876543;012345678901;SIP0;"; string line = $"{_now:dd.MM.yy HH:mm:ss};CALL;4;abc;9876543;012345678901;SIP0;";
var result = CallMonitorEventArgs.Parse(line); var result = CallMonitorEventArgs.Parse(line);
Assert.IsNotNull(result); Assert.IsNotNull(result);
Assert.IsNull(result.LinePort); Assert.IsNull(result.LinePort);
@@ -129,7 +128,7 @@ namespace FritzCallMonitor.Tests
[TestMethod] [TestMethod]
public void ShouldHandleInvalidDurationInDisconnect() public void ShouldHandleInvalidDurationInDisconnect()
{ {
string line = $"{NOW:dd.MM.yy HH:mm:ss};DISCONNECT;2;abc;"; string line = $"{_now:dd.MM.yy HH:mm:ss};DISCONNECT;2;abc;";
var result = CallMonitorEventArgs.Parse(line); var result = CallMonitorEventArgs.Parse(line);
Assert.IsNotNull(result); Assert.IsNotNull(result);
Assert.IsNull(result.Duration); Assert.IsNull(result.Duration);
@@ -138,7 +137,7 @@ namespace FritzCallMonitor.Tests
[TestMethod] [TestMethod]
public void ShouldReturnNullOnTooFewColumns() public void ShouldReturnNullOnTooFewColumns()
{ {
string line = $"{NOW:dd.MM.yy HH:mm:ss};RING;"; string line = $"{_now:dd.MM.yy HH:mm:ss};RING;";
var result = CallMonitorEventArgs.Parse(line); var result = CallMonitorEventArgs.Parse(line);
Assert.IsNull(result); Assert.IsNull(result);
} }
@@ -146,7 +145,7 @@ namespace FritzCallMonitor.Tests
[TestMethod] [TestMethod]
public void ShouldParseWithExtraColumns() public void ShouldParseWithExtraColumns()
{ {
string line = $"{NOW:dd.MM.yy HH:mm:ss};RING;2;012345678901;9876543;SIP0;EXTRA;COLUMN;"; string line = $"{_now:dd.MM.yy HH:mm:ss};RING;2;012345678901;9876543;SIP0;EXTRA;COLUMN;";
var result = CallMonitorEventArgs.Parse(line); var result = CallMonitorEventArgs.Parse(line);
Assert.IsNotNull(result); Assert.IsNotNull(result);
Assert.AreEqual("012345678901", result.ExternalNumber); Assert.AreEqual("012345678901", result.ExternalNumber);

View File

@@ -1,9 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <NoWarn>$(NoWarn);CA1873</NoWarn>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<Compile Include="../MSTestSettings.cs" Link="MSTestSettings.cs" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="../../src/FritzCallMonitor/FritzCallMonitor.csproj" /> <ProjectReference Include="../../src/FritzCallMonitor/FritzCallMonitor.csproj" />
</ItemGroup> </ItemGroup>

View File

@@ -7,7 +7,6 @@ using System.Threading.Tasks;
using AMWD.Net.Api.Fritz.CallMonitor.Utils; using AMWD.Net.Api.Fritz.CallMonitor.Utils;
using AMWD.Net.Api.Fritz.CallMonitor.Wrappers; using AMWD.Net.Api.Fritz.CallMonitor.Wrappers;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Moq;
namespace FritzCallMonitor.Tests namespace FritzCallMonitor.Tests
{ {
@@ -80,8 +79,8 @@ namespace FritzCallMonitor.Tests
{ {
// Arrange // Arrange
var client = GetClient(); var client = GetClient();
await client.StartAsync(TestContext.CancellationTokenSource.Token); await client.StartAsync(TestContext.CancellationToken);
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
// Act // Act
client.Dispose(); client.Dispose();
@@ -105,8 +104,8 @@ namespace FritzCallMonitor.Tests
{ {
// Arrange // Arrange
using var client = GetClient(); using var client = GetClient();
await client.StartAsync(TestContext.CancellationTokenSource.Token); await client.StartAsync(TestContext.CancellationToken);
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
// Act // Act
client.Dispose(); client.Dispose();
@@ -134,7 +133,7 @@ namespace FritzCallMonitor.Tests
client.Dispose(); client.Dispose();
// Act & Assert // Act & Assert
await Assert.ThrowsExactlyAsync<ObjectDisposedException>(async () => await client.StartAsync(TestContext.CancellationTokenSource.Token)); await Assert.ThrowsExactlyAsync<ObjectDisposedException>(async () => await client.StartAsync(TestContext.CancellationToken));
VerifyNoOtherCalls(); VerifyNoOtherCalls();
} }
@@ -147,7 +146,7 @@ namespace FritzCallMonitor.Tests
client.Dispose(); client.Dispose();
// Act & Assert // Act & Assert
await Assert.ThrowsExactlyAsync<ObjectDisposedException>(async () => await client.StopAsync(TestContext.CancellationTokenSource.Token)); await Assert.ThrowsExactlyAsync<ObjectDisposedException>(async () => await client.StopAsync(TestContext.CancellationToken));
VerifyNoOtherCalls(); VerifyNoOtherCalls();
} }
@@ -172,8 +171,8 @@ namespace FritzCallMonitor.Tests
_tcpClientConnectTaskDelays.Enqueue(Timeout.Infinite); _tcpClientConnectTaskDelays.Enqueue(Timeout.Infinite);
var client = GetClient(); var client = GetClient();
await client.StartAsync(TestContext.CancellationTokenSource.Token); await client.StartAsync(TestContext.CancellationToken);
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
// Act & Assert // Act & Assert
_tcpClientConnected = true; _tcpClientConnected = true;
@@ -208,10 +207,10 @@ namespace FritzCallMonitor.Tests
}; };
// Act // Act
await client.StartAsync(TestContext.CancellationTokenSource.Token); await client.StartAsync(TestContext.CancellationToken);
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
await client.StopAsync(TestContext.CancellationTokenSource.Token); await client.StopAsync(TestContext.CancellationToken);
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
// Assert // Assert
Assert.IsTrue(callbackCalled); Assert.IsTrue(callbackCalled);
@@ -236,10 +235,10 @@ namespace FritzCallMonitor.Tests
var client = GetClient(); var client = GetClient();
// Act & Assert // Act & Assert
await client.StartAsync(TestContext.CancellationTokenSource.Token); await client.StartAsync(TestContext.CancellationToken);
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
await client.StopAsync(TestContext.CancellationTokenSource.Token); await client.StopAsync(TestContext.CancellationToken);
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
_socketMock.Verify(m => m.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true), Times.Once); _socketMock.Verify(m => m.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true), Times.Once);
@@ -261,7 +260,7 @@ namespace FritzCallMonitor.Tests
var client = GetClient(); var client = GetClient();
// Act & Assert // Act & Assert
await client.StopAsync(TestContext.CancellationTokenSource.Token); await client.StopAsync(TestContext.CancellationToken);
VerifyNoOtherCalls(); VerifyNoOtherCalls();
} }
@@ -271,8 +270,8 @@ namespace FritzCallMonitor.Tests
{ {
// Arrange // Arrange
var client = GetClient(); var client = GetClient();
await client.StartAsync(TestContext.CancellationTokenSource.Token); await client.StartAsync(TestContext.CancellationToken);
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
// Act // Act
var stream = client.GetStream(); var stream = client.GetStream();
@@ -317,10 +316,10 @@ namespace FritzCallMonitor.Tests
using var client = GetClient(); using var client = GetClient();
// Act // Act
var startTask = client.StartAsync(TestContext.CancellationTokenSource.Token); var startTask = client.StartAsync(TestContext.CancellationToken);
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
await client.StopAsync(TestContext.CancellationTokenSource.Token); await client.StopAsync(TestContext.CancellationToken);
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
await startTask; await startTask;
// Assert // Assert
@@ -350,10 +349,10 @@ namespace FritzCallMonitor.Tests
.ThrowsAsync(new SocketException()); .ThrowsAsync(new SocketException());
// Act // Act
var startTask = client.StartAsync(TestContext.CancellationTokenSource.Token); var startTask = client.StartAsync(TestContext.CancellationToken);
await Task.Delay(1000, TestContext.CancellationTokenSource.Token); // Should try to connect two times. await Task.Delay(1000, TestContext.CancellationToken); // Should try to connect two times.
await client.StopAsync(TestContext.CancellationTokenSource.Token); await client.StopAsync(TestContext.CancellationToken);
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
await startTask; await startTask;
// Assert // Assert
@@ -394,10 +393,10 @@ namespace FritzCallMonitor.Tests
.ThrowsAsync(new ObjectDisposedException("Test")); .ThrowsAsync(new ObjectDisposedException("Test"));
// Act // Act
var startTask = client.StartAsync(TestContext.CancellationTokenSource.Token); var startTask = client.StartAsync(TestContext.CancellationToken);
await Task.Delay(1000, TestContext.CancellationTokenSource.Token); // Should try to connect two times. await Task.Delay(1000, TestContext.CancellationToken); // Should try to connect two times.
await client.StopAsync(TestContext.CancellationTokenSource.Token); await client.StopAsync(TestContext.CancellationToken);
await Task.Delay(ASYNC_DELAY, TestContext.CancellationTokenSource.Token); await Task.Delay(ASYNC_DELAY, TestContext.CancellationToken);
await startTask; await startTask;
// Assert // Assert

1
test/MSTestSettings.cs Normal file
View File

@@ -0,0 +1 @@
[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)]