Merge pull request #1322 from adamhathcock/adam/release-test-cleanup
release test cleanup
This commit is contained in:
commit
fa296525c8
10 changed files with 122 additions and 108 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -24,3 +24,4 @@ profiler-snapshots/
|
|||
.DS_Store
|
||||
*.snupkg
|
||||
benchmark-results/
|
||||
.opencode/
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ internal static partial class IEntryExtensions
|
|||
{
|
||||
extension(IEntry entry)
|
||||
{
|
||||
public async ValueTask WriteEntryToDirectoryAsync(
|
||||
internal async ValueTask WriteEntryToDirectoryAsync(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options,
|
||||
Func<string, CancellationToken, ValueTask> writeAsync,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ internal static partial class IEntryExtensions
|
|||
/// <summary>
|
||||
/// Extract to specific directory, retaining filename
|
||||
/// </summary>
|
||||
public void WriteEntryToDirectory(
|
||||
internal void WriteEntryToDirectory(
|
||||
string destinationDirectory,
|
||||
ExtractionOptions? options,
|
||||
Action<string> write
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@ internal partial class Unpack
|
|||
{
|
||||
Header.HeaderSize = 0;
|
||||
|
||||
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 7)
|
||||
if (Inp.InAddr > ReadTop - 7)
|
||||
{
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
|
|
@ -292,7 +292,7 @@ internal partial class Unpack
|
|||
CancellationToken cancellationToken = default
|
||||
)
|
||||
{
|
||||
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 16)
|
||||
if (Inp.InAddr > ReadTop - 16)
|
||||
{
|
||||
if (!await UnpReadBufAsync(cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -372,7 +372,7 @@ internal partial class Unpack
|
|||
|
||||
private bool ReadFilter(UnpackFilter Filter)
|
||||
{
|
||||
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 16)
|
||||
if (Inp.InAddr > ReadTop - 16)
|
||||
{
|
||||
if (!UnpReadBuf())
|
||||
{
|
||||
|
|
@ -762,7 +762,7 @@ internal partial class Unpack
|
|||
{
|
||||
Header.HeaderSize = 0;
|
||||
|
||||
if (!Inp.ExternalBuffer && Inp.InAddr > ReadTop - 7)
|
||||
if (Inp.InAddr > ReadTop - 7)
|
||||
{
|
||||
if (!UnpReadBuf())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -156,40 +156,24 @@ if (Decoded!=NULL)
|
|||
//struct UnpackFilter
|
||||
internal class UnpackFilter
|
||||
{
|
||||
public byte Type;
|
||||
public uint BlockStart;
|
||||
public uint BlockLength;
|
||||
public byte Channels;
|
||||
internal byte Type;
|
||||
internal uint BlockStart;
|
||||
internal uint BlockLength;
|
||||
internal byte Channels;
|
||||
|
||||
// uint Width;
|
||||
// byte PosR;
|
||||
public bool NextWindow;
|
||||
};
|
||||
|
||||
//struct UnpackFilter30
|
||||
internal class UnpackFilter30
|
||||
{
|
||||
public uint BlockStart;
|
||||
public uint BlockLength;
|
||||
public bool NextWindow;
|
||||
|
||||
// Position of parent filter in Filters array used as prototype for filter
|
||||
// in PrgStack array. Not defined for filters in Filters array.
|
||||
public uint ParentFilter;
|
||||
|
||||
/*#if !RarV2017_RAR5ONLY
|
||||
public VM_PreparedProgram Prg;
|
||||
#endif*/
|
||||
internal bool NextWindow;
|
||||
};
|
||||
|
||||
internal class AudioVariables // For RAR 2.0 archives only.
|
||||
{
|
||||
public int K1,
|
||||
internal int K1,
|
||||
K2,
|
||||
K3,
|
||||
K4,
|
||||
K5;
|
||||
public int D1,
|
||||
internal int D1,
|
||||
D2,
|
||||
D3,
|
||||
D4;
|
||||
|
|
@ -369,8 +353,6 @@ internal partial class Unpack
|
|||
#endif*/
|
||||
private int PPMEscChar;
|
||||
|
||||
private readonly byte[] UnpOldTable = new byte[HUFF_TABLE_SIZE30];
|
||||
|
||||
// If we already read decoding tables for Unpack v2,v3,v5.
|
||||
// We should not use a single variable for all algorithm versions,
|
||||
// because we can have a corrupt archive with one algorithm file
|
||||
|
|
@ -379,26 +361,6 @@ internal partial class Unpack
|
|||
private bool TablesRead2,
|
||||
TablesRead5;
|
||||
|
||||
// Virtual machine to execute filters code.
|
||||
/*#if !RarV2017_RAR5ONLY
|
||||
RarVM VM;
|
||||
#endif*/
|
||||
|
||||
// Buffer to read VM filters code. We moved it here from AddVMCode
|
||||
// function to reduce time spent in BitInput constructor.
|
||||
private readonly BitInput VMCodeInp = new(true);
|
||||
|
||||
// Filters code, one entry per filter.
|
||||
private readonly List<UnpackFilter30> Filters30 = new();
|
||||
|
||||
// Filters stack, several entrances of same filter are possible.
|
||||
private readonly List<UnpackFilter30> PrgStack = new();
|
||||
|
||||
// Lengths of preceding data blocks, one length of one last block
|
||||
// for every filter. Used to reduce the size required to write
|
||||
// the data block length if lengths are repeating.
|
||||
private readonly List<int> OldFilterLengths = new();
|
||||
|
||||
/*#if RarV2017_RAR_SMP
|
||||
// More than 8 threads are unlikely to provide a noticeable gain
|
||||
// for unpacking, but would use the additional memory.
|
||||
|
|
|
|||
|
|
@ -22,8 +22,7 @@ internal class BitInput : IDisposable
|
|||
get => inBit;
|
||||
set => inBit = value;
|
||||
}
|
||||
public bool ExternalBuffer;
|
||||
private byte[] _privateBuffer = ArrayPool<byte>.Shared.Rent(MAX_SIZE);
|
||||
private readonly byte[] _privateBuffer = ArrayPool<byte>.Shared.Rent(MAX_SIZE);
|
||||
private bool _disposed;
|
||||
|
||||
/// <summary> </summary>
|
||||
|
|
|
|||
|
|
@ -268,9 +268,9 @@
|
|||
"net10.0": {
|
||||
"Microsoft.NET.ILLink.Tasks": {
|
||||
"type": "Direct",
|
||||
"requested": "[10.0.0, )",
|
||||
"resolved": "10.0.0",
|
||||
"contentHash": "kICGrGYEzCNI3wPzfEXcwNHgTvlvVn9yJDhSdRK+oZQy4jvYH529u7O0xf5ocQKzOMjfS07+3z9PKRIjrFMJDA=="
|
||||
"requested": "[10.0.6, )",
|
||||
"resolved": "10.0.6",
|
||||
"contentHash": "QKuvS0LWX4fjFqeDkyM7Kqt8P3wYTiPD4nwU+9y59n0sCiG714fxDgbbN82vDnzq89AF/PiHl92TP2C4aFDUQA=="
|
||||
},
|
||||
"Microsoft.NETFramework.ReferenceAssemblies": {
|
||||
"type": "Direct",
|
||||
|
|
@ -442,9 +442,9 @@
|
|||
"net8.0": {
|
||||
"Microsoft.NET.ILLink.Tasks": {
|
||||
"type": "Direct",
|
||||
"requested": "[8.0.22, )",
|
||||
"resolved": "8.0.22",
|
||||
"contentHash": "MhcMithKEiyyNkD2ZfbDZPmcOdi0GheGfg8saEIIEfD/fol3iHmcV8TsZkD4ZYz5gdUuoX4YtlVySUU7Sxl9SQ=="
|
||||
"requested": "[8.0.26, )",
|
||||
"resolved": "8.0.26",
|
||||
"contentHash": "o7/yVssM2r9Wyln2s9edBd5ANZXqdSdBI+g7JqXkyJmXrhs2WsJp25K5yPnYrTgdKBCjKB8bg+O2oew4sgzFaA=="
|
||||
},
|
||||
"Microsoft.NETFramework.ReferenceAssemblies": {
|
||||
"type": "Direct",
|
||||
|
|
|
|||
83
tests/SharpCompress.Test/TempDirectory.cs
Normal file
83
tests/SharpCompress.Test/TempDirectory.cs
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharpCompress.Test;
|
||||
|
||||
internal sealed class TempDirectory : IAsyncDisposable
|
||||
{
|
||||
private const int MaxDeleteAttempts = 5;
|
||||
private static readonly TimeSpan DeleteRetryDelay = TimeSpan.FromMilliseconds(100);
|
||||
|
||||
public TempDirectory(string prefix)
|
||||
{
|
||||
Path = System.IO.Path.Combine(System.IO.Path.GetTempPath(), $"{prefix}.{Guid.NewGuid():N}");
|
||||
Directory.CreateDirectory(Path);
|
||||
}
|
||||
|
||||
public string Path { get; }
|
||||
|
||||
public string GetDirectory(string name)
|
||||
{
|
||||
var path = System.IO.Path.Combine(Path, name);
|
||||
Directory.CreateDirectory(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
public string CreateDirectory(string name)
|
||||
{
|
||||
var path = System.IO.Path.Combine(Path, name, System.IO.Path.GetRandomFileName());
|
||||
Directory.CreateDirectory(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
public void ResetDirectory(string name)
|
||||
{
|
||||
DeleteDirectory(System.IO.Path.Combine(Path, name));
|
||||
Directory.CreateDirectory(System.IO.Path.Combine(Path, name));
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
for (var attempt = 1; attempt <= MaxDeleteAttempts; attempt++)
|
||||
{
|
||||
try
|
||||
{
|
||||
DeleteDirectory(Path);
|
||||
if (Directory.Exists(Path))
|
||||
{
|
||||
throw new IOException(
|
||||
$"Temp test directory '{Path}' still exists after deletion."
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
when (IsRetryableDeleteException(ex) && attempt < MaxDeleteAttempts)
|
||||
{
|
||||
await Task.Delay(DeleteRetryDelay).ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex) when (IsRetryableDeleteException(ex))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Failed to clean up temp test directory '{Path}'.",
|
||||
ex
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Temp test directory '{Path}' was not cleaned up.");
|
||||
}
|
||||
|
||||
private static void DeleteDirectory(string path)
|
||||
{
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
Directory.Delete(path, true);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsRetryableDeleteException(Exception ex) =>
|
||||
ex is IOException or UnauthorizedAccessException;
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using SharpCompress.Readers;
|
||||
using Xunit;
|
||||
|
|
@ -31,70 +30,40 @@ public class TestBase : IAsyncDisposable
|
|||
MISC_TEST_FILES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "MiscTest");
|
||||
}
|
||||
|
||||
private readonly Guid _testGuid = Guid.NewGuid();
|
||||
private readonly string _testTempDirectory;
|
||||
private readonly TempDirectory _tempDirectory;
|
||||
protected readonly string SCRATCH_FILES_PATH;
|
||||
protected readonly string SCRATCH2_FILES_PATH;
|
||||
|
||||
protected TestBase()
|
||||
{
|
||||
_testTempDirectory = Path.Combine(Path.GetTempPath(), $"SharpCompress.Test.{_testGuid:N}");
|
||||
SCRATCH_FILES_PATH = Path.Combine(_testTempDirectory, "Scratch");
|
||||
SCRATCH2_FILES_PATH = Path.Combine(_testTempDirectory, "Scratch2");
|
||||
|
||||
Directory.CreateDirectory(SCRATCH_FILES_PATH);
|
||||
Directory.CreateDirectory(SCRATCH2_FILES_PATH);
|
||||
_tempDirectory = new TempDirectory("SharpCompress.Test");
|
||||
SCRATCH_FILES_PATH = _tempDirectory.GetDirectory("Scratch");
|
||||
SCRATCH2_FILES_PATH = _tempDirectory.GetDirectory("Scratch2");
|
||||
}
|
||||
|
||||
//always use async dispose since we have I/O and sync Dispose doesn't wait when using xunit
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
DeleteScratchDirectory(_testTempDirectory);
|
||||
}
|
||||
// Always use async dispose since we have I/O and sync Dispose doesn't wait when using xunit.
|
||||
public ValueTask DisposeAsync() => _tempDirectory.DisposeAsync();
|
||||
|
||||
public void CleanScratch()
|
||||
{
|
||||
ResetScratchDirectory(SCRATCH_FILES_PATH);
|
||||
ResetScratchDirectory(SCRATCH2_FILES_PATH);
|
||||
_tempDirectory.ResetDirectory("Scratch");
|
||||
_tempDirectory.ResetDirectory("Scratch2");
|
||||
}
|
||||
|
||||
private static void ResetScratchDirectory(string path)
|
||||
{
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
Directory.Delete(path, true);
|
||||
}
|
||||
protected string CreateScratchDirectory(string name) =>
|
||||
_tempDirectory.CreateDirectory(Path.Combine("Scratch", name));
|
||||
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
protected string CreateScratch2Directory(string name) =>
|
||||
_tempDirectory.CreateDirectory(Path.Combine("Scratch2", name));
|
||||
|
||||
private static void DeleteScratchDirectory(string path)
|
||||
{
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
protected string GetScratchPath(params string[] parts) =>
|
||||
CombinePath(SCRATCH_FILES_PATH, parts);
|
||||
|
||||
try
|
||||
{
|
||||
Directory.Delete(path, true);
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Failed to clean up temp test directory '{path}'.",
|
||||
ex
|
||||
);
|
||||
}
|
||||
protected string GetScratch2Path(params string[] parts) =>
|
||||
CombinePath(SCRATCH2_FILES_PATH, parts);
|
||||
|
||||
if (Directory.Exists(path))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Temp test directory '{path}' was not cleaned up."
|
||||
);
|
||||
}
|
||||
}
|
||||
private static string CombinePath(string root, string[] parts) =>
|
||||
parts.Length == 0 ? root : Path.Combine(root, Path.Combine(parts));
|
||||
|
||||
public void VerifyFiles()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue