Skip to content

Commit

Permalink
Add capture_io, assert_silent and assert_output assertions
Browse files Browse the repository at this point in the history
  • Loading branch information
ysbaddaden committed May 27, 2018
1 parent 1e36f66 commit a89275d
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 0 deletions.
66 changes: 66 additions & 0 deletions src/assertions.cr
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
require "mutex"
require "tempfile"

lib LibC
fun dup(Int) : Int
end

class Exception
getter file : String?
getter line : Int32?
Expand Down Expand Up @@ -60,6 +65,7 @@ module Minitest
# TODO: assert_silent / refute_silent
module Assertions
@@diff : Bool?
@@mutex = Mutex.new

def self.diff?
if (diff = @@diff).is_a?(Bool)
Expand Down Expand Up @@ -295,6 +301,66 @@ module Minitest
end


def assert_silent(file = __FILE__, line = __LINE__)
assert_output("", "", file, line) do
yield
end
end

def assert_output(stdout = nil, stderr = nil, file = __FILE__, line = __LINE__)
output, error = capture_io do
yield
end

case stdout
when String then assert_equal stdout, output
when Regex then assert_match stdout, output
end

case stderr
when String then assert_equal stderr, error
when Regex then assert_match stderr, error
end
end

def capture_io
@@mutex.synchronize do
Tempfile.open("out") do |stdout|
Tempfile.open("err") do |stderr|
reopen(STDOUT, stdout) do
reopen(STDERR, stderr) do
yield
end
end
return {
stdout.rewind.gets_to_end,
stderr.rewind.gets_to_end,
}
ensure
stderr.delete
end
ensure
stdout.delete
end
raise "unreachable"
end
end

private def reopen(src, dst)
backup_fd = LibC.dup(src.fd)
raise Errno.new("dup") if backup_fd == -1

begin
src.reopen(dst)
yield
src.flush
ensure
LibC.dup2(backup_fd, src.fd)
LibC.close(backup_fd)
end
end


def skip(message = "", file = __FILE__, line = __LINE__)
raise Minitest::Skip.new(message.to_s, file: file, line: line)
end
Expand Down
100 changes: 100 additions & 0 deletions test/assertions_test.cr
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,106 @@ class AssertionsTest < Minitest::Test
end


def test_capture_io
# captures io (and flushes):
output, error = capture_io do
STDOUT << "hello world"
STDERR << "failed hello"
end
assert_equal "hello world", output
assert_equal "failed hello", error

# captures long output without blocking:
bytes = Bytes.new(2 * 1024 * 1024)
Random::Secure.random_bytes(bytes)

output, error = capture_io do
STDOUT.write bytes
STDERR.write bytes
end
assert_equal bytes, output.to_slice
assert_equal bytes, error.to_slice
end

def test_assert_silent
assert_silent { }
assert_raises(Minitest::Assertion) { assert_silent { STDOUT << "hello" } }
assert_raises(Minitest::Assertion) { assert_silent { STDERR << "world" } }
end

def test_assert_output
assert_output("hello", "world") do
STDOUT << "hello"
STDERR << "world"
end

assert_output(stdout: "hello") do
STDOUT << "hello"
STDERR << "world"
end

assert_output(stderr: "world") do
STDOUT << "hello"
STDERR << "world"
end

assert_output(stdout: /hello/) do
STDOUT << "hello world"
STDERR << "failed hello"
end

assert_output(stderr: /failed/) do
STDOUT << "hello world"
STDERR << "failed hello"
end

assert_output(/hello/, /failed/) do
STDOUT << "hello world"
STDERR << "failed world"
end

assert_output("hello world", /failed/) do
STDOUT << "hello world"
STDERR << "failed world"
end

assert_output(/hello/, "failed world") do
STDOUT << "hello world"
STDERR << "failed world"
end

assert_raises(Minitest::Assertion) do
assert_output(/failed/) { STDOUT << "hello world" }
end

assert_raises(Minitest::Assertion) do
assert_output("hello") { STDOUT << "hello world" }
end

assert_raises(Minitest::Assertion) do
assert_output(stdout: "hello") { }
end

assert_raises(Minitest::Assertion) do
assert_output(stderr: "hello") { }
end

assert_raises(Minitest::Assertion) do
assert_output("world", "hello") do
STDOUT << "hello world"
STDERR << "world"
end
end

assert_raises(Minitest::Assertion) do
assert_output(/world/, /hello/) do
STDOUT << "hello world"
STDERR << "world"
end
end
end


def test_skip
ex = assert_raises(Minitest::Skip) { skip }
assert_equal "", ex.message
Expand Down

0 comments on commit a89275d

Please sign in to comment.