Files
sharpcompress/tests/SharpCompress.Test/Tar/TarArchiveTests.cs
2026-03-06 11:22:09 +00:00

343 lines
12 KiB
C#

using System;
using System.IO;
using System.Linq;
using System.Text;
using SharpCompress.Archives;
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;
namespace SharpCompress.Test.Tar;
public class TarArchiveTests : ArchiveTests
{
public TarArchiveTests() => UseExtensionInsteadOfNameToVerify = true;
[Fact]
public void TarArchiveStreamRead() => ArchiveStreamRead("Tar.tar");
[Fact]
public void TarArchivePathRead() => ArchiveFileRead("Tar.tar");
[Fact]
public void TarArchiveStreamRead_Throws_On_NonSeekable_Stream()
{
using Stream stream = new ForwardOnlyStream(
File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"))
);
Assert.Throws<ArgumentException>(() => ArchiveFactory.OpenArchive(stream));
}
[Fact]
public void Tar_FileName_Exactly_100_Characters()
{
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.OpenWriter(
stream,
ArchiveType.Tar,
new WriterOptions(CompressionType.None)
)
)
using (Stream inputStream = new MemoryStream())
{
var sw = new StreamWriter(inputStream);
sw.Write("dummy filecontent");
sw.Flush();
inputStream.Position = 0;
writer.Write(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 = ArchiveFactory.OpenArchive(unmodified))
{
Assert.Equal(1, archive2.Entries.Count());
Assert.Contains(filename, archive2.Entries.Select(entry => entry.Key));
foreach (var entry in archive2.Entries)
{
using (var sr = new StreamReader(entry.OpenEntryStream()))
{
Assert.Equal("dummy filecontent", sr.ReadLine());
}
}
}
}
[Fact]
public void Tar_NonUstarArchiveWithLongNameDoesNotSkipEntriesAfterTheLongOne()
{
var unmodified = Path.Combine(TEST_ARCHIVES_PATH, "very long filename.tar");
using var archive = ArchiveFactory.OpenArchive(unmodified);
Assert.Equal(5, archive.Entries.Count());
Assert.Contains("very long filename/", archive.Entries.Select(entry => entry.Key));
Assert.Contains(
"very long filename/very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename very long filename.jpg",
archive.Entries.Select(entry => entry.Key)
);
Assert.Contains("z_file 1.txt", archive.Entries.Select(entry => entry.Key));
Assert.Contains("z_file 2.txt", archive.Entries.Select(entry => entry.Key));
Assert.Contains("z_file 3.txt", archive.Entries.Select(entry => entry.Key));
}
[Fact]
public void Tar_VeryLongFilepathReadback()
{
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.OpenWriter(
stream,
ArchiveType.Tar,
new WriterOptions(CompressionType.None)
)
)
using (Stream inputStream = new MemoryStream())
{
var sw = new StreamWriter(inputStream);
sw.Write("dummy filecontent");
sw.Flush();
inputStream.Position = 0;
writer.Write(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 = ArchiveFactory.OpenArchive(unmodified))
{
Assert.Equal(1, archive2.Entries.Count());
Assert.Contains(longFilename, archive2.Entries.Select(entry => entry.Key));
foreach (var entry in archive2.Entries)
{
using (var sr = new StreamReader(entry.OpenEntryStream()))
{
Assert.Equal("dummy filecontent", sr.ReadLine());
}
}
}
}
[Fact]
public void Tar_UstarArchivePathReadLongName()
{
var unmodified = Path.Combine(TEST_ARCHIVES_PATH, "ustar with long names.tar");
using var archive = ArchiveFactory.OpenArchive(unmodified);
Assert.Equal(6, archive.Entries.Count());
Assert.Contains("Directory/", archive.Entries.Select(entry => entry.Key));
Assert.Contains(
"Directory/Some file with veeeeeeeeeery loooooooooong name",
archive.Entries.Select(entry => entry.Key)
);
Assert.Contains(
"Directory/Directory with veeeeeeeeeery loooooooooong name/",
archive.Entries.Select(entry => entry.Key)
);
Assert.Contains(
"Directory/Directory with veeeeeeeeeery loooooooooong name/Some file with veeeeeeeeeery loooooooooong name",
archive.Entries.Select(entry => entry.Key)
);
Assert.Contains(
"Directory/Directory with veeeeeeeeeery loooooooooong name/Directory with veeeeeeeeeery loooooooooong name/",
archive.Entries.Select(entry => entry.Key)
);
Assert.Contains(
"Directory/Directory with veeeeeeeeeery loooooooooong name/Directory with veeeeeeeeeery loooooooooong name/Some file with veeeeeeeeeery loooooooooong name",
archive.Entries.Select(entry => entry.Key)
);
}
[Fact]
public void Tar_Create_New()
{
var scratchPath = Path.Combine(SCRATCH_FILES_PATH, "Tar.tar");
var unmodified = Path.Combine(TEST_ARCHIVES_PATH, "Tar.noEmptyDirs.tar");
// var aropt = new Ar
using (var archive = TarArchive.CreateArchive())
{
archive.AddAllFromDirectory(ORIGINAL_FILES_PATH);
var twopt = new TarWriterOptions(CompressionType.None, true)
{
ArchiveEncoding = new ArchiveEncoding { Default = Encoding.GetEncoding(866) },
};
archive.SaveTo(scratchPath, twopt);
}
CompareArchivesByPath(unmodified, scratchPath);
}
[Fact]
public void Tar_Random_Write_Add()
{
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.OpenArchive(unmodified))
{
archive.AddEntry("jpg\\test.jpg", jpg);
archive.SaveTo(scratchPath, new TarWriterOptions(CompressionType.None, true));
}
CompareArchivesByPath(modified, scratchPath);
}
[Fact]
public void Tar_Random_Write_Remove()
{
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.OpenArchive(unmodified))
{
var entry = archive.Entries.Single(x =>
x.Key.NotNull().EndsWith("jpg", StringComparison.OrdinalIgnoreCase)
);
archive.RemoveEntry(entry);
archive.SaveTo(scratchPath, new TarWriterOptions(CompressionType.None, true));
}
CompareArchivesByPath(modified, scratchPath);
}
[Fact]
public void Tar_Containing_Rar_Archive()
{
var archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.ContainsRar.tar");
using Stream stream = File.OpenRead(archiveFullPath);
using var archive = ArchiveFactory.OpenArchive(stream);
Assert.True(archive.Type == ArchiveType.Tar);
}
[Fact]
public void Tar_Empty_Archive()
{
var archiveFullPath = Path.Combine(TEST_ARCHIVES_PATH, "Tar.Empty.tar");
using Stream stream = File.OpenRead(archiveFullPath);
using var archive = ArchiveFactory.OpenArchive(stream);
Assert.True(archive.Type == ArchiveType.Tar);
}
[Theory]
[InlineData(10)]
[InlineData(128)]
public void Tar_Japanese_Name(int length)
{
using var mstm = new MemoryStream();
var enc = new ArchiveEncoding { Default = Encoding.UTF8 };
var twopt = new TarWriterOptions(CompressionType.None, true) { ArchiveEncoding = enc };
var fname = new string((char)0x3042, length);
using (var tw = new TarWriter(mstm, twopt))
using (var input = new MemoryStream(new byte[32]))
{
tw.Write(fname, input, null);
}
using (var inputMemory = new MemoryStream(mstm.ToArray()))
{
var tropt = new ReaderOptions { ArchiveEncoding = enc };
using (var tr = TarReader.OpenReader(inputMemory, tropt))
{
while (tr.MoveToNextEntry())
{
Assert.Equal(fname, tr.Entry.Key);
}
}
}
}
[Fact]
public void Tar_Read_One_At_A_Time()
{
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))
{
tarWriter.Write("test1.txt", testFileStream);
testFileStream.Position = 0;
tarWriter.Write("test2.txt", testFileStream);
}
memoryStream.Position = 0;
var numberOfEntries = 0;
using (var archive = ArchiveFactory.OpenArchive(memoryStream))
{
foreach (var entry in archive.Entries)
{
++numberOfEntries;
using var tarEntryStream = entry.OpenEntryStream();
using var testFileStream = new MemoryStream();
tarEntryStream.CopyTo(testFileStream);
Assert.Equal(testBytes.Length, testFileStream.Length);
}
}
Assert.Equal(2, numberOfEntries);
}
[Fact]
public void Tar_Detect_Test()
{
var isTar = TarArchive.IsTarFile(Path.Combine(TEST_ARCHIVES_PATH, "false.positive.tar"));
Assert.False(isTar);
}
[Fact]
public void TarArchiveStreamRead_Autodetect_CompressedTar()
{
using Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"));
using var archive = ArchiveFactory.OpenArchive(stream);
Assert.Equal(ArchiveType.Tar, archive.Type);
Assert.NotEmpty(archive.Entries);
}
[Fact]
public void TarReaderStreamRead_Autodetect_CompressedTar()
{
using Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"));
using var reader = ReaderFactory.OpenReader(stream);
Assert.Equal(ArchiveType.Tar, reader.Type);
Assert.True(reader.MoveToNextEntry());
}
}