diff --git a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs
index dea60f7e..dd0035b1 100644
--- a/tests/SharpCompress.Test/Rar/RarArchiveTests.cs
+++ b/tests/SharpCompress.Test/Rar/RarArchiveTests.cs
@@ -645,15 +645,16 @@ public class RarArchiveTests : ArchiveTests
///
/// Test for issue: InvalidOperationException when extracting RAR files.
- /// This test verifies that RAR extraction completes successfully without throwing
- /// InvalidOperationException when the actual decompressed size may differ from
- /// the header-specified size. The fix changed the validation from (_position != Length)
- /// to (_position < Length) to only catch premature stream termination, not oversized decompression.
+ /// This test verifies the fix for the validation logic that was changed from
+ /// (_position != Length) to (_position < Length).
+ /// The old logic would throw an exception when position exceeded expected length,
+ /// but the new logic only throws when decompression ends prematurely (position < expected).
///
[Fact]
- public void Rar_ExtractionCompletesWithoutInvalidOperationException()
+ public void Rar_StreamValidation_OnlyThrowsOnPrematureEnd()
{
- // Test multiple RAR formats to ensure the fix works across all versions
+ // Test normal extraction - should NOT throw InvalidOperationException
+ // even if actual decompressed size differs from header
var testFiles = new[] { "Rar.rar", "Rar5.rar", "Rar4.rar", "Rar2.rar" };
foreach (var testFile in testFiles)
@@ -662,14 +663,13 @@ public class RarArchiveTests : ArchiveTests
using var archive = RarArchive.Open(stream);
// Extract all entries and read them completely
- // This ensures we read to the end of each entry stream without throwing
foreach (var entry in archive.Entries.Where(e => !e.IsDirectory))
{
using var entryStream = entry.OpenEntryStream();
using var ms = new MemoryStream();
- // Read the entire stream - this is where the exception would occur
- // if the validation was too strict (_position != Length instead of _position < Length)
+ // This should complete without throwing InvalidOperationException
+ // The fix ensures we only throw when position < expected length, not when position >= expected
entryStream.CopyTo(ms);
// Verify we read some data
@@ -680,4 +680,53 @@ public class RarArchiveTests : ArchiveTests
}
}
}
+
+ ///
+ /// Test that InvalidOperationException is correctly thrown only when decompression
+ /// ends prematurely (position < expected length), not when position >= expected length.
+ /// This verifies the fix where the condition was changed from (_position != Length)
+ /// to (_position < Length).
+ ///
+ [Fact]
+ public void Rar_StreamValidation_CorrectExceptionBehavior()
+ {
+ // This test documents the expected exception behavior:
+ // - OLD behavior: Threw when _position != Length (including position > Length)
+ // This incorrectly threw exceptions for valid RAR files where actual size > header size
+ // - NEW behavior: Only throws when _position < Length (premature termination)
+ // This correctly allows files where actual size >= header size
+
+ var testFile = "Rar.rar";
+ using var stream = File.OpenRead(Path.Combine(TEST_ARCHIVES_PATH, testFile));
+ using var archive = RarArchive.Open(stream);
+
+ var entry = archive.Entries.FirstOrDefault(e => !e.IsDirectory);
+ Assert.NotNull(entry);
+
+ using var entryStream = entry!.OpenEntryStream();
+
+ // Read all data from the stream completely
+ var buffer = new byte[4096];
+ long totalBytesRead = 0;
+ int bytesRead;
+ while ((bytesRead = entryStream.Read(buffer, 0, buffer.Length)) > 0)
+ {
+ totalBytesRead += bytesRead;
+ }
+
+ // Verify we read data
+ Assert.True(totalBytesRead > 0, "Should have read some data from the entry");
+
+ // After reading to EOF, further reads should return 0 without throwing
+ // This is the key fix: the old code would throw if position != expected length,
+ // but the new code only throws if position < expected length
+ bytesRead = entryStream.Read(buffer, 0, buffer.Length);
+ Assert.Equal(0, bytesRead);
+
+ // Note: To test the actual exception case (position < Length), we would need
+ // a truncated or corrupted RAR file where the unpacker stops before reaching
+ // the expected length. Such a file would trigger:
+ // throw new InvalidOperationException($"unpacked file size does not match header: expected {Length} found {_position}")
+ // when count > 0 && outTotal == 0 && _position < Length
+ }
}