blob: 5daaf5545c343a35cc0e095a9bcff92a53ba27c9 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
require 'mspec/helpers/tmp'
# Lower-level output speccing mechanism for a single
# output stream. Unlike OutputMatcher which provides
# methods to capture the output, we actually replace
# the FD itself so that there is no reliance on a
# certain method being used.
class OutputToFDMatcher
def initialize(expected, to)
@to, @expected = to, expected
case @to
when STDOUT
@to_name = "STDOUT"
when STDERR
@to_name = "STDERR"
when IO
@to_name = @to.object_id.to_s
else
raise ArgumentError, "#{@to.inspect} is not a supported output target"
end
end
def with_tmp
path = tmp("mspec_output_to_#{$$}_#{Time.now.to_i}")
File.open(path, 'w+') { |io|
yield(io)
}
ensure
File.delete path if path
end
def matches?(block)
old_to = @to.dup
with_tmp do |out|
# Replacing with a file handle so that Readline etc. work
@to.reopen out
begin
block.call
ensure
@to.reopen old_to
old_to.close
end
out.rewind
@actual = out.read
case @expected
when Regexp
!(@actual =~ @expected).nil?
else
@actual == @expected
end
end
end
def failure_message()
["Expected (#{@to_name}): #{@expected.inspect}\n",
"#{'but got'.rjust(@to_name.length + 10)}: #{@actual.inspect}\nBacktrace"]
end
def negative_failure_message()
["Expected output (#{@to_name}) to NOT be:\n", @actual.inspect]
end
end
class Object
def output_to_fd(what, where = STDOUT)
OutputToFDMatcher.new what, where
end
end
|