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
2 changes: 2 additions & 0 deletions src/ZLogger/Internal/Shims/Shims.NetStandard2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ internal static partial class Shims
{
public static int GetBytes(this Encoding encoding, ReadOnlySpan<char> chars, ReadOnlySpan<byte> bytes)
{
if (chars.Length == 0 || bytes.Length == 0) return 0;
unsafe
{
fixed (char* charsPtr = &chars[0])
Expand All @@ -19,6 +20,7 @@ public static int GetBytes(this Encoding encoding, ReadOnlySpan<char> chars, Rea

public static string GetString(this Encoding encoding, ReadOnlySpan<byte> bytes)
{
if (bytes.Length == 0) return string.Empty;
unsafe
{
fixed (byte* bytesPtr = &bytes[0])
Expand Down
2 changes: 2 additions & 0 deletions tests/ZLogger.Tests/EnumDictionaryTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ public void HttpStatusCodeTest()
{
EnumDictionary<HttpStatusCode>.GetStringName(HttpStatusCode.InternalServerError).Should().Be("InternalServerError");
EnumDictionary<HttpStatusCode>.GetStringName(HttpStatusCode.RequestEntityTooLarge).Should().Be("RequestEntityTooLarge");
#if NET
EnumDictionary<HttpStatusCode>.GetUtf8Name(HttpStatusCode.NetworkAuthenticationRequired).ToArray().Should().Equal(Encoding.UTF8.GetBytes("NetworkAuthenticationRequired"));
EnumDictionary<HttpStatusCode>.GetJsonEncodedName(HttpStatusCode.UnprocessableEntity).Should().Be(JsonEncodedText.Encode("UnprocessableEntity"));
#endif
}
}

Expand Down
18 changes: 9 additions & 9 deletions tests/ZLogger.Tests/RollingFileProviderTest.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
Expand All @@ -11,7 +11,7 @@ namespace ZLogger.Tests;

public class RollingFileProviderTest
{
readonly string directory = Path.Join(Path.GetTempPath(), "zlogger-test");
readonly string directory = Path.Combine(Path.GetTempPath(), "zlogger-test");

public RollingFileProviderTest()
{
Expand All @@ -30,15 +30,15 @@ public async Task RollByInterval()
{
var timeProvider = new FakeTimeProvider(new DateTimeOffset(2000, 1, 2, 3, 4, 5, TimeSpan.Zero));

var path1= Path.Join(directory, $"ZLoggerRollingTest_{timeProvider.GetUtcNow():yyyy-MM-dd}-0.log");
var path1= Path.Combine(directory, $"ZLoggerRollingTest_{timeProvider.GetUtcNow():yyyy-MM-dd}-0.log");
if (File.Exists(path1)) File.Delete(path1);

using var loggerFactory = LoggerFactory.Create(x =>
{
x.SetMinimumLevel(LogLevel.Debug);
x.AddZLoggerRollingFile(options =>
{
options.FilePathSelector = (dt, seq) => Path.Join(directory, $"ZLoggerRollingTest_{dt:yyyy-MM-dd}-{seq}.log");
options.FilePathSelector = (dt, seq) => Path.Combine(directory, $"ZLoggerRollingTest_{dt:yyyy-MM-dd}-{seq}.log");
options.RollingInterval = RollingInterval.Day;
options.RollingSizeKB = 5;
options.TimeProvider = timeProvider;
Expand All @@ -57,7 +57,7 @@ public async Task RollByInterval()

// Next day
timeProvider.Advance(TimeSpan.FromDays(1));
var path2 = Path.Join(directory, $"ZLoggerRollingTest_{timeProvider.GetUtcNow():yyyy-MM-dd}-0.log");
var path2 = Path.Combine(directory, $"ZLoggerRollingTest_{timeProvider.GetUtcNow():yyyy-MM-dd}-0.log");
logger.LogDebug("a");
logger.LogDebug("v");
logger.LogDebug("c");
Expand Down Expand Up @@ -89,15 +89,15 @@ public async Task RollBySize()
{
var timeProvider = new FakeTimeProvider(new DateTimeOffset(2000, 1, 2, 3, 4, 5, TimeSpan.Zero));

var path1 = Path.Join(directory, $"ZLoggerRollingTest_{timeProvider.GetUtcNow():yyyy-MM-dd}-0.log");
var path2 = Path.Join(directory, $"ZLoggerRollingTest_{timeProvider.GetUtcNow():yyyy-MM-dd}-1.log");
var path1 = Path.Combine(directory, $"ZLoggerRollingTest_{timeProvider.GetUtcNow():yyyy-MM-dd}-0.log");
var path2 = Path.Combine(directory, $"ZLoggerRollingTest_{timeProvider.GetUtcNow():yyyy-MM-dd}-1.log");

using var loggerFactory = LoggerFactory.Create(x =>
{
x.SetMinimumLevel(LogLevel.Debug);
x.AddZLoggerRollingFile(options =>
{
options.FilePathSelector = (dt, seq) => Path.Join(directory, $"ZLoggerRollingTest_{dt:yyyy-MM-dd}-{seq}.log");
options.FilePathSelector = (dt, seq) => Path.Combine(directory, $"ZLoggerRollingTest_{dt:yyyy-MM-dd}-{seq}.log");
options.RollingInterval = RollingInterval.Day;
options.RollingSizeKB = 5;
options.TimeProvider = timeProvider;
Expand All @@ -119,4 +119,4 @@ static StreamReader OpenFile(string path)
{
return new StreamReader(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read), Encoding.UTF8);
}
}
}
134 changes: 134 additions & 0 deletions tests/ZLogger.Tests/ShimTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#if NETFRAMEWORK
using System;
using System.Text;

namespace ZLogger.Tests
{
public class ShimNetStandardTests
{
[Theory]
[InlineData("")]
[InlineData("a")]
[InlineData("hello")]
[InlineData("Живко")] // Cyrillic
[InlineData("mañana café")] // Latin-1 accents
[InlineData("汉字テスト")] // CJK/Kana mix
public void GetBytes_Matches_Framework_For_Exact_Buffer_Utf8(string text)
{
var enc = Encoding.UTF8;

// What the framework would produce (reference)
var expected = enc.GetBytes(text);

// Exact-size buffer
var buffer = new byte[expected.Length];

// IMPORTANT: call the shim explicitly (avoid BCL span overload)
int written = Shims.GetBytes(enc, text.AsSpan(), buffer.AsSpan());

written.Should().Be(expected.Length);
buffer.Should().Equal(expected);
}

[Theory]
[InlineData("")]
[InlineData("a")]
[InlineData("hello")]
[InlineData("Žužu")] // Latin-2
[InlineData("Здрасти")] // Bulgarian
public void GetBytes_Matches_Framework_For_Exact_Buffer_Unicode(string text)
{
var enc = Encoding.Unicode; // UTF-16 LE
var expected = enc.GetBytes(text);
var buffer = new byte[expected.Length];

int written = Shims.GetBytes(enc, text.AsSpan(), buffer.AsSpan());

written.Should().Be(expected.Length);
buffer.Should().Equal(expected);
}

[Fact]
public void GetBytes_Returns_Zero_When_Chars_Empty()
{
var enc = Encoding.UTF8;
var buf = new byte[16];

int written = Shims.GetBytes(enc, ReadOnlySpan<char>.Empty, buf);

written.Should().Be(0);
buf.Should().OnlyContain(b => b == 0); // untouched
}

[Fact]
public void GetBytes_Returns_Zero_When_Bytes_Empty()
{
var enc = Encoding.UTF8;
var text = "whatever";

int written = Shims.GetBytes(enc, text.AsSpan(), ReadOnlySpan<byte>.Empty);

written.Should().Be(0);
}

[Theory]
[InlineData("hello")]
[InlineData("Здрасти")]
[InlineData("mañana café")]
[InlineData("漢字テスト")]
public void GetString_Matches_Framework(string text)
{
var enc = Encoding.UTF8;
var bytes = enc.GetBytes(text);

// Slice in the middle too, to ensure length parameter is respected.
var span = new ReadOnlySpan<byte>(bytes);

string shim = Shims.GetString(enc, span);
string bcl = enc.GetString(bytes);

shim.Should().Be(bcl);
}

[Fact]
public void GetString_Returns_Empty_On_Empty_Bytes()
{
var enc = Encoding.UTF8;
Shims.GetString(enc, ReadOnlySpan<byte>.Empty).Should().Be(string.Empty);
}

[Theory]
[InlineData("x", 'x', true)]
[InlineData("xyz", 'x', true)]
[InlineData("xyz", 'y', false)]
[InlineData("", 'x', false)]
[InlineData("Жоро", 'Ж', true)]
[InlineData("жоро", 'Ж', false)]
public void StartsWith_Behavior(string input, char value, bool expected)
{
// Explicit call to the shim — do NOT rely on string.StartsWith(char) on newer TFMs
bool actual = Shims.StartsWith(input, value);
actual.Should().Be(expected);
}

[Fact]
public void GetBytes_With_Partial_Slice_Writes_For_Slice_Length()
{
var enc = Encoding.UTF8;
const string text = "ABCDE";

var full = enc.GetBytes(text);
// Give the shim only the first 3 chars and a correctly sized byte buffer for those 3
var chars = text.AsSpan(0, 3);

var expected = enc.GetBytes(chars.ToArray()); // reference for 3 chars
var buffer = new byte[expected.Length];

int written = Shims.GetBytes(enc, chars, buffer);

written.Should().Be(expected.Length);
buffer.Should().Equal(expected);
}
}
}
#endif
3 changes: 2 additions & 1 deletion tests/ZLogger.Tests/ZLogger.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<TargetFrameworks>net8.0;net48</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>latest</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand Down