rspec 1.1.4 → 1.1.5
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.
- data/{CHANGES → History.txt} +116 -64
- data/Manifest.txt +403 -0
- data/{MIT-LICENSE → README.txt} +43 -0
- data/Rakefile +39 -212
- data/{TODO → TODO.txt} +0 -0
- data/bin/autospec +4 -0
- data/bin/spec +1 -1
- data/examples/pure/yielding_example.rb +33 -0
- data/examples/stories/game-of-life/.loadpath +5 -0
- data/examples/stories/game-of-life/behaviour/everything.rb +1 -1
- data/examples/stories/game-of-life/behaviour/stories/CellsWithMoreThanThreeNeighboursDie.story +17 -17
- data/init.rb +9 -0
- data/lib/autotest/discover.rb +1 -1
- data/lib/autotest/rspec.rb +3 -29
- data/lib/spec.rb +10 -12
- data/lib/spec/adapters.rb +1 -0
- data/lib/spec/adapters/ruby_engine.rb +26 -0
- data/lib/spec/adapters/ruby_engine/mri.rb +8 -0
- data/lib/spec/adapters/ruby_engine/rubinius.rb +8 -0
- data/lib/spec/example/errors.rb +6 -0
- data/lib/spec/example/example_group_methods.rb +17 -14
- data/lib/spec/example/example_matcher.rb +2 -0
- data/lib/spec/example/example_methods.rb +4 -9
- data/lib/spec/example/module_inclusion_warnings.rb +2 -1
- data/lib/spec/expectations/extensions/object.rb +2 -2
- data/lib/spec/expectations/handler.rb +8 -16
- data/lib/spec/extensions/main.rb +2 -17
- data/lib/spec/matchers.rb +8 -2
- data/lib/spec/matchers/be.rb +0 -3
- data/lib/spec/matchers/change.rb +44 -40
- data/lib/spec/matchers/has.rb +1 -1
- data/lib/spec/matchers/have.rb +17 -12
- data/lib/spec/matchers/operator_matcher.rb +10 -4
- data/lib/spec/matchers/simple_matcher.rb +113 -10
- data/lib/spec/mocks.rb +1 -1
- data/lib/spec/mocks/argument_constraints.rb +185 -0
- data/lib/spec/mocks/argument_expectation.rb +35 -173
- data/lib/spec/mocks/framework.rb +1 -1
- data/lib/spec/mocks/message_expectation.rb +30 -5
- data/lib/spec/mocks/methods.rb +14 -2
- data/lib/spec/mocks/mock.rb +4 -0
- data/lib/spec/mocks/proxy.rb +46 -5
- data/lib/spec/mocks/spec_methods.rb +9 -1
- data/lib/spec/rake/spectask.rb +14 -22
- data/lib/spec/rake/verify_rcov.rb +3 -3
- data/lib/spec/runner.rb +18 -6
- data/lib/spec/runner/backtrace_tweaker.rb +6 -7
- data/lib/spec/runner/command_line.rb +6 -17
- data/lib/spec/runner/drb_command_line.rb +1 -1
- data/lib/spec/runner/formatter/base_formatter.rb +3 -1
- data/lib/spec/runner/formatter/base_text_formatter.rb +5 -9
- data/lib/spec/runner/formatter/html_formatter.rb +1 -1
- data/lib/spec/runner/formatter/nested_text_formatter.rb +1 -1
- data/lib/spec/runner/formatter/progress_bar_formatter.rb +2 -2
- data/lib/spec/runner/formatter/specdoc_formatter.rb +1 -1
- data/lib/spec/runner/formatter/story/html_formatter.rb +62 -16
- data/lib/spec/runner/formatter/story/plain_text_formatter.rb +68 -16
- data/lib/spec/runner/formatter/story/progress_bar_formatter.rb +42 -0
- data/lib/spec/runner/heckle_runner.rb +2 -2
- data/lib/spec/runner/option_parser.rb +2 -1
- data/lib/spec/runner/options.rb +18 -9
- data/lib/spec/runner/reporter.rb +24 -4
- data/lib/spec/runner/spec_parser.rb +1 -1
- data/lib/spec/story/runner.rb +1 -2
- data/lib/spec/story/runner/story_mediator.rb +14 -0
- data/lib/spec/story/runner/story_parser.rb +20 -0
- data/lib/spec/story/step.rb +40 -28
- data/lib/spec/story/step_mother.rb +2 -1
- data/lib/spec/story/world.rb +6 -2
- data/lib/spec/version.rb +13 -22
- data/rake_tasks/failing_examples_with_html.rake +1 -1
- data/rake_tasks/verify_rcov.rake +2 -2
- data/rspec.gemspec +33 -0
- data/spec/autotest/rspec_spec.rb +90 -141
- data/spec/spec/adapters/ruby_engine_spec.rb +16 -0
- data/spec/spec/example/base_formatter_spec.rb +112 -0
- data/spec/spec/example/example_group_factory_spec.rb +2 -2
- data/spec/spec/example/example_group_methods_spec.rb +55 -4
- data/spec/spec/example/example_group_spec.rb +4 -3
- data/spec/spec/example/example_methods_spec.rb +18 -14
- data/spec/spec/example/pending_module_spec.rb +38 -0
- data/spec/spec/example/shared_example_group_spec.rb +1 -1
- data/spec/spec/expectations/extensions/object_spec.rb +0 -12
- data/spec/spec/extensions/main_spec.rb +3 -8
- data/spec/spec/matchers/change_spec.rb +16 -6
- data/spec/spec/matchers/handler_spec.rb +58 -37
- data/spec/spec/matchers/has_spec.rb +10 -0
- data/spec/spec/matchers/have_spec.rb +105 -2
- data/spec/spec/matchers/operator_matcher_spec.rb +35 -2
- data/spec/spec/matchers/simple_matcher_spec.rb +64 -2
- data/spec/spec/mocks/any_number_of_times_spec.rb +7 -0
- data/spec/spec/mocks/bug_report_496.rb +17 -0
- data/spec/spec/mocks/failing_mock_argument_constraints_spec.rb +7 -1
- data/spec/spec/mocks/hash_including_matcher_spec.rb +45 -24
- data/spec/spec/mocks/mock_spec.rb +55 -10
- data/spec/spec/mocks/nil_expectation_warning_spec.rb +54 -0
- data/spec/spec/mocks/null_object_mock_spec.rb +14 -0
- data/spec/spec/mocks/options_hash_spec.rb +18 -28
- data/spec/spec/mocks/partial_mock_spec.rb +2 -0
- data/spec/spec/mocks/passing_mock_argument_constraints_spec.rb +20 -6
- data/spec/spec/mocks/stub_spec.rb +7 -0
- data/spec/spec/runner/command_line_spec.rb +5 -12
- data/spec/spec/runner/drb_command_line_spec.rb +13 -6
- data/spec/spec/runner/formatter/html_formatter_spec.rb +2 -1
- data/spec/spec/runner/formatter/nested_text_formatter_spec.rb +3 -3
- data/spec/spec/runner/formatter/progress_bar_formatter_spec.rb +20 -2
- data/spec/spec/runner/formatter/spec_mate_formatter_spec.rb +2 -1
- data/spec/spec/runner/formatter/specdoc_formatter_spec.rb +3 -3
- data/spec/spec/runner/formatter/story/html_formatter_spec.rb +76 -2
- data/spec/spec/runner/formatter/story/plain_text_formatter_spec.rb +161 -0
- data/spec/spec/runner/formatter/story/progress_bar_formatter_spec.rb +82 -0
- data/spec/spec/runner/heckle_runner_spec.rb +8 -8
- data/spec/spec/runner/option_parser_spec.rb +21 -6
- data/spec/spec/runner/output_one_time_fixture_runner.rb +1 -1
- data/spec/spec/runner/quiet_backtrace_tweaker_spec.rb +6 -0
- data/spec/spec/runner/reporter_spec.rb +51 -5
- data/spec/spec/runner/spec_parser_spec.rb +4 -4
- data/spec/spec/story/runner/plain_text_story_runner_spec.rb +2 -5
- data/spec/spec/story/runner/story_mediator_spec.rb +10 -0
- data/spec/spec/story/runner/story_parser_spec.rb +23 -6
- data/spec/spec/story/scenario_spec.rb +1 -3
- data/spec/spec/story/step_mother_spec.rb +12 -0
- data/spec/spec/story/step_spec.rb +57 -4
- data/spec/spec/story/story_spec.rb +1 -3
- data/spec/spec/story/world_spec.rb +1 -1
- data/spec/spec_helper.rb +21 -68
- data/stories/all.rb +1 -1
- data/stories/configuration/before_blocks.story +21 -0
- data/stories/configuration/stories.rb +7 -0
- data/stories/example_groups/stories.rb +3 -4
- data/stories/resources/spec/before_blocks_example.rb +32 -0
- data/stories/stories/multiline_steps.story +23 -0
- data/stories/stories/steps/multiline_steps.rb +13 -0
- data/stories/stories/stories.rb +6 -0
- data/story_server/prototype/javascripts/builder.js +136 -0
- data/story_server/prototype/javascripts/controls.js +972 -0
- data/story_server/prototype/javascripts/dragdrop.js +976 -0
- data/story_server/prototype/javascripts/effects.js +1117 -0
- data/story_server/prototype/javascripts/prototype.js +4140 -0
- data/story_server/prototype/javascripts/rspec.js +149 -0
- data/story_server/prototype/javascripts/scriptaculous.js +58 -0
- data/story_server/prototype/javascripts/slider.js +276 -0
- data/story_server/prototype/javascripts/sound.js +55 -0
- data/story_server/prototype/javascripts/unittest.js +568 -0
- data/story_server/prototype/lib/server.rb +24 -0
- data/story_server/prototype/stories.html +176 -0
- data/story_server/prototype/stylesheets/rspec.css +136 -0
- data/story_server/prototype/stylesheets/test.css +90 -0
- metadata +166 -166
- data/README +0 -36
- data/UPGRADE +0 -7
- data/bin/spec_translator +0 -8
- data/lib/spec/mocks/argument_constraint_matchers.rb +0 -31
- data/lib/spec/translator.rb +0 -114
- data/spec/spec/example/example_spec.rb +0 -53
- data/spec/spec/runner/execution_context_spec.rb +0 -37
- data/spec/spec/translator_spec.rb +0 -265
|
@@ -2,38 +2,29 @@ module Spec
|
|
|
2
2
|
module Expectations
|
|
3
3
|
class InvalidMatcherError < ArgumentError; end
|
|
4
4
|
|
|
5
|
-
module MatcherHandlerHelper
|
|
6
|
-
def describe_matcher(matcher)
|
|
7
|
-
matcher.respond_to?(:description) ? matcher.description : "[#{matcher.class.name} does not provide a description]"
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
|
|
11
5
|
class ExpectationMatcherHandler
|
|
12
6
|
class << self
|
|
13
|
-
include MatcherHandlerHelper
|
|
14
7
|
def handle_matcher(actual, matcher, &block)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
end
|
|
8
|
+
::Spec::Matchers.last_should = "should"
|
|
9
|
+
return Spec::Matchers::PositiveOperatorMatcher.new(actual) if matcher.nil?
|
|
18
10
|
|
|
19
11
|
unless matcher.respond_to?(:matches?)
|
|
20
12
|
raise InvalidMatcherError, "Expected a matcher, got #{matcher.inspect}."
|
|
21
13
|
end
|
|
22
14
|
|
|
23
15
|
match = matcher.matches?(actual, &block)
|
|
24
|
-
::Spec::Matchers.
|
|
16
|
+
::Spec::Matchers.last_matcher = matcher
|
|
25
17
|
Spec::Expectations.fail_with(matcher.failure_message) unless match
|
|
18
|
+
match
|
|
26
19
|
end
|
|
27
20
|
end
|
|
28
21
|
end
|
|
29
22
|
|
|
30
23
|
class NegativeExpectationMatcherHandler
|
|
31
24
|
class << self
|
|
32
|
-
include MatcherHandlerHelper
|
|
33
25
|
def handle_matcher(actual, matcher, &block)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
end
|
|
26
|
+
::Spec::Matchers.last_should = "should not"
|
|
27
|
+
return Spec::Matchers::NegativeOperatorMatcher.new(actual) if matcher.nil?
|
|
37
28
|
|
|
38
29
|
unless matcher.respond_to?(:matches?)
|
|
39
30
|
raise InvalidMatcherError, "Expected a matcher, got #{matcher.inspect}."
|
|
@@ -49,8 +40,9 @@ EOF
|
|
|
49
40
|
)
|
|
50
41
|
end
|
|
51
42
|
match = matcher.matches?(actual, &block)
|
|
52
|
-
::Spec::Matchers.
|
|
43
|
+
::Spec::Matchers.last_matcher = matcher
|
|
53
44
|
Spec::Expectations.fail_with(matcher.negative_failure_message) if match
|
|
45
|
+
match
|
|
54
46
|
end
|
|
55
47
|
end
|
|
56
48
|
end
|
data/lib/spec/extensions/main.rb
CHANGED
|
@@ -23,7 +23,7 @@ module Spec
|
|
|
23
23
|
raise ArgumentError if args.empty?
|
|
24
24
|
raise ArgumentError unless block
|
|
25
25
|
args << {} unless Hash === args.last
|
|
26
|
-
args.last[:spec_path] = caller(0)[1]
|
|
26
|
+
args.last[:spec_path] = File.expand_path(caller(0)[1])
|
|
27
27
|
Spec::Example::ExampleGroupFactory.create_example_group(*args, &block)
|
|
28
28
|
end
|
|
29
29
|
alias :context :describe
|
|
@@ -80,23 +80,8 @@ module Spec
|
|
|
80
80
|
raise NameError.new(e.message + "\nThe first argument to share_as must be a legal name for a constant\n")
|
|
81
81
|
end
|
|
82
82
|
end
|
|
83
|
-
|
|
84
|
-
private
|
|
85
|
-
|
|
86
|
-
def rspec_options
|
|
87
|
-
$rspec_options ||= begin; \
|
|
88
|
-
parser = ::Spec::Runner::OptionParser.new(STDERR, STDOUT); \
|
|
89
|
-
parser.order!(ARGV); \
|
|
90
|
-
$rspec_options = parser.options; \
|
|
91
|
-
end
|
|
92
|
-
$rspec_options
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def init_rspec_options(options)
|
|
96
|
-
$rspec_options = options if $rspec_options.nil?
|
|
97
|
-
end
|
|
98
83
|
end
|
|
99
84
|
end
|
|
100
85
|
end
|
|
101
86
|
|
|
102
|
-
include Spec::Extensions::Main
|
|
87
|
+
include Spec::Extensions::Main
|
data/lib/spec/matchers.rb
CHANGED
|
@@ -134,10 +134,16 @@ module Spec
|
|
|
134
134
|
#
|
|
135
135
|
module Matchers
|
|
136
136
|
module ModuleMethods
|
|
137
|
-
attr_accessor :
|
|
137
|
+
attr_accessor :last_matcher, :last_should
|
|
138
138
|
|
|
139
139
|
def clear_generated_description
|
|
140
|
-
self.
|
|
140
|
+
self.last_matcher = nil
|
|
141
|
+
self.last_should = nil
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def generated_description
|
|
145
|
+
last_should.nil? ? nil :
|
|
146
|
+
"#{last_should} #{last_matcher.respond_to?(:description) ? last_matcher.description : 'NO NAME'}"
|
|
141
147
|
end
|
|
142
148
|
end
|
|
143
149
|
|
data/lib/spec/matchers/be.rb
CHANGED
|
@@ -23,9 +23,6 @@ module Spec
|
|
|
23
23
|
rcov_error_report = "http://eigenclass.org/hiki.rb?rcov-0.8.0"
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
# This supports should_exist > target.exists? in the old world.
|
|
27
|
-
# We should consider deprecating that ability as in the new world
|
|
28
|
-
# you can't write "should exist" unless you have your own custom matcher.
|
|
29
26
|
begin
|
|
30
27
|
return @result = actual.__send__(present_tense_predicate, *@args)
|
|
31
28
|
rescue
|
data/lib/spec/matchers/change.rb
CHANGED
|
@@ -4,60 +4,60 @@ module Spec
|
|
|
4
4
|
#Based on patch from Wilson Bilkovich
|
|
5
5
|
class Change #:nodoc:
|
|
6
6
|
def initialize(receiver=nil, message=nil, &block)
|
|
7
|
-
@
|
|
8
|
-
@
|
|
9
|
-
|
|
7
|
+
@message = message || "result"
|
|
8
|
+
@value_proc = block || lambda {
|
|
9
|
+
receiver.__send__(message)
|
|
10
|
+
}
|
|
10
11
|
end
|
|
11
12
|
|
|
12
|
-
def matches?(
|
|
13
|
-
if
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@
|
|
20
|
-
|
|
21
|
-
return false if @from && (@from != @before)
|
|
22
|
-
return false if @to && (@to != @after)
|
|
13
|
+
def matches?(event_proc)
|
|
14
|
+
raise_block_syntax_error if block_given?
|
|
15
|
+
|
|
16
|
+
@before = evaluate_value_proc
|
|
17
|
+
event_proc.call
|
|
18
|
+
@after = evaluate_value_proc
|
|
19
|
+
|
|
20
|
+
return false if @from unless @from == @before
|
|
21
|
+
return false if @to unless @to == @after
|
|
23
22
|
return (@before + @amount == @after) if @amount
|
|
24
23
|
return ((@after - @before) >= @minimum) if @minimum
|
|
25
24
|
return ((@after - @before) <= @maximum) if @maximum
|
|
26
25
|
return @before != @after
|
|
27
26
|
end
|
|
28
27
|
|
|
29
|
-
def
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
def raise_block_syntax_error
|
|
29
|
+
raise MatcherError.new(<<-MESSAGE
|
|
30
|
+
block passed to should or should_not change must use {} instead of do/end
|
|
31
|
+
MESSAGE
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def evaluate_value_proc
|
|
36
|
+
@value_proc.call
|
|
33
37
|
end
|
|
34
38
|
|
|
35
39
|
def failure_message
|
|
36
40
|
if @to
|
|
37
|
-
"#{
|
|
41
|
+
"#{@message} should have been changed to #{@to.inspect}, but is now #{@after.inspect}"
|
|
38
42
|
elsif @from
|
|
39
|
-
"#{
|
|
43
|
+
"#{@message} should have initially been #{@from.inspect}, but was #{@before.inspect}"
|
|
40
44
|
elsif @amount
|
|
41
|
-
"#{
|
|
45
|
+
"#{@message} should have been changed by #{@amount.inspect}, but was changed by #{actual_delta.inspect}"
|
|
42
46
|
elsif @minimum
|
|
43
|
-
"#{
|
|
47
|
+
"#{@message} should have been changed by at least #{@minimum.inspect}, but was changed by #{actual_delta.inspect}"
|
|
44
48
|
elsif @maximum
|
|
45
|
-
"#{
|
|
49
|
+
"#{@message} should have been changed by at most #{@maximum.inspect}, but was changed by #{actual_delta.inspect}"
|
|
46
50
|
else
|
|
47
|
-
"#{
|
|
51
|
+
"#{@message} should have changed, but is still #{@before.inspect}"
|
|
48
52
|
end
|
|
49
53
|
end
|
|
50
54
|
|
|
51
|
-
def result
|
|
52
|
-
@message || "result"
|
|
53
|
-
end
|
|
54
|
-
|
|
55
55
|
def actual_delta
|
|
56
56
|
@after - @before
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
def negative_failure_message
|
|
60
|
-
"#{
|
|
60
|
+
"#{@message} should not have changed, but did change from #{@before.inspect} to #{@after.inspect}"
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
def by(amount)
|
|
@@ -125,20 +125,24 @@ EOF
|
|
|
125
125
|
# employee.develop_great_new_social_networking_app
|
|
126
126
|
# }.should change(employee, :title).from("Mail Clerk").to("CEO")
|
|
127
127
|
#
|
|
128
|
-
# Evaluates
|
|
129
|
-
#
|
|
128
|
+
# Evaluates <tt>receiver.message</tt> or <tt>block</tt> before and after
|
|
129
|
+
# it evaluates the c object (generated by the lambdas in the examples
|
|
130
|
+
# above).
|
|
131
|
+
#
|
|
132
|
+
# Then compares the values before and after the <tt>receiver.message</tt>
|
|
133
|
+
# and evaluates the difference compared to the expected difference.
|
|
130
134
|
#
|
|
131
|
-
#
|
|
132
|
-
#
|
|
135
|
+
# == WARNING
|
|
136
|
+
# <tt>should_not change</tt> only supports the form with no
|
|
137
|
+
# subsequent calls to <tt>by</tt>, <tt>by_at_least</tt>,
|
|
138
|
+
# <tt>by_at_most</tt>, <tt>to</tt> or <tt>from</tt>.
|
|
133
139
|
#
|
|
134
|
-
#
|
|
135
|
-
#
|
|
136
|
-
#
|
|
140
|
+
# blocks passed to <tt>should</tt> <tt>change</tt> and <tt>should_not</tt>
|
|
141
|
+
# <tt>change</tt> must use the <tt>{}</tt> form (<tt>do/end</tt> is not
|
|
142
|
+
# supported).
|
|
137
143
|
#
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
def change(target=nil, message=nil, &block)
|
|
141
|
-
Matchers::Change.new(target, message, &block)
|
|
144
|
+
def change(receiver=nil, message=nil, &block)
|
|
145
|
+
Matchers::Change.new(receiver, message, &block)
|
|
142
146
|
end
|
|
143
147
|
end
|
|
144
148
|
end
|
data/lib/spec/matchers/has.rb
CHANGED
data/lib/spec/matchers/have.rb
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
module Spec
|
|
2
2
|
module Matchers
|
|
3
|
-
|
|
4
3
|
class Have #:nodoc:
|
|
5
4
|
def initialize(expected, relativity=:exactly)
|
|
6
5
|
@expected = (expected == :no ? 0 : expected)
|
|
@@ -15,23 +14,15 @@ module Spec
|
|
|
15
14
|
}
|
|
16
15
|
end
|
|
17
16
|
|
|
18
|
-
def method_missing(sym, *args, &block)
|
|
19
|
-
@collection_name = sym
|
|
20
|
-
@plural_collection_name = Inflector.pluralize(sym.to_s) if Object.const_defined?(:Inflector)
|
|
21
|
-
@args = args
|
|
22
|
-
@block = block
|
|
23
|
-
self
|
|
24
|
-
end
|
|
25
|
-
|
|
26
17
|
def matches?(collection_owner)
|
|
27
18
|
if collection_owner.respond_to?(@collection_name)
|
|
28
|
-
collection = collection_owner.
|
|
19
|
+
collection = collection_owner.__send__(@collection_name, *@args, &@block)
|
|
29
20
|
elsif (@plural_collection_name && collection_owner.respond_to?(@plural_collection_name))
|
|
30
|
-
collection = collection_owner.
|
|
21
|
+
collection = collection_owner.__send__(@plural_collection_name, *@args, &@block)
|
|
31
22
|
elsif (collection_owner.respond_to?(:length) || collection_owner.respond_to?(:size))
|
|
32
23
|
collection = collection_owner
|
|
33
24
|
else
|
|
34
|
-
collection_owner.
|
|
25
|
+
collection_owner.__send__(@collection_name, *@args, &@block)
|
|
35
26
|
end
|
|
36
27
|
@actual = collection.size if collection.respond_to?(:size)
|
|
37
28
|
@actual = collection.length if collection.respond_to?(:length)
|
|
@@ -75,8 +66,22 @@ EOF
|
|
|
75
66
|
"have #{relative_expectation} #{@collection_name}"
|
|
76
67
|
end
|
|
77
68
|
|
|
69
|
+
def respond_to?(sym)
|
|
70
|
+
@expected.respond_to?(sym) || super
|
|
71
|
+
end
|
|
72
|
+
|
|
78
73
|
private
|
|
79
74
|
|
|
75
|
+
def method_missing(sym, *args, &block)
|
|
76
|
+
@collection_name = sym
|
|
77
|
+
if inflector = (defined?(ActiveSupport::Inflector) ? ActiveSupport::Inflector : (defined?(Inflector) ? Inflector : nil))
|
|
78
|
+
@plural_collection_name = inflector.pluralize(sym.to_s)
|
|
79
|
+
end
|
|
80
|
+
@args = args
|
|
81
|
+
@block = block
|
|
82
|
+
self
|
|
83
|
+
end
|
|
84
|
+
|
|
80
85
|
def relative_expectation
|
|
81
86
|
"#{relativities[@relativity]}#{@expected}"
|
|
82
87
|
end
|
|
@@ -45,14 +45,19 @@ module Spec
|
|
|
45
45
|
def fail_with_message(message)
|
|
46
46
|
Spec::Expectations.fail_with(message, @expected, @target)
|
|
47
47
|
end
|
|
48
|
+
|
|
49
|
+
def description
|
|
50
|
+
"#{@operator} #{@expected.inspect}"
|
|
51
|
+
end
|
|
48
52
|
|
|
49
53
|
end
|
|
50
54
|
|
|
51
55
|
class PositiveOperatorMatcher < BaseOperatorMatcher #:nodoc:
|
|
52
56
|
|
|
53
57
|
def __delegate_method_missing_to_target(operator, expected)
|
|
54
|
-
|
|
55
|
-
|
|
58
|
+
@operator = operator
|
|
59
|
+
::Spec::Matchers.last_matcher = self
|
|
60
|
+
return true if @target.__send__(operator, expected)
|
|
56
61
|
return fail_with_message("expected: #{expected.inspect},\n got: #{@target.inspect} (using #{operator})") if ['==','===', '=~'].include?(operator)
|
|
57
62
|
return fail_with_message("expected: #{operator} #{expected.inspect},\n got: #{operator.gsub(/./, ' ')} #{@target.inspect}")
|
|
58
63
|
end
|
|
@@ -62,8 +67,9 @@ module Spec
|
|
|
62
67
|
class NegativeOperatorMatcher < BaseOperatorMatcher #:nodoc:
|
|
63
68
|
|
|
64
69
|
def __delegate_method_missing_to_target(operator, expected)
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
@operator = operator
|
|
71
|
+
::Spec::Matchers.last_matcher = self
|
|
72
|
+
return true unless @target.__send__(operator, expected)
|
|
67
73
|
return fail_with_message("expected not: #{operator} #{expected.inspect},\n got: #{operator.gsub(/./, ' ')} #{@target.inspect}")
|
|
68
74
|
end
|
|
69
75
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Spec
|
|
2
2
|
module Matchers
|
|
3
3
|
class SimpleMatcher
|
|
4
|
-
|
|
4
|
+
attr_writer :failure_message, :negative_failure_message, :description
|
|
5
5
|
|
|
6
6
|
def initialize(description, &match_block)
|
|
7
7
|
@description = description
|
|
@@ -10,20 +10,123 @@ module Spec
|
|
|
10
10
|
|
|
11
11
|
def matches?(actual)
|
|
12
12
|
@actual = actual
|
|
13
|
-
|
|
13
|
+
case @match_block.arity
|
|
14
|
+
when 2
|
|
15
|
+
@match_block.call(@actual, self)
|
|
16
|
+
else
|
|
17
|
+
@match_block.call(@actual)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def description
|
|
22
|
+
@description || explanation
|
|
14
23
|
end
|
|
15
24
|
|
|
16
|
-
def failure_message
|
|
17
|
-
|
|
25
|
+
def failure_message
|
|
26
|
+
@failure_message || (@description.nil? ? explanation : %[expected #{@description.inspect} but got #{@actual.inspect}])
|
|
18
27
|
end
|
|
19
|
-
|
|
20
|
-
def negative_failure_message
|
|
21
|
-
|
|
28
|
+
|
|
29
|
+
def negative_failure_message
|
|
30
|
+
@negative_failure_message || (@description.nil? ? explanation : %[expected not to get #{@description.inspect}, but got #{@actual.inspect}])
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def explanation
|
|
34
|
+
"No description provided. See RDoc for simple_matcher()"
|
|
22
35
|
end
|
|
23
36
|
end
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
37
|
+
|
|
38
|
+
# simple_matcher makes it easy for you to create your own custom matchers
|
|
39
|
+
# in just a few lines of code when you don't need all the power of a
|
|
40
|
+
# completely custom matcher object.
|
|
41
|
+
#
|
|
42
|
+
# The <tt>description</tt> argument will appear as part of any failure
|
|
43
|
+
# message, and is also the source for auto-generated descriptions.
|
|
44
|
+
#
|
|
45
|
+
# The <tt>match_block</tt> can have an arity of 1 or 2. The first block
|
|
46
|
+
# argument will be the given value. The second, if the block accepts it
|
|
47
|
+
# will be the matcher itself, giving you access to set custom failure
|
|
48
|
+
# messages in favor of the defaults.
|
|
49
|
+
#
|
|
50
|
+
# The <tt>match_block</tt> should return a boolean: <tt>true</tt>
|
|
51
|
+
# indicates a match, which will pass if you use <tt>should</tt> and fail
|
|
52
|
+
# if you use <tt>should_not</tt>. false (or nil) indicates no match,
|
|
53
|
+
# which will do the reverse: fail if you use <tt>should</tt> and pass if
|
|
54
|
+
# you use <tt>should_not</tt>.
|
|
55
|
+
#
|
|
56
|
+
# An error in the <tt>match_block</tt> will bubble up, resulting in a
|
|
57
|
+
# failure.
|
|
58
|
+
#
|
|
59
|
+
# == Example with default messages
|
|
60
|
+
#
|
|
61
|
+
# def be_even
|
|
62
|
+
# simple_matcher("an even number") { |given| given % 2 == 0 }
|
|
63
|
+
# end
|
|
64
|
+
#
|
|
65
|
+
# describe 2 do
|
|
66
|
+
# it "should be even" do
|
|
67
|
+
# 2.should be_even
|
|
68
|
+
# end
|
|
69
|
+
# end
|
|
70
|
+
#
|
|
71
|
+
# Given an odd number, this example would produce an error message stating:
|
|
72
|
+
# expected "an even number", got 3.
|
|
73
|
+
#
|
|
74
|
+
# Unfortunately, if you're a fan of auto-generated descriptions, this will
|
|
75
|
+
# produce "should an even number." Not the most desirable result. You can
|
|
76
|
+
# control that using custom messages:
|
|
77
|
+
#
|
|
78
|
+
# == Example with custom messages
|
|
79
|
+
#
|
|
80
|
+
# def rhyme_with(expected)
|
|
81
|
+
# simple_matcher("rhyme with #{expected.inspect}") do |given, matcher|
|
|
82
|
+
# matcher.failure_message = "expected #{given.inspect} to rhyme with #{expected.inspect}"
|
|
83
|
+
# matcher.negative_failure_message = "expected #{given.inspect} not to rhyme with #{expected.inspect}"
|
|
84
|
+
# actual.rhymes_with? expected
|
|
85
|
+
# end
|
|
86
|
+
# end
|
|
87
|
+
#
|
|
88
|
+
# # OR
|
|
89
|
+
#
|
|
90
|
+
# def rhyme_with(expected)
|
|
91
|
+
# simple_matcher do |given, matcher|
|
|
92
|
+
# matcher.description = "rhyme with #{expected.inspect}"
|
|
93
|
+
# matcher.failure_message = "expected #{given.inspect} to rhyme with #{expected.inspect}"
|
|
94
|
+
# matcher.negative_failure_message = "expected #{given.inspect} not to rhyme with #{expected.inspect}"
|
|
95
|
+
# actual.rhymes_with? expected
|
|
96
|
+
# end
|
|
97
|
+
# end
|
|
98
|
+
#
|
|
99
|
+
# describe "pecan" do
|
|
100
|
+
# it "should rhyme with 'be gone'" do
|
|
101
|
+
# nut = "pecan"
|
|
102
|
+
# nut.extend Rhymer
|
|
103
|
+
# nut.should rhyme_with("be gone")
|
|
104
|
+
# end
|
|
105
|
+
# end
|
|
106
|
+
#
|
|
107
|
+
# The resulting messages would be:
|
|
108
|
+
# description: rhyme with "be gone"
|
|
109
|
+
# failure_message: expected "pecan" to rhyme with "be gone"
|
|
110
|
+
# negative failure_message: expected "pecan" not to rhyme with "be gone"
|
|
111
|
+
#
|
|
112
|
+
# == Wrapped Expectations
|
|
113
|
+
#
|
|
114
|
+
# Because errors will bubble up, it is possible to wrap other expectations
|
|
115
|
+
# in a SimpleMatcher.
|
|
116
|
+
#
|
|
117
|
+
# def be_even
|
|
118
|
+
# simple_matcher("an even number") { |given| (given % 2).should == 0 }
|
|
119
|
+
# end
|
|
120
|
+
#
|
|
121
|
+
# BE VERY CAREFUL when you do this. Only use wrapped expectations for
|
|
122
|
+
# matchers that will always be used in only the positive
|
|
123
|
+
# (<tt>should</tt>) or negative (<tt>should_not</tt>), but not both.
|
|
124
|
+
# The reason is that is you wrap a <tt>should</tt> and call the wrapper
|
|
125
|
+
# with <tt>should_not</tt>, the correct result (the <tt>should</tt>
|
|
126
|
+
# failing), will fail when you want it to pass.
|
|
127
|
+
#
|
|
128
|
+
def simple_matcher(description=nil, &match_block)
|
|
129
|
+
SimpleMatcher.new(description, &match_block)
|
|
27
130
|
end
|
|
28
131
|
end
|
|
29
132
|
end
|