Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/unit-testing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Unit testing (Windows / MSBuild)

on:
workflow_dispatch:
push:
branches: ["master"]
pull_request:
branches: ["master"]
schedule:
- cron: "0 0 * * 0" # weekly, Sunday 00:00 UTC

permissions:
contents: read

jobs:
test:
runs-on: windows-latest

env:
SOLUTION_NAME: TechnitiumLibrary.sln
BUILD_CONFIGURATION: Debug

steps:
- uses: actions/checkout@v4

- name: Install .NET 9 SDK
uses: actions/setup-dotnet@v4
with:
dotnet-version: 9.0.x

- name: Add MSBuild to PATH
uses: microsoft/setup-msbuild@v2

- name: Restore
run: msbuild ${{ env.SOLUTION_NAME }} /t:Restore

- name: Build
run: msbuild ${{ env.SOLUTION_NAME }} /m /p:Configuration=${{ env.BUILD_CONFIGURATION }}

- name: Test (msbuild)
run: msbuild TechnitiumLibrary.UnitTests\TechnitiumLibrary.UnitTests.csproj /t:Test /p:Configuration=${{ env.BUILD_CONFIGURATION }}
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
# TechnitiumLibrary
A library for .net based applications.

## Quality Assurance

[![Unit testing (Windows / MSBuild)](https://github.com/TechnitiumSoftware/TechnitiumLibrary/actions/workflows/unit-testing.yml/badge.svg)](https://github.com/TechnitiumSoftware/TechnitiumLibrary/actions/workflows/unit-testing.yml)
3 changes: 3 additions & 0 deletions TechnitiumLibrary.UnitTests/MSTestSettings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;

[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)]
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
Technitium Library
Copyright (C) 2026 Shreyas Zare (shreyas@technitium.com)
Copyright (C) 2026 Zafer Balkan (zafer@zaferbalkan.com)

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

*/

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using TechnitiumLibrary.Net.Firewall;

namespace TechnitiumLibrary.UnitTests.TechnitiumLibrary.Net.Firewall
{
[TestClass]
public sealed class WindowsFirewallTests
{
[TestMethod]
[OSCondition(OperatingSystems.Windows)]
public void AddPort_ShouldThrow_WhenUnsupportedProtocol()
{
// Protocol ICMPv4 cannot be added using AddPort
Assert.ThrowsExactly<Exception>(() => WindowsFirewall.AddPort("bad", Protocol.ICMPv4, port: 55, enable: true));
}

[TestMethod]
[OSCondition(OperatingSystems.Windows)]
public void RemovePort_ShouldThrow_WhenUnsupportedProtocol()
{
// RemovePort validates only TCP, UDP, ANY
Assert.ThrowsExactly<Exception>(() => WindowsFirewall.RemovePort(Protocol.IGMP, 123));
}

[TestMethod]
[OSCondition(OperatingSystems.Windows)]
public void PortExists_ShouldThrow_WhenUnsupportedProtocol()
{
Assert.ThrowsExactly<Exception>(() => WindowsFirewall.PortExists(Protocol.IGMP, 44));
}

[TestMethod]
[OSCondition(OperatingSystems.Windows)]
public void RuleExistsVista_ShouldReturnDoesNotExist_WhenInputsClearlyNotMatchingAnything()
{
// Since firewall is not guaranteed to have this rule,
// safest expected response is DoesNotExists.
RuleStatus result = WindowsFirewall.RuleExistsVista(
name: "__Definitely_Not_A_Real_Rule__",
applicationPath: "__Fake__");

Assert.AreEqual(RuleStatus.DoesNotExists, result);
}

[TestMethod]
[OSCondition(OperatingSystems.Windows)]
public void ApplicationExists_ShouldReturnDoesNotExist_WhenApplicationIsNotRegistered()
{
// Public observable guarantee:
// if the system has no such application entry → DoesNotExists

const string fakePath = "C:\\DefinitelyNotExisting\\app.exe";

RuleStatus status = WindowsFirewall.ApplicationExists(fakePath);

Assert.AreEqual(RuleStatus.DoesNotExists, status);
}
}
}
15 changes: 15 additions & 0 deletions TechnitiumLibrary.UnitTests/TechnitiumLibrary.UnitTests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="MSTest.Sdk/4.0.1">

<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<LangVersion>latest</LangVersion>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<UseVSTest>true</UseVSTest>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\TechnitiumLibrary.Net.Firewall\TechnitiumLibrary.Net.Firewall.csproj" />
</ItemGroup>

</Project>
6 changes: 6 additions & 0 deletions TechnitiumLibrary.sln
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TechnitiumLibrary", "Techni
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TechnitiumLibrary.Security.OTP", "TechnitiumLibrary.Security.OTP\TechnitiumLibrary.Security.OTP.csproj", "{72AF4EB6-EB81-4655-9998-8BF24B304614}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TechnitiumLibrary.UnitTests", "TechnitiumLibrary.UnitTests\TechnitiumLibrary.UnitTests.csproj", "{D0CD41D8-E5F0-4EEF-81E3-587A2A877C49}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -75,6 +77,10 @@ Global
{72AF4EB6-EB81-4655-9998-8BF24B304614}.Debug|Any CPU.Build.0 = Debug|Any CPU
{72AF4EB6-EB81-4655-9998-8BF24B304614}.Release|Any CPU.ActiveCfg = Release|Any CPU
{72AF4EB6-EB81-4655-9998-8BF24B304614}.Release|Any CPU.Build.0 = Release|Any CPU
{D0CD41D8-E5F0-4EEF-81E3-587A2A877C49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D0CD41D8-E5F0-4EEF-81E3-587A2A877C49}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D0CD41D8-E5F0-4EEF-81E3-587A2A877C49}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D0CD41D8-E5F0-4EEF-81E3-587A2A877C49}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
2 changes: 1 addition & 1 deletion TechnitiumLibrary/Base32.cs
Original file line number Diff line number Diff line change
Expand Up @@ -317,4 +317,4 @@ public static byte[] FromBase32HexString(string data)

#endregion
}
}
}
2 changes: 1 addition & 1 deletion TechnitiumLibrary/CollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,4 @@ public static int GetArrayHashCode<T>(this IReadOnlyCollection<T> value)
return hashCode;
}
}
}
}