mspec 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. data/LICENSE +22 -0
  2. data/README +101 -0
  3. data/Rakefile +44 -0
  4. data/bin/mkspec +7 -0
  5. data/bin/mspec +7 -0
  6. data/bin/mspec-ci +8 -0
  7. data/bin/mspec-run +8 -0
  8. data/bin/mspec-tag +8 -0
  9. data/lib/mspec.rb +6 -0
  10. data/lib/mspec/commands/mkspec.rb +147 -0
  11. data/lib/mspec/commands/mspec-ci.rb +71 -0
  12. data/lib/mspec/commands/mspec-run.rb +80 -0
  13. data/lib/mspec/commands/mspec-tag.rb +87 -0
  14. data/lib/mspec/commands/mspec.rb +143 -0
  15. data/lib/mspec/expectations.rb +2 -0
  16. data/lib/mspec/expectations/expectations.rb +12 -0
  17. data/lib/mspec/expectations/should.rb +23 -0
  18. data/lib/mspec/guards.rb +13 -0
  19. data/lib/mspec/guards/bug.rb +27 -0
  20. data/lib/mspec/guards/compliance.rb +18 -0
  21. data/lib/mspec/guards/conflict.rb +16 -0
  22. data/lib/mspec/guards/endian.rb +40 -0
  23. data/lib/mspec/guards/extensions.rb +12 -0
  24. data/lib/mspec/guards/guard.rb +120 -0
  25. data/lib/mspec/guards/noncompliance.rb +12 -0
  26. data/lib/mspec/guards/platform.rb +38 -0
  27. data/lib/mspec/guards/quarantine.rb +15 -0
  28. data/lib/mspec/guards/runner.rb +30 -0
  29. data/lib/mspec/guards/superuser.rb +15 -0
  30. data/lib/mspec/guards/support.rb +12 -0
  31. data/lib/mspec/guards/version.rb +40 -0
  32. data/lib/mspec/helpers.rb +6 -0
  33. data/lib/mspec/helpers/bignum.rb +5 -0
  34. data/lib/mspec/helpers/const_lookup.rb +5 -0
  35. data/lib/mspec/helpers/flunk.rb +5 -0
  36. data/lib/mspec/helpers/io.rb +13 -0
  37. data/lib/mspec/helpers/scratch.rb +17 -0
  38. data/lib/mspec/helpers/tmp.rb +32 -0
  39. data/lib/mspec/matchers.rb +16 -0
  40. data/lib/mspec/matchers/base.rb +95 -0
  41. data/lib/mspec/matchers/be_ancestor_of.rb +24 -0
  42. data/lib/mspec/matchers/be_close.rb +27 -0
  43. data/lib/mspec/matchers/be_empty.rb +20 -0
  44. data/lib/mspec/matchers/be_false.rb +20 -0
  45. data/lib/mspec/matchers/be_kind_of.rb +24 -0
  46. data/lib/mspec/matchers/be_nil.rb +20 -0
  47. data/lib/mspec/matchers/be_true.rb +20 -0
  48. data/lib/mspec/matchers/complain.rb +56 -0
  49. data/lib/mspec/matchers/eql.rb +26 -0
  50. data/lib/mspec/matchers/equal.rb +26 -0
  51. data/lib/mspec/matchers/equal_utf16.rb +34 -0
  52. data/lib/mspec/matchers/include.rb +32 -0
  53. data/lib/mspec/matchers/output.rb +67 -0
  54. data/lib/mspec/matchers/output_to_fd.rb +71 -0
  55. data/lib/mspec/matchers/raise_error.rb +48 -0
  56. data/lib/mspec/mocks.rb +3 -0
  57. data/lib/mspec/mocks/mock.rb +123 -0
  58. data/lib/mspec/mocks/object.rb +28 -0
  59. data/lib/mspec/mocks/proxy.rb +112 -0
  60. data/lib/mspec/runner.rb +13 -0
  61. data/lib/mspec/runner/actions.rb +6 -0
  62. data/lib/mspec/runner/actions/debug.rb +17 -0
  63. data/lib/mspec/runner/actions/filter.rb +40 -0
  64. data/lib/mspec/runner/actions/gdb.rb +17 -0
  65. data/lib/mspec/runner/actions/tag.rb +97 -0
  66. data/lib/mspec/runner/actions/tally.rb +80 -0
  67. data/lib/mspec/runner/actions/timer.rb +22 -0
  68. data/lib/mspec/runner/filters.rb +4 -0
  69. data/lib/mspec/runner/filters/match.rb +22 -0
  70. data/lib/mspec/runner/filters/profile.rb +54 -0
  71. data/lib/mspec/runner/filters/regexp.rb +7 -0
  72. data/lib/mspec/runner/filters/tag.rb +29 -0
  73. data/lib/mspec/runner/formatters.rb +7 -0
  74. data/lib/mspec/runner/formatters/dotted.rb +81 -0
  75. data/lib/mspec/runner/formatters/html.rb +87 -0
  76. data/lib/mspec/runner/formatters/specdoc.rb +27 -0
  77. data/lib/mspec/runner/formatters/spinner.rb +89 -0
  78. data/lib/mspec/runner/formatters/summary.rb +8 -0
  79. data/lib/mspec/runner/formatters/unit.rb +25 -0
  80. data/lib/mspec/runner/formatters/yaml.rb +43 -0
  81. data/lib/mspec/runner/mspec.rb +232 -0
  82. data/lib/mspec/runner/object.rb +20 -0
  83. data/lib/mspec/runner/shared.rb +12 -0
  84. data/lib/mspec/runner/state.rb +116 -0
  85. data/lib/mspec/runner/tag.rb +20 -0
  86. data/lib/mspec/utils/name_map.rb +130 -0
  87. data/lib/mspec/utils/options.rb +344 -0
  88. data/lib/mspec/utils/script.rb +77 -0
  89. data/lib/mspec/version.rb +3 -0
  90. data/spec/commands/mkspec_spec.rb +321 -0
  91. data/spec/commands/mspec_ci_spec.rb +139 -0
  92. data/spec/commands/mspec_run_spec.rb +146 -0
  93. data/spec/commands/mspec_spec.rb +359 -0
  94. data/spec/commands/mspec_tag_spec.rb +131 -0
  95. data/spec/expectations/expectations_spec.rb +16 -0
  96. data/spec/expectations/should_spec.rb +99 -0
  97. data/spec/guards/bug_spec.rb +137 -0
  98. data/spec/guards/compliance_spec.rb +70 -0
  99. data/spec/guards/conflict_spec.rb +20 -0
  100. data/spec/guards/endian_spec.rb +42 -0
  101. data/spec/guards/extensions_spec.rb +36 -0
  102. data/spec/guards/guard_spec.rb +355 -0
  103. data/spec/guards/noncompliance_spec.rb +36 -0
  104. data/spec/guards/platform_spec.rb +84 -0
  105. data/spec/guards/quarantine_spec.rb +19 -0
  106. data/spec/guards/runner_spec.rb +75 -0
  107. data/spec/guards/superuser_spec.rb +22 -0
  108. data/spec/guards/support_spec.rb +22 -0
  109. data/spec/guards/version_spec.rb +133 -0
  110. data/spec/helpers/bignum_spec.rb +11 -0
  111. data/spec/helpers/const_lookup_spec.rb +19 -0
  112. data/spec/helpers/flunk_spec.rb +15 -0
  113. data/spec/helpers/io_spec.rb +34 -0
  114. data/spec/helpers/scratch_spec.rb +22 -0
  115. data/spec/helpers/tmp_spec.rb +72 -0
  116. data/spec/matchers/base_spec.rb +180 -0
  117. data/spec/matchers/be_ancestor_of_spec.rb +28 -0
  118. data/spec/matchers/be_close_spec.rb +46 -0
  119. data/spec/matchers/be_empty_spec.rb +26 -0
  120. data/spec/matchers/be_false_spec.rb +28 -0
  121. data/spec/matchers/be_kind_of_spec.rb +29 -0
  122. data/spec/matchers/be_nil_spec.rb +27 -0
  123. data/spec/matchers/be_true_spec.rb +28 -0
  124. data/spec/matchers/complain_spec.rb +52 -0
  125. data/spec/matchers/eql_spec.rb +33 -0
  126. data/spec/matchers/equal_spec.rb +33 -0
  127. data/spec/matchers/equal_utf16_spec.rb +47 -0
  128. data/spec/matchers/include_spec.rb +37 -0
  129. data/spec/matchers/output_spec.rb +74 -0
  130. data/spec/matchers/output_to_fd_spec.rb +33 -0
  131. data/spec/matchers/raise_error_spec.rb +56 -0
  132. data/spec/mocks/mock_spec.rb +272 -0
  133. data/spec/mocks/proxy_spec.rb +259 -0
  134. data/spec/runner/actions/debug_spec.rb +61 -0
  135. data/spec/runner/actions/filter_spec.rb +84 -0
  136. data/spec/runner/actions/gdb_spec.rb +61 -0
  137. data/spec/runner/actions/tag_spec.rb +253 -0
  138. data/spec/runner/actions/tally_spec.rb +107 -0
  139. data/spec/runner/actions/timer_spec.rb +42 -0
  140. data/spec/runner/filters/a.yaml +4 -0
  141. data/spec/runner/filters/b.yaml +11 -0
  142. data/spec/runner/filters/match_spec.rb +44 -0
  143. data/spec/runner/filters/profile_spec.rb +117 -0
  144. data/spec/runner/filters/regexp_spec.rb +13 -0
  145. data/spec/runner/filters/tag_spec.rb +77 -0
  146. data/spec/runner/formatters/dotted_spec.rb +184 -0
  147. data/spec/runner/formatters/html_spec.rb +191 -0
  148. data/spec/runner/formatters/specdoc_spec.rb +57 -0
  149. data/spec/runner/formatters/spinner_spec.rb +78 -0
  150. data/spec/runner/formatters/summary_spec.rb +29 -0
  151. data/spec/runner/formatters/unit_spec.rb +71 -0
  152. data/spec/runner/formatters/yaml_spec.rb +123 -0
  153. data/spec/runner/mspec_spec.rb +393 -0
  154. data/spec/runner/shared_spec.rb +41 -0
  155. data/spec/runner/state_spec.rb +535 -0
  156. data/spec/runner/tag_spec.rb +93 -0
  157. data/spec/runner/tags.txt +3 -0
  158. data/spec/spec_helper.rb +46 -0
  159. data/spec/utils/name_map_spec.rb +178 -0
  160. data/spec/utils/options_spec.rb +862 -0
  161. data/spec/utils/script_spec.rb +240 -0
  162. metadata +217 -0
@@ -0,0 +1,24 @@
1
+ class BeAncestorOfMatcher
2
+ def initialize(expected)
3
+ @expected = expected
4
+ end
5
+
6
+ def matches?(actual)
7
+ @actual = actual
8
+ @expected.ancestors.include? @actual
9
+ end
10
+
11
+ def failure_message
12
+ ["Expected #{@actual}", "to be an ancestor of #{@expected}"]
13
+ end
14
+
15
+ def negative_failure_message
16
+ ["Expected #{@actual}", "not to be an ancestor of #{@expected}"]
17
+ end
18
+ end
19
+
20
+ class Object
21
+ def be_ancestor_of(expected)
22
+ BeAncestorOfMatcher.new(expected)
23
+ end
24
+ end
@@ -0,0 +1,27 @@
1
+ TOLERANCE = 0.00003 unless Object.const_defined?(:TOLERANCE)
2
+
3
+ class BeCloseMatcher
4
+ def initialize(expected, tolerance)
5
+ @expected = expected
6
+ @tolerance = tolerance
7
+ end
8
+
9
+ def matches?(actual)
10
+ @actual = actual
11
+ (@actual - @expected).abs < @tolerance
12
+ end
13
+
14
+ def failure_message
15
+ ["Expected #{@expected}", "to be within +/- #{@tolerance} of #{@actual}"]
16
+ end
17
+
18
+ def negative_failure_message
19
+ ["Expected #{@expected}", "not to be within +/- #{@tolerance} of #{@actual}"]
20
+ end
21
+ end
22
+
23
+ class Object
24
+ def be_close(expected, tolerance)
25
+ BeCloseMatcher.new(expected, tolerance)
26
+ end
27
+ end
@@ -0,0 +1,20 @@
1
+ class BeEmptyMatcher
2
+ def matches?(actual)
3
+ @actual = actual
4
+ @actual.empty?
5
+ end
6
+
7
+ def failure_message
8
+ ["Expected #{@actual.inspect}", "to be empty"]
9
+ end
10
+
11
+ def negative_failure_message
12
+ ["Expected #{@actual.inspect}", "not to be empty"]
13
+ end
14
+ end
15
+
16
+ class Object
17
+ def be_empty
18
+ BeEmptyMatcher.new
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ class BeFalseMatcher
2
+ def matches?(actual)
3
+ @actual = actual
4
+ @actual == false
5
+ end
6
+
7
+ def failure_message
8
+ ["Expected #{@actual.inspect}", "to be false"]
9
+ end
10
+
11
+ def negative_failure_message
12
+ ["Expected #{@actual.inspect}", "not to be false"]
13
+ end
14
+ end
15
+
16
+ class Object
17
+ def be_false
18
+ BeFalseMatcher.new
19
+ end
20
+ end
@@ -0,0 +1,24 @@
1
+ class BeKindOfMatcher
2
+ def initialize(expected)
3
+ @expected = expected
4
+ end
5
+
6
+ def matches?(actual)
7
+ @actual = actual
8
+ @actual.is_a?(@expected)
9
+ end
10
+
11
+ def failure_message
12
+ ["Expected #{@actual.inspect} (#{@actual.class})", "to be kind of #{@expected}"]
13
+ end
14
+
15
+ def negative_failure_message
16
+ ["Expected #{@actual.inspect} (#{@actual.class})", "not to be kind of #{@expected}"]
17
+ end
18
+ end
19
+
20
+ class Object
21
+ def be_kind_of(expected)
22
+ BeKindOfMatcher.new(expected)
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ class BeNilMatcher
2
+ def matches?(actual)
3
+ @actual = actual
4
+ @actual.nil?
5
+ end
6
+
7
+ def failure_message
8
+ ["Expected #{@actual.inspect}", "to be nil"]
9
+ end
10
+
11
+ def negative_failure_message
12
+ ["Expected #{@actual.inspect}", "not to be nil"]
13
+ end
14
+ end
15
+
16
+ class Object
17
+ def be_nil
18
+ BeNilMatcher.new
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ class BeTrueMatcher
2
+ def matches?(actual)
3
+ @actual = actual
4
+ @actual == true
5
+ end
6
+
7
+ def failure_message
8
+ ["Expected #{@actual.inspect}", "to be true"]
9
+ end
10
+
11
+ def negative_failure_message
12
+ ["Expected #{@actual.inspect}", "not to be true"]
13
+ end
14
+ end
15
+
16
+ class Object
17
+ def be_true
18
+ BeTrueMatcher.new
19
+ end
20
+ end
@@ -0,0 +1,56 @@
1
+ require 'mspec/helpers/io'
2
+
3
+ class ComplainMatcher
4
+ def initialize(complaint)
5
+ @complaint = complaint
6
+ end
7
+
8
+ def matches?(proc)
9
+ @saved_err = $stderr
10
+ @stderr = $stderr = IOStub.new
11
+ @verbose = $VERBOSE
12
+ $VERBOSE = false
13
+
14
+ proc.call
15
+
16
+ unless @complaint.nil?
17
+ case @complaint
18
+ when Regexp
19
+ return false unless $stderr =~ @complaint
20
+ else
21
+ return false unless $stderr == @complaint
22
+ end
23
+ end
24
+
25
+ return $stderr.empty? ? false : true
26
+ ensure
27
+ $VERBOSE = @verbose
28
+ $stderr = @saved_err
29
+ end
30
+
31
+ def failure_message
32
+ if @complaint.nil?
33
+ ["Expected a warning", "but received none"]
34
+ elsif @complaint.kind_of? Regexp
35
+ ["Expected warning to match:", @complaint.inspect]
36
+ else
37
+ ["Expected warning: #{@complaint.inspect}", "but got: #{@stderr.chomp.inspect}"]
38
+ end
39
+ end
40
+
41
+ def negative_failure_message
42
+ if @complaint.nil?
43
+ ["Unexpected warning: ", @stderr.chomp.inspect]
44
+ elsif @complaint.kind_of? Regexp
45
+ ["Expected warning not to match:", @complaint.inspect]
46
+ else
47
+ ["Expected warning: #{@complaint.inspect}", "but got: #{@stderr.chomp.inspect}"]
48
+ end
49
+ end
50
+ end
51
+
52
+ class Object
53
+ def complain(complaint=nil)
54
+ ComplainMatcher.new(complaint)
55
+ end
56
+ end
@@ -0,0 +1,26 @@
1
+ class EqlMatcher
2
+ def initialize(expected)
3
+ @expected = expected
4
+ end
5
+
6
+ def matches?(actual)
7
+ @actual = actual
8
+ @actual.eql?(@expected)
9
+ end
10
+
11
+ def failure_message
12
+ ["Expected #{@actual.pretty_inspect}",
13
+ "to have same value and type as #{@expected.pretty_inspect}"]
14
+ end
15
+
16
+ def negative_failure_message
17
+ ["Expected #{@actual.pretty_inspect}",
18
+ "not to have same value or type as #{@expected.pretty_inspect}"]
19
+ end
20
+ end
21
+
22
+ class Object
23
+ def eql(expected)
24
+ EqlMatcher.new(expected)
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ class EqualMatcher
2
+ def initialize(expected)
3
+ @expected = expected
4
+ end
5
+
6
+ def matches?(actual)
7
+ @actual = actual
8
+ @actual.equal?(@expected)
9
+ end
10
+
11
+ def failure_message
12
+ ["Expected #{@actual.pretty_inspect}",
13
+ "to be identical to #{@expected.pretty_inspect}"]
14
+ end
15
+
16
+ def negative_failure_message
17
+ ["Expected #{@actual.pretty_inspect}",
18
+ "not to be identical to #{@expected.pretty_inspect}"]
19
+ end
20
+ end
21
+
22
+ class Object
23
+ def equal(expected)
24
+ EqualMatcher.new(expected)
25
+ end
26
+ end
@@ -0,0 +1,34 @@
1
+ class EqualUtf16Matcher
2
+ def initialize(expected)
3
+ @expected = expected
4
+ end
5
+
6
+ def matches?(actual)
7
+ @actual = actual
8
+ @actual == @expected || @actual == expected_swapped
9
+ end
10
+
11
+ def expected_swapped
12
+ if @expected.respond_to?(:to_str)
13
+ @expected_swapped ||= @expected.to_str.gsub(/(.)(.)/, '\2\1')
14
+ else
15
+ @expected_swapped ||= @expected.collect { |s| s.to_str.gsub(/(.)(.)/, '\2\1') }
16
+ end
17
+ end
18
+
19
+ def failure_message
20
+ ["Expected #{@actual.pretty_inspect}",
21
+ "to equal #{@expected.pretty_inspect} or #{expected_swapped.pretty_inspect}"]
22
+ end
23
+
24
+ def negative_failure_message
25
+ ["Expected #{@actual.pretty_inspect}",
26
+ "not to equal #{@expected.pretty_inspect} nor #{expected_swapped.pretty_inspect}"]
27
+ end
28
+ end
29
+
30
+ class Object
31
+ def equal_utf16(expected)
32
+ EqualUtf16Matcher.new(expected)
33
+ end
34
+ end
@@ -0,0 +1,32 @@
1
+ class IncludeMatcher
2
+ def initialize(*expected)
3
+ @expected = expected
4
+ end
5
+
6
+ def matches?(actual)
7
+ @actual = actual
8
+ @expected.each do |e|
9
+ @element = e
10
+ unless @actual.include?(e)
11
+ return false
12
+ end
13
+ end
14
+ return true
15
+ end
16
+
17
+ def failure_message
18
+ ["Expected #{@actual.inspect}", "to include #{@element.inspect}"]
19
+ end
20
+
21
+ def negative_failure_message
22
+ ["Expected #{@actual.inspect}", "not to include #{@element.inspect}"]
23
+ end
24
+ end
25
+
26
+ # Cannot override #include at the toplevel in MRI
27
+ module MSpec
28
+ def include(*expected)
29
+ IncludeMatcher.new(*expected)
30
+ end
31
+ module_function :include
32
+ end
@@ -0,0 +1,67 @@
1
+ require 'mspec/helpers/io'
2
+
3
+ class OutputMatcher
4
+ def initialize(stdout, stderr)
5
+ @out = stdout
6
+ @err = stderr
7
+ end
8
+
9
+ def matches?(proc)
10
+ @saved_out = $stdout
11
+ @saved_err = $stderr
12
+ @stdout = $stdout = IOStub.new
13
+ @stderr = $stderr = IOStub.new
14
+
15
+ proc.call
16
+
17
+ unless @out.nil?
18
+ case @out
19
+ when Regexp
20
+ return false unless $stdout =~ @out
21
+ else
22
+ return false unless $stdout == @out
23
+ end
24
+ end
25
+
26
+ unless @err.nil?
27
+ case @err
28
+ when Regexp
29
+ return false unless $stderr =~ @err
30
+ else
31
+ return false unless $stderr == @err
32
+ end
33
+ end
34
+
35
+ return true
36
+ ensure
37
+ $stdout = @saved_out
38
+ $stderr = @saved_err
39
+ end
40
+
41
+ def failure_message
42
+ expected_out = "\n"
43
+ actual_out = "\n"
44
+ unless @out.nil?
45
+ expected_out << " $stdout: #{@out.inspect}\n"
46
+ actual_out << " $stdout: #{@stdout.chomp.inspect}\n"
47
+ end
48
+ unless @err.nil?
49
+ expected_out << " $stderr: #{@err.inspect}\n"
50
+ actual_out << " $stderr: #{@stderr.chomp.inspect}\n"
51
+ end
52
+ ["Expected:#{expected_out}", " got:#{actual_out}"]
53
+ end
54
+
55
+ def negative_failure_message
56
+ out = ""
57
+ out << " $stdout: #{@stdout.chomp.dump}\n" unless @out.nil?
58
+ out << " $stderr: #{@stderr.chomp.dump}\n" unless @err.nil?
59
+ ["Expected output not to be:\n", out]
60
+ end
61
+ end
62
+
63
+ class Object
64
+ def output(stdout=nil, stderr=nil)
65
+ OutputMatcher.new(stdout, stderr)
66
+ end
67
+ end
@@ -0,0 +1,71 @@
1
+ require 'mspec/helpers/tmp'
2
+ require 'fileutils'
3
+
4
+ # Lower-level output speccing mechanism for a single
5
+ # output stream. Unlike OutputMatcher which provides
6
+ # methods to capture the output, we actually replace
7
+ # the FD itself so that there is no reliance on a
8
+ # certain method being used.
9
+ class OutputToFDMatcher
10
+ def initialize(expected, to)
11
+ @to, @expected = to, expected
12
+
13
+ case @to
14
+ when STDOUT
15
+ @to_name = "STDOUT"
16
+ when STDERR
17
+ @to_name = "STDERR"
18
+ when IO
19
+ @to_name = @to.object_id.to_s
20
+ else
21
+ raise ArgumentError, "#{@to.inspect} is not a supported output target"
22
+ end
23
+ end
24
+
25
+ def matches?(block)
26
+ old_to = @to.dup
27
+ out = File.open(tmp("mspec_output_to_#{$$}_#{Time.now.to_i}"), 'w+')
28
+
29
+ # Replacing with a file handle so that Readline etc. work
30
+ @to.reopen out
31
+
32
+ block.call
33
+
34
+ ensure
35
+ begin
36
+ @to.reopen old_to
37
+
38
+ out.rewind
39
+ @actual = out.read
40
+
41
+ case @expected
42
+ when Regexp
43
+ return !(@actual =~ @expected).nil?
44
+ else
45
+ return @actual == @expected
46
+ end
47
+
48
+ # Clean up
49
+ ensure
50
+ out.close unless out.closed?
51
+ FileUtils.rm out.path
52
+ end
53
+
54
+ return true
55
+ end
56
+
57
+ def failure_message()
58
+ ["Expected (#{@to_name}): #{@expected.inspect}\n",
59
+ "#{'but got'.rjust(@to_name.length + 10)}: #{@actual.inspect}\nBacktrace"]
60
+ end
61
+
62
+ def negative_failure_message()
63
+ ["Expected output (#{@to_name}) to NOT be:\n", @actual.inspect]
64
+ end
65
+ end
66
+
67
+ class Object
68
+ def output_to_fd(what, where = STDOUT)
69
+ OutputToFDMatcher.new what, where
70
+ end
71
+ end