mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-09-23 07:25:11 +00:00
Merge pull request #404 from MattKotsenas/bugfix/idisposable
Enable parallel test execution
This commit is contained in:
@@ -92,7 +92,7 @@ namespace SharpCompress.Archives
|
||||
public static IArchive Open(string filePath, ReaderOptions options = null)
|
||||
{
|
||||
filePath.CheckNotNullOrEmpty("filePath");
|
||||
return Open(new FileInfo(filePath), options ?? new ReaderOptions());
|
||||
return Open(new FileInfo(filePath), options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -103,36 +103,31 @@ namespace SharpCompress.Archives
|
||||
public static IArchive Open(FileInfo fileInfo, ReaderOptions options = null)
|
||||
{
|
||||
fileInfo.CheckNotNull("fileInfo");
|
||||
options = options ?? new ReaderOptions();
|
||||
options = options ?? new ReaderOptions { LeaveStreamOpen = false };
|
||||
using (var stream = fileInfo.OpenRead())
|
||||
{
|
||||
if (ZipArchive.IsZipFile(stream, null))
|
||||
{
|
||||
stream.Dispose();
|
||||
return ZipArchive.Open(fileInfo, options);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (SevenZipArchive.IsSevenZipFile(stream))
|
||||
{
|
||||
stream.Dispose();
|
||||
return SevenZipArchive.Open(fileInfo, options);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (GZipArchive.IsGZipFile(stream))
|
||||
{
|
||||
stream.Dispose();
|
||||
return GZipArchive.Open(fileInfo, options);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (RarArchive.IsRarFile(stream, options))
|
||||
{
|
||||
stream.Dispose();
|
||||
return RarArchive.Open(fileInfo, options);
|
||||
}
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
if (TarArchive.IsTarFile(stream))
|
||||
{
|
||||
stream.Dispose();
|
||||
return TarArchive.Open(fileInfo, options);
|
||||
}
|
||||
throw new InvalidOperationException("Cannot determine compressed stream type. Supported Archive Formats: Zip, GZip, Tar, Rar, 7Zip");
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
using System;
|
||||
using SharpCompress.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Common.Tar
|
||||
{
|
||||
internal class TarReadOnlySubStream : Stream
|
||||
internal class TarReadOnlySubStream : NonDisposingStream
|
||||
{
|
||||
private bool _isDisposed;
|
||||
private long _amountRead;
|
||||
|
||||
public TarReadOnlySubStream(Stream stream, long bytesToRead)
|
||||
public TarReadOnlySubStream(Stream stream, long bytesToRead) : base(stream, throwOnDispose: false)
|
||||
{
|
||||
Stream = stream;
|
||||
BytesLeftToRead = bytesToRead;
|
||||
}
|
||||
|
||||
@@ -36,12 +36,11 @@ namespace SharpCompress.Common.Tar
|
||||
var buffer = new byte[skipBytes];
|
||||
Stream.ReadFully(buffer);
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private long BytesLeftToRead { get; set; }
|
||||
|
||||
public Stream Stream { get; }
|
||||
|
||||
public override bool CanRead => true;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
|
||||
@@ -33,15 +34,18 @@ namespace SharpCompress.Common
|
||||
/// </summary>
|
||||
public virtual bool IsMultiVolume => true;
|
||||
|
||||
private bool _disposed;
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_actualStream.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
_actualStream.Dispose();
|
||||
_disposed = true;
|
||||
}
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.IO
|
||||
{
|
||||
public class ReadOnlyAppendingStream : Stream
|
||||
{
|
||||
private readonly Queue<Stream> streams;
|
||||
private Stream current;
|
||||
|
||||
public ReadOnlyAppendingStream(IEnumerable<Stream> streams)
|
||||
{
|
||||
this.streams = new Queue<Stream>(streams);
|
||||
}
|
||||
|
||||
public override bool CanRead => true;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override long Length => throw new NotImplementedException();
|
||||
|
||||
public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (current == null && streams.Count == 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (current == null)
|
||||
{
|
||||
current = streams.Dequeue();
|
||||
}
|
||||
int totalRead = 0;
|
||||
while (totalRead < count)
|
||||
{
|
||||
int read = current.Read(buffer, offset + totalRead, count - totalRead);
|
||||
if (read <= 0)
|
||||
{
|
||||
if (streams.Count == 0)
|
||||
{
|
||||
return totalRead;
|
||||
}
|
||||
current = streams.Dequeue();
|
||||
}
|
||||
totalRead += read;
|
||||
}
|
||||
return totalRead;
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,33 +3,22 @@ using System.IO;
|
||||
|
||||
namespace SharpCompress.IO
|
||||
{
|
||||
internal class BufferedSubStream : Stream
|
||||
internal class BufferedSubStream : NonDisposingStream
|
||||
{
|
||||
private long position;
|
||||
private int cacheOffset;
|
||||
private int cacheLength;
|
||||
private readonly byte[] cache;
|
||||
|
||||
public BufferedSubStream(Stream stream, long origin, long bytesToRead)
|
||||
public BufferedSubStream(Stream stream, long origin, long bytesToRead) : base(stream, throwOnDispose: false)
|
||||
{
|
||||
Stream = stream;
|
||||
position = origin;
|
||||
BytesLeftToRead = bytesToRead;
|
||||
cache = new byte[32 << 10];
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
//Stream.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private long BytesLeftToRead { get; set; }
|
||||
|
||||
public Stream Stream { get; }
|
||||
|
||||
public override bool CanRead => true;
|
||||
|
||||
public override bool CanSeek => false;
|
||||
|
||||
@@ -3,13 +3,10 @@ using System.IO;
|
||||
|
||||
namespace SharpCompress.IO
|
||||
{
|
||||
internal class CountingWritableSubStream : Stream
|
||||
internal class CountingWritableSubStream : NonDisposingStream
|
||||
{
|
||||
private readonly Stream writableStream;
|
||||
|
||||
internal CountingWritableSubStream(Stream stream)
|
||||
internal CountingWritableSubStream(Stream stream) : base(stream, throwOnDispose: false)
|
||||
{
|
||||
writableStream = stream;
|
||||
}
|
||||
|
||||
public ulong Count { get; private set; }
|
||||
@@ -22,7 +19,7 @@ namespace SharpCompress.IO
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
writableStream.Flush();
|
||||
Stream.Flush();
|
||||
}
|
||||
|
||||
public override long Length => throw new NotSupportedException();
|
||||
@@ -46,13 +43,13 @@ namespace SharpCompress.IO
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
writableStream.Write(buffer, offset, count);
|
||||
Stream.Write(buffer, offset, count);
|
||||
Count += (uint)count;
|
||||
}
|
||||
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
writableStream.WriteByte(value);
|
||||
Stream.WriteByte(value);
|
||||
++Count;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace SharpCompress.IO
|
||||
{
|
||||
Stream.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
public Stream Stream { get; }
|
||||
@@ -74,10 +75,5 @@ namespace SharpCompress.IO
|
||||
{
|
||||
Stream.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
Stream.WriteByte(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,10 +15,9 @@ namespace SharpCompress.IO
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
if (ThrowOnDispose)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
throw new InvalidOperationException($"Attempt to dispose of a {nameof(NonDisposingStream)} when {nameof(ThrowOnDispose)} is {ThrowOnDispose}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,11 +43,6 @@ namespace SharpCompress.IO
|
||||
return Stream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override int ReadByte()
|
||||
{
|
||||
return Stream.ReadByte();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
return Stream.Seek(offset, origin);
|
||||
@@ -63,10 +57,5 @@ namespace SharpCompress.IO
|
||||
{
|
||||
Stream.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override void WriteByte(byte value)
|
||||
{
|
||||
Stream.WriteByte(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ namespace SharpCompress.IO
|
||||
}
|
||||
|
||||
public ReadOnlySubStream(Stream stream, long? origin, long bytesToRead)
|
||||
: base(stream, false)
|
||||
: base(stream, throwOnDispose: false)
|
||||
{
|
||||
if (origin != null)
|
||||
{
|
||||
|
||||
@@ -10,7 +10,7 @@ using Xunit;
|
||||
|
||||
namespace SharpCompress.Test
|
||||
{
|
||||
public class ArchiveTests : TestBase
|
||||
public class ArchiveTests : ReaderTests
|
||||
{
|
||||
protected void ArchiveStreamReadExtractAll(string testArchive, CompressionType compression)
|
||||
{
|
||||
@@ -29,7 +29,7 @@ namespace SharpCompress.Test
|
||||
Assert.True(archive.IsSolid);
|
||||
using (var reader = archive.ExtractAllEntries())
|
||||
{
|
||||
ReaderTests.UseReader(this, reader, compression);
|
||||
UseReader(reader, compression);
|
||||
}
|
||||
VerifyFiles();
|
||||
|
||||
@@ -104,116 +104,42 @@ namespace SharpCompress.Test
|
||||
protected void ArchiveFileRead(string testArchive, ReaderOptions readerOptions = null)
|
||||
{
|
||||
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
|
||||
ArchiveFileRead(testArchive.AsEnumerable(), readerOptions);
|
||||
}
|
||||
|
||||
protected void ArchiveFileRead(IEnumerable<string> testArchives, ReaderOptions readerOptions = null)
|
||||
{
|
||||
foreach (var path in testArchives)
|
||||
using (var archive = ArchiveFactory.Open(testArchive, readerOptions))
|
||||
{
|
||||
using (var archive = ArchiveFactory.Open(path, readerOptions))
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
//archive.EntryExtractionBegin += archive_EntryExtractionBegin;
|
||||
//archive.FilePartExtractionBegin += archive_FilePartExtractionBegin;
|
||||
//archive.CompressedBytesRead += archive_CompressedBytesRead;
|
||||
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true
|
||||
});
|
||||
}
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true
|
||||
});
|
||||
}
|
||||
VerifyFiles();
|
||||
}
|
||||
VerifyFiles();
|
||||
}
|
||||
|
||||
private void archive_CompressedBytesRead(object sender, CompressedBytesReadEventArgs e)
|
||||
{
|
||||
Console.WriteLine("Read Compressed File Part Bytes: {0} Percentage: {1}%",
|
||||
e.CurrentFilePartCompressedBytesRead, CreatePercentage(e.CurrentFilePartCompressedBytesRead, partTotal));
|
||||
|
||||
string percentage = entryTotal.HasValue ? CreatePercentage(e.CompressedBytesRead,
|
||||
entryTotal.Value).ToString() : "Unknown";
|
||||
Console.WriteLine("Read Compressed File Entry Bytes: {0} Percentage: {1}%",
|
||||
e.CompressedBytesRead, percentage);
|
||||
}
|
||||
|
||||
private void archive_FilePartExtractionBegin(object sender, FilePartExtractionBeginEventArgs e)
|
||||
{
|
||||
partTotal = e.Size;
|
||||
Console.WriteLine("Initializing File Part Extraction: " + e.Name);
|
||||
}
|
||||
|
||||
private void archive_EntryExtractionBegin(object sender, ArchiveExtractionEventArgs<IArchiveEntry> e)
|
||||
{
|
||||
entryTotal = e.Item.Size;
|
||||
Console.WriteLine("Initializing File Entry Extraction: " + e.Item.Key);
|
||||
}
|
||||
|
||||
private long? entryTotal;
|
||||
private long partTotal;
|
||||
private long totalSize;
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrate the ExtractionOptions.PreserveFileTime and ExtractionOptions.PreserveAttributes extract options
|
||||
/// </summary>
|
||||
protected void ArchiveFileReadEx(string testArchive)
|
||||
{
|
||||
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
|
||||
ArchiveFileReadEx(testArchive.AsEnumerable());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Demonstrate the TotalUncompressSize property, and the ExtractionOptions.PreserveFileTime and ExtractionOptions.PreserveAttributes extract options
|
||||
/// </summary>
|
||||
protected void ArchiveFileReadEx(IEnumerable<string> testArchives)
|
||||
{
|
||||
foreach (var path in testArchives)
|
||||
using (var archive = ArchiveFactory.Open(testArchive))
|
||||
{
|
||||
using (var archive = ArchiveFactory.Open(path))
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
totalSize = archive.TotalUncompressSize;
|
||||
//archive.EntryExtractionBegin += Archive_EntryExtractionBeginEx;
|
||||
//archive.EntryExtractionEnd += Archive_EntryExtractionEndEx;
|
||||
//archive.CompressedBytesRead += Archive_CompressedBytesReadEx;
|
||||
|
||||
foreach (var entry in archive.Entries.Where(entry => !entry.IsDirectory))
|
||||
{
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true,
|
||||
PreserveAttributes = true,
|
||||
PreserveFileTime = true
|
||||
});
|
||||
}
|
||||
entry.WriteToDirectory(SCRATCH_FILES_PATH,
|
||||
new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true,
|
||||
PreserveAttributes = true,
|
||||
PreserveFileTime = true
|
||||
});
|
||||
}
|
||||
VerifyFilesEx();
|
||||
}
|
||||
}
|
||||
|
||||
private void Archive_EntryExtractionEndEx(object sender, ArchiveExtractionEventArgs<IArchiveEntry> e)
|
||||
{
|
||||
partTotal += e.Item.Size;
|
||||
}
|
||||
|
||||
private void Archive_CompressedBytesReadEx(object sender, CompressedBytesReadEventArgs e)
|
||||
{
|
||||
string percentage = entryTotal.HasValue ? CreatePercentage(e.CompressedBytesRead, entryTotal.Value).ToString() : "-";
|
||||
string tortalPercentage = CreatePercentage(partTotal + e.CompressedBytesRead, totalSize).ToString();
|
||||
Console.WriteLine(@"Read Compressed File Progress: {0}% Total Progress {1}%", percentage, tortalPercentage);
|
||||
}
|
||||
|
||||
private void Archive_EntryExtractionBeginEx(object sender, ArchiveExtractionEventArgs<IArchiveEntry> e)
|
||||
{
|
||||
entryTotal = e.Item.Size;
|
||||
}
|
||||
|
||||
private int CreatePercentage(long n, long d)
|
||||
{
|
||||
return (int)(((double)n / (double)d) * 100);
|
||||
VerifyFilesEx();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace SharpCompress.Test.GZip
|
||||
[Fact]
|
||||
public void GZip_Archive_Generic()
|
||||
{
|
||||
using (Stream stream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open))
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")))
|
||||
using (var archive = ArchiveFactory.Open(stream))
|
||||
{
|
||||
var entry = archive.Entries.First();
|
||||
@@ -30,7 +30,7 @@ namespace SharpCompress.Test.GZip
|
||||
[Fact]
|
||||
public void GZip_Archive()
|
||||
{
|
||||
using (Stream stream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open))
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")))
|
||||
using (var archive = GZipArchive.Open(stream))
|
||||
{
|
||||
var entry = archive.Entries.First();
|
||||
@@ -45,7 +45,7 @@ namespace SharpCompress.Test.GZip
|
||||
public void GZip_Archive_NoAdd()
|
||||
{
|
||||
string jpg = Path.Combine(ORIGINAL_FILES_PATH, "jpg", "test.jpg");
|
||||
using (Stream stream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open))
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")))
|
||||
using (var archive = GZipArchive.Open(stream))
|
||||
{
|
||||
Assert.Throws<InvalidOperationException>(() => archive.AddEntry("jpg\\test.jpg", jpg));
|
||||
@@ -58,7 +58,7 @@ namespace SharpCompress.Test.GZip
|
||||
public void GZip_Archive_Multiple_Reads()
|
||||
{
|
||||
var inputStream = new MemoryStream();
|
||||
using (var fileStream = File.Open(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"), FileMode.Open))
|
||||
using (var fileStream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz")))
|
||||
{
|
||||
fileStream.CopyTo(inputStream);
|
||||
inputStream.Position = 0;
|
||||
|
||||
@@ -42,16 +42,12 @@ namespace SharpCompress.Test.GZip
|
||||
public void GZip_Writer_Generic_Bad_Compression()
|
||||
{
|
||||
Assert.Throws<InvalidFormatException>(() =>
|
||||
{
|
||||
using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz")))
|
||||
using (var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.BZip2))
|
||||
{
|
||||
writer.Write("Tar.tar", Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"));
|
||||
}
|
||||
CompareArchivesByPath(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz"),
|
||||
Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar.gz"));
|
||||
|
||||
});
|
||||
{
|
||||
using (Stream stream = File.OpenWrite(Path.Combine(SCRATCH_FILES_PATH, "Tar.tar.gz")))
|
||||
using (var writer = WriterFactory.Open(stream, ArchiveType.GZip, CompressionType.BZip2))
|
||||
{
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Test
|
||||
namespace SharpCompress.Test.Mocks
|
||||
{
|
||||
public class ForwardOnlyStream : Stream
|
||||
{
|
||||
@@ -16,9 +16,15 @@ namespace SharpCompress.Test
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
stream.Dispose();
|
||||
IsDisposed = true;
|
||||
if (!IsDisposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
stream.Dispose();
|
||||
IsDisposed = true;
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanRead => true;
|
||||
@@ -44,11 +50,6 @@ namespace SharpCompress.Test
|
||||
return stream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override int ReadByte()
|
||||
{
|
||||
return stream.ReadByte();
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
69
tests/SharpCompress.Test/Mocks/TestStream.cs
Normal file
69
tests/SharpCompress.Test/Mocks/TestStream.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Test.Mocks
|
||||
{
|
||||
public class TestStream : Stream
|
||||
{
|
||||
private readonly Stream stream;
|
||||
|
||||
public TestStream(Stream stream) : this(stream, stream.CanRead, stream.CanWrite, stream.CanSeek)
|
||||
{
|
||||
}
|
||||
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
public TestStream(Stream stream, bool read, bool write, bool seek)
|
||||
{
|
||||
this.stream = stream;
|
||||
CanRead = read;
|
||||
CanWrite = write;
|
||||
CanSeek = seek;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
stream.Dispose();
|
||||
IsDisposed = true;
|
||||
}
|
||||
|
||||
public override bool CanRead { get; }
|
||||
|
||||
public override bool CanSeek { get; }
|
||||
|
||||
public override bool CanWrite { get; }
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
stream.Flush();
|
||||
}
|
||||
|
||||
public override long Length => stream.Length;
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get => stream.Position;
|
||||
set => stream.Position = value;
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return stream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
return stream.Seek(offset, origin);
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
stream.SetLength(value);
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
stream.Write(buffer, offset, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ namespace SharpCompress.Test.Rar
|
||||
|
||||
private void ReadEncryptedFlag(string testArchive, bool isEncrypted)
|
||||
{
|
||||
using (var stream = GetReaderStream(testArchive))
|
||||
using (var stream = new FileStream(Path.Combine(TEST_ARCHIVES_PATH, testArchive), FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
foreach (var header in rarHeaderFactory.ReadHeaders(stream))
|
||||
{
|
||||
@@ -58,10 +58,5 @@ namespace SharpCompress.Test.Rar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private FileStream GetReaderStream(string testArchive)
|
||||
{
|
||||
return new FileStream(Path.Combine(TEST_ARCHIVES_PATH, testArchive), FileMode.Open);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,26 +199,7 @@ namespace SharpCompress.Test.Rar
|
||||
|
||||
private void ReadRar(string testArchive, string password)
|
||||
{
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testArchive)))
|
||||
using (var reader = RarReader.Open(stream, new ReaderOptions()
|
||||
{
|
||||
Password = password
|
||||
}))
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
Assert.Equal(CompressionType.Rar, reader.Entry.CompressionType);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
VerifyFiles();
|
||||
Read(testArchive, CompressionType.Rar, new ReaderOptions { Password = password });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -234,7 +215,7 @@ namespace SharpCompress.Test.Rar
|
||||
private void DoRar_Entry_Stream(string filename)
|
||||
{
|
||||
using (Stream stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename)))
|
||||
using (var reader = RarReader.Open(stream))
|
||||
using (var reader = ReaderFactory.Open(stream))
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
@@ -267,7 +248,7 @@ namespace SharpCompress.Test.Rar
|
||||
public void Rar_Reader_Audio_program()
|
||||
{
|
||||
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Rar.Audio_program.rar")))
|
||||
using (var reader = RarReader.Open(stream, new ReaderOptions()
|
||||
using (var reader = ReaderFactory.Open(stream, new ReaderOptions()
|
||||
{
|
||||
LookForHeader = true
|
||||
}))
|
||||
@@ -333,7 +314,7 @@ namespace SharpCompress.Test.Rar
|
||||
private void DoRar_Solid_Skip_Reader(string filename)
|
||||
{
|
||||
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename)))
|
||||
using (var reader = RarReader.Open(stream, new ReaderOptions()
|
||||
using (var reader = ReaderFactory.Open(stream, new ReaderOptions()
|
||||
{
|
||||
LookForHeader = true
|
||||
}))
|
||||
@@ -366,7 +347,7 @@ namespace SharpCompress.Test.Rar
|
||||
private void DoRar_Reader_Skip(string filename)
|
||||
{
|
||||
using (var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, filename)))
|
||||
using (var reader = RarReader.Open(stream, new ReaderOptions()
|
||||
using (var reader = ReaderFactory.Open(stream, new ReaderOptions()
|
||||
{
|
||||
LookForHeader = true
|
||||
}))
|
||||
|
||||
@@ -1,51 +1,66 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Test.Mocks;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpCompress.Test
|
||||
{
|
||||
public class ReaderTests : TestBase
|
||||
public abstract class ReaderTests : TestBase
|
||||
{
|
||||
protected void Read(string testArchive, CompressionType expectedCompression)
|
||||
protected void Read(string testArchive, CompressionType expectedCompression, ReaderOptions options = null)
|
||||
{
|
||||
testArchive = Path.Combine(TEST_ARCHIVES_PATH, testArchive);
|
||||
Read(testArchive.AsEnumerable(), expectedCompression);
|
||||
|
||||
options = options ?? new ReaderOptions();
|
||||
|
||||
options.LeaveStreamOpen = true;
|
||||
ReadImpl(testArchive, expectedCompression, options);
|
||||
|
||||
options.LeaveStreamOpen = false;
|
||||
ReadImpl(testArchive, expectedCompression, options);
|
||||
VerifyFiles();
|
||||
}
|
||||
|
||||
protected void Read(IEnumerable<string> testArchives, CompressionType expectedCompression)
|
||||
private void ReadImpl(string testArchive, CompressionType expectedCompression, ReaderOptions options)
|
||||
{
|
||||
foreach (var path in testArchives)
|
||||
using (var file = File.OpenRead(testArchive))
|
||||
{
|
||||
using (var stream = new NonDisposingStream(new ForwardOnlyStream(File.OpenRead(path)), true))
|
||||
using (var reader = ReaderFactory.Open(stream, new ReaderOptions()
|
||||
{
|
||||
LeaveStreamOpen = true
|
||||
}))
|
||||
using (var protectedStream = new NonDisposingStream(new ForwardOnlyStream(file), throwOnDispose: true))
|
||||
{
|
||||
UseReader(this, reader, expectedCompression);
|
||||
stream.ThrowOnDispose = false;
|
||||
using (var testStream = new TestStream(protectedStream))
|
||||
{
|
||||
using (var reader = ReaderFactory.Open(testStream, options))
|
||||
{
|
||||
UseReader(reader, expectedCompression);
|
||||
protectedStream.ThrowOnDispose = false;
|
||||
Assert.False(testStream.IsDisposed, "{nameof(testStream)} prematurely closed");
|
||||
}
|
||||
|
||||
// Boolean XOR -- If the stream should be left open (true), then the stream should not be diposed (false)
|
||||
// and if the stream should be closed (false), then the stream should be disposed (true)
|
||||
var message = $"{nameof(options.LeaveStreamOpen)} is set to '{options.LeaveStreamOpen}', so {nameof(testStream.IsDisposed)} should be set to '{!testStream.IsDisposed}', but is set to {testStream.IsDisposed}";
|
||||
Assert.True(options.LeaveStreamOpen != testStream.IsDisposed, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void UseReader(TestBase test, IReader reader, CompressionType expectedCompression)
|
||||
public void UseReader(IReader reader, CompressionType expectedCompression)
|
||||
{
|
||||
while (reader.MoveToNextEntry())
|
||||
{
|
||||
if (!reader.Entry.IsDirectory)
|
||||
{
|
||||
Assert.Equal(reader.Entry.CompressionType, expectedCompression);
|
||||
reader.WriteEntryToDirectory(test.SCRATCH_FILES_PATH, new ExtractionOptions()
|
||||
Assert.Equal(expectedCompression, reader.Entry.CompressionType);
|
||||
reader.WriteEntryToDirectory(SCRATCH_FILES_PATH, new ExtractionOptions()
|
||||
{
|
||||
ExtractFullPath = true,
|
||||
Overwrite = true
|
||||
});
|
||||
}
|
||||
}
|
||||
test.VerifyFiles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ using Xunit;
|
||||
|
||||
namespace SharpCompress.Test.Streams
|
||||
{
|
||||
public class StreamTests
|
||||
public class LzmaStreamTests
|
||||
{
|
||||
[Fact]
|
||||
public void TestLzma2Decompress1Byte()
|
||||
@@ -2,7 +2,7 @@
|
||||
using SharpCompress.IO;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpCompress.Test
|
||||
namespace SharpCompress.Test.Streams
|
||||
{
|
||||
public class RewindableStreamTest
|
||||
{
|
||||
@@ -3,6 +3,7 @@ using System.IO;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.Tar;
|
||||
using SharpCompress.Test.Mocks;
|
||||
using Xunit;
|
||||
|
||||
namespace SharpCompress.Test.Tar
|
||||
|
||||
@@ -6,8 +6,6 @@ using System.Text;
|
||||
using SharpCompress.Readers;
|
||||
using Xunit;
|
||||
|
||||
[assembly: CollectionBehavior(DisableTestParallelization = true)]
|
||||
|
||||
namespace SharpCompress.Test
|
||||
{
|
||||
public class TestBase : IDisposable
|
||||
@@ -39,12 +37,6 @@ namespace SharpCompress.Test
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// WARNING: This garbage collection is needed to reclaim leaked file handles
|
||||
// (likely due to improperly handled IDisposables). Without it, The following
|
||||
// delete fails because files are still is use. This GC should be removed once
|
||||
// all the files pass without it.
|
||||
GC.Collect(2, GCCollectionMode.Forced, true, false);
|
||||
|
||||
Directory.Delete(SCRATCH_BASE_PATH, true);
|
||||
}
|
||||
|
||||
@@ -169,14 +161,6 @@ namespace SharpCompress.Test
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsFileLocked(new FileInfo(file1)))
|
||||
{
|
||||
throw new InvalidOperationException($"{file1} is not disposed");
|
||||
}
|
||||
if (IsFileLocked(new FileInfo(file2)))
|
||||
{
|
||||
throw new InvalidOperationException($"{file2} is not disposed");
|
||||
}
|
||||
using (var file1Stream = File.OpenRead(file1))
|
||||
using (var file2Stream = File.OpenRead(file2))
|
||||
{
|
||||
@@ -205,8 +189,7 @@ namespace SharpCompress.Test
|
||||
}
|
||||
|
||||
protected void CompareArchivesByPath(string file1, string file2) {
|
||||
ReaderOptions readerOptions = new ReaderOptions();
|
||||
|
||||
ReaderOptions readerOptions = new ReaderOptions { LeaveStreamOpen = false };
|
||||
readerOptions.ArchiveEncoding.Default = Encoding.GetEncoding(866);
|
||||
|
||||
//don't compare the order. OS X reads files from the file system in a different order therefore makes the archive ordering different
|
||||
@@ -231,29 +214,5 @@ namespace SharpCompress.Test
|
||||
}
|
||||
}
|
||||
|
||||
protected bool IsFileLocked(FileInfo file)
|
||||
{
|
||||
FileStream stream = null;
|
||||
|
||||
try
|
||||
{
|
||||
stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None);
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
//the file is unavailable because it is:
|
||||
//still being written to
|
||||
//or being processed by another thread
|
||||
//or does not exist (has already been processed)
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
stream?.Close();
|
||||
}
|
||||
|
||||
//file is not locked
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
using System.IO;
|
||||
|
||||
namespace SharpCompress.Test
|
||||
{
|
||||
public class TestStream : Stream
|
||||
{
|
||||
private readonly Stream stream;
|
||||
|
||||
public TestStream(Stream stream)
|
||||
: this(stream, true, true, true)
|
||||
{
|
||||
}
|
||||
|
||||
public bool IsDisposed { get; private set; }
|
||||
|
||||
public TestStream(Stream stream, bool read, bool write, bool seek)
|
||||
{
|
||||
this.stream = stream;
|
||||
CanRead = read;
|
||||
CanWrite = write;
|
||||
CanSeek = seek;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
stream.Dispose();
|
||||
IsDisposed = true;
|
||||
}
|
||||
|
||||
public override bool CanRead { get; }
|
||||
|
||||
public override bool CanSeek { get; }
|
||||
|
||||
public override bool CanWrite { get; }
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
stream.Flush();
|
||||
}
|
||||
|
||||
public override long Length => stream.Length;
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get => stream.Position;
|
||||
set => stream.Position = value;
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return stream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
return stream.Seek(offset, origin);
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
stream.SetLength(value);
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
stream.Write(buffer, offset, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using SharpCompress.Archives;
|
||||
using SharpCompress.Common;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.Zip;
|
||||
using SharpCompress.Test.Mocks;
|
||||
using SharpCompress.Writers;
|
||||
using SharpCompress.Writers.Zip;
|
||||
using Xunit;
|
||||
@@ -133,7 +134,7 @@ namespace SharpCompress.Test.Zip
|
||||
var eo = new ZipWriterEntryOptions() { DeflateCompressionLevel = Compressors.Deflate.CompressionLevel.None };
|
||||
|
||||
using (var zip = File.OpenWrite(filename))
|
||||
using(var st = forward_only ? (Stream)new NonSeekableStream(zip) : zip)
|
||||
using(var st = forward_only ? (Stream)new ForwardOnlyStream(zip) : zip)
|
||||
using (var zipWriter = (ZipWriter)WriterFactory.Open(st, ArchiveType.Zip, opts))
|
||||
{
|
||||
|
||||
@@ -186,38 +187,5 @@ namespace SharpCompress.Test.Zip
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper to create non-seekable streams from filestream
|
||||
/// </summary>
|
||||
private class NonSeekableStream : Stream
|
||||
{
|
||||
private readonly Stream stream;
|
||||
public NonSeekableStream(Stream s) { stream = s; }
|
||||
public override bool CanRead => stream.CanRead;
|
||||
public override bool CanSeek => false;
|
||||
public override bool CanWrite => stream.CanWrite;
|
||||
public override long Length => throw new NotImplementedException();
|
||||
public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
||||
public override void Flush() { stream.Flush(); }
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{ return stream.Read(buffer, offset, count); }
|
||||
|
||||
public override int ReadByte()
|
||||
{ return stream.ReadByte(); }
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{ throw new NotImplementedException(); }
|
||||
|
||||
public override void SetLength(long value)
|
||||
{ throw new NotImplementedException(); }
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{ stream.Write(buffer, offset, count); }
|
||||
|
||||
public override void WriteByte(byte value)
|
||||
{ stream.WriteByte(value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using SharpCompress.Common;
|
||||
using SharpCompress.IO;
|
||||
using SharpCompress.Readers;
|
||||
using SharpCompress.Readers.Zip;
|
||||
using SharpCompress.Test.Mocks;
|
||||
using SharpCompress.Writers;
|
||||
using Xunit;
|
||||
|
||||
@@ -268,40 +269,48 @@ namespace SharpCompress.Test.Zip
|
||||
VerifyFiles();
|
||||
}
|
||||
|
||||
private class NonSeekableMemoryStream : MemoryStream
|
||||
{
|
||||
public override bool CanSeek => false;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestSharpCompressWithEmptyStream()
|
||||
{
|
||||
|
||||
MemoryStream stream = new NonSeekableMemoryStream();
|
||||
|
||||
using (IWriter zipWriter = WriterFactory.Open(stream, ArchiveType.Zip, CompressionType.Deflate))
|
||||
var expected = new Tuple<string, byte[]>[]
|
||||
{
|
||||
zipWriter.Write("foo.txt", new MemoryStream(new byte[0]));
|
||||
zipWriter.Write("foo2.txt", new MemoryStream(new byte[10]));
|
||||
}
|
||||
new Tuple<string, byte[]>("foo.txt", new byte[0]),
|
||||
new Tuple<string, byte[]>("foo2.txt", new byte[10])
|
||||
};
|
||||
|
||||
stream = new MemoryStream(stream.ToArray());
|
||||
File.WriteAllBytes(Path.Combine(SCRATCH_FILES_PATH, "foo.zip"), stream.ToArray());
|
||||
|
||||
using (IReader zipReader = ZipReader.Open(new NonDisposingStream(stream, true)))
|
||||
using (var memory = new MemoryStream())
|
||||
{
|
||||
while (zipReader.MoveToNextEntry())
|
||||
Stream stream = new TestStream(memory, read: true, write: true, seek: false);
|
||||
|
||||
using (IWriter zipWriter = WriterFactory.Open(stream, ArchiveType.Zip, CompressionType.Deflate))
|
||||
{
|
||||
using (EntryStream entry = zipReader.OpenEntryStream())
|
||||
zipWriter.Write(expected[0].Item1, new MemoryStream(expected[0].Item2));
|
||||
zipWriter.Write(expected[1].Item1, new MemoryStream(expected[1].Item2));
|
||||
}
|
||||
|
||||
stream = new MemoryStream(memory.ToArray());
|
||||
File.WriteAllBytes(Path.Combine(SCRATCH_FILES_PATH, "foo.zip"), memory.ToArray());
|
||||
|
||||
using (IReader zipReader = ZipReader.Open(new NonDisposingStream(stream, true)))
|
||||
{
|
||||
var i = 0;
|
||||
while (zipReader.MoveToNextEntry())
|
||||
{
|
||||
MemoryStream tempStream = new MemoryStream();
|
||||
const int bufSize = 0x1000;
|
||||
byte[] buf = new byte[bufSize];
|
||||
int bytesRead = 0;
|
||||
while ((bytesRead = entry.Read(buf, 0, bufSize)) > 0)
|
||||
using (EntryStream entry = zipReader.OpenEntryStream())
|
||||
{
|
||||
tempStream.Write(buf, 0, bytesRead);
|
||||
MemoryStream tempStream = new MemoryStream();
|
||||
const int bufSize = 0x1000;
|
||||
byte[] buf = new byte[bufSize];
|
||||
int bytesRead = 0;
|
||||
while ((bytesRead = entry.Read(buf, 0, bufSize)) > 0)
|
||||
{
|
||||
tempStream.Write(buf, 0, bytesRead);
|
||||
}
|
||||
|
||||
Assert.Equal(expected[i].Item1, zipReader.Entry.Key);
|
||||
Assert.Equal(expected[i].Item2, tempStream.ToArray());
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user