using System.Collections.Generic; using System.Formats.Tar; using System.IO; using FluentAssertions; using StellaOps.Replay.Core; using ZstdSharp; using Xunit; namespace StellaOps.Replay.Core.Tests; public sealed class ReplayBundleWriterTests { [Fact] public async Task WriteTarZstAsync_IsDeterministicAndSorted() { var entries = new[] { new ReplayBundleEntry("b.txt", "beta"u8.ToArray()), new ReplayBundleEntry("a.txt", "alpha"u8.ToArray()) }; await using var buffer = new MemoryStream(); var first = await ReplayBundleWriter.WriteTarZstAsync(entries, buffer, compressionLevel: 3); var firstBytes = buffer.ToArray(); await using var buffer2 = new MemoryStream(); var second = await ReplayBundleWriter.WriteTarZstAsync(entries.Reverse(), buffer2, compressionLevel: 3); first.ZstSha256.Should().Be(second.ZstSha256); first.TarSha256.Should().Be(second.TarSha256); firstBytes.Should().Equal(buffer2.ToArray()); // Decompress and verify ordering/content buffer.Position = 0; await using var decompressed = new MemoryStream(); await using (var decompress = new DecompressionStream(buffer, 16 * 1024, leaveOpen: true, enableMultiThreaded: false)) { await decompress.CopyToAsync(decompressed); } decompressed.Position = 0; var reader = new TarReader(decompressed, leaveOpen: true); var names = new List(); TarEntry? entry; while ((entry = reader.GetNextEntry()) != null) { names.Add(entry.Name); using var ms = new MemoryStream(); entry.DataStream!.CopyTo(ms); var text = System.Text.Encoding.UTF8.GetString(ms.ToArray()); text.Should().Be(entry.Name.StartsWith("a") ? "alpha" : "beta"); } names.Should().BeEquivalentTo(new[] { "a.txt", "b.txt" }, opts => opts.WithStrictOrdering()); } [Fact] public void BuildCasUri_UsesPrefixAndShard() { ReplayBundleWriter.BuildCasUri("abcdef", null).Should().Be("cas://replay/ab/abcdef.tar.zst"); ReplayBundleWriter.BuildCasUri("1234", "custom").Should().Be("cas://custom/12/1234.tar.zst"); } }