clarion-given 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 (38) hide show
  1. checksums.yaml +7 -0
  2. data/lib/given/assertions.rb +71 -0
  3. data/lib/given/binary_operation.rb +34 -0
  4. data/lib/given/core.rb +11 -0
  5. data/lib/given/evaluator.rb +52 -0
  6. data/lib/given/ext/numeric.rb +31 -0
  7. data/lib/given/extensions.rb +277 -0
  8. data/lib/given/failure.rb +80 -0
  9. data/lib/given/failure_matcher.rb +100 -0
  10. data/lib/given/file_cache.rb +18 -0
  11. data/lib/given/fuzzy_number.rb +68 -0
  12. data/lib/given/fuzzy_shortcuts.rb +1 -0
  13. data/lib/given/line_extractor.rb +57 -0
  14. data/lib/given/minitest/all.rb +12 -0
  15. data/lib/given/minitest/before_extension.rb +36 -0
  16. data/lib/given/minitest/configure.rb +7 -0
  17. data/lib/given/minitest/context_extension.rb +3 -0
  18. data/lib/given/minitest/failure_must_raise.rb +13 -0
  19. data/lib/given/minitest/framework.rb +37 -0
  20. data/lib/given/minitest/new_assertions.rb +22 -0
  21. data/lib/given/module_methods.rb +83 -0
  22. data/lib/given/natural_assertion.rb +191 -0
  23. data/lib/given/rspec/all.rb +29 -0
  24. data/lib/given/rspec/before_extensions.rb +15 -0
  25. data/lib/given/rspec/configure.rb +20 -0
  26. data/lib/given/rspec/framework.rb +46 -0
  27. data/lib/given/rspec/have_failed.rb +37 -0
  28. data/lib/given/rspec/have_failed_212.rb +39 -0
  29. data/lib/given/rspec/have_failed_pre212.rb +22 -0
  30. data/lib/given/rspec/monkey.rb +42 -0
  31. data/lib/given/rspec/use_natural_assertions.rb +10 -0
  32. data/lib/given/version.rb +9 -0
  33. data/lib/given.rb +2 -0
  34. data/lib/minitest/given.rb +1 -0
  35. data/lib/minitest-given.rb +9 -0
  36. data/lib/rspec/given.rb +1 -0
  37. data/lib/rspec-given.rb +9 -0
  38. metadata +96 -0
@@ -0,0 +1,68 @@
1
+
2
+ module Given
3
+ module Fuzzy
4
+ class FuzzyNumber
5
+
6
+ DEFAULT_EPSILON = 10 * Float::EPSILON
7
+
8
+ attr_reader :exact_value, :delta_amount
9
+
10
+ def initialize(exact_value)
11
+ @exact_value = exact_value
12
+ @delta_amount = exact_value * DEFAULT_EPSILON
13
+ end
14
+
15
+ def exactly_equals?(other)
16
+ other.is_a?(self.class) &&
17
+ exact_value == other.exact_value &&
18
+ delta_amount == other.delta_amount
19
+ end
20
+
21
+ # Low limit of the fuzzy number.
22
+ def low_limit
23
+ exact_value - delta_amount
24
+ end
25
+
26
+ # High limit of the fuzzy number.
27
+ def high_limit
28
+ exact_value + delta_amount
29
+ end
30
+
31
+ # True if the other number is in range of the fuzzy number.
32
+ def ==(other)
33
+ (other - exact_value).abs <= delta_amount
34
+ end
35
+
36
+ def to_s
37
+ "<Approximately #{exact_value} +/- #{delta_amount}>"
38
+ end
39
+
40
+ # Set the delta for a fuzzy number.
41
+ def delta(delta)
42
+ @delta_amount = delta.abs
43
+ self
44
+ end
45
+
46
+ # Specifying a percentage of the exact number to be used in
47
+ # setting the delta.
48
+ def percent(percentage)
49
+ delta(exact_value * (percentage / 100.0))
50
+ end
51
+
52
+ # Specifying the number of epsilons to be used in setting the
53
+ # delta.
54
+ def epsilon(neps)
55
+ delta(exact_value * (neps * Float::EPSILON))
56
+ end
57
+ end
58
+
59
+ # Create an approximate number that is approximately equal to
60
+ # the given number, plus or minus the delta value. If no
61
+ # explicit delta is given, then the default delta that is about
62
+ # 10X the size of the smallest possible change in the given
63
+ # number will be used.
64
+ def about(*args)
65
+ FuzzyNumber.new(*args)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1 @@
1
+ require 'given/ext/numeric'
@@ -0,0 +1,57 @@
1
+ require 'ripper'
2
+ require 'sorcerer'
3
+ require 'given/file_cache'
4
+
5
+ module Given
6
+ class LineExtractor
7
+ def initialize(file_cache=nil)
8
+ @files = file_cache || FileCache.new
9
+ end
10
+
11
+ def line(file_name, line)
12
+ lines = @files.get(file_name)
13
+ extract_lines_from(lines, line-1)
14
+ end
15
+
16
+ def to_s
17
+ "<LineExtractor>"
18
+ end
19
+
20
+ private
21
+
22
+ def extract_lines_from(lines, line_index)
23
+ result = lines[line_index]
24
+ while result && incomplete?(result)
25
+ line_index += 1
26
+ result << lines[line_index]
27
+ end
28
+ result
29
+ end
30
+
31
+ def incomplete?(string)
32
+ builder = Ripper::SexpBuilder.new(string)
33
+ sexp = builder.parse
34
+ if builder.error?
35
+ # Modern Ripper recovers from syntax errors by dropping
36
+ # statements. A truncated source line parses to a program with
37
+ # no sourceable content; anything else is left alone.
38
+ extractable_source(sexp).empty?
39
+ else
40
+ ! complete_sexp?(sexp)
41
+ end
42
+ end
43
+
44
+ def extractable_source(sexp)
45
+ Sorcerer.source(sexp)
46
+ rescue Sorcerer::Resource::NotSexpError
47
+ ""
48
+ end
49
+
50
+ def complete_sexp?(sexp)
51
+ Sorcerer.source(sexp)
52
+ true
53
+ rescue Sorcerer::Resource::NotSexpError => ex
54
+ false
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,12 @@
1
+ require 'minitest/spec'
2
+ require 'given'
3
+
4
+ require 'given/minitest/before_extension'
5
+ require 'given/minitest/context_extension'
6
+ require 'given/minitest/failure_must_raise'
7
+ require 'given/minitest/framework'
8
+ require 'given/minitest/configure'
9
+
10
+ unless Minitest::Spec.instance_methods.include?(:assertions)
11
+ require 'given/minitest/new_assertions'
12
+ end
@@ -0,0 +1,36 @@
1
+
2
+ # The before blocks defined in Minitest are inadequate for our use.
3
+ # This before_extension file allows us to use real before blocks.
4
+
5
+ module Minitest
6
+ class Spec
7
+
8
+ # Redefine setup to trigger before chains
9
+ alias original_setup_without_given setup
10
+ def setup
11
+ original_setup_without_given
12
+ _gvn_establish_befores
13
+ end
14
+
15
+ # Establish the before blocks
16
+ def _gvn_establish_befores
17
+ return if defined?(@_gvn_ran_befores) && @_gvn_ran_befores
18
+ @_gvn_ran_befores = true
19
+ _gvn_contexts.each do |context|
20
+ context._Gvn_before_blocks.each do |before_block|
21
+ instance_eval(&before_block)
22
+ end
23
+ end
24
+ end
25
+
26
+ # Lazy accessor for Given's before blocks
27
+ def self._Gvn_before_blocks
28
+ @_Gvn_before_blocks ||= []
29
+ end
30
+
31
+ # Define a Given style before block
32
+ def self._Gvn_before(&block)
33
+ _Gvn_before_blocks << block
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,7 @@
1
+
2
+ # Configure Minitest to use the Given extensions.
3
+
4
+ Minitest::Spec.send(:extend, Given::ClassExtensions)
5
+ Minitest::Spec.send(:include, Given::FailureMethod)
6
+ Minitest::Spec.send(:include, Given::InstanceExtensions)
7
+ Given.use_natural_assertions if Given::NATURAL_ASSERTIONS_SUPPORTED
@@ -0,0 +1,3 @@
1
+
2
+ # Minitest Specs don't provide a context.
3
+ alias :context :describe
@@ -0,0 +1,13 @@
1
+ module Given
2
+
3
+ class Failure
4
+ # Minitest expectation method. Since Failure inherits from
5
+ # BasicObject, we need to add this method explicitly.
6
+ def must_raise(*args)
7
+ ::Minitest::Spec.current.assert_raises(*args) do
8
+ die
9
+ end
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,37 @@
1
+
2
+ module Minitest
3
+ module Given
4
+
5
+ # Framework adapter for Minitest/Given
6
+ #
7
+ class Framework
8
+ def start_evaluation
9
+ @starting_assertion_count = example.assertions
10
+ end
11
+
12
+ def explicit_assertions?
13
+ example.assertions > @starting_assertion_count
14
+ end
15
+
16
+ def count_assertion
17
+ example.assertions += 1
18
+ end
19
+
20
+ def fail_with(*args)
21
+ raise Minitest::Assertion, args.join(" ")
22
+ end
23
+
24
+ def pending_error
25
+ Minitest::Skip
26
+ end
27
+
28
+ private
29
+
30
+ def example
31
+ Minitest::Spec.current
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ Given.framework = Minitest::Given::Framework.new
@@ -0,0 +1,22 @@
1
+
2
+ module Minitest
3
+ module Given
4
+
5
+ # If this version of Minitest does not support the #assertions and
6
+ # #assertions= methods, define a working version of them.
7
+ #
8
+ # This allows Minitest/Given to work with Minitest 4.x.
9
+ #
10
+ module NewAssertions
11
+ def assertions
12
+ _assertions
13
+ end
14
+
15
+ def assertions=(new_value)
16
+ self._assertions = new_value
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ Minitest::Spec.__send__(:include, Minitest::Given::NewAssertions)
@@ -0,0 +1,83 @@
1
+
2
+ module Given
3
+ # Does this platform support natural assertions?
4
+ RBX_IN_USE = (defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx')
5
+ JRUBY_IN_USE = defined?(JRUBY_VERSION)
6
+ OLD_JRUBY_IN_USE = JRUBY_IN_USE && (JRUBY_VERSION < '1.7.5')
7
+
8
+ NATURAL_ASSERTIONS_SUPPORTED = ! (OLD_JRUBY_IN_USE || RBX_IN_USE)
9
+
10
+ def self.framework
11
+ @_gvn_framework
12
+ end
13
+
14
+ def self.framework=(framework)
15
+ @_gvn_framework = framework
16
+ end
17
+
18
+ def self.source_caching_disabled
19
+ @_gvn_source_caching_disabled
20
+ end
21
+
22
+ def self.source_caching_disabled=(value)
23
+ @_gvn_source_caching_disabled = value
24
+ end
25
+
26
+ # Globally enable/disable natural assertions.
27
+ #
28
+ # There is a similar function in Extensions that works at a
29
+ # describe or context scope.
30
+ def self.use_natural_assertions(enabled=true)
31
+ ok_to_use_natural_assertions(enabled)
32
+ @natural_assertions_enabled = enabled
33
+ end
34
+
35
+ # TRUE if natural assertions are globally enabled?
36
+ def self.natural_assertions_enabled?
37
+ @natural_assertions_enabled
38
+ end
39
+
40
+ # Is is OK to use natural assertions on this platform.
41
+ #
42
+ # An error is raised if the the platform does not support natural
43
+ # assertions and the flag is attempting to enable them.
44
+ def self.ok_to_use_natural_assertions(enabled)
45
+ if enabled && ! NATURAL_ASSERTIONS_SUPPORTED
46
+ fail ArgumentError, "Natural Assertions are disabled for JRuby"
47
+ end
48
+ end
49
+
50
+ # Return file and line number where the block is defined.
51
+ def self.location_of(block)
52
+ block.source_location
53
+ end
54
+
55
+ # Methods forwarded to the framework object.
56
+
57
+ # Fail an example with the given messages.
58
+ def self.fail_with(*args)
59
+ Given.framework.fail_with(*args)
60
+ end
61
+
62
+ # Mark the start of a Then assertion evaluation.
63
+ def self.start_evaluation(*args)
64
+ Given.framework.start_evaluation(*args)
65
+ end
66
+
67
+ # Were there any explicit framework assertions made during the
68
+ # execution of the Then block?
69
+ def self.explicit_assertions?(*args)
70
+ Given.framework.explicit_assertions?(*args)
71
+ end
72
+
73
+ # Increment the number of assertions made in the framework.
74
+ def self.count_assertion(*args)
75
+ Given.framework.count_assertion(*args)
76
+ end
77
+
78
+ # Error object used by the current framework to indicate a pending
79
+ # example.
80
+ def self.pending_error
81
+ Given.framework.pending_error
82
+ end
83
+ end
@@ -0,0 +1,191 @@
1
+ require 'given/module_methods'
2
+ require 'given/evaluator'
3
+ require 'given/binary_operation'
4
+
5
+ if Given::NATURAL_ASSERTIONS_SUPPORTED
6
+ require 'ripper'
7
+ require 'sorcerer'
8
+ end
9
+
10
+ module Given
11
+
12
+ InvalidThenError = Class.new(StandardError)
13
+
14
+ class NaturalAssertion
15
+
16
+ def initialize(clause_type, block, example, line_extractor)
17
+ @clause_type = clause_type
18
+ @evaluator = Evaluator.new(example, block)
19
+ @line_extractor = line_extractor
20
+ set_file_and_line(block)
21
+ end
22
+
23
+ VOID_SEXP = [:void_stmt]
24
+
25
+ def has_content?
26
+ assertion_sexp != VOID_SEXP
27
+ end
28
+
29
+ def message
30
+ @output = "#{@clause_type} expression failed at #{source_line}\n"
31
+ @output << "Failing expression: #{source.strip}\n" if @clause_type != "Then"
32
+ explain_failure
33
+ display_pairs(expression_value_pairs)
34
+ @output << "\n"
35
+ @output
36
+ end
37
+
38
+ private
39
+
40
+ def explain_failure
41
+ binary = BinaryOperation.parse(assertion_sexp)
42
+ if binary && binary.explain
43
+ @output << explain_expected("expected", binary.left, binary.explain, binary.right)
44
+ end
45
+ end
46
+
47
+ def explain_expected(expect_msg, expect_sexp, got_msg, got_sexp)
48
+ width = [expect_msg.size, got_msg.size].max
49
+ sprintf("%#{width}s: %s\n%#{width}s: %s\n",
50
+ expect_msg, eval_sexp(expect_sexp),
51
+ got_msg, eval_sexp(got_sexp))
52
+ end
53
+
54
+ def expression_value_pairs
55
+ assertion_subexpressions.map { |exp|
56
+ [exp, @evaluator.eval_string(exp)]
57
+ }
58
+ end
59
+
60
+ def assertion_subexpressions
61
+ Sorcerer.subexpressions(assertion_sexp).reverse.uniq.reverse
62
+ end
63
+
64
+ def assertion_sexp
65
+ @assertion_sexp ||= extract_test_expression(Ripper::SexpBuilder.new(source).parse)
66
+ end
67
+
68
+ def source
69
+ @source ||= @line_extractor.line(@code_file, @code_line)
70
+ end
71
+
72
+ def set_file_and_line(block)
73
+ @code_file, @code_line = @evaluator.location
74
+ @code_line = @code_line.to_i
75
+ end
76
+
77
+ def extract_test_expression(sexp)
78
+ brace_block = extract_brace_block(sexp)
79
+ extract_first_statement(brace_block)
80
+ end
81
+
82
+ def extract_brace_block(sexp)
83
+ unless then_block?(sexp)
84
+ source = Sorcerer.source(sexp)
85
+ fail InvalidThenError, "Unexpected code at #{source_line}\n#{source}"
86
+ end
87
+ sexp[1][2][2]
88
+ end
89
+
90
+ def then_block?(sexp)
91
+ program_sexp?(sexp) && method_with_block?(sexp) && has_block_sexp?(sexp)
92
+ end
93
+
94
+ def program_sexp?(sexp)
95
+ delve(sexp,0) == :program
96
+ end
97
+
98
+ def method_with_block?(sexp)
99
+ delve(sexp,1,0) == :stmts_add &&
100
+ delve(sexp,1,2,0) == :method_add_block
101
+ end
102
+
103
+ def has_block_sexp?(sexp)
104
+ delve(sexp,1,2,2,0) == :brace_block || delve(sexp,1,2,2,0) == :do_block
105
+ end
106
+
107
+ def extract_first_statement(block_sexp)
108
+ if contains_multiple_statements?(block_sexp)
109
+ source = Sorcerer.source(block_sexp)
110
+ fail InvalidThenError, "Multiple statements in Then block at #{source_line}\n#{source}"
111
+ end
112
+ extract_statement_from_block(block_sexp)
113
+ end
114
+
115
+ def contains_multiple_statements?(block_sexp)
116
+ stmts = block_statements(block_sexp)
117
+ !(delve(stmts,0) == :stmts_add &&
118
+ delve(stmts,1,0) == :stmts_new)
119
+ end
120
+
121
+ def extract_statement_from_block(block_sexp)
122
+ delve(block_statements(block_sexp),2)
123
+ end
124
+
125
+ # The statements of a block body. Modern Ripper wraps do_block
126
+ # bodies in a :bodystmt node; brace_block bodies (and older
127
+ # Ripper) expose the :stmts_add node directly.
128
+ def block_statements(block_sexp)
129
+ body = delve(block_sexp,2)
130
+ if body.is_a?(Array) && body[0] == :bodystmt
131
+ body[1]
132
+ else
133
+ body
134
+ end
135
+ end
136
+
137
+ # Safely dive into an array with a list of indicies. Return nil
138
+ # if the element doesn't exist, or if the intermediate result is
139
+ # not indexable.
140
+ def delve(ary, *indicies)
141
+ result = ary
142
+ while !indicies.empty? && result
143
+ return nil unless result.respond_to?(:[])
144
+ i = indicies.shift
145
+ result = result[i]
146
+ end
147
+ result
148
+ end
149
+
150
+ def eval_sexp(sexp)
151
+ expr_string = Sorcerer.source(sexp)
152
+ @evaluator.eval_string(expr_string)
153
+ end
154
+
155
+ WRAP_WIDTH = 20
156
+
157
+ def display_pairs(pairs)
158
+ width = suggest_width(pairs) + 4
159
+ pairs.each do |x, v|
160
+ v = adjust_indentation(v)
161
+ fmt = multi_line?(v) ?
162
+ "%-#{width}s\n#{' '*width} <- %s\n" :
163
+ "%-#{width}s <- %s\n"
164
+ @output << sprintf(fmt, v, x)
165
+ end
166
+ end
167
+
168
+ def adjust_indentation(string)
169
+ string.to_s.gsub(/^/, ' ')
170
+ end
171
+
172
+ def multi_line?(string)
173
+ (string.size > WRAP_WIDTH) || (string =~ /\n/)
174
+ end
175
+
176
+ def suggest_width(pairs)
177
+ pairs.map { |x,v|
178
+ max_line_length(v)
179
+ }.select { |n| n < WRAP_WIDTH }.max || 10
180
+ end
181
+
182
+ def max_line_length(string)
183
+ string.to_s.split(/\n/).map { |s| s.size }.max
184
+ end
185
+
186
+ def source_line
187
+ "#{@code_file}:#{@code_line}"
188
+ end
189
+ end
190
+
191
+ end
@@ -0,0 +1,29 @@
1
+ require 'rspec'
2
+ require 'given'
3
+
4
+ module RSpec
5
+ module Given
6
+ end
7
+ end
8
+
9
+ if Given::NATURAL_ASSERTIONS_SUPPORTED
10
+ require 'given/rspec/monkey'
11
+ raise "Unsupported version of RSpec (#{RSpec::Version::STRING}), unable to detect assertions" unless RSpec::Given::MONKEY
12
+ end
13
+
14
+ require 'given/rspec/have_failed'
15
+ require 'given/rspec/before_extensions'
16
+ require 'given/rspec/framework'
17
+ require 'given/rspec/use_natural_assertions'
18
+ require 'given/rspec/configure'
19
+
20
+ module Given
21
+ def self.using_old_rspec?
22
+ defined?(Spec) &&
23
+ defined?(Spec::VERSION) &&
24
+ defined?(Spec::VERSION::SUMMARY) &&
25
+ Spec::VERSION::SUMMARY =~ /^rspec +1\./
26
+ end
27
+ end
28
+
29
+ raise "Unsupported version of RSpec" if Given.using_old_rspec?
@@ -0,0 +1,15 @@
1
+
2
+ module RSpec
3
+ module Given
4
+ module BeforeHack
5
+
6
+ # Some frameworks don't support a robust before block, so we
7
+ # always use this one. In RSpec, we just delegate to the real
8
+ # before block handler.
9
+ def _Gvn_before(*args, &block)
10
+ before(*args, &block)
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ require 'rspec'
2
+ require 'rspec/given' unless defined?(RSpec::Given)
3
+
4
+ RSpec.configure do |c|
5
+ c.extend(Given::ClassExtensions)
6
+ c.include(Given::InstanceExtensions)
7
+ c.include(Given::Fuzzy)
8
+ c.include(Given::FailureMethod)
9
+ c.extend(RSpec::Given::BeforeHack)
10
+ c.include(RSpec::Given::HaveFailed)
11
+
12
+ if c.respond_to?(:backtrace_exclusion_patterns)
13
+ c.backtrace_exclusion_patterns << /lib\/rspec\/given/
14
+ else
15
+ c.backtrace_clean_patterns << /lib\/rspec\/given/
16
+ end
17
+
18
+ Given.use_natural_assertions if Given::NATURAL_ASSERTIONS_SUPPORTED
19
+ Given.source_caching_disabled = false
20
+ end
@@ -0,0 +1,46 @@
1
+
2
+ module RSpec
3
+ module Given
4
+
5
+ # Framework interface for RSpec/Given.
6
+ #
7
+ class Framework
8
+ def start_evaluation
9
+ @matcher_called = false
10
+ end
11
+
12
+ def explicit_assertions?
13
+ @matcher_called
14
+ end
15
+
16
+ def count_assertion
17
+ end
18
+
19
+ def explicitly_asserted
20
+ @matcher_called = true
21
+ end
22
+
23
+ def fail_with(*args)
24
+ ::RSpec::Expectations.fail_with(*args)
25
+ end
26
+
27
+ # Use the RSpec pending error if we can find it.
28
+ if defined?(RSpec::Core::Pending::PendingDeclaredInExample)
29
+ def pending_error
30
+ RSpec::Core::Pending::PendingDeclaredInExample
31
+ end
32
+ elsif defined?(RSpec::Core::Pending::SkipDeclaredInExample)
33
+ def pending_error
34
+ RSpec::Core::Pending::SkipDeclaredInExample
35
+ end
36
+ else
37
+ PendingError = Class.new(StandardError)
38
+ def pending_error
39
+ PendingError
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ Given.framework = RSpec::Given::Framework.new
@@ -0,0 +1,37 @@
1
+
2
+ # The implementation of RaiseError changed between RSpec 2.11 and 2.12.
3
+ if RSpec::Matchers::BuiltIn::RaiseError.instance_methods.include?(:does_not_match?)
4
+ require 'given/rspec/have_failed_212.rb'
5
+ else
6
+ require 'given/rspec/have_failed_pre212.rb'
7
+ end
8
+
9
+ module RSpec
10
+ module Given
11
+ module HaveFailed
12
+
13
+ # Specializes the RaiseError matcher to handle
14
+ # Failure/non-failure objects.
15
+
16
+ # Simular to raise_error(...), but reads a bit better when using
17
+ # a failure result from a when clause.
18
+ #
19
+ # Typical Usage:
20
+ #
21
+ # When(:result) { fail "OUCH" }
22
+ # Then { expect(result).to have_failed(StandardError, /OUCH/) }
23
+ #
24
+ # When(:result) { good_code }
25
+ # Then { expect(result).to_not have_failed }
26
+ #
27
+ # :call-seq:
28
+ # have_failed([exception_class [, message_pattern]])
29
+ # have_failed([exception_class [, message_pattern]]) { |ex| ... }
30
+ #
31
+ def have_failed(error=Exception, message=nil, &block)
32
+ HaveFailedMatcher.new(error, message, &block)
33
+ end
34
+ alias have_raised have_failed
35
+ end
36
+ end
37
+ end