Skip to content

Commit 717e6ba

Browse files
committed
Improve test managed edge cases across platforms
1 parent 63f58b1 commit 717e6ba

2 files changed

Lines changed: 120 additions & 5 deletions

File tree

.github/workflows/managed.yml

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,43 @@ on:
1111
pull_request:
1212

1313
jobs:
14+
test:
15+
name: Test (${{ matrix.name }})
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
include:
20+
- name: Linux x64
21+
os: ubuntu-latest
22+
rid: linux-x64
23+
- name: Linux ARM64
24+
os: ubuntu-24.04-arm
25+
rid: linux-arm64
26+
- name: Windows x64
27+
os: windows-latest
28+
rid: win-x64
29+
- name: Windows ARM64
30+
os: windows-11-arm
31+
rid: win-arm64
32+
- name: macOS ARM64
33+
os: macos-latest
34+
rid: osx-arm64
35+
runs-on: ${{ matrix.os }}
36+
steps:
37+
- uses: actions/checkout@v7
38+
- uses: actions/setup-dotnet@v5
39+
with:
40+
global-json-file: src/global.json
41+
- name: Test
42+
run: dotnet test src/Blake3.Tests/Blake3.Tests.csproj --configuration Release --runtime ${{ matrix.rid }}
43+
1444
build:
45+
needs: test
46+
permissions:
47+
id-token: write
48+
actions: write
49+
contents: write
1550
runs-on: 'ubuntu-latest'
1651
steps:
1752
- name: "Build, Test, Pack and Publish"
1853
uses: xoofx/.github/.github/actions/dotnet-releaser-action@main
19-
with:
20-
NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }}

src/Blake3.Tests/ManagedHasherTests.cs

Lines changed: 85 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,17 @@ public class ManagedHasherTests
2222

2323
private static readonly int[] BoundaryLengths =
2424
[
25-
0, 1, 2, 3, 4, 5, 7, 8, 15, 16, 31, 32, 63, 64, 65, 100,
25+
0, 1, 2, 3, 4, 5, 6, 7, 8, 15, 16, 31, 32, 63, 64, 65, 100,
2626
127, 128, 129, 255, 512, 960, 1000, 1023, 1024, 1025, 2048, 2049,
27-
3072, 3073, 4096, 4097, 8192, 8193, 16384, 31744, 102400,
27+
3072, 3073, 4096, 4097, 5120, 5121, 6144, 6145, 7168, 7169, 8192,
28+
8193, 16383, 16384, 16385, 31743, 31744, 31745, 102400,
29+
];
30+
31+
// Mirrors the upstream BLAKE3 test_compare_update_multiple cases through four chunks.
32+
private static readonly int[] IncrementalUpdateLengths =
33+
[
34+
0, 1, 2, 3, 4, 5, 6, 7, 8, 63, 64, 65, 127, 128, 129,
35+
1023, 1024, 1025, 2048, 2049, 3072, 3073, 4096,
2836
];
2937

3038
[Test]
@@ -151,6 +159,30 @@ public void FragmentedUpdatesMatchNative(int length)
151159
});
152160
}
153161

162+
[Test]
163+
public void EveryPairOfBoundaryUpdatesMatchesNative()
164+
{
165+
const int OutputLength = 303;
166+
foreach (var firstLength in IncrementalUpdateLengths)
167+
{
168+
foreach (var secondLength in IncrementalUpdateLengths)
169+
{
170+
var input = CreateVectorInput(firstLength + secondLength);
171+
var expected = new byte[OutputLength];
172+
var actual = new byte[OutputLength];
173+
Hasher.Hash(input, expected);
174+
175+
using var managed = ManagedHasher.New();
176+
managed.Update(input.AsSpan(0, firstLength));
177+
managed.Update(input.AsSpan(firstLength, secondLength));
178+
managed.Finalize(actual);
179+
180+
Assert.That(actual, Is.EqualTo(expected),
181+
$"firstLength={firstLength}, secondLength={secondLength}");
182+
}
183+
}
184+
}
185+
154186
[TestCase(0)]
155187
[TestCase(1)]
156188
[TestCase(64)]
@@ -214,6 +246,33 @@ public void XofSeekResetJoinAndGenericUpdatesMatchNative()
214246
Assert.That(ManagedHasher.Hash(MemoryMarshal.AsBytes(values.AsSpan())), Is.EqualTo(managed.Finalize()));
215247
}
216248

249+
[Test]
250+
public void ResetPreservesKeyedAndDeriveKeyModes()
251+
{
252+
var discardedInput = CreateVectorInput((3 * 1024) + 7);
253+
var input = CreateVectorInput(1027);
254+
255+
using var nativeKeyed = Hasher.NewKeyed(VectorKey);
256+
using var managedKeyed = ManagedHasher.NewKeyed(VectorKey);
257+
managedKeyed.Update(discardedInput);
258+
managedKeyed.Reset();
259+
nativeKeyed.Update(input);
260+
managedKeyed.Update(input);
261+
262+
using var nativeDerived = Hasher.NewDeriveKey(VectorContext);
263+
using var managedDerived = ManagedHasher.NewDeriveKey(VectorContext);
264+
managedDerived.Update(discardedInput);
265+
managedDerived.Reset();
266+
nativeDerived.Update(input);
267+
managedDerived.Update(input);
268+
269+
Assert.Multiple(() =>
270+
{
271+
AssertManagedHashEqualsNative(managedKeyed.Finalize(), nativeKeyed.Finalize());
272+
AssertManagedHashEqualsNative(managedDerived.Finalize(), nativeDerived.Finalize());
273+
});
274+
}
275+
217276
[TestCase(262143)]
218277
[TestCase(262144)]
219278
[TestCase(300123)]
@@ -324,6 +383,20 @@ public void DeriveKeyByteContextUsesNativeLossyUtf8Semantics()
324383
AssertManagedHashEqualsNative(managed.Finalize(), native.Finalize());
325384
}
326385

386+
[TestCase("")]
387+
[TestCase("BLAKE3 managed context \u2026 \u2603 \u2014 \ud83d\udd11")]
388+
[TestCase("context with unpaired surrogate \ud800")]
389+
public void DeriveKeyStringContextMatchesNativeForUnicode(string context)
390+
{
391+
using var native = Hasher.NewDeriveKey(context);
392+
using var managed = ManagedHasher.NewDeriveKey(context);
393+
var input = CreateVectorInput(1025);
394+
native.Update(input);
395+
managed.Update(input);
396+
397+
AssertManagedHashEqualsNative(managed.Finalize(), native.Finalize());
398+
}
399+
327400
[Test]
328401
public void DisposedHasherRejectsOperations()
329402
{
@@ -333,19 +406,28 @@ public void DisposedHasherRejectsOperations()
333406
Assert.Multiple(() =>
334407
{
335408
Assert.Throws<ObjectDisposedException>(() => hasher.Update([1]));
409+
Assert.Throws<ObjectDisposedException>(() => hasher.Update<int>([1]));
336410
Assert.Throws<ObjectDisposedException>(() => hasher.UpdateWithJoin([1]));
411+
Assert.Throws<ObjectDisposedException>(() => hasher.UpdateWithJoin<int>([1]));
337412
Assert.Throws<ObjectDisposedException>(() => hasher.Finalize());
413+
Assert.Throws<ObjectDisposedException>(() => hasher.Finalize(new byte[1]));
414+
Assert.Throws<ObjectDisposedException>(() => hasher.Finalize(0L, new byte[1]));
415+
Assert.Throws<ObjectDisposedException>(() => hasher.Finalize(0UL, new byte[1]));
338416
Assert.Throws<ObjectDisposedException>(() => hasher.Reset());
417+
Assert.DoesNotThrow(hasher.Dispose);
339418
});
340419
}
341420

342421
[Test]
343-
public void KeyMustBeExactly32Bytes()
422+
public void InvalidArgumentsAreRejected()
344423
{
424+
using var hasher = ManagedHasher.New();
345425
Assert.Multiple(() =>
346426
{
347427
Assert.Throws<ArgumentOutOfRangeException>(() => ManagedHasher.NewKeyed(new byte[31]));
348428
Assert.Throws<ArgumentOutOfRangeException>(() => ManagedHasher.NewKeyed(new byte[33]));
429+
Assert.Throws<ArgumentNullException>(() => ManagedHasher.NewDeriveKey((string)null!));
430+
Assert.Throws<ArgumentOutOfRangeException>(() => hasher.Finalize(-1L, new byte[1]));
349431
});
350432
}
351433

0 commit comments

Comments
 (0)