dchelimsky-rspec 1.1.11.1 → 1.1.11.2
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/History.txt +11 -3
- data/Manifest.txt +35 -46
- data/README.txt +30 -12
- data/Rakefile +9 -9
- data/{stories/configuration/before_blocks.story → features/configuration/before_blocks.feature} +2 -2
- data/{stories/example_groups/autogenerated_docstrings → features/example_groups/autogenerated_docstrings.feature} +1 -1
- data/{stories/example_groups/example_group_with_should_methods → features/example_groups/example_group_with_should_methods.feature} +3 -3
- data/{stories/example_groups/nested_groups → features/example_groups/nested_groups.feature} +1 -1
- data/{stories/example_groups/output → features/example_groups/output.feature} +3 -8
- data/{stories/interop/examples_and_tests_together → features/interop/examples_and_tests_together.feature} +5 -4
- data/{stories/interop/test_but_not_test_unit → features/interop/test_but_not_test_unit.feature} +2 -2
- data/{stories/interop/test_case_with_should_methods → features/interop/test_case_with_should_methods.feature} +2 -2
- data/{stories/mock_framework_integration/use_flexmock.story → features/mock_framework_integration/use_flexmock.feature} +1 -1
- data/features/step_definitions/running_rspec.rb +48 -0
- data/features/support/env.rb +25 -0
- data/{stories/resources → features/support}/helpers/cmdline.rb +0 -0
- data/{stories/resources → features/support}/helpers/story_helper.rb +0 -0
- data/{stories/resources → features/support}/matchers/smart_match.rb +0 -0
- data/{plugins → lib/adapters}/mock_frameworks/flexmock.rb +0 -0
- data/{plugins → lib/adapters}/mock_frameworks/mocha.rb +0 -0
- data/{plugins → lib/adapters}/mock_frameworks/rr.rb +0 -0
- data/{plugins → lib/adapters}/mock_frameworks/rspec.rb +1 -1
- data/lib/autotest/rspec.rb +3 -2
- data/lib/spec/dsl/main.rb +8 -4
- data/lib/spec/example/configuration.rb +1 -1
- data/lib/spec/example/example_group_factory.rb +6 -2
- data/lib/spec/example/example_group_methods.rb +47 -54
- data/lib/spec/example/shared_example_group.rb +2 -2
- data/lib/spec/example.rb +163 -14
- data/lib/spec/interop/test/unit/testresult.rb +1 -1
- data/lib/spec/interop/test/unit/testsuite_adapter.rb +1 -1
- data/lib/spec/matchers/match_array.rb +75 -0
- data/lib/spec/matchers/operator_matcher.rb +34 -7
- data/lib/spec/matchers.rb +2 -1
- data/lib/spec/mocks/argument_constraints.rb +43 -5
- data/lib/spec/runner/example_group_runner.rb +2 -2
- data/lib/spec/runner/option_parser.rb +12 -6
- data/lib/spec/runner/options.rb +9 -9
- data/lib/spec/runner/spec_parser.rb +3 -2
- data/lib/spec/runner.rb +54 -188
- data/lib/spec/version.rb +1 -1
- data/lib/spec.rb +0 -29
- data/{rake_tasks → resources/rake}/examples.rake +0 -0
- data/{rake_tasks → resources/rake}/examples_with_rcov.rake +0 -0
- data/{rake_tasks → resources/rake}/failing_examples_with_html.rake +0 -0
- data/{rake_tasks → resources/rake}/verify_rcov.rake +0 -0
- data/{stories/resources → resources}/spec/before_blocks_example.rb +1 -1
- data/{stories/resources → resources}/spec/example_group_with_should_methods.rb +1 -1
- data/{stories/resources → resources}/spec/simple_spec.rb +1 -1
- data/resources/spec/spec_with_flexmock.rb +19 -0
- data/{stories/resources → resources}/test/spec_and_test_together.rb +1 -1
- data/{stories/resources → resources}/test/spec_including_test_but_not_unit.rb +1 -1
- data/{stories/resources → resources}/test/test_case_with_should_methods.rb +2 -2
- data/rspec.gemspec +5 -4
- data/spec/autotest/rspec_spec.rb +2 -1
- data/spec/spec/dsl/main_spec.rb +8 -5
- data/spec/spec/example/configuration_spec.rb +9 -9
- data/spec/spec/example/example_group_factory_spec.rb +22 -3
- data/spec/spec/example/example_group_methods_spec.rb +19 -15
- data/spec/spec/example/example_group_spec.rb +41 -41
- data/spec/spec/example/example_methods_spec.rb +5 -5
- data/spec/spec/example/helper_method_spec.rb +24 -0
- data/spec/spec/example/pending_module_spec.rb +2 -8
- data/spec/spec/example/shared_example_group_spec.rb +5 -5
- data/spec/spec/matchers/description_generation_spec.rb +5 -0
- data/spec/spec/matchers/handler_spec.rb +7 -7
- data/spec/spec/matchers/match_array_spec.rb +83 -0
- data/spec/spec/matchers/raise_error_spec.rb +18 -0
- data/spec/spec/mocks/hash_including_matcher_spec.rb +39 -2
- data/spec/spec/mocks/hash_not_including_matcher_spec.rb +67 -0
- data/spec/spec/mocks/mock_spec.rb +5 -6
- data/spec/spec/mocks/nil_expectation_warning_spec.rb +1 -1
- data/spec/spec/runner/formatter/base_text_formatter_spec.rb +22 -0
- data/spec/spec/runner/option_parser_spec.rb +4 -17
- data/spec/spec/runner/options_spec.rb +19 -5
- data/spec/spec/runner/resources/custom_example_group_runner.rb +14 -0
- data/spec/spec/runner/spec_parser_spec.rb +10 -0
- data/spec/spec/spec_spec.rb +21 -0
- metadata +39 -49
- data/lib/spec/adapters/ruby_engine/mri.rb +0 -8
- data/lib/spec/adapters/ruby_engine/rubinius.rb +0 -8
- data/lib/spec/adapters/ruby_engine.rb +0 -26
- data/lib/spec/adapters.rb +0 -1
- data/lib/spec/extensions/class.rb +0 -24
- data/lib/spec/extensions.rb +0 -1
- data/spec/spec/adapters/ruby_engine_spec.rb +0 -16
- data/stories/all.rb +0 -5
- data/stories/configuration/stories.rb +0 -7
- data/stories/example_groups/stories.rb +0 -7
- data/stories/helper.rb +0 -6
- data/stories/interop/stories.rb +0 -7
- data/stories/mock_framework_integration/stories.rb +0 -7
- data/stories/pending_stories/README +0 -3
- data/stories/resources/spec/spec_with_flexmock.rb +0 -18
- data/stories/resources/steps/running_rspec.rb +0 -50
- data/stories/resources/stories/failing_story.rb +0 -15
- data/stories/stories/multiline_steps.story +0 -23
- data/stories/stories/steps/multiline_steps.rb +0 -13
- data/stories/stories/stories.rb +0 -6
@@ -13,13 +13,13 @@ module Spec
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.description_text(*args)
|
16
|
-
args.inject("") do |
|
17
|
-
|
18
|
-
|
16
|
+
args.inject("") do |description, arg|
|
17
|
+
description << " " unless (description == "" || arg.to_s =~ /^(\s|\.|#)/)
|
18
|
+
description << arg.to_s
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
attr_reader :
|
22
|
+
attr_reader :description_options, :spec_path
|
23
23
|
alias :options :description_options
|
24
24
|
|
25
25
|
# Provides the backtrace up to where this example_group was declared.
|
@@ -42,7 +42,7 @@ WARNING
|
|
42
42
|
|
43
43
|
def inherited(klass)
|
44
44
|
super
|
45
|
-
klass
|
45
|
+
Spec::Runner.options.add_example_group klass
|
46
46
|
Spec::Runner.register_at_exit_hook
|
47
47
|
end
|
48
48
|
|
@@ -61,11 +61,9 @@ WARNING
|
|
61
61
|
# end
|
62
62
|
#
|
63
63
|
def describe(*args, &example_group_block)
|
64
|
-
args << {} unless Hash === args.last
|
65
64
|
if example_group_block
|
65
|
+
Spec::Example::add_spec_path_to(args)
|
66
66
|
options = args.last
|
67
|
-
# Ruby 1.9 - the next line uses example_group_block.binding instead of example_group_block
|
68
|
-
options[:spec_path] = eval("caller(0)[1]", example_group_block.binding) unless options[:spec_path]
|
69
67
|
if options[:shared]
|
70
68
|
create_shared_example_group(*args, &example_group_block)
|
71
69
|
else
|
@@ -82,12 +80,28 @@ WARNING
|
|
82
80
|
end
|
83
81
|
|
84
82
|
def create_subclass(*args, &example_group_block) # :nodoc:
|
85
|
-
|
83
|
+
subclass("Subclass") do
|
86
84
|
set_description(*args)
|
87
85
|
module_eval(&example_group_block)
|
88
86
|
end
|
89
87
|
end
|
90
88
|
|
89
|
+
# Creates a new subclass of self, with a name "under" our own name.
|
90
|
+
# Example:
|
91
|
+
#
|
92
|
+
# x = Foo::Bar.subclass('Zap'){}
|
93
|
+
# x.name # => Foo::Bar::Zap_1
|
94
|
+
# x.superclass.name # => Foo::Bar
|
95
|
+
def subclass(base_name, &body) # :nodoc:
|
96
|
+
@class_count ||= 0
|
97
|
+
@class_count += 1
|
98
|
+
klass = Class.new(self)
|
99
|
+
class_name = "#{base_name}_#{@class_count}"
|
100
|
+
const_set(class_name, klass)
|
101
|
+
klass.instance_eval(&body)
|
102
|
+
klass
|
103
|
+
end
|
104
|
+
|
91
105
|
# Use this to pull in examples from shared example groups.
|
92
106
|
# See Spec::Runner for information about shared example groups.
|
93
107
|
def it_should_behave_like(*shared_example_groups)
|
@@ -147,18 +161,18 @@ WARNING
|
|
147
161
|
alias_method :xit, :xexample
|
148
162
|
alias_method :xspecify, :xexample
|
149
163
|
|
150
|
-
def run
|
151
|
-
examples = examples_to_run
|
152
|
-
reporter.add_example_group(self) unless
|
164
|
+
def run(run_options)
|
165
|
+
examples = examples_to_run(run_options)
|
166
|
+
run_options.reporter.add_example_group(self) unless examples.empty?
|
153
167
|
return true if examples.empty?
|
154
|
-
return dry_run(examples) if dry_run?
|
168
|
+
return dry_run(examples, run_options) if run_options.dry_run?
|
155
169
|
|
156
170
|
plugin_mock_framework
|
157
171
|
define_methods_from_predicate_matchers
|
158
172
|
|
159
|
-
success, before_all_instance_variables = run_before_all
|
160
|
-
success, after_all_instance_variables = execute_examples(success, before_all_instance_variables, examples)
|
161
|
-
success = run_after_all(success, after_all_instance_variables)
|
173
|
+
success, before_all_instance_variables = run_before_all(run_options)
|
174
|
+
success, after_all_instance_variables = execute_examples(success, before_all_instance_variables, examples, run_options)
|
175
|
+
success = run_after_all(success, after_all_instance_variables, run_options)
|
162
176
|
end
|
163
177
|
|
164
178
|
def description
|
@@ -208,10 +222,10 @@ WARNING
|
|
208
222
|
self
|
209
223
|
end
|
210
224
|
|
211
|
-
def examples #:nodoc:
|
225
|
+
def examples(run_options=nil) #:nodoc:
|
212
226
|
examples = example_objects.dup
|
213
227
|
add_method_examples(examples)
|
214
|
-
|
228
|
+
(run_options && run_options.reverse) ? examples.reverse : examples
|
215
229
|
end
|
216
230
|
|
217
231
|
def number_of_examples #:nodoc:
|
@@ -226,14 +240,6 @@ WARNING
|
|
226
240
|
@after_each_parts = nil
|
227
241
|
end
|
228
242
|
|
229
|
-
def register
|
230
|
-
Spec::Runner.options.add_example_group self
|
231
|
-
end
|
232
|
-
|
233
|
-
def unregister #:nodoc:
|
234
|
-
Spec::Runner.options.remove_example_group self
|
235
|
-
end
|
236
|
-
|
237
243
|
def run_before_each(example)
|
238
244
|
each_ancestor_example_group_class do |example_group_class|
|
239
245
|
example.eval_each_fail_fast(example_group_class.before_each_parts)
|
@@ -247,15 +253,14 @@ WARNING
|
|
247
253
|
end
|
248
254
|
|
249
255
|
private
|
250
|
-
def dry_run(examples)
|
256
|
+
def dry_run(examples, run_options)
|
251
257
|
examples.each do |example|
|
252
|
-
|
253
|
-
|
258
|
+
run_options.reporter.example_started(example)
|
259
|
+
run_options.reporter.example_finished(example)
|
254
260
|
end
|
255
|
-
return true
|
256
261
|
end
|
257
262
|
|
258
|
-
def run_before_all
|
263
|
+
def run_before_all(run_options)
|
259
264
|
before_all = new("before(:all)")
|
260
265
|
begin
|
261
266
|
each_ancestor_example_group_class do |example_group_class|
|
@@ -263,23 +268,23 @@ WARNING
|
|
263
268
|
end
|
264
269
|
return [true, before_all.instance_variable_hash]
|
265
270
|
rescue Exception => e
|
266
|
-
reporter.failure(before_all, e)
|
271
|
+
run_options.reporter.failure(before_all, e)
|
267
272
|
return [false, before_all.instance_variable_hash]
|
268
273
|
end
|
269
274
|
end
|
270
275
|
|
271
|
-
def execute_examples(success, instance_variables, examples)
|
276
|
+
def execute_examples(success, instance_variables, examples, run_options)
|
272
277
|
return [success, instance_variables] unless success
|
273
278
|
|
274
279
|
after_all_instance_variables = instance_variables
|
275
280
|
examples.each do |example_group_instance|
|
276
|
-
success &= example_group_instance.execute(
|
281
|
+
success &= example_group_instance.execute(run_options, instance_variables)
|
277
282
|
after_all_instance_variables = example_group_instance.instance_variable_hash
|
278
283
|
end
|
279
284
|
return [success, after_all_instance_variables]
|
280
285
|
end
|
281
286
|
|
282
|
-
def run_after_all(success, instance_variables)
|
287
|
+
def run_after_all(success, instance_variables, run_options)
|
283
288
|
after_all = new("after(:all)")
|
284
289
|
after_all.set_instance_variables_from_hash(instance_variables)
|
285
290
|
each_ancestor_example_group_class(:superclass_first) do |example_group_class|
|
@@ -287,34 +292,22 @@ WARNING
|
|
287
292
|
end
|
288
293
|
return success
|
289
294
|
rescue Exception => e
|
290
|
-
reporter.failure(after_all, e)
|
295
|
+
run_options.reporter.failure(after_all, e)
|
291
296
|
return false
|
292
297
|
end
|
293
298
|
|
294
|
-
def examples_to_run
|
295
|
-
all_examples = examples
|
296
|
-
return all_examples unless specified_examples?
|
299
|
+
def examples_to_run(run_options)
|
300
|
+
all_examples = examples(run_options)
|
301
|
+
return all_examples unless specified_examples?(run_options)
|
297
302
|
all_examples.reject do |example|
|
298
303
|
matcher = ExampleGroupMethods.matcher_class.
|
299
304
|
new(description.to_s, example.description)
|
300
|
-
!matcher.matches?(
|
305
|
+
!matcher.matches?(run_options.examples)
|
301
306
|
end
|
302
307
|
end
|
303
308
|
|
304
|
-
def specified_examples?
|
305
|
-
|
306
|
-
end
|
307
|
-
|
308
|
-
def specified_examples
|
309
|
-
Spec::Runner.options.examples
|
310
|
-
end
|
311
|
-
|
312
|
-
def reporter
|
313
|
-
Spec::Runner.options.reporter
|
314
|
-
end
|
315
|
-
|
316
|
-
def dry_run?
|
317
|
-
Spec::Runner.options.dry_run
|
309
|
+
def specified_examples?(run_options)
|
310
|
+
run_options.examples && !run_options.examples.empty?
|
318
311
|
end
|
319
312
|
|
320
313
|
def example_objects
|
@@ -34,11 +34,11 @@ module Spec
|
|
34
34
|
existing_example_group = find(new_example_group.description)
|
35
35
|
return false unless existing_example_group
|
36
36
|
return true if new_example_group.equal?(existing_example_group)
|
37
|
-
return true if
|
37
|
+
return true if expanded_path(new_example_group) == expanded_path(existing_example_group)
|
38
38
|
raise ArgumentError.new("Shared Example '#{existing_example_group.description}' already exists")
|
39
39
|
end
|
40
40
|
|
41
|
-
def
|
41
|
+
def expanded_path(example_group)
|
42
42
|
File.expand_path(example_group.spec_path)
|
43
43
|
end
|
44
44
|
end
|
data/lib/spec/example.rb
CHANGED
@@ -1,24 +1,173 @@
|
|
1
1
|
module Spec
|
2
|
+
# == Example Groups and Code Examples
|
3
|
+
#
|
4
|
+
# A Code Example is an executable example of how a bit of code is expected
|
5
|
+
# to behave.
|
6
|
+
#
|
7
|
+
# An Example Group is a group of code examples.
|
8
|
+
#
|
9
|
+
# RSpec exposes a DSL to describe groups of examples.
|
10
|
+
#
|
11
|
+
# describe Account do
|
12
|
+
# it "should have a balance of $0" do
|
13
|
+
# account = Account.new
|
14
|
+
# account.balance.should == Money.new(0, :dollars)
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# == Before and After
|
19
|
+
#
|
20
|
+
# You can use the <tt>before()</tt> and <tt>after()</tt> methods to extract
|
21
|
+
# common code within an Example Group. Both methods take an optional scope
|
22
|
+
# argument so you can run the block before :each example or before :all
|
23
|
+
# examples
|
24
|
+
#
|
25
|
+
# describe "..." do
|
26
|
+
# before :all do
|
27
|
+
# ...
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# before :each do
|
31
|
+
# ...
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# it "should do something" do
|
35
|
+
# ...
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# it "should do something else" do
|
39
|
+
# ...
|
40
|
+
# end
|
41
|
+
#
|
42
|
+
# after :each do
|
43
|
+
# ...
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# after :all do
|
47
|
+
# ...
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# The <tt>before :each</tt> block will run before each of the examples, once
|
53
|
+
# for each example. Likewise, the <tt>after :each</tt> block will run after
|
54
|
+
# each of the examples.
|
55
|
+
#
|
56
|
+
# It is also possible to specify a <tt>before :all</tt> and <tt>after
|
57
|
+
# :all</tt> block that will run only once for each example group, before the
|
58
|
+
# first <code>before :each</code> and after the last <code>after
|
59
|
+
# :each</code> respectively. The use of these is generally discouraged,
|
60
|
+
# because it introduces dependencies between the examples. Still, it might
|
61
|
+
# prove useful for very expensive operations if you know what you are doing.
|
62
|
+
#
|
63
|
+
# == Local helper methods
|
64
|
+
#
|
65
|
+
# You can include local helper methods by simply expressing them within an
|
66
|
+
# example group:
|
67
|
+
#
|
68
|
+
# describe "..." do
|
69
|
+
#
|
70
|
+
# it "..." do
|
71
|
+
# helper_method
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# def helper_method
|
75
|
+
# ...
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# == Included helper methods
|
81
|
+
#
|
82
|
+
# You can include helper methods in multiple example groups by expressing
|
83
|
+
# them within a module, and then including that module in your example
|
84
|
+
# groups:
|
85
|
+
#
|
86
|
+
# module AccountExampleHelperMethods
|
87
|
+
# def helper_method
|
88
|
+
# ...
|
89
|
+
# end
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# describe "A new account" do
|
93
|
+
# include AccountExampleHelperMethods
|
94
|
+
# before do
|
95
|
+
# @account = Account.new
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# it "should have a balance of $0" do
|
99
|
+
# helper_method
|
100
|
+
# @account.balance.should eql(Money.new(0, :dollars))
|
101
|
+
# end
|
102
|
+
# end
|
103
|
+
#
|
104
|
+
# == Shared Example Groups
|
105
|
+
#
|
106
|
+
# You can define a shared example group, that may be used on other groups
|
107
|
+
#
|
108
|
+
# share_examples_for "All Editions" do
|
109
|
+
# it "all editions behaviour" ...
|
110
|
+
# end
|
111
|
+
#
|
112
|
+
# describe SmallEdition do
|
113
|
+
# it_should_behave_like "All Editions"
|
114
|
+
#
|
115
|
+
# it "should do small edition stuff" do
|
116
|
+
# ...
|
117
|
+
# end
|
118
|
+
# end
|
119
|
+
#
|
120
|
+
# You can also assign the shared group to a module and include that
|
121
|
+
#
|
122
|
+
# share_as :AllEditions do
|
123
|
+
# it "should do all editions stuff" ...
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# describe SmallEdition do
|
127
|
+
# it_should_behave_like AllEditions
|
128
|
+
#
|
129
|
+
# it "should do small edition stuff" do
|
130
|
+
# ...
|
131
|
+
# end
|
132
|
+
# end
|
133
|
+
#
|
134
|
+
# And, for those of you who prefer to use something more like Ruby, you can
|
135
|
+
# just include the module directly
|
136
|
+
#
|
137
|
+
# describe SmallEdition do
|
138
|
+
# include AllEditions
|
139
|
+
#
|
140
|
+
# it "should do small edition stuff" do
|
141
|
+
# ...
|
142
|
+
# end
|
143
|
+
# end
|
2
144
|
module Example
|
3
|
-
|
4
|
-
|
5
|
-
|
145
|
+
class << self
|
146
|
+
def args_and_options(*args) # :nodoc:
|
147
|
+
with_options_from(args) do |options|
|
148
|
+
return args, options
|
149
|
+
end
|
6
150
|
end
|
7
|
-
end
|
8
151
|
|
9
|
-
|
10
|
-
|
11
|
-
|
152
|
+
def scope_from(*args) # :nodoc:
|
153
|
+
args[0] || :each
|
154
|
+
end
|
12
155
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
156
|
+
def scope_and_options(*args) # :nodoc:
|
157
|
+
args, options = args_and_options(*args)
|
158
|
+
return scope_from(*args), options
|
159
|
+
end
|
160
|
+
|
161
|
+
def add_spec_path_to(args) # :nodoc:
|
162
|
+
args << {} unless Hash === args.last
|
163
|
+
args.last[:spec_path] ||= caller(0)[2]
|
164
|
+
end
|
17
165
|
|
18
|
-
|
166
|
+
private
|
19
167
|
|
20
|
-
|
21
|
-
|
168
|
+
def with_options_from(args)
|
169
|
+
yield Hash === args.last ? args.pop : {} if block_given?
|
170
|
+
end
|
22
171
|
end
|
23
172
|
end
|
24
173
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Spec
|
2
|
+
module Matchers
|
3
|
+
|
4
|
+
class MatchArray #:nodoc:
|
5
|
+
|
6
|
+
def initialize(expected)
|
7
|
+
@expected = expected
|
8
|
+
end
|
9
|
+
|
10
|
+
def matches?(actual)
|
11
|
+
@actual = actual
|
12
|
+
@extra_items = difference_between_arrays(@actual, @expected)
|
13
|
+
@missing_items = difference_between_arrays(@expected, @actual)
|
14
|
+
@extra_items.empty? && @missing_items.empty?
|
15
|
+
end
|
16
|
+
|
17
|
+
def failure_message
|
18
|
+
message = "expected collection contained: #{@expected.sort.inspect}\n"
|
19
|
+
message += "actual collection contained: #{@actual.sort.inspect}\n"
|
20
|
+
message += "the missing elements were: #{@missing_items.sort.inspect}\n" unless @missing_items.empty?
|
21
|
+
message += "the extra elements were: #{@extra_items.sort.inspect}\n" unless @extra_items.empty?
|
22
|
+
message
|
23
|
+
end
|
24
|
+
|
25
|
+
def description
|
26
|
+
"contain exactly #{_pretty_print(@expected)}"
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def difference_between_arrays(array_1, array_2)
|
32
|
+
difference = array_1.dup
|
33
|
+
array_2.each do |element|
|
34
|
+
if index = difference.index(element)
|
35
|
+
difference.delete_at(index)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
difference
|
39
|
+
end
|
40
|
+
|
41
|
+
def _pretty_print(array)
|
42
|
+
result = ""
|
43
|
+
array.each_with_index do |item, index|
|
44
|
+
if index < (array.length - 2)
|
45
|
+
result << "#{item.inspect}, "
|
46
|
+
elsif index < (array.length - 1)
|
47
|
+
result << "#{item.inspect} and "
|
48
|
+
else
|
49
|
+
result << "#{item.inspect}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
result
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
# :call-seq:
|
58
|
+
# should =~ expected
|
59
|
+
#
|
60
|
+
# Passes if actual contains all of the expected regardless of order.
|
61
|
+
# This works for collections. Pass in multiple args and it will only
|
62
|
+
# pass if all args are found in collection.
|
63
|
+
#
|
64
|
+
# NOTE: there is no should_not version of array.should =~ other_array
|
65
|
+
#
|
66
|
+
# == Examples
|
67
|
+
#
|
68
|
+
# [1,2,3].should =~ [1,2,3] # => would pass
|
69
|
+
# [1,2,3].should =~ [2,3,1] # => would pass
|
70
|
+
# [1,2,3,4].should =~ [1,2,3] # => would fail
|
71
|
+
# [1,2,2,3].should =~ [1,2,3] # => would fail
|
72
|
+
# [1,2,3].should =~ [1,2,3,4] # => would fail
|
73
|
+
OperatorMatcher.register(Array, '=~', Spec::Matchers::MatchArray)
|
74
|
+
end
|
75
|
+
end
|
@@ -1,22 +1,43 @@
|
|
1
1
|
module Spec
|
2
2
|
module Matchers
|
3
|
+
|
3
4
|
class OperatorMatcher
|
5
|
+
@operator_registry = {}
|
6
|
+
|
7
|
+
def self.register(klass, operator, matcher)
|
8
|
+
@operator_registry[klass] ||= {}
|
9
|
+
@operator_registry[klass][operator] = matcher
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.get(klass, operator)
|
13
|
+
return @operator_registry[klass][operator] if @operator_registry[klass]
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
|
4
17
|
def initialize(actual)
|
5
18
|
@actual = actual
|
6
19
|
end
|
7
|
-
|
8
|
-
|
9
|
-
define_method
|
10
|
-
|
11
|
-
|
12
|
-
|
20
|
+
|
21
|
+
def self.use_custom_matcher_or_delegate(operator)
|
22
|
+
define_method(operator) do |expected|
|
23
|
+
if matcher = OperatorMatcher.get(@actual.class, operator)
|
24
|
+
return @actual.send(matcher_method, matcher.new(expected))
|
25
|
+
else
|
26
|
+
::Spec::Matchers.last_matcher = self
|
27
|
+
@operator, @expected = operator, expected
|
28
|
+
__delegate_operator(@actual, operator, expected)
|
29
|
+
end
|
13
30
|
end
|
14
31
|
end
|
15
32
|
|
33
|
+
['==', '===', '=~', '>', '>=', '<', '<='].each do |operator|
|
34
|
+
use_custom_matcher_or_delegate operator
|
35
|
+
end
|
36
|
+
|
16
37
|
def fail_with_message(message)
|
17
38
|
Spec::Expectations.fail_with(message, @expected, @actual)
|
18
39
|
end
|
19
|
-
|
40
|
+
|
20
41
|
def description
|
21
42
|
"#{@operator} #{@expected.inspect}"
|
22
43
|
end
|
@@ -24,6 +45,9 @@ module Spec
|
|
24
45
|
end
|
25
46
|
|
26
47
|
class PositiveOperatorMatcher < OperatorMatcher #:nodoc:
|
48
|
+
def matcher_method
|
49
|
+
:should
|
50
|
+
end
|
27
51
|
|
28
52
|
def __delegate_operator(actual, operator, expected)
|
29
53
|
return true if actual.__send__(operator, expected)
|
@@ -37,6 +61,9 @@ module Spec
|
|
37
61
|
end
|
38
62
|
|
39
63
|
class NegativeOperatorMatcher < OperatorMatcher #:nodoc:
|
64
|
+
def matcher_method
|
65
|
+
:should_not
|
66
|
+
end
|
40
67
|
|
41
68
|
def __delegate_operator(actual, operator, expected)
|
42
69
|
return true unless actual.__send__(operator, expected)
|
data/lib/spec/matchers.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'spec/matchers/operator_matcher'
|
1
2
|
require 'spec/matchers/generated_descriptions'
|
2
3
|
require 'spec/matchers/errors'
|
3
4
|
require 'spec/matchers/method_missing'
|
@@ -5,6 +6,7 @@ require 'spec/matchers/simple_matcher'
|
|
5
6
|
require 'spec/matchers/be'
|
6
7
|
require 'spec/matchers/be_close'
|
7
8
|
require 'spec/matchers/change'
|
9
|
+
require 'spec/matchers/match_array'
|
8
10
|
require 'spec/matchers/eql'
|
9
11
|
require 'spec/matchers/equal'
|
10
12
|
require 'spec/matchers/exist'
|
@@ -16,7 +18,6 @@ require 'spec/matchers/raise_error'
|
|
16
18
|
require 'spec/matchers/respond_to'
|
17
19
|
require 'spec/matchers/satisfy'
|
18
20
|
require 'spec/matchers/throw_symbol'
|
19
|
-
require 'spec/matchers/operator_matcher'
|
20
21
|
|
21
22
|
module Spec
|
22
23
|
|
@@ -73,6 +73,25 @@ module Spec
|
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
76
|
+
class HashNotIncludingConstraint
|
77
|
+
def initialize(expected)
|
78
|
+
@expected = expected
|
79
|
+
end
|
80
|
+
|
81
|
+
def ==(actual)
|
82
|
+
@expected.each do | key, value |
|
83
|
+
return false if actual.has_key?(key) && value == actual[key]
|
84
|
+
end
|
85
|
+
true
|
86
|
+
rescue NoMethodError => ex
|
87
|
+
return false
|
88
|
+
end
|
89
|
+
|
90
|
+
def description
|
91
|
+
"hash_not_including(#{@expected.inspect.sub(/^\{/,"").sub(/\}$/,"")})"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
76
95
|
class DuckTypeConstraint
|
77
96
|
def initialize(*methods_to_respond_to)
|
78
97
|
@methods_to_respond_to = methods_to_respond_to
|
@@ -153,12 +172,31 @@ module Spec
|
|
153
172
|
end
|
154
173
|
|
155
174
|
# :call-seq:
|
156
|
-
# object.should_receive(:message).with(hash_including(:
|
157
|
-
#
|
158
|
-
#
|
175
|
+
# object.should_receive(:message).with(hash_including(:key => val))
|
176
|
+
# object.should_receive(:message).with(hash_including(:key))
|
177
|
+
# object.should_receive(:message).with(hash_including(:key, :key2 => val2))
|
178
|
+
# Passes if the argument is a hash that includes the specified key(s) or key/value
|
159
179
|
# pairs. If the hash includes other keys, it will still pass.
|
160
|
-
def hash_including(
|
161
|
-
HashIncludingConstraint.new(
|
180
|
+
def hash_including(*args)
|
181
|
+
HashIncludingConstraint.new(anythingize_lonely_keys(*args))
|
182
|
+
end
|
183
|
+
|
184
|
+
# :call-seq:
|
185
|
+
# object.should_receive(:message).with(hash_not_including(:key => val))
|
186
|
+
# object.should_receive(:message).with(hash_not_including(:key))
|
187
|
+
# object.should_receive(:message).with(hash_not_including(:key, :key2 => :val2))
|
188
|
+
#
|
189
|
+
# Passes if the argument is a hash that doesn't include the specified key(s) or key/value
|
190
|
+
def hash_not_including(*args)
|
191
|
+
HashNotIncludingConstraint.new(anythingize_lonely_keys(*args))
|
192
|
+
end
|
193
|
+
|
194
|
+
private
|
195
|
+
|
196
|
+
def anythingize_lonely_keys(*args)
|
197
|
+
hash = args.last.class == Hash ? args.delete_at(-1) : {}
|
198
|
+
args.each { | arg | hash[arg] = anything }
|
199
|
+
hash
|
162
200
|
end
|
163
201
|
end
|
164
202
|
end
|
@@ -15,11 +15,11 @@ module Spec
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
def run
|
18
|
+
def run(run_options)
|
19
19
|
prepare
|
20
20
|
success = true
|
21
21
|
example_groups.each do |example_group|
|
22
|
-
success = success & example_group.run
|
22
|
+
success = success & example_group.run(run_options)
|
23
23
|
end
|
24
24
|
return success
|
25
25
|
ensure
|