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

Add capture_io method from Minitest #399

Closed
wants to merge 4 commits into
base: master
from

Conversation

Projects
None yet
4 participants
@wikimatze

wikimatze commented Dec 24, 2013

I was writing a builder with thor and wanted to test my task with proper output. What I needed is to capture $stdout and $stdin to test those things. I searched the web for it and could only find capture_io frm Minitest.

The main idea of capture_io is written in the following snippet:

require 'stringio'

def capture_io
  captured_stdout, captured_stderr = StringIO.new, StringIO.new

  orig_stdout, orig_stderr = $stdout, $stderr
  $stdout, $stderr         = captured_stdout, captured_stderr

  yield

  return captured_stdout.string, captured_stderr.string

ensure
  $stdout = orig_stdout
  $stderr = orig_stderr
end

out, err = capture_io do
  puts "Some info"
  warn "You did a bad thing"
end

puts out

It is really just a helper method and @myronmarston mentioned on twitter the following:

@wikimatze It does not, but I'm open to adding a matcher for it. Want to open an issue?

— Myron Marston (@myronmarston) December 23, 2013
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

I tried to implement it as a matcher but lowered the code coverage. I'm not sure what and how to test it, help is more than welcome.

If anybody wants to use the ability before it's included in RSpec you can make use of by adding the following lines to your spec_helper.rb:

require 'minitest/unit'

RSpec.configure do |conf|
  conf.include Minitest::Assertions
end

If this pull request is excepted, I can cleanup my helper and stay in the RSpec environment.

Happy Xmas.

@myronmarston

View changes

Show outdated Hide outdated lib/rspec/matchers/built_in/be_instance_of.rb Outdated
@myronmarston

View changes

Show outdated Hide outdated lib/rspec/matchers.rb Outdated
@myronmarston

This comment has been minimized.

Show comment
Hide comment
@myronmarston

myronmarston Dec 24, 2013

Member

As far as tests go, here's a few to get you started:

shared_examples_for "output_to_stream" do |stream_name|
  matcher_method = :"output_to_#{stream_name}"

  define_method :matcher do |*args|
    send(matcher_method, *args)
  end

  context "expect { ... }.to #{matcher_method} (with no arg)" do
    it "passes if the block prints to #{stream_name}" do
      expect { stream.puts 'foo' }.to matcher
    end

    it "fails if the block does not print to #{stream_name}" do
      expect {
        expect { }.to matcher
      }.to fail_with("expected block to output to #{stream_name}, but did not")
    end
  end

  context "expect { ... }.not_to #{matcher_method} (with no arg)" do
    it "passes if the block does not print to #{stream_name}" do
      expect { }.not_to matcher
    end

    it "fails if the block prints to #{stream_name}" do
      expect {
        expect { stream.puts 'foo' }.not_to matcher
      }.to fail_with("expected block to output to #{stream_name}, but did not")
    end
  end

  context "expect { ... }.to #{matcher_method}('string')" do
    it "passes if the block prints that string to #{stream_name}" do
      expect { stream.puts 'foo' }.to matcher('foo')
    end

    it "fails if the block does not print to #{stream_name}" do
      expect {
        expect { }.to matcher('foo')
      }.to fail_with('expected block to output "foo" to #{stream_name}, but output nothing')
    end

    it "fails if the block prints a different string to #{stream_name}" do
      expect {
        expect { stream.puts 'food' }.to matcher('foo')
      }.to fail_with('expected block to output "foo" to #{stream_name}, but output "food"')
    end
  end
end

describe "output_to_stdout matcher" do
  include_examples "output_to_stream", :stdout do
    let(:stream) { $stdout }
  end
end

describe "output_to_stderr matcher" do
  include_examples "output_to_stream", :stderr do
    let(:stream) { $stderr }
  end
end

There's a lot more needed to flesh out all the different cases but that should get you started.

Member

myronmarston commented Dec 24, 2013

As far as tests go, here's a few to get you started:

shared_examples_for "output_to_stream" do |stream_name|
  matcher_method = :"output_to_#{stream_name}"

  define_method :matcher do |*args|
    send(matcher_method, *args)
  end

  context "expect { ... }.to #{matcher_method} (with no arg)" do
    it "passes if the block prints to #{stream_name}" do
      expect { stream.puts 'foo' }.to matcher
    end

    it "fails if the block does not print to #{stream_name}" do
      expect {
        expect { }.to matcher
      }.to fail_with("expected block to output to #{stream_name}, but did not")
    end
  end

  context "expect { ... }.not_to #{matcher_method} (with no arg)" do
    it "passes if the block does not print to #{stream_name}" do
      expect { }.not_to matcher
    end

    it "fails if the block prints to #{stream_name}" do
      expect {
        expect { stream.puts 'foo' }.not_to matcher
      }.to fail_with("expected block to output to #{stream_name}, but did not")
    end
  end

  context "expect { ... }.to #{matcher_method}('string')" do
    it "passes if the block prints that string to #{stream_name}" do
      expect { stream.puts 'foo' }.to matcher('foo')
    end

    it "fails if the block does not print to #{stream_name}" do
      expect {
        expect { }.to matcher('foo')
      }.to fail_with('expected block to output "foo" to #{stream_name}, but output nothing')
    end

    it "fails if the block prints a different string to #{stream_name}" do
      expect {
        expect { stream.puts 'food' }.to matcher('foo')
      }.to fail_with('expected block to output "foo" to #{stream_name}, but output "food"')
    end
  end
end

describe "output_to_stdout matcher" do
  include_examples "output_to_stream", :stdout do
    let(:stream) { $stdout }
  end
end

describe "output_to_stderr matcher" do
  include_examples "output_to_stream", :stderr do
    let(:stream) { $stderr }
  end
end

There's a lot more needed to flesh out all the different cases but that should get you started.

@zorbash

This comment has been minimized.

Show comment
Hide comment
@zorbash

zorbash Dec 30, 2013

Looking forward to see this one get merged (with proper tests of course)

zorbash commented Dec 30, 2013

Looking forward to see this one get merged (with proper tests of course)

module RSpec
module Matchers
module BuiltIn
class Couple < BaseMatcher

This comment has been minimized.

@myronmarston

myronmarston Dec 30, 2013

Member

Why did you call this Couple? I have no idea what that has to do with printing to a stream...

@myronmarston

myronmarston Dec 30, 2013

Member

Why did you call this Couple? I have no idea what that has to do with printing to a stream...

def output_to_stdout(expected)
Couple.new(expected)
end

This comment has been minimized.

@myronmarston

myronmarston Dec 30, 2013

Member

Why is this method here? You've already defined this in lib/rspec/matchers.rb.

@myronmarston

myronmarston Dec 30, 2013

Member

Why is this method here? You've already defined this in lib/rspec/matchers.rb.

def output_to_stderr(expected)
Couple.new(expected)
end

This comment has been minimized.

@myronmarston

myronmarston Dec 30, 2013

Member

Why is this method here? You've already defined this in lib/rspec/matchers.rb.

@myronmarston

myronmarston Dec 30, 2013

Member

Why is this method here? You've already defined this in lib/rspec/matchers.rb.

end
def matches?
output_to_stream

This comment has been minimized.

@myronmarston

myronmarston Dec 30, 2013

Member

This needs to compare what is output (if anything) against @expected.

@myronmarston

myronmarston Dec 30, 2013

Member

This needs to compare what is output (if anything) against @expected.

@myronmarston

This comment has been minimized.

Show comment
Hide comment
@myronmarston

myronmarston Dec 30, 2013

Member

@matthias-guenther -- there's a fair bit here left to do. I wasn't sure if you were ready for more feedback, but I left a few comments. Let us know if you get to a point of not being able to finish this (e.g. due to getting too busy with other things, or whatever).

Member

myronmarston commented Dec 30, 2013

@matthias-guenther -- there's a fair bit here left to do. I wasn't sure if you were ready for more feedback, but I left a few comments. Let us know if you get to a point of not being able to finish this (e.g. due to getting too busy with other things, or whatever).

@wikimatze

This comment has been minimized.

Show comment
Hide comment
@wikimatze

wikimatze Dec 30, 2013

@myronmarston the next month will be very busy for me and I already spent the maxium amount of time to this issue, I'm now at a point where I need a remote pairing session to solve this task.

So you or @zorbash are going to write the tests for it, I'm eager to review and learn from it, thanks for the feedback and comments so far.

wikimatze commented Dec 30, 2013

@myronmarston the next month will be very busy for me and I already spent the maxium amount of time to this issue, I'm now at a point where I need a remote pairing session to solve this task.

So you or @zorbash are going to write the tests for it, I'm eager to review and learn from it, thanks for the feedback and comments so far.

@myronmarston

This comment has been minimized.

Show comment
Hide comment
@myronmarston

myronmarston Jan 9, 2014

Member

I'm going to close this in favor of #410 as that's further along.

Member

myronmarston commented Jan 9, 2014

I'm going to close this in favor of #410 as that's further along.

@myronmarston

This comment has been minimized.

Show comment
Hide comment
@myronmarston

myronmarston Jan 9, 2014

Member

Thanks for getting the ball rolling on this, @matthias-guenther!

Member

myronmarston commented Jan 9, 2014

Thanks for getting the ball rolling on this, @matthias-guenther!

@wikimatze

This comment has been minimized.

Show comment
Hide comment
@wikimatze

wikimatze Jan 9, 2014

That's fine, next time when I know that I will have more time, I will solve the problem on my own. I'm sure there are some missing features which needs to be added to RSpec.

wikimatze commented Jan 9, 2014

That's fine, next time when I know that I will have more time, I will solve the problem on my own. I'm sure there are some missing features which needs to be added to RSpec.

@lucapette

This comment has been minimized.

Show comment
Hide comment
@lucapette

lucapette Jan 9, 2014

Contributor

@matthias-guenther yes, thank you for the inspiration. @myronmarston I have limited about of time this week but I'm almost done with the tasks coming out of your great feedback.

Contributor

lucapette commented Jan 9, 2014

@matthias-guenther yes, thank you for the inspiration. @myronmarston I have limited about of time this week but I'm almost done with the tasks coming out of your great feedback.

@zorbash

This comment has been minimized.

Show comment
Hide comment
@zorbash

zorbash Jan 9, 2014

Great! I wish i'd seen the comment by @matthias-guenther earlier, so that i'd helped more.

zorbash commented Jan 9, 2014

Great! I wish i'd seen the comment by @matthias-guenther earlier, so that i'd helped more.

@wikimatze

This comment has been minimized.

Show comment
Hide comment
@wikimatze

wikimatze commented Jan 10, 2014

No problem @zorbash!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment