-
-
Notifications
You must be signed in to change notification settings - Fork 395
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
Compound expectations of OutputMatcher do not receive captured output #1391
Comments
If you can reproduce this with just |
The following: RSpec.describe 'A' do
it do
expect { puts "foo\nbar" }.to output(/foo/).to_stdout
.and output(/bar/).to_stdout
end
end fails on it own, without And we alias I suppose in order for chaining to work, in Would you like to open a PR to fix that, @wspurgin ? |
The spec passes with adding this to original_stream.write(captured_stream.string) but there's a side effect - the output gets printed in the console. This can be worked around with a check: original_stream.write(captured_stream.string) unless $stdout == STDOUT |
Thanks @pirj - I agree that it should work (and doesn't) when using I'm happy to attempt a PR. Thanks for that guidance too about just writing the captured output back into the original stream again! I'll mull over if there's a way to reuse the captured stream or at least a way to silence any extraneous output. If something is supposed to output to stdout (or any IO), IMHO it's fine if, in the end, it still ends up in stdout/the IO in question and Rspec makes no attempt to mask it from making it there. |
To my best recollection, stdout gets printed with a delay somewhere in the footer. It's not much use for output when it's interleaved with e.g. progress formatter. |
This is the issue reported in rspec#1391 - expecting like expect { puts "foobar" } .to output.to_stdout(/foo/) .and output.to_stdout(/bar/) fails, because the two matchers get nested, and inner matcher catches the stream write, hiding it from the outer one.
@pirj - your solutions work perfectly for the I have a solution for the I do have a solution to most of it (weird though it looks), but I'm stuck on one last detail, and while I was digging into it, I realized that this matcher is actually more broken than it seems - it doesn't actually put stderr back when it's done. That's because it's relying on The simplest solution I see is to override This addition seems to let the current draft PR pass all specs (on ruby 3.2.2):
|
I believe this is the solution: rspec/rspec-support#598 Surprisingly, I haven't been able to come up with a situation in which the fact that the stream the Splitter is holding is actually a Tempfile and not the real stderr stream causes a problem, since we're intercepting all of that output anyway. So this may not actually be an independent issue, unless someone tries to do fairly complex things with |
Do you mean that we can potentially simplify some logic checking if it’s a Tempfile? |
I don't think it'll be simpler, just more correct. Unless you're referring to some logic I didn't notice that already did so? My explanation above was a bit tangled though (and the problem took some work for me to understand in the first place) - I can lay out a clearer picture of what's currently wrong, if that would help? |
Certainly, if you’re up for it! |
I am always up for explaining my thoughts more, I hold back mostly because I tend to over-explain things, and I'm bad at telling which stuff people already follow without facial expressions :-) So, everything is around this class.
Now, And doing something similar to what you suggested for the other matchers here worked just fine for the The first reason is that But the second reason is more subtle. That And in a composed context, that matters twice: once because in the inner context (after 'restoring' the But.. that logic was already there, and when I went to check, it actually does already fail to restore that stream currently, even in a non-nested context. This spec (below) fails on the last line in the current gems, because the IO inside the Splitter never gets restored from being a Tempfile (and a closed, unlinked, then reopened one, at that). But.. I can't come up with a test (aside from compound matchers) that that actually breaks, aside from complex assertions about stderr itself, so I'm not sure it's worthy of calling an actual "bug".
That is what the other PR here resolves - after that change, this spec passes, and it also allows the compound matcher fix to work (aside from in jruby, which I'm still trying to work out). Incidentally, investigating this stuff in a context where the stderr/stdout streams are being reopened into a tempfile is a special kind of painful, I had to print-debug everything using statements like |
This is the issue reported in rspec#1391 - expecting like expect { puts "foobar" } .to output.to_stdout(/foo/) .and output.to_stdout(/bar/) fails, because the two matchers get nested, and inner matcher catches the stream write, hiding it from the outer one.
This is the issue reported in rspec#1391 - expecting like expect { puts "foobar" } .to output.to_stdout(/foo/) .and output.to_stdout(/bar/) fails, because the two matchers get nested, and inner matcher catches the stream write, hiding it from the outer one.
Compound expectations with OutputMatcher not receiving captured output
❤️ Thanks for any help on this in advance - it might just be user error.
When constructing a compound expectation using the
output
matcher, I'd expect something like this to pass:Instead a failure is reported:
Running them individually passes however:
Your environment
Steps to reproduce
Expected behavior
I'd expect that compound statements would both use the same STDOUT output and match against that
Actual behavior
The text was updated successfully, but these errors were encountered: