mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-22 23:15:20 +00:00
add tar specific tests
This commit is contained in:
@@ -75,6 +75,23 @@ public static class IArchiveEntryExtensions
|
||||
entry.WriteToFile
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Extract to specific directory asynchronously, retaining filename
|
||||
/// </summary>
|
||||
public static Task WriteToDirectoryAsync(
|
||||
this IArchiveEntry entry,
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options = null,
|
||||
CancellationToken cancellationToken = default
|
||||
) =>
|
||||
ExtractionMethods.WriteEntryToDirectoryAsync(
|
||||
entry,
|
||||
destinationDirectory,
|
||||
options,
|
||||
(x, opt) => entry.WriteToFileAsync(x, opt, cancellationToken),
|
||||
cancellationToken
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Extract to specific file
|
||||
/// </summary>
|
||||
|
||||
@@ -257,7 +257,13 @@ public class TarArchive : AbstractWritableArchive<TarArchiveEntry, TarVolume>
|
||||
{
|
||||
using var entryStream = entry.OpenEntryStream();
|
||||
await writer
|
||||
.WriteAsync(entry.Key.NotNull("Entry Key is null"), entryStream, cancellationToken)
|
||||
.WriteAsync(
|
||||
entry.Key.NotNull("Entry Key is null"),
|
||||
entryStream,
|
||||
entry.LastModifiedTime,
|
||||
entry.Size,
|
||||
cancellationToken
|
||||
)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Common.Tar.Headers;
|
||||
using SharpCompress.Compressors;
|
||||
@@ -91,6 +93,40 @@ public class TarWriter : AbstractWriter
|
||||
PadTo512(size.Value);
|
||||
}
|
||||
|
||||
public override async Task WriteAsync(
|
||||
string filename,
|
||||
Stream source,
|
||||
DateTime? modificationTime,
|
||||
CancellationToken cancellationToken = default
|
||||
) => await WriteAsync(filename, source, modificationTime, null, cancellationToken);
|
||||
|
||||
public async Task WriteAsync(
|
||||
string filename,
|
||||
Stream source,
|
||||
DateTime? modificationTime,
|
||||
long? size,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (!source.CanSeek && size is null)
|
||||
{
|
||||
throw new ArgumentException("Seekable stream is required if no size is given.");
|
||||
}
|
||||
|
||||
var realSize = size ?? source.Length;
|
||||
|
||||
var header = new TarHeader(WriterOptions.ArchiveEncoding);
|
||||
|
||||
header.LastModifiedTime = modificationTime ?? TarHeader.EPOCH;
|
||||
header.Name = NormalizeFilename(filename);
|
||||
header.Size = realSize;
|
||||
header.Write(OutputStream);
|
||||
var written = await source
|
||||
.TransferToAsync(OutputStream, realSize, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
PadTo512(written);
|
||||
}
|
||||
|
||||
private void PadTo512(long size)
|
||||
{
|
||||
var zeros = unchecked((int)(((size + 511L) & ~511L) - size));
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Compressors.Xz;
|
||||
@@ -569,4 +570,56 @@ public class ArchiveTests : ReaderTests
|
||||
|
||||
return (extractedData, crc);
|
||||
}
|
||||
|
||||
protected async Task ArchiveStreamReadAsync(
|
||||
string testArchive,
|
||||
ReaderOptions? readerOptions = null
|
||||
)
|
||||
{
|
||||
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
|
||||
await ArchiveStreamReadAsync(
|
||||
ArchiveFactory.AutoFactory,
|
||||
readerOptions,
|
||||
new[] { testArchive }
|
||||
);
|
||||
}
|
||||
|
||||
protected async Task ArchiveStreamReadAsync(
|
||||
IArchiveFactory archiveFactory,
|
||||
ReaderOptions? readerOptions,
|
||||
IEnumerable<string> testArchives
|
||||
)
|
||||
{
|
||||
foreach (var path in testArchives)
|
||||
{
|
||||
using (
|
||||
var stream = SharpCompressStream.Create(
|
||||
File.OpenRead(path),
|
||||
leaveOpen: true,
|
||||
throwOnDispose: true
|
||||
)
|
||||
)
|
||||
using (var archive = archiveFactory.Open(stream, readerOptions))
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
await entry.WriteToDirectoryAsync(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true, Overwrite = true }
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
//SevenZipArchive_BZip2_Split test needs this
|
||||
stream.ThrowOnDispose = false;
|
||||
throw;
|
||||
}
|
||||
stream.ThrowOnDispose = false;
|
||||
}
|
||||
VerifyFiles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
223
tests/SharpCompress.Test/Tar/TarArchiveAsyncTests.cs
Normal file
223
tests/SharpCompress.Test/Tar/TarArchiveAsyncTests.cs
Normal file
@@ -0,0 +1,223 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Archives;
|
||||
using SharpCompress.Archives.Tar;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.Tar;
|
||||
using SharpCompress.Writers;
|
||||
using SharpCompress.Writers.Tar;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpCompress.Test.Tar;
|
||||
|
||||
public class TarArchiveAsyncTests : ArchiveTests
|
||||
{
|
||||
public TarArchiveAsyncTests() => UseExtensionInsteadOfNameToVerify = true;
|
||||
|
||||
[Fact]
|
||||
public async Task TarArchiveStreamRead_Async() => await ArchiveStreamReadAsync("Tar.tar");
|
||||
|
||||
[Fact]
|
||||
public async Task Tar_FileName_Exactly_100_Characters_Async()
|
||||
{
|
||||
var archive = "Tar_FileName_Exactly_100_Characters.tar";
|
||||
|
||||
// create the 100 char filename
|
||||
var filename =
|
||||
"filename_with_exactly_100_characters_______________________________________________________________X";
|
||||
|
||||
// Step 1: create a tar file containing a file with the test name
|
||||
using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive)))
|
||||
using (var writer = WriterFactory.Open(stream, ArchiveType.Tar, CompressionType.None))
|
||||
using (Stream inputStream = new MemoryStream())
|
||||
{
|
||||
var sw = new StreamWriter(inputStream);
|
||||
await sw.WriteAsync("dummy filecontent");
|
||||
await sw.FlushAsync();
|
||||
|
||||
inputStream.Position = 0;
|
||||
await writer.WriteAsync(filename, inputStream, null);
|
||||
}
|
||||
|
||||
// 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))
|
||||
{
|
||||
Assert.Equal(1, archive2.Entries.Count);
|
||||
Assert.Contains(filename, archive2.Entries.Select(entry => entry.Key));
|
||||
|
||||
foreach (var entry in archive2.Entries)
|
||||
{
|
||||
Assert.Equal(
|
||||
"dummy filecontent",
|
||||
await new StreamReader(entry.OpenEntryStream()).ReadLineAsync()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Tar_VeryLongFilepathReadback_Async()
|
||||
{
|
||||
var archive = "Tar_VeryLongFilepathReadback.tar";
|
||||
|
||||
// create a very long filename
|
||||
var longFilename = "";
|
||||
for (var i = 0; i < 600; i = longFilename.Length)
|
||||
{
|
||||
longFilename += i.ToString("D10") + "-";
|
||||
}
|
||||
|
||||
longFilename += ".txt";
|
||||
|
||||
// Step 1: create a tar file containing a file with a long name
|
||||
using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive)))
|
||||
using (var writer = WriterFactory.Open(stream, ArchiveType.Tar, CompressionType.None))
|
||||
using (Stream inputStream = new MemoryStream())
|
||||
{
|
||||
var sw = new StreamWriter(inputStream);
|
||||
await sw.WriteAsync("dummy filecontent");
|
||||
await sw.FlushAsync();
|
||||
|
||||
inputStream.Position = 0;
|
||||
await writer.WriteAsync(longFilename, inputStream, null);
|
||||
}
|
||||
|
||||
// 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))
|
||||
{
|
||||
Assert.Equal(1, archive2.Entries.Count);
|
||||
Assert.Contains(longFilename, archive2.Entries.Select(entry => entry.Key));
|
||||
|
||||
foreach (var entry in archive2.Entries)
|
||||
{
|
||||
Assert.Equal(
|
||||
"dummy filecontent",
|
||||
await new StreamReader(entry.OpenEntryStream()).ReadLineAsync()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Tar_Create_New_Async()
|
||||
{
|
||||
var scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.tar");
|
||||
var unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar");
|
||||
|
||||
using (var archive = TarArchive.Create())
|
||||
{
|
||||
archive.AddAllFromDirectory(ORIGINAL_FILES_PATH);
|
||||
var twopt = new TarWriterOptions(CompressionType.None, true);
|
||||
twopt.ArchiveEncoding = new ArchiveEncoding { Default = Encoding.GetEncoding(866) };
|
||||
await archive.SaveToAsync(scratchPath, twopt);
|
||||
}
|
||||
CompareArchivesByPath(unmodified, scratchPath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Tar_Random_Write_Add_Async()
|
||||
{
|
||||
var jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg");
|
||||
var scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.mod.tar");
|
||||
var unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.mod.tar");
|
||||
var modified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar");
|
||||
|
||||
using (var archive = TarArchive.Open(unmodified))
|
||||
{
|
||||
archive.AddEntry("jpg\\test.jpg", jpg);
|
||||
await archive.SaveToAsync(scratchPath, new WriterOptions(CompressionType.None));
|
||||
}
|
||||
CompareArchivesByPath(modified, scratchPath);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Tar_Random_Write_Remove_Async()
|
||||
{
|
||||
var scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.mod.tar");
|
||||
var modified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.mod.tar");
|
||||
var unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar");
|
||||
|
||||
using (var archive = TarArchive.Open(unmodified))
|
||||
{
|
||||
var entry = archive.Entries.Single(x =>
|
||||
x.Key.NotNull().EndsWith("jpg", StringComparison.OrdinalIgnoreCase)
|
||||
);
|
||||
archive.RemoveEntry(entry);
|
||||
await archive.SaveToAsync(scratchPath, new WriterOptions(CompressionType.None));
|
||||
}
|
||||
CompareArchivesByPath(modified, scratchPath);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(10)]
|
||||
[InlineData(128)]
|
||||
public async Task Tar_Japanese_Name_Async(int length)
|
||||
{
|
||||
using var mstm = new MemoryStream();
|
||||
var enc = new ArchiveEncoding { Default = Encoding.UTF8 };
|
||||
var twopt = new TarWriterOptions(CompressionType.None, true);
|
||||
twopt.ArchiveEncoding = enc;
|
||||
var fname = new string((char)0x3042, length);
|
||||
using (var tw = new TarWriter(mstm, twopt))
|
||||
using (var input = new MemoryStream(new byte[32]))
|
||||
{
|
||||
await tw.WriteAsync(fname, input, null);
|
||||
}
|
||||
using (var inputMemory = new MemoryStream(mstm.ToArray()))
|
||||
{
|
||||
var tropt = new ReaderOptions { ArchiveEncoding = enc };
|
||||
using (var tr = TarReader.Open(inputMemory, tropt))
|
||||
{
|
||||
while (tr.MoveToNextEntry())
|
||||
{
|
||||
Assert.Equal(fname, tr.Entry.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Tar_Read_One_At_A_Time_Async()
|
||||
{
|
||||
var archiveEncoding = new ArchiveEncoding { Default = Encoding.UTF8 };
|
||||
var tarWriterOptions = new TarWriterOptions(CompressionType.None, true)
|
||||
{
|
||||
ArchiveEncoding = archiveEncoding,
|
||||
};
|
||||
var testBytes = Encoding.UTF8.GetBytes("This is a test.");
|
||||
|
||||
using var memoryStream = new MemoryStream();
|
||||
using (var tarWriter = new TarWriter(memoryStream, tarWriterOptions))
|
||||
using (var testFileStream = new MemoryStream(testBytes))
|
||||
{
|
||||
await tarWriter.WriteAsync("test1.txt", testFileStream, null);
|
||||
testFileStream.Position = 0;
|
||||
await tarWriter.WriteAsync("test2.txt", testFileStream, null);
|
||||
}
|
||||
|
||||
memoryStream.Position = 0;
|
||||
|
||||
var numberOfEntries = 0;
|
||||
|
||||
using (var archiveFactory = TarArchive.Open(memoryStream))
|
||||
{
|
||||
foreach (var entry in archiveFactory.Entries)
|
||||
{
|
||||
++numberOfEntries;
|
||||
|
||||
using var tarEntryStream = entry.OpenEntryStream();
|
||||
using var testFileStream = new MemoryStream();
|
||||
await tarEntryStream.CopyToAsync(testFileStream);
|
||||
Assert.Equal(testBytes.Length, testFileStream.Length);
|
||||
}
|
||||
}
|
||||
|
||||
Assert.Equal(2, numberOfEntries);
|
||||
}
|
||||
}
|
||||
83
tests/SharpCompress.Test/Tar/TarWriterAsyncTests.cs
Normal file
83
tests/SharpCompress.Test/Tar/TarWriterAsyncTests.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Writers.Tar;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpCompress.Test.Tar;
|
||||
|
||||
public class TarWriterAsyncTests : WriterTests
|
||||
{
|
||||
static TarWriterAsyncTests()
|
||||
{
|
||||
#if !NETFRAMEWORK
|
||||
//fix issue where these tests could not be ran in isolation
|
||||
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
|
||||
#endif
|
||||
}
|
||||
|
||||
public TarWriterAsyncTests()
|
||||
: base(ArchiveType.Tar) => UseExtensionInsteadOfNameToVerify = true;
|
||||
|
||||
[Fact]
|
||||
public async Task Tar_Writer_Async() =>
|
||||
await WriteAsync(
|
||||
CompressionType.None,
|
||||
"Tar.noEmptyDirs.tar",
|
||||
"Tar.noEmptyDirs.tar",
|
||||
Encoding.GetEncoding(866)
|
||||
);
|
||||
|
||||
[Fact]
|
||||
public async Task Tar_BZip2_Writer_Async() =>
|
||||
await WriteAsync(
|
||||
CompressionType.BZip2,
|
||||
"Tar.noEmptyDirs.tar.bz2",
|
||||
"Tar.noEmptyDirs.tar.bz2",
|
||||
Encoding.GetEncoding(866)
|
||||
);
|
||||
|
||||
[Fact]
|
||||
public async Task Tar_LZip_Writer_Async() =>
|
||||
await WriteAsync(
|
||||
CompressionType.LZip,
|
||||
"Tar.noEmptyDirs.tar.lz",
|
||||
"Tar.noEmptyDirs.tar.lz",
|
||||
Encoding.GetEncoding(866)
|
||||
);
|
||||
|
||||
[Fact]
|
||||
public async Task Tar_Rar_Write_Async() =>
|
||||
await Assert.ThrowsAsync<InvalidFormatException>(async () =>
|
||||
await WriteAsync(
|
||||
CompressionType.Rar,
|
||||
"Zip.ppmd.noEmptyDirs.zip",
|
||||
"Zip.ppmd.noEmptyDirs.zip"
|
||||
)
|
||||
);
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public async Task Tar_Finalize_Archive_Async(bool finalizeArchive)
|
||||
{
|
||||
using var stream = new MemoryStream();
|
||||
using Stream content = File.OpenRead(Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg"));
|
||||
using (
|
||||
var writer = new TarWriter(
|
||||
stream,
|
||||
new TarWriterOptions(CompressionType.None, finalizeArchive)
|
||||
)
|
||||
)
|
||||
{
|
||||
await writer.WriteAsync("doesn't matter", content, null);
|
||||
}
|
||||
|
||||
var paddedContentWithHeader = (content.Length / 512 * 512) + 512 + 512;
|
||||
var expectedStreamLength = finalizeArchive
|
||||
? paddedContentWithHeader + (512 * 2)
|
||||
: paddedContentWithHeader;
|
||||
Assert.Equal(expectedStreamLength, stream.Length);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
@@ -51,4 +53,49 @@ public class WriterTests : TestBase
|
||||
}
|
||||
VerifyFiles();
|
||||
}
|
||||
|
||||
protected async Task WriteAsync(
|
||||
CompressionType compressionType,
|
||||
string archive,
|
||||
string archiveToVerifyAgainst,
|
||||
Encoding? encoding = null,
|
||||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH2_FILES_PATH, archive)))
|
||||
{
|
||||
var writerOptions = new WriterOptions(compressionType) { LeaveStreamOpen = true };
|
||||
|
||||
writerOptions.ArchiveEncoding.Default = encoding ?? Encoding.Default;
|
||||
|
||||
using var writer = WriterFactory.Open(stream, _type, writerOptions);
|
||||
await writer.WriteAllAsync(
|
||||
ORIGINAL_FILES_PATH,
|
||||
"*",
|
||||
SearchOption.AllDirectories,
|
||||
cancellationToken
|
||||
);
|
||||
}
|
||||
CompareArchivesByPath(
|
||||
Path.Combine(SCRATCH2_FILES_PATH, archive),
|
||||
Path.Combine(TEST_ARCHIVES_PATH, archiveToVerifyAgainst)
|
||||
);
|
||||
|
||||
using (Stream stream = File.OpenRead(Path.Combine(SCRATCH2_FILES_PATH, archive)))
|
||||
{
|
||||
var readerOptions = new ReaderOptions();
|
||||
|
||||
readerOptions.ArchiveEncoding.Default = encoding ?? Encoding.Default;
|
||||
|
||||
using var reader = ReaderFactory.Open(
|
||||
SharpCompressStream.Create(stream, leaveOpen: true),
|
||||
readerOptions
|
||||
);
|
||||
reader.WriteAllToDirectory(
|
||||
SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions { ExtractFullPath = true }
|
||||
);
|
||||
}
|
||||
VerifyFiles();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user