1
0

5 Commits

Author SHA1 Message Date
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
a6c3df5d17 Bump to v0.1.2 2025-11-08 16:48:08 +01:00
452fe47969 Made things virtual for mocking purposes 2025-11-08 10:32:35 +01:00
8f71e4dbe4 Updated README 2025-10-25 10:09:01 +02:00
5949de6611 Changed property names to be more descriptive 2025-10-24 22:17:06 +02:00
12 changed files with 227 additions and 58 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: 8.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: 8.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

@@ -7,7 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
_nothing changed yet_ ### Changed
- Migrated main repository from Gitlab to Gitea (CI/CD)
## [v0.1.2] - 2025-11-08
### Changed
- Public elements are now `virtual` to allow mocking in unit tests
## [v0.1.1] - 2025-10-24
### Changed
- Property names of the event should be more descriptive:
- From `CallerNumber` to `ExternalNumber`
- From `CalleeNumber` to `InternalNumber`
## [v0.1.0] - 2025-08-28 ## [v0.1.0] - 2025-08-28
@@ -27,6 +45,8 @@ _Inital release_
[Unreleased]: https://github.com/AM-WD/FritzCallMonitor/compare/v0.1.0...HEAD [Unreleased]: https://github.com/AM-WD/FritzCallMonitor/compare/v0.1.2...HEAD
[v0.1.2]: https://github.com/AM-WD/FritzCallMonitor/compare/v0.1.1...v0.1.2
[v0.1.1]: https://github.com/AM-WD/FritzCallMonitor/compare/v0.1.0...v0.1.1
[v0.1.0]: https://github.com/AM-WD/FritzCallMonitor/commits/v0.1.0 [v0.1.0]: https://github.com/AM-WD/FritzCallMonitor/commits/v0.1.0

View File

@@ -21,7 +21,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FritzCallMonitor.Tests", "t
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{3DF1F30A-77F3-4F24-8739-CB89EE07BB8B}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{3DF1F30A-77F3-4F24-8739-CB89EE07BB8B}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
.gitlab-ci.yml = .gitlab-ci.yml
Directory.Build.props = Directory.Build.props Directory.Build.props = Directory.Build.props
EndProjectSection EndProjectSection
EndProject EndProject
@@ -42,6 +41,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{B5851E79-4
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FritzCallMonitor.Demo", "src\FritzCallMonitor.Demo\FritzCallMonitor.Demo.csproj", "{6D718239-B477-4517-B8A5-9FBFCF3F3F2D}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FritzCallMonitor.Demo", "src\FritzCallMonitor.Demo\FritzCallMonitor.Demo.csproj", "{6D718239-B477-4517-B8A5-9FBFCF3F3F2D}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{9EB88C90-FBC7-4DB8-9484-DFC74553FF40}"
ProjectSection(SolutionItems) = preProject
.gitea\workflows\branch-build.yml = .gitea\workflows\branch-build.yml
.gitea\workflows\release-build.yml = .gitea\workflows\release-build.yml
EndProjectSection
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -71,6 +76,7 @@ Global
{6FA27A08-FCE1-405E-A4A4-3A89FF4579F3} = {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} {B5851E79-416B-40CA-959C-ADCAFCC8BADB} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{6D718239-B477-4517-B8A5-9FBFCF3F3F2D} = {C386CB98-2D60-4E40-B869-73053972BD28} {6D718239-B477-4517-B8A5-9FBFCF3F3F2D} = {C386CB98-2D60-4E40-B869-73053972BD28}
{9EB88C90-FBC7-4DB8-9484-DFC74553FF40} = {3DF1F30A-77F3-4F24-8739-CB89EE07BB8B}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {68E37BBB-3CC2-4B0B-8093-7F2F56345EF3} SolutionGuid = {68E37BBB-3CC2-4B0B-8093-7F2F56345EF3}

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

@@ -44,11 +44,11 @@ namespace FritzCallMonitor.Demo
switch (e.Event) switch (e.Event)
{ {
case EventType.Ring: case EventType.Ring:
Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss K} | #{e.ConnectionId} | Incoming Call from {e.CallerNumber} to {e.CalleeNumber}"); Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss K} | #{e.ConnectionId} | Incoming Call from {e.ExternalNumber} to {e.InternalNumber}");
break; break;
case EventType.Connect: case EventType.Connect:
Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss K} | #{e.ConnectionId} | Call connected to {e.CallerNumber}"); Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss K} | #{e.ConnectionId} | Call connected to {e.ExternalNumber}");
break; break;
case EventType.Disconnect: case EventType.Disconnect:
@@ -56,7 +56,7 @@ namespace FritzCallMonitor.Demo
break; break;
case EventType.Call: case EventType.Call:
Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss K} | #{e.ConnectionId} | Outgoing Call from {e.CalleeNumber} to {e.CallerNumber}"); Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss K} | #{e.ConnectionId} | Outgoing Call from {e.InternalNumber} to {e.ExternalNumber}");
break; break;
} }
}; };

View File

@@ -51,12 +51,12 @@ namespace AMWD.Net.Api.Fritz.CallMonitor
/// <remarks> /// <remarks>
/// The event provides details using the <see cref="CallMonitorEventArgs"/> parameter. /// The event provides details using the <see cref="CallMonitorEventArgs"/> parameter.
/// </remarks> /// </remarks>
public event EventHandler<CallMonitorEventArgs>? OnEvent; public virtual event EventHandler<CallMonitorEventArgs>? OnEvent;
/// <summary> /// <summary>
/// Gets or sets a logger instance. /// Gets or sets a logger instance.
/// </summary> /// </summary>
public ILogger? Logger public virtual ILogger? Logger
{ {
get => _logger; get => _logger;
set set
@@ -69,7 +69,7 @@ namespace AMWD.Net.Api.Fritz.CallMonitor
/// <summary> /// <summary>
/// Releases all resources used by the current instance of the <see cref="CallMonitorClient"/>. /// Releases all resources used by the current instance of the <see cref="CallMonitorClient"/>.
/// </summary> /// </summary>
public void Dispose() public virtual void Dispose()
{ {
if (_isDisposed) if (_isDisposed)
return; return;

View File

@@ -31,12 +31,12 @@ namespace AMWD.Net.Api.Fritz.CallMonitor
/// <summary> /// <summary>
/// Gets the external number displayed in the FRITZ!Box. /// Gets the external number displayed in the FRITZ!Box.
/// </summary> /// </summary>
public string? CallerNumber { get; private set; } public string? ExternalNumber { get; private set; }
/// <summary> /// <summary>
/// Gets the internal number registered in the FRITZ!Box. /// Gets the internal number registered in the FRITZ!Box.
/// </summary> /// </summary>
public string? CalleeNumber { get; private set; } public string? InternalNumber { get; private set; }
/// <summary> /// <summary>
/// Gets the duration of the call (only on <see cref="EventType.Disconnect"/> event). /// Gets the duration of the call (only on <see cref="EventType.Disconnect"/> event).
@@ -71,13 +71,13 @@ namespace AMWD.Net.Api.Fritz.CallMonitor
switch (eventType) switch (eventType)
{ {
case EventType.Ring: case EventType.Ring:
args.CallerNumber = columns[3]; args.ExternalNumber = columns[3];
args.CalleeNumber = columns[4]; args.InternalNumber = columns[4];
break; break;
case EventType.Connect: case EventType.Connect:
args.LinePort = int.TryParse(columns[3], out int connectLinePort) ? connectLinePort : null; args.LinePort = int.TryParse(columns[3], out int connectLinePort) ? connectLinePort : null;
args.CallerNumber = columns[4]; args.ExternalNumber = columns[4];
break; break;
case EventType.Disconnect: case EventType.Disconnect:
@@ -87,8 +87,8 @@ namespace AMWD.Net.Api.Fritz.CallMonitor
case EventType.Call: case EventType.Call:
args.LinePort = int.TryParse(columns[3], out int callLinePort) ? callLinePort : null; args.LinePort = int.TryParse(columns[3], out int callLinePort) ? callLinePort : null;
args.CalleeNumber = columns[4]; args.InternalNumber = columns[4];
args.CallerNumber = columns[5]; args.ExternalNumber = columns[5];
break; break;
default: default:

View File

@@ -19,11 +19,11 @@ using (var client = new CallMonitorClient(host, port))
switch (e.Event) switch (e.Event)
{ {
case EventType.Ring: case EventType.Ring:
Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss} | #{e.ConnectionId} | Incoming Call from {e.CallerNumber} to {e.CalleeNumber}"); Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss} | #{e.ConnectionId} | Incoming Call from {e.ExternalNumber} to {e.InternalNumber}");
break; break;
case EventType.Connect: case EventType.Connect:
Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss} | #{e.ConnectionId} | Call connected to {e.CallerNumber}"); Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss} | #{e.ConnectionId} | Call connected to {e.ExternalNumber}");
break; break;
case EventType.Disconnect: case EventType.Disconnect:
@@ -31,7 +31,7 @@ using (var client = new CallMonitorClient(host, port))
break; break;
case EventType.Call: case EventType.Call:
Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss} | #{e.ConnectionId} | Outgoing Call from {e.CalleeNumber} to {e.CallerNumber}"); Console.WriteLine($"{e.Timestamp:yyyy-MM-dd HH:mm:ss} | #{e.ConnectionId} | Outgoing Call from {e.InternalNumber} to {e.ExternalNumber}");
break; break;
} }
}; };
@@ -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

@@ -21,6 +21,7 @@ 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 string _dateOffset; private string _dateOffset;
@@ -34,7 +35,7 @@ namespace FritzCallMonitor.Tests
[TestInitialize] [TestInitialize]
public void Initialize() public void Initialize()
{ {
var offset = TimeZoneInfo.Local.GetUtcOffset(DateTime.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");
@@ -43,7 +44,7 @@ namespace FritzCallMonitor.Tests
_readAsyncResponses = new Queue<(int, byte[])>(); _readAsyncResponses = new Queue<(int, byte[])>();
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes("25.08.25 20:15:30;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>()));
} }
@@ -166,8 +167,8 @@ namespace FritzCallMonitor.Tests
Assert.AreEqual(EventType.Ring, eventArgs.Event); Assert.AreEqual(EventType.Ring, eventArgs.Event);
Assert.AreEqual(2, eventArgs.ConnectionId); Assert.AreEqual(2, eventArgs.ConnectionId);
Assert.IsNull(eventArgs.LinePort); Assert.IsNull(eventArgs.LinePort);
Assert.AreEqual("012345678901", eventArgs.CallerNumber); Assert.AreEqual("012345678901", eventArgs.ExternalNumber);
Assert.AreEqual("9876543", eventArgs.CalleeNumber); Assert.AreEqual("9876543", eventArgs.InternalNumber);
Assert.IsNull(eventArgs.Duration); Assert.IsNull(eventArgs.Duration);
_tcpClientMock.VerifyGet(m => m.IsConnected, Times.Exactly(2)); _tcpClientMock.VerifyGet(m => m.IsConnected, Times.Exactly(2));
@@ -184,7 +185,7 @@ namespace FritzCallMonitor.Tests
{ {
// Arrange // Arrange
_readAsyncResponses.Clear(); _readAsyncResponses.Clear();
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes("25.08.25 20:15:30;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>()));
@@ -209,8 +210,8 @@ namespace FritzCallMonitor.Tests
Assert.AreEqual(EventType.Ring, eventArgs.Event); Assert.AreEqual(EventType.Ring, eventArgs.Event);
Assert.AreEqual(2, eventArgs.ConnectionId); Assert.AreEqual(2, eventArgs.ConnectionId);
Assert.IsNull(eventArgs.LinePort); Assert.IsNull(eventArgs.LinePort);
Assert.AreEqual("012345678901", eventArgs.CallerNumber); Assert.AreEqual("012345678901", eventArgs.ExternalNumber);
Assert.AreEqual("9876543", eventArgs.CalleeNumber); Assert.AreEqual("9876543", eventArgs.InternalNumber);
Assert.IsNull(eventArgs.Duration); Assert.IsNull(eventArgs.Duration);
_tcpClientMock.VerifyGet(m => m.IsConnected, Times.Exactly(3)); _tcpClientMock.VerifyGet(m => m.IsConnected, Times.Exactly(3));
@@ -227,7 +228,7 @@ namespace FritzCallMonitor.Tests
{ {
// Arrange // Arrange
_readAsyncResponses.Clear(); _readAsyncResponses.Clear();
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes("25.08.25 20:15:30;RING;2;012345678901;9876543;SIP0;\n25.08.25 20:15:30"))); _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>()));
@@ -259,7 +260,7 @@ namespace FritzCallMonitor.Tests
{ {
// Arrange // Arrange
_readAsyncResponses.Clear(); _readAsyncResponses.Clear();
_readAsyncResponses.Enqueue((0, Encoding.UTF8.GetBytes("25.08.25 20:15:30;TEST;2;012345678901;9876543;SIP0;\n25.08.25 20:15:30"))); _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>()));

View File

@@ -8,10 +8,12 @@ namespace FritzCallMonitor.Tests
{ {
private string _dateOffset; private string _dateOffset;
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(DateTime.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");
@@ -21,7 +23,7 @@ namespace FritzCallMonitor.Tests
public void ShouldParseRingEvent() public void ShouldParseRingEvent()
{ {
// Arrange // Arrange
string line = "25.08.25 20:15:30;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);
@@ -29,15 +31,15 @@ namespace FritzCallMonitor.Tests
Assert.AreEqual(EventType.Ring, result.Event); Assert.AreEqual(EventType.Ring, result.Event);
Assert.AreEqual(2, result.ConnectionId); Assert.AreEqual(2, result.ConnectionId);
Assert.IsNull(result.LinePort); Assert.IsNull(result.LinePort);
Assert.AreEqual("012345678901", result.CallerNumber); Assert.AreEqual("012345678901", result.ExternalNumber);
Assert.AreEqual("9876543", result.CalleeNumber); Assert.AreEqual("9876543", result.InternalNumber);
Assert.IsNull(result.Duration); Assert.IsNull(result.Duration);
} }
[TestMethod] [TestMethod]
public void ShouldParseConnectEvent() public void ShouldParseConnectEvent()
{ {
string line = "25.08.25 20:15:30;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);
@@ -45,15 +47,15 @@ namespace FritzCallMonitor.Tests
Assert.AreEqual(EventType.Connect, result.Event); Assert.AreEqual(EventType.Connect, result.Event);
Assert.AreEqual(1, result.ConnectionId); Assert.AreEqual(1, result.ConnectionId);
Assert.AreEqual(3, result.LinePort); Assert.AreEqual(3, result.LinePort);
Assert.AreEqual("012345678901", result.CallerNumber); Assert.AreEqual("012345678901", result.ExternalNumber);
Assert.IsNull(result.CalleeNumber); Assert.IsNull(result.InternalNumber);
Assert.IsNull(result.Duration); Assert.IsNull(result.Duration);
} }
[TestMethod] [TestMethod]
public void ShouldParseDisconnectEvent() public void ShouldParseDisconnectEvent()
{ {
string line = "25.08.25 20:15:30;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);
@@ -61,15 +63,15 @@ namespace FritzCallMonitor.Tests
Assert.AreEqual(EventType.Disconnect, result.Event); Assert.AreEqual(EventType.Disconnect, result.Event);
Assert.AreEqual(2, result.ConnectionId); Assert.AreEqual(2, result.ConnectionId);
Assert.IsNull(result.LinePort); Assert.IsNull(result.LinePort);
Assert.IsNull(result.CallerNumber); Assert.IsNull(result.ExternalNumber);
Assert.IsNull(result.CalleeNumber); Assert.IsNull(result.InternalNumber);
Assert.AreEqual(TimeSpan.FromSeconds(42), result.Duration); Assert.AreEqual(TimeSpan.FromSeconds(42), result.Duration);
} }
[TestMethod] [TestMethod]
public void ShouldParseCallEvent() public void ShouldParseCallEvent()
{ {
string line = "25.08.25 20:15:30;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);
@@ -77,8 +79,8 @@ namespace FritzCallMonitor.Tests
Assert.AreEqual(EventType.Call, result.Event); Assert.AreEqual(EventType.Call, result.Event);
Assert.AreEqual(4, result.ConnectionId); Assert.AreEqual(4, result.ConnectionId);
Assert.AreEqual(7, result.LinePort); Assert.AreEqual(7, result.LinePort);
Assert.AreEqual("012345678901", result.CallerNumber); Assert.AreEqual("012345678901", result.ExternalNumber);
Assert.AreEqual("9876543", result.CalleeNumber); Assert.AreEqual("9876543", result.InternalNumber);
Assert.IsNull(result.Duration); Assert.IsNull(result.Duration);
} }
@@ -93,7 +95,7 @@ namespace FritzCallMonitor.Tests
[TestMethod] [TestMethod]
public void ShouldReturnNullOnUnknownEventType() public void ShouldReturnNullOnUnknownEventType()
{ {
string line = "25.08.25 20:15:30;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);
} }
@@ -101,7 +103,7 @@ namespace FritzCallMonitor.Tests
[TestMethod] [TestMethod]
public void ShouldReturnNullOnInvalidConnectionId() public void ShouldReturnNullOnInvalidConnectionId()
{ {
string line = "25.08.25 20:15:30;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);
} }
@@ -109,7 +111,7 @@ namespace FritzCallMonitor.Tests
[TestMethod] [TestMethod]
public void ShouldHandleInvalidLinePortInConnect() public void ShouldHandleInvalidLinePortInConnect()
{ {
string line = "25.08.25 20:15:30;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);
@@ -118,7 +120,7 @@ namespace FritzCallMonitor.Tests
[TestMethod] [TestMethod]
public void ShouldHandleInvalidLinePortInCall() public void ShouldHandleInvalidLinePortInCall()
{ {
string line = "25.08.25 20:15:30;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);
@@ -127,7 +129,7 @@ namespace FritzCallMonitor.Tests
[TestMethod] [TestMethod]
public void ShouldHandleInvalidDurationInDisconnect() public void ShouldHandleInvalidDurationInDisconnect()
{ {
string line = "25.08.25 20:15:30;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);
@@ -136,7 +138,7 @@ namespace FritzCallMonitor.Tests
[TestMethod] [TestMethod]
public void ShouldReturnNullOnTooFewColumns() public void ShouldReturnNullOnTooFewColumns()
{ {
string line = "25.08.25 20:15:30;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);
} }
@@ -144,11 +146,11 @@ namespace FritzCallMonitor.Tests
[TestMethod] [TestMethod]
public void ShouldParseWithExtraColumns() public void ShouldParseWithExtraColumns()
{ {
string line = "25.08.25 20:15:30;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.CallerNumber); Assert.AreEqual("012345678901", result.ExternalNumber);
Assert.AreEqual("9876543", result.CalleeNumber); Assert.AreEqual("9876543", result.InternalNumber);
} }
} }
} }