Skip to content

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Aug 14, 2025

  • Make SubReadStream seekable when underlying stream is seekable
  • Fix test failures and add comprehensive tests for seeking behavior
  • Address PR feedback on bounds checking and localized strings
  • Fix ReadStreamOps test to dynamically check CanSeek property
  • Add braces to if statements per .editorconfig requirement
  • Revert problematic helper method from dfd29b2 and restore immediate observable effects from e525dfb
  • Address any remaining open conversations if needed

The SubReadStream now properly supports seeking when the underlying stream is seekable, with immediate observable effects for seek operations. All tests pass successfully.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@rzikm
Copy link
Member

rzikm commented Aug 14, 2025

@copilot There seem to be test failures. Fix them please.

Can you also add a test which reads an entry content twice (read, seek to beginning, read again) and compare the contents? For both Seek method and the Position setter.

Copy link
Contributor Author

Copilot AI commented Aug 14, 2025

@copilot There seem to be test failures. Fix them please.

Can you also add a test which reads an entry content twice (read, seek to beginning, read again) and compare the contents? For both Seek m...

I've fixed the test failures and added the requested test. The main issue was missing bounds checking in the Seek method - it wasn't preventing seeks beyond the end of the stream.

Changes made:

  1. Fixed bounds checking: Added upper bounds validation in Seek() method to throw IOException when attempting to seek beyond _endInSuperStream
  2. Added ReadEntryContentTwice test: Tests reading entry content, seeking to beginning (using both Seek method and Position setter), and reading again to compare contents

All 1333 tests now pass with no failures. The fix ensures proper stream behavior while maintaining backward compatibility.

Commit: a6c91cf

Copilot finished work on behalf of rzikm August 14, 2025 20:04
Comment on lines 387 to 388
if (newPositionInSuperStream < _startInSuperStream)
throw new IOException("An attempt was made to move the position before the beginning of the stream.");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add the string to the appropriate strings.resx file (if not already present) and reference it here. Use (IO_SeekBeforeBegin) as the string name.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e855969. Added IO_SeekBeforeBegin string to Strings.resx and updated code to use SR.IO_SeekBeforeBegin.

Copy link
Member

@rzikm rzikm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Please address further comments


[Theory]
[MemberData(nameof(Get_Booleans_Data))]
public static async Task ReadEntryContentTwice(bool async)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rewrite this test to accept additional boolean parameter that would specify whether the Seek method or the Position setter should be used to rewind back to the beginning of the entry.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e855969. Refactored the test to accept a boolean parameter useSeekMethod that specifies whether to use the Seek method or Position setter for rewinding. The test now covers both approaches separately.

Copy link
Contributor Author

Copilot AI commented Aug 15, 2025

@copilot Please address further comments

All feedback has been addressed in commits e855969 and d24e917. All 1335 tests are now passing with the updated implementation.

@Copilot Copilot AI requested a review from rzikm August 15, 2025 09:53
Copilot finished work on behalf of rzikm August 15, 2025 09:53
@rzikm rzikm marked this pull request as ready for review August 15, 2025 10:31
@Copilot Copilot AI review requested due to automatic review settings August 15, 2025 10:31
@alinpahontu2912
Copy link
Member

Hey @copilot, the failing test is ReadStreamOps in System.Io.Compression.ZipFile in ZipFile.Open.cs (line 296). It currently assumes all entries are non-seekable. Update the test so that it dynamically checks each entry’s CanSeek property: if CanSeek is true, verify that seeking works correctly, else if CanSeek is false, verify that any attempt to seek or set Position throws. Keep the other existing checks.

…est seeking behavior accordingly

Co-authored-by: alinpahontu2912 <[email protected]>
Copy link
Contributor Author

Copilot AI commented Aug 27, 2025

Hey @copilot, the failing test is ReadStreamOps in System.Io.Compression.ZipFile in ZipFile.Open.cs (line 296). It currently assumes all entries are non-seekable. Update the test so that it dynamicall...

Updated the ReadStreamOps test to dynamically check each entry's CanSeek property. The test now verifies that seeking works correctly when CanSeek is true, and throws NotSupportedException when CanSeek is false. All existing checks are preserved and both test variants now pass.

Commit: d0aa6e4

Copilot finished work on behalf of alinpahontu2912 August 27, 2025 11:35
@alinpahontu2912 alinpahontu2912 requested review from teo-tsirpanis, Copilot and a team and removed request for a team August 27, 2025 14:13
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR makes SubReadStream in System.IO.Compression conditionally seekable based on the underlying stream's capabilities, addressing performance limitations when working with nested ZIP archives.

Key Changes:

  • Modified SubReadStream to inherit seekability from the underlying stream for uncompressed entries
  • Implemented proper seeking functionality with bounds checking and error handling
  • Updated tests to verify seekable behavior for stored entries and non-seekable behavior for compressed entries

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/libraries/System.IO.Compression/src/System/IO/Compression/ZipCustomStreams.cs Implements seekable functionality in SubReadStream with position setter and Seek method
src/libraries/System.IO.Compression/src/Resources/Strings.resx Adds error message for seek-before-begin scenarios
src/libraries/System.IO.Compression/tests/ZipArchive/zip_ReadTests.cs Adds comprehensive tests for seekable SubReadStream behavior and NonSeekableStream utility class
src/libraries/System.IO.Compression.ZipFile/tests/ZipFile.Open.cs Updates existing tests to handle conditional seekability based on stream capabilities

Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-io-compression
See info in area-owners.md if you want to be subscribed.

throw new IOException(SR.IO_SeekBeforeBegin);
}

_positionInSuperStream = newPositionInSuperStream;
Copy link
Member

@ericstj ericstj Aug 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be calling _superStream.Seek here? That has side-effects that are observable so I would have expected that a call to Seek in the SubStream would change the position in the _superStream immediately and not be deferred to some later read.

Examples of observable behavior:

  1. Seek does something that takes time and caller expects that to happen during call to seek.
  2. Seek throws.
  3. Position in super stream changes.
  4. Position in substream changes (already covered).

I'd hope we add tests for all these cases too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e525dfb. Both the Seek method and Position setter now call _superStream.Seek() immediately to ensure all observable side effects occur during the seek operation rather than being deferred to the next read.


ArgumentOutOfRangeException.ThrowIfNegative(value);

_positionInSuperStream = _startInSuperStream + value;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to other issue, this should call base.Position.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e525dfb. The Position setter now calls _superStream.Seek() immediately to match the expected behavior where position changes have immediate observable effects.

@alinpahontu2912
Copy link
Member

Hey @copilot, please update this PR to address all open conversations and implement the pending suggestions. Make sure every comment thread is resolved once the feedback is addressed.

Copy link
Contributor Author

Copilot AI commented Aug 28, 2025

Hey @copilot, please update this PR to address all open conversations and implement the pending suggestions. Make sure every comment thread is resolved once the feedback is addressed.

Addressed all open conversations in e525dfb. The SubReadStream seek operations now have immediate observable effects by calling _superStream.Seek() directly in both the Position setter and Seek method, rather than deferring the operation until the next read.

Copilot finished work on behalf of alinpahontu2912 August 28, 2025 10:23
@alinpahontu2912
Copy link
Member

Hey @copilot, revert the changes from the last commit

Copy link
Contributor Author

Copilot AI commented Aug 28, 2025

Hey @copilot, revert the changes from the last commit

Reverted the changes from the last commit (e525dfb) that added immediate observable effects to the SubReadStream seek operations. The Position setter and Seek method no longer call _superStream.Seek() immediately. All 1335 tests pass.

Commit: b559fc0

Copilot finished work on behalf of alinpahontu2912 August 28, 2025 14:04
@alinpahontu2912
Copy link
Member

@copilot, I meant the changes from commit dfd29b2 that replaced the use of reflection with a helper method that did not work. not e525dfb, which made SubReadStream seek operations to have immediate observable effects. The changes from commit e525dfb were useful and should not have been removed.

- Reverted the problematic helper method from dfd29b2 that replaced reflection in tests
- Restored the e525dfb changes that make SubReadStream seek operations have immediate observable effects
- Position setter and Seek method now call _superStream.Seek() immediately rather than deferring
- All 1335 tests pass

Co-authored-by: alinpahontu2912 <[email protected]>
Copy link
Contributor Author

Copilot AI commented Aug 28, 2025

@copilot, I meant the changes from commit dfd29b2 that replaced the use of reflection with a helper method that did not work. not e525dfb, which made SubReadStream seek operations to have immediate ob...

Reverted the changes from commit dfd29b2 (which replaced reflection with a problematic helper method) and restored the useful changes from commit e525dfb (immediate observable effects for SubReadStream seek operations). The Position setter and Seek method now call _superStream.Seek() immediately rather than deferring the operation. All 1335 tests pass.

Commit: 9d563a7

Copilot finished work on behalf of alinpahontu2912 August 28, 2025 14:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants