Skip to content

Commit

Permalink
Apply feedbacks
Browse files Browse the repository at this point in the history
  • Loading branch information
buyaa-n committed Jul 25, 2024
1 parent ecd4907 commit e206031
Show file tree
Hide file tree
Showing 11 changed files with 150 additions and 322 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,16 @@ public static IEnumerable<object[]> UncompressedTestFiles()
yield return new object[] { Path.Combine("UncompressedTestFiles", "sum") };
yield return new object[] { Path.Combine("UncompressedTestFiles", "xargs.1") };
}
public static IEnumerable<object[]> UncompressedTestFilesZLib()
{
yield return new object[] { Path.Combine("UncompressedTestFiles", "TestDocument.doc") };
yield return new object[] { Path.Combine("UncompressedTestFiles", "TestDocument.docx") };
yield return new object[] { Path.Combine("UncompressedTestFiles", "TestDocument.pdf") };
yield return new object[] { Path.Combine("UncompressedTestFiles", "sum") };
}
public static IEnumerable<object[]> ZLibOptionsRoundTripTestData()
{
yield return new object[] { Path.Combine("UncompressedTestFiles", "TestDocument.doc"), new ZLibCompressionOptions() { CompressionLevel = -1, CompressionStrategy = ZLibCompressionStrategy.Default } };
yield return new object[] { Path.Combine("UncompressedTestFiles", "TestDocument.doc"), new ZLibCompressionOptions() { CompressionLevel = 0, CompressionStrategy = ZLibCompressionStrategy.Default } };
yield return new object[] { Path.Combine("UncompressedTestFiles", "TestDocument.docx"), new ZLibCompressionOptions() { CompressionLevel = 3, CompressionStrategy = ZLibCompressionStrategy.Filtered } };
yield return new object[] { Path.Combine("UncompressedTestFiles", "TestDocument.pdf"), new ZLibCompressionOptions() { CompressionLevel = 5, CompressionStrategy = ZLibCompressionStrategy.RunLengthEncoding } };
yield return new object[] { Path.Combine("UncompressedTestFiles", "TestDocument.txt"), new ZLibCompressionOptions() { CompressionLevel = 7, CompressionStrategy = ZLibCompressionStrategy.HuffmanOnly } };
Expand All @@ -38,7 +45,7 @@ public static IEnumerable<object[]> ZLibOptionsRoundTripTestData()
yield return new object[] { Path.Combine("UncompressedTestFiles", "cp.html"), new ZLibCompressionOptions() { CompressionLevel = 4, CompressionStrategy = ZLibCompressionStrategy.Default } };
yield return new object[] { Path.Combine("UncompressedTestFiles", "fields.c"), new ZLibCompressionOptions() { CompressionLevel = 6, CompressionStrategy = ZLibCompressionStrategy.HuffmanOnly } };
yield return new object[] { Path.Combine("UncompressedTestFiles", "grammar.lsp"), new ZLibCompressionOptions() { CompressionLevel = 8, CompressionStrategy = ZLibCompressionStrategy.Default } };
yield return new object[] { Path.Combine("UncompressedTestFiles", "kennedy.xls"), new ZLibCompressionOptions() { CompressionLevel = -1, CompressionStrategy = ZLibCompressionStrategy.Fixed } };
yield return new object[] { Path.Combine("UncompressedTestFiles", "kennedy.xls"), new ZLibCompressionOptions() { CompressionLevel = 1, CompressionStrategy = ZLibCompressionStrategy.Fixed } };
yield return new object[] { Path.Combine("UncompressedTestFiles", "lcet10.txt"), new ZLibCompressionOptions() { CompressionLevel = 1, CompressionStrategy = ZLibCompressionStrategy.Filtered } };
yield return new object[] { Path.Combine("UncompressedTestFiles", "plrabn12.txt"), new ZLibCompressionOptions() { CompressionLevel = 2, CompressionStrategy = ZLibCompressionStrategy.RunLengthEncoding } };
yield return new object[] { Path.Combine("UncompressedTestFiles", "ptt5"), new ZLibCompressionOptions() { CompressionLevel = 3, CompressionStrategy = ZLibCompressionStrategy.Default } };
Expand All @@ -55,6 +62,7 @@ public abstract class CompressionStreamTestBase : CompressionTestBase
public abstract Stream CreateStream(Stream stream, CompressionMode mode, bool leaveOpen);
public abstract Stream CreateStream(Stream stream, CompressionLevel level);
public abstract Stream CreateStream(Stream stream, CompressionLevel level, bool leaveOpen);
public abstract Stream CreateStream(Stream stream, ZLibCompressionOptions options, bool leaveOpen);
public abstract Stream BaseStream(Stream stream);
public virtual int BufferSize { get => 8192; }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,13 +369,14 @@ public async Task TestLeaveOpenAfterValidDecompress()
[Fact]
public void Ctor_ArgumentValidation()
{
Assert.Throws<ArgumentNullException>(() => CreateStream(null, CompressionLevel.Fastest));
Assert.Throws<ArgumentNullException>(() => CreateStream(null, CompressionMode.Decompress));
Assert.Throws<ArgumentNullException>(() => CreateStream(null, CompressionMode.Compress));
Assert.Throws<ArgumentNullException>("stream", () => CreateStream(null, CompressionLevel.Fastest));
Assert.Throws<ArgumentNullException>("stream", () => CreateStream(null, CompressionMode.Decompress));
Assert.Throws<ArgumentNullException>("stream", () => CreateStream(null, CompressionMode.Compress));

Assert.Throws<ArgumentNullException>(() => CreateStream(null, CompressionLevel.Fastest, true));
Assert.Throws<ArgumentNullException>(() => CreateStream(null, CompressionMode.Decompress, false));
Assert.Throws<ArgumentNullException>(() => CreateStream(null, CompressionMode.Compress, true));
Assert.Throws<ArgumentNullException>("stream", () => CreateStream(null, CompressionLevel.Fastest, true));
Assert.Throws<ArgumentNullException>("stream", () => CreateStream(null, CompressionMode.Decompress, false));
Assert.Throws<ArgumentNullException>("stream", () => CreateStream(null, CompressionMode.Compress, true));
Assert.Throws<ArgumentNullException>("compressionOptions", () => CreateStream(new MemoryStream(), null, true));

AssertExtensions.Throws<ArgumentException>("mode", () => CreateStream(new MemoryStream(), (CompressionMode)42));
AssertExtensions.Throws<ArgumentException>("mode", () => CreateStream(new MemoryStream(), (CompressionMode)43, true));
Expand Down Expand Up @@ -471,7 +472,7 @@ public async Task BaseStream_ValidAfterDisposeWithTrueLeaveOpen(CompressionMode
}

[Theory]
[MemberData(nameof(UncompressedTestFiles))]
[MemberData(nameof(UncompressedTestFilesZLib))]
public async Task CompressionLevel_SizeInOrder(string testFile)
{
using var uncompressedStream = await LocalMemoryStream.readAppFileAsync(testFile);
Expand All @@ -493,7 +494,59 @@ async Task<long> GetLengthAsync(CompressionLevel compressionLevel)

Assert.True(noCompressionLength >= fastestLength);
Assert.True(fastestLength >= optimalLength);
// Assert.True(optimalLength >= smallestLength); // for some files this condition is failing (cp.html, grammar.lsp, xargs.1)
Assert.True(optimalLength >= smallestLength);
}

[Theory]
[MemberData(nameof(ZLibOptionsRoundTripTestData))]
public async Task RoundTripWithZLibCompressionOptions(string testFile, ZLibCompressionOptions options)
{
var uncompressedStream = await LocalMemoryStream.readAppFileAsync(testFile);
var compressedStream = CompressTestFile(uncompressedStream, options);
using var decompressor = CreateStream(compressedStream, mode: CompressionMode.Decompress);
var decompressorOutput = new MemoryStream();
int _bufferSize = 1024;
var bytes = new byte[_bufferSize];
bool finished = false;
int retCount;
while (!finished)
{
retCount = await decompressor.ReadAsync(bytes, 0, _bufferSize);

if (retCount != 0)
await decompressorOutput.WriteAsync(bytes, 0, retCount);
else
finished = true;
}
decompressor.Dispose();
decompressorOutput.Position = 0;
uncompressedStream.Position = 0;

byte[] uncompressedStreamBytes = uncompressedStream.ToArray();
byte[] decompressorOutputBytes = decompressorOutput.ToArray();

Assert.Equal(uncompressedStreamBytes.Length, decompressorOutputBytes.Length);
for (int i = 0; i < uncompressedStreamBytes.Length; i++)
{
Assert.Equal(uncompressedStreamBytes[i], decompressorOutputBytes[i]);
}
}

private MemoryStream CompressTestFile(LocalMemoryStream testStream, ZLibCompressionOptions options)
{
var compressorOutput = new MemoryStream();
using (var compressionStream = CreateStream(compressorOutput, options, leaveOpen: true))
{
var buffer = new byte[4096];
int bytesRead;
while ((bytesRead = testStream.Read(buffer, 0, buffer.Length)) > 0)
{
compressionStream.Write(buffer, 0, bytesRead);
}
}

compressorOutput.Position = 0;
return compressorOutput;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ public sealed partial class BrotliStream : Stream
/// <summary>Initializes a new instance of the <see cref="System.IO.Compression.BrotliStream" /> class by using the specified stream and compression level.</summary>
/// <param name="stream">The stream to which compressed data is written.</param>
/// <param name="compressionLevel">One of the enumeration values that indicates whether to emphasize speed or compression efficiency when compressing data to the stream.</param>
/// <exception cref="ArgumentNullException"/> if <paramref name="stream"/> is <see langword="null" />.
public BrotliStream(Stream stream, CompressionLevel compressionLevel) : this(stream, compressionLevel, leaveOpen: false) { }

/// <summary>Initializes a new instance of the <see cref="System.IO.Compression.BrotliStream" /> class by using the specified stream and compression level, and optionally leaves the stream open.</summary>
/// <param name="stream">The stream to which compressed data is written.</param>
/// <param name="compressionLevel">One of the enumeration values that indicates whether to emphasize speed or compression efficiency when compressing data to the stream.</param>
/// <param name="leaveOpen"><see langword="true" /> to leave the stream open after disposing the <see cref="System.IO.Compression.BrotliStream" /> object; otherwise, <see langword="false" />.</param>
/// <exception cref="ArgumentNullException"/> if <paramref name="stream"/> is <see langword="null" />.
public BrotliStream(Stream stream, CompressionLevel compressionLevel, bool leaveOpen) : this(stream, CompressionMode.Compress, leaveOpen)
{
_encoder.SetQuality(BrotliUtils.GetQualityFromCompressionLevel(compressionLevel));
Expand All @@ -33,8 +35,11 @@ public BrotliStream(Stream stream, CompressionLevel compressionLevel, bool leave
/// <param name="stream">The stream to which compressed data is written.</param>
/// <param name="compressionOptions">The Brotli options for fine tuning the compression stream.</param>
/// <param name="leaveOpen"><see langword="true" /> to leave the stream open after disposing the <see cref="System.IO.Compression.BrotliStream" /> object; otherwise, <see langword="false" />.</param>
/// <exception cref="ArgumentNullException"/> if <paramref name="stream"/> or <paramref name="compressionOptions"/> is <see langword="null" />.
public BrotliStream(Stream stream, BrotliCompressionOptions compressionOptions, bool leaveOpen = false) : this(stream, CompressionMode.Compress, leaveOpen)
{
ArgumentNullException.ThrowIfNull(compressionOptions);

_encoder.SetQuality(compressionOptions.Quality);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,25 @@ public class BrotliStreamUnitTests : CompressionStreamUnitTestBase
public override Stream CreateStream(Stream stream, CompressionMode mode, bool leaveOpen) => new BrotliStream(stream, mode, leaveOpen);
public override Stream CreateStream(Stream stream, CompressionLevel level) => new BrotliStream(stream, level);
public override Stream CreateStream(Stream stream, CompressionLevel level, bool leaveOpen) => new BrotliStream(stream, level, leaveOpen);
public override Stream CreateStream(Stream stream, ZLibCompressionOptions options, bool leaveOpen) =>
new BrotliStream(stream, options == null ? null : new BrotliCompressionOptions() { Quality = options.CompressionLevel }, leaveOpen);
public override Stream BaseStream(Stream stream) => ((BrotliStream)stream).BaseStream;

protected override bool FlushGuaranteesAllDataWritten => false;

public static IEnumerable<object[]> UncompressedTestFilesBrotli()
{
yield return new object[] { Path.Combine("UncompressedTestFiles", "TestDocument.txt") };
yield return new object[] { Path.Combine("UncompressedTestFiles", "alice29.txt") };
yield return new object[] { Path.Combine("UncompressedTestFiles", "asyoulik.txt") };
yield return new object[] { Path.Combine("UncompressedTestFiles", "cp.html") };
yield return new object[] { Path.Combine("UncompressedTestFiles", "fields.c") };
yield return new object[] { Path.Combine("UncompressedTestFiles", "lcet10.txt") };
yield return new object[] { Path.Combine("UncompressedTestFiles", "plrabn12.txt") };
yield return new object[] { Path.Combine("UncompressedTestFiles", "sum") };
yield return new object[] { Path.Combine("UncompressedTestFiles", "xargs.1") };
}

// The tests are relying on an implementation detail of BrotliStream, using knowledge of its internal buffer size
// in various test calculations. Currently the implementation is using the ArrayPool, which will round up to a
// power-of-2. If the buffer size employed changes (which could also mean that ArrayPool<byte>.Shared starts giving
Expand Down Expand Up @@ -77,55 +92,8 @@ public void InvalidBrotliCompressionQuality()
Assert.Throws<ArgumentOutOfRangeException>("value", () => options.Quality = 12);
}

public static IEnumerable<object[]> BrotliOptionsRoundTripTestData()
{
yield return new object[] { 1000, new BrotliCompressionOptions() { Quality = 0 } };
yield return new object[] { 900, new BrotliCompressionOptions() { Quality = 3 } };
yield return new object[] { 1200, new BrotliCompressionOptions() { Quality = 5 } };
yield return new object[] { 2000, new BrotliCompressionOptions() { Quality = 6 } };
yield return new object[] { 3000, new BrotliCompressionOptions() { Quality = 2 } };
yield return new object[] { 1500, new BrotliCompressionOptions() { Quality = 7 } };
yield return new object[] { 500, new BrotliCompressionOptions() { Quality = 9 } };
yield return new object[] { 1000, new BrotliCompressionOptions() { Quality = 11 } };
}

[Theory]
[MemberData(nameof(BrotliOptionsRoundTripTestData))]
public static void Roundtrip_WriteByte_ReadByte_DifferentQuality_Success(int totalLength, BrotliCompressionOptions options)
{
byte[] correctUncompressedBytes = Enumerable.Range(0, totalLength).Select(i => (byte)i).ToArray();

byte[] compressedBytes;
using (var ms = new MemoryStream())
{
var bs = new BrotliStream(ms, options);
foreach (byte b in correctUncompressedBytes)
{
bs.WriteByte(b);
}
bs.Dispose();
compressedBytes = ms.ToArray();
}

byte[] decompressedBytes = new byte[correctUncompressedBytes.Length];
using (var ms = new MemoryStream(compressedBytes))
using (var bs = new BrotliStream(ms, CompressionMode.Decompress))
{
for (int i = 0; i < decompressedBytes.Length; i++)
{
int b = bs.ReadByte();
Assert.InRange(b, 0, 255);
decompressedBytes[i] = (byte)b;
}
Assert.Equal(-1, bs.ReadByte());
Assert.Equal(-1, bs.ReadByte());
}

Assert.Equal<byte>(correctUncompressedBytes, decompressedBytes);
}

[Theory]
[MemberData(nameof(UncompressedTestFiles))]
[MemberData(nameof(UncompressedTestFilesBrotli))]
public async void BrotliCompressionQuality_SizeInOrder(string testFile)
{
using var uncompressedStream = await LocalMemoryStream.readAppFileAsync(testFile);
Expand Down Expand Up @@ -156,11 +124,11 @@ async Task<long> GetLengthAsync(int compressionQuality)

Assert.True(quality1 <= quality0);
Assert.True(quality2 <= quality1);
Assert.True(quality3 <= quality1);
Assert.True(quality4 <= quality2);
Assert.True(quality5 <= quality1);
Assert.True(quality6 <= quality1);
Assert.True(quality7 <= quality4);
Assert.True(quality3 <= quality2);
Assert.True(quality4 <= quality3);
Assert.True(quality5 <= quality4);
Assert.True(quality6 <= quality5);
Assert.True(quality7 <= quality6);
Assert.True(quality8 <= quality7);
Assert.True(quality9 <= quality8);
Assert.True(quality10 <= quality9);
Expand Down
Loading

0 comments on commit e206031

Please sign in to comment.