mirror of
https://github.com/adamhathcock/sharpcompress.git
synced 2026-07-08 18:16:30 +00:00
tightens up tests
This commit is contained in:
@@ -27,6 +27,8 @@ Primary references:
|
||||
- `TarWriterOptions.HeaderFormat` is now honored in sync and async file and directory write paths.
|
||||
- Tar tests now cover `USTAR` and `GNU_TAR_LONG_LINK`, including USTAR long-name failure scenarios.
|
||||
- Symlink coverage now includes `TarWithSymlink.tar.gz` for reader sync and async paths.
|
||||
- Tar tests now explicitly cover unsupported tar wrapper compression writes (`Xz`, `ZStandard`, `Lzw`) for sync and async writer paths.
|
||||
- `TarArchive.OpenAsyncArchive(Stream)` now enforces the same seekable-stream contract as `TarArchive.OpenArchive(Stream)`.
|
||||
- Sparse handling remains explicitly unsupported.
|
||||
- Non-modeled PAX keys remain explicitly unsupported.
|
||||
|
||||
@@ -183,20 +185,11 @@ This is not inherently wrong, but it should be clearly documented everywhere sup
|
||||
|
||||
## Sync and Async API Inconsistencies
|
||||
|
||||
### Seekability requirements differ at the API boundary
|
||||
### Seekability contract alignment is resolved
|
||||
|
||||
Synchronous `TarArchive.OpenArchive(Stream)` explicitly throws if the stream is not seekable.
|
||||
`TarArchive.OpenArchive(Stream)` and `TarArchive.OpenAsyncArchive(Stream)` now both enforce the same seekable-stream contract and throw `ArgumentException` for non-seekable input.
|
||||
|
||||
Asynchronous `TarArchive.OpenAsyncArchive(Stream)` does not perform the same public guard.
|
||||
|
||||
Impact:
|
||||
|
||||
- callers do not see the same contract from sync and async overloads
|
||||
- behavior is harder to reason about from API docs alone
|
||||
|
||||
Recommended action:
|
||||
|
||||
- either align the contracts or document the difference explicitly
|
||||
Tar tests include an async regression case for non-seekable stream open.
|
||||
|
||||
### Header format alignment between sync and async is resolved
|
||||
|
||||
@@ -236,19 +229,15 @@ Recommended action:
|
||||
|
||||
- either add fixtures and tests or document these as unsupported with no test coverage
|
||||
|
||||
### No tests for unsupported write wrappers
|
||||
### Unsupported-wrapper writer coverage is now present
|
||||
|
||||
There are negative tests for an invalid `Rar` compression type, but not for unsupported tar wrappers that a user might reasonably infer from read support.
|
||||
|
||||
Missing negative cases include:
|
||||
Tar writer tests now explicitly verify `InvalidFormatException` for unsupported tar wrapper compression types:
|
||||
|
||||
- `CompressionType.Xz`
|
||||
- `CompressionType.ZStandard`
|
||||
- `CompressionType.Lzw`
|
||||
|
||||
Recommended action:
|
||||
|
||||
- add explicit negative tests so the supported write matrix stays intentional
|
||||
Coverage exists in both sync and async writer test paths.
|
||||
|
||||
## Documentation Gaps
|
||||
|
||||
@@ -287,8 +276,6 @@ Recommended action:
|
||||
|
||||
### Priority 1
|
||||
|
||||
- Add negative writer tests for unsupported wrapper compressions
|
||||
- Evaluate whether sync and async archive open contracts should match exactly
|
||||
- Improve metadata round-trip behavior only if there is a consumer need
|
||||
- Evaluate whether non-modeled PAX keys should remain ignored or be surfaced in a future metadata API
|
||||
|
||||
@@ -298,7 +285,7 @@ The SharpCompress Tar implementation is strong on common read scenarios and basi
|
||||
|
||||
- documentation overstating or under-describing support
|
||||
- incomplete feature coverage for less common tar dialect features
|
||||
- archive/read behavioral differences that are not always explicit in docs
|
||||
- intentionally deferred metadata and API-surface decisions
|
||||
- test coverage holes around advanced tar metadata features
|
||||
|
||||
`docs/TAR_SPEC.md` should be treated as the implementation baseline. This document identifies where that baseline is incomplete, inconsistent, or incorrectly reflected elsewhere in the repository.
|
||||
|
||||
@@ -149,11 +149,11 @@ Implementation files:
|
||||
|
||||
### Open Behavior
|
||||
|
||||
Synchronous `TarArchive.OpenArchive(Stream)` requires a seekable stream and throws `ArgumentException` when `CanSeek` is `false`.
|
||||
`TarArchive.OpenArchive(Stream)` and `TarArchive.OpenAsyncArchive(Stream)` require a seekable stream and throw `ArgumentException` when `CanSeek` is `false`.
|
||||
|
||||
`TarArchive.OpenArchive(FileInfo)` and the list-based overloads use `SourceStream` and determine wrapper compression by calling `TarFactory.GetCompressionType`.
|
||||
|
||||
Asynchronous `OpenAsyncArchive` overloads use `TarFactory.GetCompressionTypeAsync` and do not enforce the same explicit seekability check at the public API boundary.
|
||||
Asynchronous `OpenAsyncArchive` overloads use `TarFactory.GetCompressionTypeAsync` for wrapper detection.
|
||||
|
||||
### Entry Loading
|
||||
|
||||
@@ -417,7 +417,7 @@ This section documents current implementation limits, not desired future behavio
|
||||
|
||||
### Archive behavior limitations
|
||||
|
||||
- Sync archive open requires a seekable input stream
|
||||
- Stream-based archive open requires a seekable input stream
|
||||
- Compressed tar archive access is not full random-access in the same sense as uncompressed seekable tar
|
||||
|
||||
## Test Coverage Map
|
||||
|
||||
@@ -103,6 +103,12 @@ public partial class TarArchive
|
||||
)
|
||||
{
|
||||
stream.NotNull(nameof(stream));
|
||||
|
||||
if (stream is not { CanSeek: true })
|
||||
{
|
||||
throw new ArgumentException("Stream must be seekable", nameof(stream));
|
||||
}
|
||||
|
||||
var sourceStream = new SourceStream(
|
||||
stream,
|
||||
i => null,
|
||||
|
||||
@@ -22,6 +22,18 @@ public class TarArchiveAsyncTests : ArchiveTests
|
||||
[Fact]
|
||||
public async ValueTask TarArchiveStreamRead_Async() => await ArchiveStreamReadAsync("Tar.tar");
|
||||
|
||||
[Fact]
|
||||
public async ValueTask TarArchiveStreamRead_Async_Throws_On_NonSeekable_Stream()
|
||||
{
|
||||
using Stream stream = new ForwardOnlyStream(
|
||||
File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, "Tar.tar"))
|
||||
);
|
||||
|
||||
await Assert.ThrowsAsync<ArgumentException>(async () =>
|
||||
await TarArchive.OpenAsyncArchive(new AsyncOnlyStream(stream))
|
||||
);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async ValueTask Tar_FileName_Exactly_100_Characters_Async()
|
||||
{
|
||||
|
||||
@@ -61,6 +61,21 @@ public class TarWriterAsyncTests : WriterTests
|
||||
)
|
||||
);
|
||||
|
||||
[Theory]
|
||||
[InlineData(CompressionType.Xz)]
|
||||
[InlineData(CompressionType.ZStandard)]
|
||||
[InlineData(CompressionType.Lzw)]
|
||||
public async ValueTask Tar_UnsupportedWrapperCompression_Write_Async(
|
||||
CompressionType compressionType
|
||||
) =>
|
||||
await Assert.ThrowsAsync<InvalidFormatException>(async () =>
|
||||
await WriteAsync(
|
||||
compressionType,
|
||||
"Zip.ppmd.noEmptyDirs.zip",
|
||||
"Zip.ppmd.noEmptyDirs.zip"
|
||||
)
|
||||
);
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
|
||||
@@ -55,6 +55,15 @@ public class TarWriterTests : WriterTests
|
||||
Write(CompressionType.Rar, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip")
|
||||
);
|
||||
|
||||
[Theory]
|
||||
[InlineData(CompressionType.Xz)]
|
||||
[InlineData(CompressionType.ZStandard)]
|
||||
[InlineData(CompressionType.Lzw)]
|
||||
public void Tar_UnsupportedWrapperCompression_Write(CompressionType compressionType) =>
|
||||
Assert.Throws<InvalidFormatException>(() =>
|
||||
Write(compressionType, "Zip.ppmd.noEmptyDirs.zip", "Zip.ppmd.noEmptyDirs.zip")
|
||||
);
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
|
||||
Reference in New Issue
Block a user