From fc85f1fa2cdb79be4ef102dbc8230c1166ab5316 Mon Sep 17 00:00:00 2001 From: Adam Hathcock Date: Tue, 13 Jan 2026 14:28:45 +0000 Subject: [PATCH] more tar async fixes --- .../Polyfills/AsyncEnumerableExtensions.cs | 24 ++++++++++++++++++ tests/SharpCompress.Test/ArchiveTests.cs | 12 ++++----- .../Tar/TarArchiveAsyncTests.cs | 25 ++++++++++--------- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/SharpCompress/Polyfills/AsyncEnumerableExtensions.cs b/src/SharpCompress/Polyfills/AsyncEnumerableExtensions.cs index a1280e69..5f219211 100644 --- a/src/SharpCompress/Polyfills/AsyncEnumerableExtensions.cs +++ b/src/SharpCompress/Polyfills/AsyncEnumerableExtensions.cs @@ -31,6 +31,30 @@ public static class EnumerableExtensions public static class AsyncEnumerableExtensions { + public static async IAsyncEnumerable Select( + this IAsyncEnumerable source, + Func selector) + { + await foreach (var element in source) + { + yield return selector(element); + } + } + public static async ValueTask CountAsync( + this IAsyncEnumerable source, + CancellationToken cancellationToken = default) + { + await using var e = source.GetAsyncEnumerator(cancellationToken); + + var count = 0; + while (await e.MoveNextAsync()) + { + checked { count++; } + } + + return count; + } + public static async IAsyncEnumerable TakeAsync( this IAsyncEnumerable source, int count) diff --git a/tests/SharpCompress.Test/ArchiveTests.cs b/tests/SharpCompress.Test/ArchiveTests.cs index 45a1ef98..302c4d45 100644 --- a/tests/SharpCompress.Test/ArchiveTests.cs +++ b/tests/SharpCompress.Test/ArchiveTests.cs @@ -643,7 +643,7 @@ public class ArchiveTests : ReaderTests } [Fact] - public void ArchiveFactory_Open_WithPreWrappedStream() + public async Task ArchiveFactory_Open_WithPreWrappedStream() { // Test that ArchiveFactory.Open works correctly with a stream that's already wrapped // This addresses the issue where ZIP files fail to open on Linux @@ -652,25 +652,25 @@ public class ArchiveTests : ReaderTests // Open with a pre-wrapped stream using (var fileStream = File.OpenRead(testArchive)) using (var wrappedStream = SharpCompressStream.Create(fileStream, bufferSize: 32768)) - using (var archive = ArchiveFactory.Open(wrappedStream)) + await using (var archive = await ArchiveFactory.OpenAsync(new AsyncOnlyStream(wrappedStream))) { Assert.Equal(ArchiveType.Zip, archive.Type); - Assert.Equal(3, archive.Entries.Count()); + Assert.Equal(3, await archive.EntriesAsync.CountAsync()); } } [Fact] - public void ArchiveFactory_Open_WithRawFileStream() + public async Task ArchiveFactory_Open_WithRawFileStream() { // Test that ArchiveFactory.Open works correctly with a raw FileStream // This is the common use case reported in the issue var testArchive = Path.Combine(TEST_ARCHIVES_PATH, "Zip.bzip2.noEmptyDirs.zip"); using (var stream = File.OpenRead(testArchive)) - using (var archive = ArchiveFactory.Open(stream)) + await using (var archive = await ArchiveFactory.OpenAsync(new AsyncOnlyStream(stream))) { Assert.Equal(ArchiveType.Zip, archive.Type); - Assert.Equal(3, archive.Entries.Count()); + Assert.Equal(3, await archive.EntriesAsync.CountAsync()); } } } diff --git a/tests/SharpCompress.Test/Tar/TarArchiveAsyncTests.cs b/tests/SharpCompress.Test/Tar/TarArchiveAsyncTests.cs index f29d4553..4481cdaa 100644 --- a/tests/SharpCompress.Test/Tar/TarArchiveAsyncTests.cs +++ b/tests/SharpCompress.Test/Tar/TarArchiveAsyncTests.cs @@ -8,6 +8,7 @@ using SharpCompress.Archives.Tar; using SharpCompress.Common; using SharpCompress.Readers; using SharpCompress.Readers.Tar; +using SharpCompress.Test.Mocks; using SharpCompress.Writers; using SharpCompress.Writers.Tar; using Xunit; @@ -45,12 +46,12 @@ public class TarArchiveAsyncTests : ArchiveTests // Step 2: check if the written tar file can be read correctly var unmodified = Path.Combine(SCRATCH2_FILES_PATH, archive); - using (var archive2 = TarArchive.Open(unmodified)) + await using (var archive2 = TarArchive.OpenAsync(new AsyncOnlyStream(File.OpenRead(unmodified)))) { - Assert.Equal(1, archive2.Entries.Count()); - Assert.Contains(filename, archive2.Entries.Select(entry => entry.Key)); + Assert.Equal(1, await archive2.EntriesAsync.CountAsync()); + Assert.Contains(filename, await archive2.EntriesAsync.Select(entry => entry.Key).ToListAsync()); - foreach (var entry in archive2.Entries) + await foreach (var entry in archive2.EntriesAsync) { Assert.Equal( "dummy filecontent", @@ -89,12 +90,12 @@ public class TarArchiveAsyncTests : ArchiveTests // Step 2: check if the written tar file can be read correctly var unmodified = Path.Combine(SCRATCH2_FILES_PATH, archive); - using (var archive2 = TarArchive.Open(unmodified)) + await using (var archive2 = TarArchive.OpenAsync(new AsyncOnlyStream(File.OpenRead(unmodified)))) { - Assert.Equal(1, archive2.Entries.Count()); - Assert.Contains(longFilename, archive2.Entries.Select(entry => entry.Key)); + Assert.Equal(1, await archive2.EntriesAsync.CountAsync()); + Assert.Contains(longFilename, await archive2.EntriesAsync.Select(entry => entry.Key).ToListAsync()); - foreach (var entry in archive2.Entries) + await foreach (var entry in archive2.EntriesAsync) { Assert.Equal( "dummy filecontent", @@ -172,9 +173,9 @@ public class TarArchiveAsyncTests : ArchiveTests using (var inputMemory = new MemoryStream(mstm.ToArray())) { var tropt = new ReaderOptions { ArchiveEncoding = enc }; - using (var tr = TarReader.Open(inputMemory, tropt)) + await using (var tr = ReaderFactory.OpenAsync(inputMemory, tropt)) { - while (tr.MoveToNextEntry()) + while (await tr.MoveToNextEntryAsync()) { Assert.Equal(fname, tr.Entry.Key); } @@ -205,9 +206,9 @@ public class TarArchiveAsyncTests : ArchiveTests var numberOfEntries = 0; - using (var archiveFactory = TarArchive.Open(memoryStream)) +await using (var archiveFactory = TarArchive.OpenAsync(new AsyncOnlyStream(memoryStream))) { - foreach (var entry in archiveFactory.Entries) + await foreach (var entry in archiveFactory.EntriesAsync) { ++numberOfEntries;