Skip to content
Open
Show file tree
Hide file tree
Changes from 7 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,146 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.IO;
using System.Linq;
using System.Text;
using TechnitiumLibrary.IO;

namespace TechnitiumLibrary.UnitTests.TechnitiumLibrary.IO
{
[TestClass]
public sealed class BinaryReaderExtensionsTests
{
private static BinaryReader ReaderOf(params byte[] bytes)
{
return new BinaryReader(new MemoryStream(bytes));
}

// -----------------------------------------------
// ReadLength()
// -----------------------------------------------

[TestMethod]
public void ReadLength_ShouldReadSingleByteLengths()
{
// GIVEN
BinaryReader reader = ReaderOf(0x05);

// WHEN
int length = reader.ReadLength();

// THEN
Assert.AreEqual(5, length);
Assert.AreEqual(1, reader.BaseStream.Position);
}

[TestMethod]
public void ReadLength_ShouldReadMultiByteBigEndianLengths()
{
// GIVEN
// 0x82 => 2-byte length follows → value = 0x01 0x2C → 300 decimal
BinaryReader reader = ReaderOf(0x82, 0x01, 0x2C);

// WHEN
int length = reader.ReadLength();

// THEN
Assert.AreEqual(300, length);
Assert.AreEqual(3, reader.BaseStream.Position);
}

[TestMethod]
public void ReadLength_ShouldThrow_WhenLengthPrefixTooLarge()
{
// GIVEN
// lower 7 bits = 0x05, meaning "next 5 bytes", exceeding allowed 4
BinaryReader reader = ReaderOf(0x85);

// WHEN-THEN
Assert.ThrowsExactly<IOException>(() => reader.ReadLength());
}

// -----------------------------------------------
// ReadBuffer()
// -----------------------------------------------

[TestMethod]
public void ReadBuffer_ShouldReturnBytes_WhenLengthPrefixed()
{
// GIVEN
// length=3, then bytes 0xAA, 0xBB, 0xCC
BinaryReader reader = ReaderOf(0x03, 0xAA, 0xBB, 0xCC);

// WHEN
byte[] data = reader.ReadBuffer();

// THEN
Assert.HasCount(3, data);
CollectionAssert.AreEqual(new byte[] { 0xAA, 0xBB, 0xCC }, data);
}

// -----------------------------------------------
// ReadShortString()
// -----------------------------------------------

[TestMethod]
public void ReadShortString_ShouldDecodeUtf8StringCorrectly()
{
// GIVEN
string text = "Hello";
byte[] encoded = Encoding.UTF8.GetBytes(text);

byte[] bytes = new byte[] { (byte)encoded.Length }.Concat(encoded).ToArray();
BinaryReader reader = ReaderOf(bytes);

// WHEN
string result = reader.ReadShortString();

// THEN
Assert.AreEqual(text, result);
}

[TestMethod]
public void ReadShortString_ShouldUseSpecifiedEncoding()
{
// GIVEN
string text = "Å";
Encoding encoding = Encoding.UTF32;
byte[] encoded = encoding.GetBytes(text);

byte[] bytes = new byte[] { (byte)encoded.Length }.Concat(encoded).ToArray();
BinaryReader reader = ReaderOf(bytes);

// WHEN
string result = reader.ReadShortString(encoding);

// THEN
Assert.AreEqual(text, result);
}

// -----------------------------------------------
// ReadDateTime()
// -----------------------------------------------

[TestMethod]
public void ReadDateTime_ShouldConvertEpochMilliseconds()
{
// GIVEN
DateTime expected = new DateTime(2024, 01, 01, 12, 00, 00, DateTimeKind.Utc);
long millis = (long)(expected - DateTime.UnixEpoch).TotalMilliseconds;

byte[] encoded = BitConverter.GetBytes(millis);

// Normalize to little-endian, which BinaryReader expects
if (!BitConverter.IsLittleEndian)
Array.Reverse(encoded);

BinaryReader reader = ReaderOf(encoded);

// WHEN
DateTime result = reader.ReadDateTime();

// THEN
Assert.AreEqual(expected, result);
}
}
}
Loading
Loading