Skip to content

Commit 5c43f6c

Browse files
committed
Added unit tests
Signed-off-by: Zafer Balkan <zafer@zaferbalkan.com>
1 parent 90ebeae commit 5c43f6c

13 files changed

Lines changed: 1946 additions & 0 deletions

.github/workflows/unit-testing.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Unit testing (Windows / MSBuild)
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches: ["master"]
7+
pull_request:
8+
branches: ["master"]
9+
schedule:
10+
- cron: "0 0 * * 0" # weekly, Sunday 00:00 UTC
11+
12+
permissions:
13+
contents: read
14+
15+
jobs:
16+
test:
17+
runs-on: windows-latest
18+
19+
env:
20+
SOLUTION_NAME: TechnitiumLibrary.sln
21+
BUILD_CONFIGURATION: Debug
22+
23+
steps:
24+
- uses: actions/checkout@v4
25+
26+
- name: Install .NET 9 SDK
27+
uses: actions/setup-dotnet@v4
28+
with:
29+
dotnet-version: 9.0.x
30+
31+
- name: Add MSBuild to PATH
32+
uses: microsoft/setup-msbuild@v1
33+
34+
- name: Restore
35+
run: msbuild ${{ env.SOLUTION_NAME }} /t:Restore
36+
37+
- name: Build
38+
run: msbuild ${{ env.SOLUTION_NAME }} /m /p:Configuration=${{ env.BUILD_CONFIGURATION }}
39+
40+
- name: Test (msbuild)
41+
run: msbuild TechnitiumLibrary.Tests\TechnitiumLibrary.Tests.csproj /t:Test /p:Configuration=${{ env.BUILD_CONFIGURATION }}

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
# TechnitiumLibrary
22
A library for .net based applications.
3+
4+
## Quality Assurance
5+
6+
[![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)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
3+
[assembly: Parallelize(Scope = ExecutionScope.MethodLevel)]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<Project Sdk="MSTest.Sdk/4.0.1">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net9.0</TargetFramework>
5+
<LangVersion>latest</LangVersion>
6+
<ImplicitUsings>disable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<UseVSTest>true</UseVSTest>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<ProjectReference Include="..\TechnitiumLibrary\TechnitiumLibrary.csproj" />
13+
</ItemGroup>
14+
15+
</Project>
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
using System;
3+
using System.Text;
4+
5+
namespace TechnitiumLibrary.UnitTests.TechnitiumLibrary
6+
{
7+
[TestClass]
8+
public class Base32Tests
9+
{
10+
// RFC vectors for Base32
11+
private static readonly (string clear, string enc)[] RfcVectors =
12+
{
13+
("f", "MY======"),
14+
("fo", "MZXQ===="),
15+
("foo", "MZXW6==="),
16+
("foob", "MZXW6YQ="),
17+
("fooba", "MZXW6YTB"),
18+
("foobar", "MZXW6YTBOI======")
19+
};
20+
21+
// Values that must decode and encode back identically
22+
private static readonly string[] RoundTripValues =
23+
{
24+
"", "10", "test130", "test", "8", "0", "=", "foobar"
25+
};
26+
27+
// Arbitrary real-world binary sample from PHP tests
28+
private static readonly byte[] RandomBytes =
29+
Convert.FromBase64String("HgxBl1kJ4souh+ELRIHm/x8yTc/cgjDmiCNyJR/NJfs=");
30+
31+
32+
// -------------------- RFC vectors --------------------
33+
34+
[TestMethod]
35+
public void ToBase32String_RfcVectors_ProduceExpectedOutput()
36+
{
37+
foreach ((string clear, string encoded) in RfcVectors)
38+
{
39+
// Arrange
40+
byte[] data = Encoding.ASCII.GetBytes(clear);
41+
42+
// Act
43+
string result = Base32.ToBase32String(data);
44+
45+
// Assert
46+
Assert.AreEqual(encoded, result, "Base32 encoding must match RFC vectors.");
47+
}
48+
}
49+
50+
[TestMethod]
51+
public void FromBase32String_RfcVectors_DecodeCorrectly()
52+
{
53+
foreach ((string clear, string encoded) in RfcVectors)
54+
{
55+
// Arrange
56+
byte[] expected = Encoding.ASCII.GetBytes(clear);
57+
58+
// Act
59+
byte[] result = Base32.FromBase32String(encoded);
60+
61+
// Assert
62+
CollectionAssert.AreEqual(expected, result, "Decoding must invert RFC vectors.");
63+
}
64+
}
65+
66+
67+
// -------------------- RandomBytes encoding/decoding --------------------
68+
69+
[TestMethod]
70+
public void ToBase32String_RandomBytes_MatchesExpectedEncoding()
71+
{
72+
// Given test fixture from PHP
73+
const string expected = "DYGEDF2ZBHRMULUH4EFUJAPG74PTETOP3SBDBZUIENZCKH6NEX5Q====";
74+
75+
// Act
76+
string actual = Base32.ToBase32String(RandomBytes);
77+
78+
Assert.AreEqual(expected, actual, "Binary encoding must be stable and deterministic.");
79+
}
80+
81+
[TestMethod]
82+
public void FromBase32String_RandomBytes_ReturnsOriginalInput()
83+
{
84+
// Arrange
85+
const string encoded = "DYGEDF2ZBHRMULUH4EFUJAPG74PTETOP3SBDBZUIENZCKH6NEX5Q====";
86+
87+
// Act
88+
byte[] decoded = Base32.FromBase32String(encoded);
89+
90+
// Assert
91+
CollectionAssert.AreEqual(RandomBytes, decoded);
92+
}
93+
94+
95+
// -------------------- General encode/decode identity tests --------------------
96+
97+
[TestMethod]
98+
public void EncodeDecode_RoundTrip_GivenKnownClearInputs_ReturnsOriginalValues()
99+
{
100+
foreach (string clear in RoundTripValues)
101+
{
102+
// Arrange
103+
byte[] bytes = Encoding.UTF8.GetBytes(clear);
104+
105+
// Act
106+
string encoded = Base32.ToBase32String(bytes);
107+
byte[] decoded = Base32.FromBase32String(encoded);
108+
109+
// Assert
110+
string decodedText = Encoding.UTF8.GetString(decoded);
111+
Assert.AreEqual(clear, decodedText, "Encode + decode must round-trip.");
112+
}
113+
}
114+
115+
116+
// -------------------- Explicit edge case tests --------------------
117+
118+
[TestMethod]
119+
public void FromBase32String_GivenEmptyString_ReturnsEmptyArray()
120+
{
121+
byte[] result = Base32.FromBase32String("");
122+
Assert.IsEmpty(result);
123+
}
124+
125+
[TestMethod]
126+
public void ToBase32String_GivenEmptyBytes_ReturnsEmptyString()
127+
{
128+
string result = Base32.ToBase32String(Array.Empty<byte>());
129+
Assert.IsEmpty(result);
130+
}
131+
132+
[TestMethod]
133+
public void FromBase32String_GivenNullString_ThrowsException()
134+
{
135+
Assert.ThrowsExactly<NullReferenceException>(() => Base32.FromBase32String(null));
136+
137+
}
138+
139+
[TestMethod]
140+
public void FromBase32HexString_GivenNullString_ThrowsException()
141+
{
142+
Assert.ThrowsExactly<NullReferenceException>(() => Base32.FromBase32HexString(null));
143+
144+
}
145+
146+
[TestMethod]
147+
public void FromBase32String_GivenStringWithSpace_ThrowsException()
148+
{
149+
Assert.ThrowsExactly<IndexOutOfRangeException>(() => Base32.FromBase32String("MZXW6YTBOI====== "));
150+
151+
}
152+
153+
[TestMethod]
154+
public void FromBase32HexString_GivenNullStringSpace_ThrowsException()
155+
{
156+
Assert.ThrowsExactly<IndexOutOfRangeException>(() => Base32.FromBase32HexString("MZXW6YTBOI====== "));
157+
}
158+
}
159+
160+
[TestClass]
161+
public class Base32HexTests
162+
{
163+
private static readonly (string clear, string enc)[] RfcVectors =
164+
{
165+
("f", "CO======"),
166+
("fo", "CPNG===="),
167+
("foo", "CPNMU==="),
168+
("foob", "CPNMUOG="),
169+
("fooba", "CPNMUOJ1"),
170+
("foobar", "CPNMUOJ1E8======"),
171+
};
172+
173+
private static readonly string[] RoundTripValues =
174+
{
175+
"", "10", "test130", "test", "8", "0", "=", "foobar"
176+
};
177+
178+
private static readonly byte[] RandomBytes =
179+
Convert.FromBase64String("HgxBl1kJ4souh+ELRIHm/x8yTc/cgjDmiCNyJR/NJfs=");
180+
181+
182+
// ---------------- RFC vectors ----------------
183+
184+
[TestMethod]
185+
public void ToBase32HexString_RfcVectors_ProduceExpectedOutput()
186+
{
187+
foreach ((string clear, string encoded) in RfcVectors)
188+
{
189+
byte[] data = Encoding.ASCII.GetBytes(clear);
190+
string result = Base32.ToBase32HexString(data);
191+
Assert.AreEqual(encoded, result, "Hex encoding must match RFC vectors.");
192+
}
193+
}
194+
195+
[TestMethod]
196+
public void FromBase32HexString_RfcVectors_DecodeCorrectly()
197+
{
198+
foreach ((string clear, string encoded) in RfcVectors)
199+
{
200+
byte[] expected = Encoding.ASCII.GetBytes(clear);
201+
byte[] result = Base32.FromBase32HexString(encoded);
202+
CollectionAssert.AreEqual(expected, result);
203+
}
204+
}
205+
206+
207+
// ---------------- Known binary test ----------------
208+
209+
[TestMethod]
210+
public void ToBase32HexString_RandomBytes_MatchesExpectedEncoding()
211+
{
212+
const string expected = "3O6435QP17HCKBK7S45K90F6VSFJ4JEFRI131PK84DP2A7UD4NTG====";
213+
string result = Base32.ToBase32HexString(RandomBytes);
214+
Assert.AreEqual(expected, result);
215+
}
216+
217+
[TestMethod]
218+
public void FromBase32HexString_RandomBytes_ReturnsOriginalInput()
219+
{
220+
const string encoded = "3O6435QP17HCKBK7S45K90F6VSFJ4JEFRI131PK84DP2A7UD4NTG====";
221+
byte[] decoded = Base32.FromBase32HexString(encoded);
222+
CollectionAssert.AreEqual(RandomBytes, decoded);
223+
}
224+
225+
226+
// ---------------- Roundtrip tests ----------------
227+
228+
[TestMethod]
229+
public void EncodeDecode_RoundTrip_GivenKnownClearInputs_ReturnsOriginal()
230+
{
231+
foreach (string clear in RoundTripValues)
232+
{
233+
byte[] bytes = Encoding.UTF8.GetBytes(clear);
234+
string encoded = Base32.ToBase32HexString(bytes);
235+
byte[] decodedBytes = Base32.FromBase32HexString(encoded);
236+
string decoded = Encoding.UTF8.GetString(decodedBytes);
237+
238+
Assert.AreEqual(clear, decoded);
239+
}
240+
}
241+
242+
243+
// ---------------- Explicit empty edge cases ----------------
244+
245+
[TestMethod]
246+
public void FromBase32HexString_GivenEmpty_ReturnsEmptyArray()
247+
{
248+
byte[] result = Base32.FromBase32HexString("");
249+
Assert.IsEmpty(result);
250+
}
251+
252+
[TestMethod]
253+
public void ToBase32HexString_GivenEmptyBytes_ReturnsEmptyString()
254+
{
255+
string result = Base32.ToBase32HexString(Array.Empty<byte>());
256+
Assert.IsEmpty(result);
257+
}
258+
}
259+
}

0 commit comments

Comments
 (0)