From d876b0bbe012b5d9fd425fa2658c8960e8a6e594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nils=20m=C3=A5s=C3=A9n?= Date: Sat, 9 Oct 2021 20:59:39 +0200 Subject: [PATCH 1/6] feat(gzip): add GzipOutputStream async support --- .../GZip/GzipOutputStream.cs | 184 +++++++++++++----- .../GZip/GZipTests.cs | 45 +++++ 2 files changed, 181 insertions(+), 48 deletions(-) diff --git a/src/ICSharpCode.SharpZipLib/GZip/GzipOutputStream.cs b/src/ICSharpCode.SharpZipLib/GZip/GzipOutputStream.cs index 0b1a647fe..b15e7a5b4 100644 --- a/src/ICSharpCode.SharpZipLib/GZip/GzipOutputStream.cs +++ b/src/ICSharpCode.SharpZipLib/GZip/GzipOutputStream.cs @@ -3,7 +3,9 @@ using ICSharpCode.SharpZipLib.Zip.Compression.Streams; using System; using System.IO; -using System.Text; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; namespace ICSharpCode.SharpZipLib.GZip { @@ -162,6 +164,26 @@ public override void Write(byte[] buffer, int offset, int count) base.Write(buffer, offset, count); } +#if NETSTANDARD2_1_OR_GREATER + /// + public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + + if (state_ == OutputState.Header) + { + await WriteHeaderAsync(); + } + + if (state_ != OutputState.Footer) + { + throw new InvalidOperationException("Write not permitted in current state"); + } + + crc.Update(new ArraySegment(buffer, offset, count)); + await base.WriteAsync(buffer, offset, count, cancellationToken); + } +#endif + /// /// Writes remaining compressed output data to the output stream /// and closes it. @@ -184,6 +206,30 @@ protected override void Dispose(bool disposing) } } } + +#if NETSTANDARD2_1_OR_GREATER + /// + public override async ValueTask DisposeAsync() + { + try + { + await FinishAsync(CancellationToken.None); + } + finally + { + if (state_ != OutputState.Closed) + { + state_ = OutputState.Closed; + if (IsStreamOwner) + { + await baseOutputStream_.DisposeAsync(); + } + } + + await base.DisposeAsync(); + } + } +#endif /// /// Flushes the stream by ensuring the header is written, and then calling Flush @@ -218,75 +264,117 @@ public override void Finish() { state_ = OutputState.Finished; base.Finish(); + + byte[] gzipFooter = GetFooter(); - var totalin = (uint)(deflater_.TotalIn & 0xffffffff); - var crcval = (uint)(crc.Value & 0xffffffff); - - byte[] gzipFooter; - - unchecked - { - gzipFooter = new byte[] { - (byte) crcval, (byte) (crcval >> 8), - (byte) (crcval >> 16), (byte) (crcval >> 24), + baseOutputStream_.Write(gzipFooter, 0, gzipFooter.Length); + } + } - (byte) totalin, (byte) (totalin >> 8), - (byte) (totalin >> 16), (byte) (totalin >> 24) - }; - } +#if NETSTANDARD2_1_OR_GREATER + /// + public override async Task FinishAsync(CancellationToken ct) + { + // If no data has been written a header should be added. + if (state_ == OutputState.Header) + { + await WriteHeaderAsync(); + } - baseOutputStream_.Write(gzipFooter, 0, gzipFooter.Length); + if (state_ == OutputState.Footer) + { + state_ = OutputState.Finished; + await base.FinishAsync(ct); + await baseOutputStream_.WriteAsync(GetFooter(), ct); } } +#endif #endregion DeflaterOutputStream overrides #region Support Routines - private static string CleanFilename(string path) - => path.Substring(path.LastIndexOf('/') + 1); - - private void WriteHeader() + private byte[] GetFooter() { - if (state_ == OutputState.Header) - { - state_ = OutputState.Footer; + var totalin = (uint)(deflater_.TotalIn & 0xffffffff); + var crcval = (uint)(crc.Value & 0xffffffff); - var mod_time = (int)((DateTime.Now.Ticks - new DateTime(1970, 1, 1).Ticks) / 10000000L); // Ticks give back 100ns intervals - byte[] gzipHeader = { - // The two magic bytes - GZipConstants.ID1, - GZipConstants.ID2, + byte[] gzipFooter; + + unchecked + { + gzipFooter = new [] { + (byte) crcval, + (byte) (crcval >> 8), + (byte) (crcval >> 16), + (byte) (crcval >> 24), + (byte) totalin, + (byte) (totalin >> 8), + (byte) (totalin >> 16), + (byte) (totalin >> 24), + }; + } - // The compression type - GZipConstants.CompressionMethodDeflate, + return gzipFooter; + } - // The flags (not set) - (byte)flags, + private byte[] GetHeader() + { + var modTime = (int)((DateTime.Now.Ticks - new DateTime(1970, 1, 1).Ticks) / 10000000L); // Ticks give back 100ns intervals + byte[] gzipHeader = { + // The two magic bytes + GZipConstants.ID1, + GZipConstants.ID2, - // The modification time - (byte) mod_time, (byte) (mod_time >> 8), - (byte) (mod_time >> 16), (byte) (mod_time >> 24), + // The compression type + GZipConstants.CompressionMethodDeflate, - // The extra flags - 0, + // The flags (not set) + (byte)flags, - // The OS type (unknown) - 255 - }; + // The modification time + (byte) modTime, (byte) (modTime >> 8), + (byte) (modTime >> 16), (byte) (modTime >> 24), - baseOutputStream_.Write(gzipHeader, 0, gzipHeader.Length); + // The extra flags + 0, - if (flags.HasFlag(GZipFlags.FNAME)) - { - var fname = GZipConstants.Encoding.GetBytes(fileName); - baseOutputStream_.Write(fname, 0, fname.Length); + // The OS type (unknown) + 255 + }; - // End filename string with a \0 - baseOutputStream_.Write(new byte[] { 0 }, 0, 1); - } + if (!flags.HasFlag(GZipFlags.FNAME)) + { + return gzipHeader; } + + + return gzipHeader + .Concat(GZipConstants.Encoding.GetBytes(fileName)) + .Concat(new byte []{0}) // End filename string with a \0 + .ToArray(); + } + + private static string CleanFilename(string path) + => path.Substring(path.LastIndexOf('/') + 1); + + private void WriteHeader() + { + if (state_ != OutputState.Header) return; + state_ = OutputState.Footer; + + var gzipHeader = GetHeader(); + baseOutputStream_.Write(gzipHeader, 0, gzipHeader.Length); + } + + #if NETSTANDARD2_1_OR_GREATER + private async ValueTask WriteHeaderAsync() + { + if (state_ != OutputState.Header) return; + state_ = OutputState.Footer; + await baseOutputStream_.WriteAsync(GetHeader()); } + #endif #endregion Support Routines } diff --git a/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipTests.cs b/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipTests.cs index 62be609fc..b7ee7e444 100644 --- a/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipTests.cs +++ b/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipTests.cs @@ -4,6 +4,8 @@ using System; using System.IO; using System.Text; +using System.Threading; +using System.Threading.Tasks; namespace ICSharpCode.SharpZipLib.Tests.GZip { @@ -428,7 +430,50 @@ public void SmallBufferDecompression() } } + +#if NETCOREAPP3_1_OR_GREATER + [Test] + [Category("GZip")] + [Category("Async")] + public async Task SmallBufferDecompressionAsync() + { + var outputBufferSize = 100000; + var inputBufferSize = outputBufferSize * 4; + var inputBuffer = Utils.GetDummyBytes(inputBufferSize, seed: 0); + + var outputBuffer = new byte[outputBufferSize]; + await using var msGzip = new MemoryStream(); + await using (var gzos = new GZipOutputStream(msGzip){IsStreamOwner = false}) + { + await gzos.WriteAsync(inputBuffer, 0, inputBuffer.Length); + } + + msGzip.Seek(0, SeekOrigin.Begin); + + + using (var gzis = new GZipInputStream(msGzip)) + await using (var msRaw = new MemoryStream()) + { + + int readOut; + while ((readOut = await gzis.ReadAsync(outputBuffer, 0, outputBuffer.Length)) > 0) + { + await msRaw.WriteAsync(outputBuffer, 0, readOut); + } + + var resultBuffer = msRaw.ToArray(); + + for (var i = 0; i < resultBuffer.Length; i++) + { + Assert.AreEqual(inputBuffer[i], resultBuffer[i]); + } + + + } + } +#endif + /// /// Should gracefully handle reading from a stream that becomes unreadable after /// all of the data has been read. From c0cca1e3b275d78d28a656241de6ecd2e4512a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nils=20m=C3=A5s=C3=A9n?= Date: Sat, 9 Oct 2021 21:57:26 +0200 Subject: [PATCH 2/6] test(gzip): split async tests and add seeds --- .../GZip/GZipAsyncTests.cs | 78 +++++++++++++++++++ .../GZip/GZipTests.cs | 63 +-------------- 2 files changed, 82 insertions(+), 59 deletions(-) create mode 100644 test/ICSharpCode.SharpZipLib.Tests/GZip/GZipAsyncTests.cs diff --git a/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipAsyncTests.cs b/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipAsyncTests.cs new file mode 100644 index 000000000..626684116 --- /dev/null +++ b/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipAsyncTests.cs @@ -0,0 +1,78 @@ +using System.IO; +using System.Text; +using System.Threading.Tasks; +using ICSharpCode.SharpZipLib.GZip; +using ICSharpCode.SharpZipLib.Tests.TestSupport; +using NUnit.Framework; + +namespace ICSharpCode.SharpZipLib.Tests.GZip +{ + +#if NETCOREAPP3_1_OR_GREATER + [TestFixture] + public class GZipAsyncTests + { + [Test] + [Category("GZip")] + [Category("Async")] + public async Task SmallBufferDecompressionAsync([Values(0, 1, 3)] int seed) + { + var outputBufferSize = 100000; + var outputBuffer = new byte[outputBufferSize]; + var inputBuffer = Utils.GetDummyBytes(outputBufferSize * 4, seed); + + await using var msGzip = new MemoryStream(); + await using (var gzos = new GZipOutputStream(msGzip){IsStreamOwner = false}) + { + await gzos.WriteAsync(inputBuffer, 0, inputBuffer.Length); + } + + msGzip.Seek(0, SeekOrigin.Begin); + + using (var gzis = new GZipInputStream(msGzip)) + await using (var msRaw = new MemoryStream()) + { + int readOut; + while ((readOut = gzis.Read(outputBuffer, 0, outputBuffer.Length)) > 0) + { + await msRaw.WriteAsync(outputBuffer, 0, readOut); + } + + var resultBuffer = msRaw.ToArray(); + for (var i = 0; i < resultBuffer.Length; i++) + { + Assert.AreEqual(inputBuffer[i], resultBuffer[i]); + } + } + } + + /// + /// Basic compress/decompress test + /// + [Test] + [Category("GZip")] + [Category("Async")] + public async Task OriginalFilenameAsync() + { + var content = "FileContents"; + + await using var ms = new MemoryStream(); + await using (var outStream = new GZipOutputStream(ms) { IsStreamOwner = false }) + { + outStream.FileName = "/path/to/file.ext"; + outStream.Write(Encoding.ASCII.GetBytes(content)); + } + + ms.Seek(0, SeekOrigin.Begin); + + using (var inStream = new GZipInputStream(ms)) + { + var readBuffer = new byte[content.Length]; + inStream.Read(readBuffer, 0, readBuffer.Length); + Assert.AreEqual(content, Encoding.ASCII.GetString(readBuffer)); + Assert.AreEqual("file.ext", inStream.GetFilename()); + } + } + } +#endif +} diff --git a/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipTests.cs b/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipTests.cs index b7ee7e444..3241fd134 100644 --- a/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipTests.cs +++ b/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipTests.cs @@ -388,32 +388,23 @@ public void FlushToUnderlyingStream() [Test] [Category("GZip")] - public void SmallBufferDecompression() + public void SmallBufferDecompression([Values(0, 1, 3)] int seed) { var outputBufferSize = 100000; - var inputBufferSize = outputBufferSize * 4; - var inputBuffer = Utils.GetDummyBytes(inputBufferSize, seed: 0); - var outputBuffer = new byte[outputBufferSize]; + var inputBuffer = Utils.GetDummyBytes(outputBufferSize * 4, seed); using var msGzip = new MemoryStream(); - using (var gzos = new GZipOutputStream(msGzip)) + using (var gzos = new GZipOutputStream(msGzip){IsStreamOwner = false}) { - gzos.IsStreamOwner = false; - gzos.Write(inputBuffer, 0, inputBuffer.Length); - - gzos.Flush(); - gzos.Finish(); } msGzip.Seek(0, SeekOrigin.Begin); - - + using (var gzis = new GZipInputStream(msGzip)) using (var msRaw = new MemoryStream()) { - int readOut; while ((readOut = gzis.Read(outputBuffer, 0, outputBuffer.Length)) > 0) { @@ -421,59 +412,13 @@ public void SmallBufferDecompression() } var resultBuffer = msRaw.ToArray(); - for (var i = 0; i < resultBuffer.Length; i++) { Assert.AreEqual(inputBuffer[i], resultBuffer[i]); } - - } } - -#if NETCOREAPP3_1_OR_GREATER - [Test] - [Category("GZip")] - [Category("Async")] - public async Task SmallBufferDecompressionAsync() - { - var outputBufferSize = 100000; - var inputBufferSize = outputBufferSize * 4; - var inputBuffer = Utils.GetDummyBytes(inputBufferSize, seed: 0); - - var outputBuffer = new byte[outputBufferSize]; - - await using var msGzip = new MemoryStream(); - await using (var gzos = new GZipOutputStream(msGzip){IsStreamOwner = false}) - { - await gzos.WriteAsync(inputBuffer, 0, inputBuffer.Length); - } - - msGzip.Seek(0, SeekOrigin.Begin); - - using (var gzis = new GZipInputStream(msGzip)) - await using (var msRaw = new MemoryStream()) - { - - int readOut; - while ((readOut = await gzis.ReadAsync(outputBuffer, 0, outputBuffer.Length)) > 0) - { - await msRaw.WriteAsync(outputBuffer, 0, readOut); - } - - var resultBuffer = msRaw.ToArray(); - - for (var i = 0; i < resultBuffer.Length; i++) - { - Assert.AreEqual(inputBuffer[i], resultBuffer[i]); - } - - - } - } -#endif - /// /// Should gracefully handle reading from a stream that becomes unreadable after /// all of the data has been read. From a888745c1fe1fd5095ca2c04a1f630f39be70354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nils=20m=C3=A5s=C3=A9n?= Date: Sat, 9 Oct 2021 22:00:13 +0200 Subject: [PATCH 3/6] fix overrides and ifdefs --- .../GZip/GzipOutputStream.cs | 38 ++++++------------- .../Streams/DeflaterOutputStream.cs | 2 +- 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/src/ICSharpCode.SharpZipLib/GZip/GzipOutputStream.cs b/src/ICSharpCode.SharpZipLib/GZip/GzipOutputStream.cs index b15e7a5b4..f8928db34 100644 --- a/src/ICSharpCode.SharpZipLib/GZip/GzipOutputStream.cs +++ b/src/ICSharpCode.SharpZipLib/GZip/GzipOutputStream.cs @@ -164,26 +164,6 @@ public override void Write(byte[] buffer, int offset, int count) base.Write(buffer, offset, count); } -#if NETSTANDARD2_1_OR_GREATER - /// - public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) - { - - if (state_ == OutputState.Header) - { - await WriteHeaderAsync(); - } - - if (state_ != OutputState.Footer) - { - throw new InvalidOperationException("Write not permitted in current state"); - } - - crc.Update(new ArraySegment(buffer, offset, count)); - await base.WriteAsync(buffer, offset, count, cancellationToken); - } -#endif - /// /// Writes remaining compressed output data to the output stream /// and closes it. @@ -270,8 +250,15 @@ public override void Finish() baseOutputStream_.Write(gzipFooter, 0, gzipFooter.Length); } } - -#if NETSTANDARD2_1_OR_GREATER + + /// + public override async Task FlushAsync(CancellationToken ct) + { + await WriteHeaderAsync(); + await base.FlushAsync(ct); + } + + /// public override async Task FinishAsync(CancellationToken ct) { @@ -288,7 +275,6 @@ public override async Task FinishAsync(CancellationToken ct) await baseOutputStream_.WriteAsync(GetFooter(), ct); } } -#endif #endregion DeflaterOutputStream overrides @@ -362,19 +348,17 @@ private void WriteHeader() { if (state_ != OutputState.Header) return; state_ = OutputState.Footer; - var gzipHeader = GetHeader(); baseOutputStream_.Write(gzipHeader, 0, gzipHeader.Length); } - #if NETSTANDARD2_1_OR_GREATER private async ValueTask WriteHeaderAsync() { if (state_ != OutputState.Header) return; state_ = OutputState.Footer; - await baseOutputStream_.WriteAsync(GetHeader()); + var gzipHeader = GetHeader(); + await baseOutputStream_.WriteAsync(gzipHeader, 0, gzipHeader.Length); } - #endif #endregion Support Routines } diff --git a/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs b/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs index 1c54b6848..a9b78dd75 100644 --- a/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs +++ b/src/ICSharpCode.SharpZipLib/Zip/Compression/Streams/DeflaterOutputStream.cs @@ -412,7 +412,7 @@ protected override void Dispose(bool disposing) } } -#if NETSTANDARD2_1 +#if NETSTANDARD2_1_OR_GREATER /// /// Calls and closes the underlying /// stream when is true. From 1c2961f52f9d25f07cacbca16e86f877e79804be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nils=20m=C3=A5s=C3=A9n?= Date: Sat, 9 Oct 2021 22:04:13 +0200 Subject: [PATCH 4/6] fix async for net45 --- src/ICSharpCode.SharpZipLib/GZip/GzipOutputStream.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/ICSharpCode.SharpZipLib/GZip/GzipOutputStream.cs b/src/ICSharpCode.SharpZipLib/GZip/GzipOutputStream.cs index f8928db34..456ec928e 100644 --- a/src/ICSharpCode.SharpZipLib/GZip/GzipOutputStream.cs +++ b/src/ICSharpCode.SharpZipLib/GZip/GzipOutputStream.cs @@ -244,9 +244,7 @@ public override void Finish() { state_ = OutputState.Finished; base.Finish(); - - byte[] gzipFooter = GetFooter(); - + var gzipFooter = GetFooter(); baseOutputStream_.Write(gzipFooter, 0, gzipFooter.Length); } } @@ -272,7 +270,8 @@ public override async Task FinishAsync(CancellationToken ct) { state_ = OutputState.Finished; await base.FinishAsync(ct); - await baseOutputStream_.WriteAsync(GetFooter(), ct); + var gzipFooter = GetFooter(); + await baseOutputStream_.WriteAsync(gzipFooter, 0, gzipFooter.Length, ct); } } @@ -352,7 +351,7 @@ private void WriteHeader() baseOutputStream_.Write(gzipHeader, 0, gzipHeader.Length); } - private async ValueTask WriteHeaderAsync() + private async Task WriteHeaderAsync() { if (state_ != OutputState.Header) return; state_ = OutputState.Footer; From 91a9b680bb91eeba6155ad8e049873c37088b466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nils=20m=C3=A5s=C3=A9n?= Date: Thu, 15 Sep 2022 11:28:52 +0200 Subject: [PATCH 5/6] fix(tests): handle lack of `await using` For ZipStreamAsyncTest we are explicitly testing for `await using`, so it's now being marked as ignored and a dummy await is added to skip warnings For GzipAsyncTests we are testing multiple async methods, so variants are added that simply skips the `await using`/`DisposeAsync` and calls the underlying `FinishAsync` --- .../GZip/GZipAsyncTests.cs | 41 +++++++++++++++++-- .../Zip/ZipStreamAsyncTests.cs | 11 +++-- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipAsyncTests.cs b/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipAsyncTests.cs index 626684116..82bdbcd0a 100644 --- a/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipAsyncTests.cs +++ b/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipAsyncTests.cs @@ -8,7 +8,7 @@ namespace ICSharpCode.SharpZipLib.Tests.GZip { -#if NETCOREAPP3_1_OR_GREATER + [TestFixture] public class GZipAsyncTests { @@ -21,6 +21,7 @@ public async Task SmallBufferDecompressionAsync([Values(0, 1, 3)] int seed) var outputBuffer = new byte[outputBufferSize]; var inputBuffer = Utils.GetDummyBytes(outputBufferSize * 4, seed); +#if NETCOREAPP3_1_OR_GREATER await using var msGzip = new MemoryStream(); await using (var gzos = new GZipOutputStream(msGzip){IsStreamOwner = false}) { @@ -44,6 +45,31 @@ public async Task SmallBufferDecompressionAsync([Values(0, 1, 3)] int seed) Assert.AreEqual(inputBuffer[i], resultBuffer[i]); } } +#else + using var msGzip = new MemoryStream(); + using (var gzos = new GZipOutputStream(msGzip){IsStreamOwner = false}) + { + await gzos.WriteAsync(inputBuffer, 0, inputBuffer.Length); + } + + msGzip.Seek(0, SeekOrigin.Begin); + + using (var gzis = new GZipInputStream(msGzip)) + using (var msRaw = new MemoryStream()) + { + int readOut; + while ((readOut = gzis.Read(outputBuffer, 0, outputBuffer.Length)) > 0) + { + await msRaw.WriteAsync(outputBuffer, 0, readOut); + } + + var resultBuffer = msRaw.ToArray(); + for (var i = 0; i < resultBuffer.Length; i++) + { + Assert.AreEqual(inputBuffer[i], resultBuffer[i]); + } + } +#endif } /// @@ -56,13 +82,23 @@ public async Task OriginalFilenameAsync() { var content = "FileContents"; +#if NETCOREAPP3_1_OR_GREATER await using var ms = new MemoryStream(); await using (var outStream = new GZipOutputStream(ms) { IsStreamOwner = false }) { outStream.FileName = "/path/to/file.ext"; outStream.Write(Encoding.ASCII.GetBytes(content)); } - +#else + var ms = new MemoryStream(); + var outStream = new GZipOutputStream(ms){ IsStreamOwner = false }; + outStream.FileName = "/path/to/file.ext"; + var bytes = Encoding.ASCII.GetBytes(content); + outStream.Write(bytes, 0, bytes.Length); + await outStream.FinishAsync(System.Threading.CancellationToken.None); + outStream.Dispose(); + +#endif ms.Seek(0, SeekOrigin.Begin); using (var inStream = new GZipInputStream(ms)) @@ -74,5 +110,4 @@ public async Task OriginalFilenameAsync() } } } -#endif } diff --git a/test/ICSharpCode.SharpZipLib.Tests/Zip/ZipStreamAsyncTests.cs b/test/ICSharpCode.SharpZipLib.Tests/Zip/ZipStreamAsyncTests.cs index 9a8aeac14..aff027bf1 100644 --- a/test/ICSharpCode.SharpZipLib.Tests/Zip/ZipStreamAsyncTests.cs +++ b/test/ICSharpCode.SharpZipLib.Tests/Zip/ZipStreamAsyncTests.cs @@ -1,8 +1,8 @@ using System.IO; using System.Threading; using System.Threading.Tasks; -using ICSharpCode.SharpZipLib.Tests.TestSupport; using ICSharpCode.SharpZipLib.Zip; +using ICSharpCode.SharpZipLib.Tests.TestSupport; using NUnit.Framework; namespace ICSharpCode.SharpZipLib.Tests.Zip @@ -10,12 +10,12 @@ namespace ICSharpCode.SharpZipLib.Tests.Zip [TestFixture] public class ZipStreamAsyncTests { -#if NETCOREAPP3_1_OR_GREATER [Test] [Category("Zip")] [Category("Async")] public async Task WriteZipStreamUsingAsync() { +#if NETCOREAPP3_1_OR_GREATER await using var ms = new MemoryStream(); await using (var outStream = new ZipOutputStream(ms){IsStreamOwner = false}) @@ -28,8 +28,11 @@ public async Task WriteZipStreamUsingAsync() } ZipTesting.AssertValidZip(ms); - } +#else + await Task.CompletedTask; + Assert.Ignore("Async Using is not supported"); #endif + } [Test] [Category("Zip")] @@ -119,4 +122,4 @@ public async Task WriteReadOnlyZipStreamAsync () } } -} +} \ No newline at end of file From e61251a3bc55ba6ee952595cdd5c8b2bfcdc03dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nils=20m=C3=A5s=C3=A9n?= Date: Thu, 15 Sep 2022 12:04:58 +0200 Subject: [PATCH 6/6] add test for empty gzip stream --- .../GZip/GZipAsyncTests.cs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipAsyncTests.cs b/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipAsyncTests.cs index 82bdbcd0a..209ae15d4 100644 --- a/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipAsyncTests.cs +++ b/test/ICSharpCode.SharpZipLib.Tests/GZip/GZipAsyncTests.cs @@ -109,5 +109,36 @@ public async Task OriginalFilenameAsync() Assert.AreEqual("file.ext", inStream.GetFilename()); } } + + /// + /// Test creating an empty gzip stream using async + /// + [Test] + [Category("GZip")] + [Category("Async")] + public async Task EmptyGZipStreamAsync() + { +#if NETCOREAPP3_1_OR_GREATER + await using var ms = new MemoryStream(); + await using (var outStream = new GZipOutputStream(ms) { IsStreamOwner = false }) + { + // No content + } +#else + var ms = new MemoryStream(); + var outStream = new GZipOutputStream(ms){ IsStreamOwner = false }; + await outStream.FinishAsync(System.Threading.CancellationToken.None); + outStream.Dispose(); + +#endif + ms.Seek(0, SeekOrigin.Begin); + + using (var inStream = new GZipInputStream(ms)) + using (var reader = new StreamReader(inStream)) + { + var content = await reader.ReadToEndAsync(); + Assert.IsEmpty(content); + } + } } }