Skip to content

Conversation

@trinistr
Copy link
Contributor

@trinistr trinistr commented Nov 7, 2025

This class currently has no specs at all. This PR adds specs for the following methods:

  • .new,
  • #free, #resize, #transfer,
  • all predicate methods,
  • incidental tests for many other methods, including .map, .for, .strings and some instance methods.

Special remarks:

  • spec for #valid? is somewhat incomplete, as garbage-collecting a string is non-trivial (I don't know how to);
  • spec for #resize does not have tests for slices as currently it seems to be an undefined behavior, and it's not clear if it should be reproduced (yes, ruby/spec is all about reproducing even weird behavior, but bugs are a gray area still).

Weird things discovered so far so I don't forget:

  • .new allows any and all flags (https://bugs.ruby-lang.org/issues/21672).
  • Documentation is wrong (.map, for example, has very early text).
  • INTERNAL and EXTERNAL are unclear, not being opposites (both can be false at the same time) and not even forming an exclusive tri-state with MAPPED.
  • Slices feel undercooked:
    • No flags are copied from the source, except READONLY.
    • No way to detect a slice except to read #to_s (or call all predicate methods to check for all-false).
    • Is calling #free even safe on a slice? (io_buffer_free seems to work fine only because no flags are copied, not actually checking "is this a slice?").
    • Calling #free on the source buffer is not safe (https://bugs.ruby-lang.org/issues/21212).
    • And #lockeding does not propagate in either direction.
    • #freeing a String-backed buffer does not invalidate its slice (shouldn't slices always become invalid without a source buffer?).
    • Slices can be resized at any point?! (Breaks the slice if size is 0, otherwise creates a new internal buffer. (Again, this is a case of "not checking for slice, and no flags are set".))
  • Is SHARED intended to be used manually or not?
  • Why is PRIVATE mapping neither INTERNAL or EXTERNAL?
  • .for and .string with a block are supposed to nullify buffer at the end, but buffer can be #transferred outside, is this intentional? (this creates a run-away buffer, able to change the string from wherever (but not a frozen string, at least)).
  • #resize on a MAPPED buffer changes it to INTERNAL on macOS and Windows.

@trinistr trinistr force-pushed the add-io-buffer-spec branch 3 times, most recently from e0188af to 4ce76f1 Compare November 7, 2025 21:14
Comment on lines 75 to 82
# This looks like a bug to me, these should be different memory models?
# Definitely looks like a bug, created issue: https://bugs.ruby-lang.org/issues/21672
it "creates internal-mapped buffer if INTERNAL and MAPPED are both specified" do
@buffer = IO::Buffer.new(10, IO::Buffer::INTERNAL | IO::Buffer::MAPPED)
@buffer.should.internal?
@buffer.should.mapped?
@buffer.should_not.empty?
end
Copy link
Contributor Author

@trinistr trinistr Nov 8, 2025

Choose a reason for hiding this comment

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

This is very clearly a bug, so I filed it as such. Not sure if the test needs to be here. Probably not? This does not seem like behavior that should be replicated. I will delete it for now.

@trinistr trinistr force-pushed the add-io-buffer-spec branch 3 times, most recently from c307df9 to 840258b Compare November 9, 2025 11:43
@trinistr trinistr changed the title Add specs for IO::Buffer Add initial specs for IO::Buffer Nov 9, 2025
@trinistr trinistr marked this pull request as ready for review November 9, 2025 12:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant