-
-
Notifications
You must be signed in to change notification settings - Fork 395
Add initial specs for IO::Buffer #1297
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
e0188af to
4ce76f1
Compare
core/io/buffer/initialize_spec.rb
Outdated
| # 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 |
There was a problem hiding this comment.
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.
c307df9 to
840258b
Compare
d80c785 to
001bdd5
Compare
| @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED) | ||
| @buffer.external?.should be_false | ||
| end | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: It seems to me that this logic is closer to the constructor methods specs (new/map/for) than to the predicates. I would keep here just a couple of examples when a predicate returns either true or false.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see what you mean, but not sure what to even leave here then, especially when many cases of these flags are not intuituve. Hmm, maybe leave these specs as-is for now, but then simplify them when we have specs for all constructors?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I mentioned above as for me it makes sense to have there a test case when a predicate returns true and a test case with false.
Yeah, it's OK to not make changes in this PR if you are going to add specs for constructors in a separate one.
| end | ||
| buffer.free | ||
| buffer.null?.should be_true | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor: seems it's duplicated in specs for #locked?.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This and other dupes: I thought it would be better to over-spec than to select which file these interactions shoud be in 😅 I guess it would make sense to remove them from #locked, as it's really a property of individual methods (like this https://github.com/ruby/ruby/blob/master/io_buffer.c#L1485)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, excessive tests shouldn't be a problem. Yes, I agree that this specs would be better to put only here.
The main criterion as for me is to look from the user point of view - where a Ruby developer would look for these specs if he wants to checks the logic.
| slice.null?.should be_false | ||
| slice.valid?.should be_false | ||
| -> { slice.get_string }.should raise_error(IO::Buffer::InvalidatedError, "Buffer has been invalidated!") | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor: seems is duplicated in specs for #valid?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't really remove duplication, but cut off excess lines in this one and the one above.
core/io/buffer/locked_spec.rb
Outdated
| # See specs of individual methods for error messages. | ||
| -> { @buffer.free }.should raise_error(IO::Buffer::LockedError) | ||
| -> { @buffer.resize(8) }.should raise_error(IO::Buffer::LockedError) | ||
| -> { @buffer.transfer }.should raise_error(IO::Buffer::LockedError) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: it makes sense to specify exception messages everywhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor: I suppose other operations changing a buffer should be mentioned here as well (e.g. set_string or write).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To both reduce duplication and retain "what does this actually do?", I added simple "allowed" and "disallowed" tests.
| @buffer.locked do | ||
| -> { @buffer.resize(10) }.should raise_error(IO::Buffer::LockedError, "Cannot resize locked buffer!") | ||
| end | ||
| end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor: seems a duplicate
001bdd5 to
9e6959a
Compare
|
Thank you! |
This class currently has no specs at all. This PR adds specs for the following methods:
.new,#free,#resize,#transfer,.map,.for,.stringsand some instance methods.Special remarks:
#valid?is somewhat incomplete, as garbage-collecting a string is non-trivial (I don't know how to);#resizedoes 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:
.newallows any and all flags (https://bugs.ruby-lang.org/issues/21672)..map, for example, has very early text) (and#lockeddoesn't mention#transfer).INTERNALandEXTERNALare unclear, not being opposites (both can be false at the same time) and not even forming an exclusive tri-state withMAPPED.READONLY.#to_s(or call all predicate methods to check for all-false).#freeeven safe on a slice? (io_buffer_free seems to work fine only because no flags are copied, not actually checking "is this a slice?").#freeon the source buffer is not safe (https://bugs.ruby-lang.org/issues/21212).#lockedstate 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?).#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".))SHAREDintended to be used manually or not?PRIVATEmapping neither INTERNAL or EXTERNAL?.forand.stringwith 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)).#resizeon a MAPPED buffer changes it to INTERNAL on macOS and Windows.