rspec-core 2.8.0.rc1 → 2.8.0.rc2
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/License.txt +24 -0
- data/README.md +197 -37
- data/features/command_line/format_option.feature +3 -3
- data/features/command_line/init.feature +18 -0
- data/features/example_groups/shared_examples.feature +1 -1
- data/features/hooks/around_hooks.feature +4 -4
- data/features/pending/pending_examples.feature +5 -5
- data/features/support/env.rb +8 -1
- data/lib/autotest/rspec2.rb +2 -6
- data/lib/rspec/core.rb +48 -158
- data/lib/rspec/core/backward_compatibility.rb +2 -0
- data/lib/rspec/core/command_line.rb +4 -0
- data/lib/rspec/core/configuration.rb +201 -106
- data/lib/rspec/core/configuration_options.rb +2 -1
- data/lib/rspec/core/deprecation.rb +2 -3
- data/lib/rspec/core/drb_options.rb +69 -58
- data/lib/rspec/core/dsl.rb +12 -0
- data/lib/rspec/core/example.rb +53 -18
- data/lib/rspec/core/example_group.rb +144 -54
- data/lib/rspec/core/extensions.rb +4 -4
- data/lib/rspec/core/extensions/instance_eval_with_args.rb +5 -0
- data/lib/rspec/core/extensions/kernel.rb +1 -1
- data/lib/rspec/core/extensions/module_eval_with_args.rb +4 -0
- data/lib/rspec/core/extensions/ordered.rb +7 -2
- data/lib/rspec/core/filter_manager.rb +69 -36
- data/lib/rspec/core/formatters/base_text_formatter.rb +1 -1
- data/lib/rspec/core/formatters/html_formatter.rb +10 -4
- data/lib/rspec/core/hooks.rb +93 -34
- data/lib/rspec/core/let.rb +62 -61
- data/lib/rspec/core/metadata.rb +103 -80
- data/lib/rspec/core/metadata_hash_builder.rb +4 -0
- data/lib/rspec/core/option_parser.rb +42 -44
- data/lib/rspec/core/pending.rb +25 -3
- data/lib/rspec/core/project_initializer.rb +62 -0
- data/lib/rspec/core/rake_task.rb +7 -13
- data/lib/rspec/core/runner.rb +2 -2
- data/lib/rspec/core/shared_context.rb +1 -1
- data/lib/rspec/core/shared_example_group.rb +11 -5
- data/lib/rspec/core/subject.rb +3 -3
- data/lib/rspec/core/version.rb +1 -1
- data/lib/rspec/monkey.rb +1 -1
- data/lib/rspec/monkey/spork/test_framework/rspec.rb +2 -0
- data/spec/command_line/order_spec.rb +19 -13
- data/spec/rspec/core/command_line_spec.rb +1 -5
- data/spec/rspec/core/configuration_options_spec.rb +22 -27
- data/spec/rspec/core/configuration_spec.rb +32 -14
- data/spec/rspec/core/drb_command_line_spec.rb +20 -37
- data/spec/rspec/core/drb_options_spec.rb +51 -3
- data/spec/rspec/core/example_group_spec.rb +101 -84
- data/spec/rspec/core/example_spec.rb +14 -0
- data/spec/rspec/core/filter_manager_spec.rb +114 -33
- data/spec/rspec/core/formatters/html_formatted-1.8.7-jruby.html +17 -69
- data/spec/rspec/core/formatters/html_formatted-1.8.7.html +14 -4
- data/spec/rspec/core/formatters/html_formatted-1.9.2.html +14 -4
- data/spec/rspec/core/formatters/html_formatted-1.9.3.html +14 -4
- data/spec/rspec/core/formatters/html_formatter_spec.rb +1 -1
- data/spec/rspec/core/formatters/text_mate_formatted-1.8.7-jruby.html +20 -72
- data/spec/rspec/core/formatters/text_mate_formatted-1.8.7.html +24 -14
- data/spec/rspec/core/formatters/text_mate_formatted-1.9.2.html +29 -19
- data/spec/rspec/core/formatters/text_mate_formatted-1.9.3.html +29 -19
- data/spec/rspec/core/formatters/text_mate_formatter_spec.rb +1 -2
- data/spec/rspec/core/metadata_spec.rb +77 -45
- data/spec/rspec/core/option_parser_spec.rb +5 -0
- data/spec/rspec/core/pending_example_spec.rb +44 -12
- data/spec/rspec/core/project_initializer_spec.rb +130 -0
- data/spec/rspec/core/rake_task_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/support/matchers.rb +2 -12
- metadata +18 -16
- data/features/command_line/configure.feature +0 -22
- data/lib/rspec/core/command_line_configuration.rb +0 -62
- data/lib/rspec/core/errors.rb +0 -13
- data/spec/rspec/core/command_line_configuration_spec.rb +0 -26
data/lib/rspec/core/let.rb
CHANGED
@@ -2,23 +2,23 @@ module RSpec
|
|
2
2
|
module Core
|
3
3
|
module Let
|
4
4
|
|
5
|
-
module
|
5
|
+
module ExampleGroupMethods
|
6
6
|
# Generates a method whose return value is memoized
|
7
7
|
# after the first call.
|
8
8
|
#
|
9
9
|
# @example
|
10
10
|
#
|
11
|
-
#
|
12
|
-
#
|
11
|
+
# describe Thing do
|
12
|
+
# let(:thing) { Thing.new }
|
13
13
|
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
14
|
+
# it "does something" do
|
15
|
+
# # first invocation, executes block, memoizes and returns result
|
16
|
+
# thing.do_something
|
17
17
|
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
18
|
+
# # second invocation, returns the memoized value
|
19
|
+
# thing.should be_something
|
20
|
+
# end
|
21
|
+
# end
|
22
22
|
def let(name, &block)
|
23
23
|
define_method(name) do
|
24
24
|
__memoized.fetch(name) {|k| __memoized[k] = instance_eval(&block) }
|
@@ -32,69 +32,70 @@ module RSpec
|
|
32
32
|
#
|
33
33
|
# @example
|
34
34
|
#
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
58
|
-
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
35
|
+
# class Thing
|
36
|
+
# def self.count
|
37
|
+
# @count ||= 0
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# def self.count=(val)
|
41
|
+
# @count += val
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# def self.reset_count
|
45
|
+
# @count = 0
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# def initialize
|
49
|
+
# self.class.count += 1
|
50
|
+
# end
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# describe Thing do
|
54
|
+
# after(:each) { Thing.reset_count }
|
55
|
+
#
|
56
|
+
# context "using let" do
|
57
|
+
# let(:thing) { Thing.new }
|
58
|
+
#
|
59
|
+
# it "is not invoked implicitly" do
|
60
|
+
# Thing.count.should eq(0)
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# it "can be invoked explicitly" do
|
64
|
+
# thing
|
65
|
+
# Thing.count.should eq(1)
|
66
|
+
# end
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
# context "using let!" do
|
70
|
+
# let!(:thing) { Thing.new }
|
71
|
+
#
|
72
|
+
# it "is invoked implicitly" do
|
73
|
+
# Thing.count.should eq(1)
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
# it "returns memoized version on first invocation" do
|
77
|
+
# thing
|
78
|
+
# Thing.count.should eq(1)
|
79
|
+
# end
|
80
|
+
# end
|
81
|
+
# end
|
82
82
|
def let!(name, &block)
|
83
83
|
let(name, &block)
|
84
84
|
before { __send__(name) }
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
|
-
|
89
|
-
|
88
|
+
# @private
|
89
|
+
module ExampleMethods
|
90
|
+
# @private
|
90
91
|
def __memoized
|
91
92
|
@__memoized ||= {}
|
92
93
|
end
|
93
94
|
end
|
94
95
|
|
95
96
|
def self.included(mod)
|
96
|
-
mod.extend
|
97
|
-
mod.__send__ :include,
|
97
|
+
mod.extend ExampleGroupMethods
|
98
|
+
mod.__send__ :include, ExampleMethods
|
98
99
|
end
|
99
100
|
|
100
101
|
end
|
data/lib/rspec/core/metadata.rb
CHANGED
@@ -1,13 +1,35 @@
|
|
1
1
|
module RSpec
|
2
2
|
module Core
|
3
|
-
# Each ExampleGroup class and Example instance
|
3
|
+
# Each ExampleGroup class and Example instance owns an instance of
|
4
|
+
# Metadata, which is Hash extended to support lazy evaluation of values
|
5
|
+
# associated with keys that may or may not be used by any example or group.
|
6
|
+
#
|
7
|
+
# In addition to metadata that is used internally, this also stores
|
8
|
+
# user-supplied metadata, e.g.
|
9
|
+
#
|
10
|
+
# describe Something, :type => :ui do
|
11
|
+
# it "does something", :slow => true do
|
12
|
+
# # ...
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# `:type => :ui` is stored in the Metadata owned by the example group, and
|
17
|
+
# `:slow => true` is stored in the Metadata owned by the example. These can
|
18
|
+
# then be used to select which examples are run using the `--tag` option on
|
19
|
+
# the command line, or several methods on `Configuration` used to filter a
|
20
|
+
# run (e.g. `filter_run_including`, `filter_run_excluding`, etc).
|
4
21
|
#
|
5
22
|
# @see Example#metadata
|
6
23
|
# @see ExampleGroup.metadata
|
24
|
+
# @see FilterManager
|
25
|
+
# @see Configuration#filter_run_including
|
26
|
+
# @see Configuration#filter_run_excluding
|
7
27
|
class Metadata < Hash
|
8
28
|
|
29
|
+
# @private
|
9
30
|
module MetadataHash
|
10
31
|
|
32
|
+
# @private
|
11
33
|
# Supports lazy evaluation of some values. Extended by
|
12
34
|
# ExampleMetadataHash and GroupMetadataHash, which get mixed in to
|
13
35
|
# Metadata for ExampleGroups and Examples (respectively).
|
@@ -23,10 +45,13 @@ module RSpec
|
|
23
45
|
super
|
24
46
|
when :execution_result
|
25
47
|
store(:execution_result, {})
|
26
|
-
when :describes
|
27
|
-
|
48
|
+
when :describes, :described_class
|
49
|
+
klass = described_class
|
50
|
+
store(:described_class, klass)
|
51
|
+
# TODO (2011-11-07 DC) deprecate :describes as a key
|
52
|
+
store(:describes, klass)
|
28
53
|
when :full_description
|
29
|
-
store(:full_description,
|
54
|
+
store(:full_description, full_description)
|
30
55
|
when :description
|
31
56
|
store(:description, build_description_from(*self[:description_args]))
|
32
57
|
else
|
@@ -34,7 +59,7 @@ module RSpec
|
|
34
59
|
end
|
35
60
|
end
|
36
61
|
|
37
|
-
|
62
|
+
private
|
38
63
|
|
39
64
|
def location
|
40
65
|
"#{self[:file_path]}:#{self[:line_number]}"
|
@@ -49,16 +74,8 @@ module RSpec
|
|
49
74
|
self[:caller].detect {|l| l !~ /\/lib\/rspec\/core/}
|
50
75
|
end
|
51
76
|
|
52
|
-
def described_class_for(m)
|
53
|
-
m[:example_group][:describes]
|
54
|
-
end
|
55
|
-
|
56
|
-
def full_description_for(m)
|
57
|
-
build_description_from(m[:example_group][:full_description], *m[:description_args])
|
58
|
-
end
|
59
|
-
|
60
77
|
def build_description_from(*parts)
|
61
|
-
parts.map {|p| p.to_s}.
|
78
|
+
parts.map {|p| p.to_s}.inject do |desc, p|
|
62
79
|
p =~ /^(#|::|\.)/ ? "#{desc}#{p}" : "#{desc} #{p}"
|
63
80
|
end || ""
|
64
81
|
end
|
@@ -68,6 +85,14 @@ module RSpec
|
|
68
85
|
# lazy evaluation of some values.
|
69
86
|
module ExampleMetadataHash
|
70
87
|
include MetadataHash
|
88
|
+
|
89
|
+
def described_class
|
90
|
+
self[:example_group].described_class
|
91
|
+
end
|
92
|
+
|
93
|
+
def full_description
|
94
|
+
build_description_from(self[:example_group][:full_description], *self[:description_args])
|
95
|
+
end
|
71
96
|
end
|
72
97
|
|
73
98
|
# Mixed in to Metadata for an ExampleGroup (extends MetadataHash) to
|
@@ -75,14 +100,13 @@ module RSpec
|
|
75
100
|
module GroupMetadataHash
|
76
101
|
include MetadataHash
|
77
102
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
return g[:describes] if g.has_key?(:describes)
|
103
|
+
def described_class
|
104
|
+
container_stack.each do |g|
|
105
|
+
return g[:describes] if g.has_key?(:describes)
|
106
|
+
return g[:described_class] if g.has_key?(:described_class)
|
83
107
|
end
|
84
108
|
|
85
|
-
|
109
|
+
container_stack.reverse.each do |g|
|
86
110
|
candidate = g[:description_args].first
|
87
111
|
return candidate unless String === candidate || Symbol === candidate
|
88
112
|
end
|
@@ -90,30 +114,26 @@ module RSpec
|
|
90
114
|
nil
|
91
115
|
end
|
92
116
|
|
93
|
-
def
|
94
|
-
build_description_from(*
|
95
|
-
a[:description_args]
|
96
|
-
end.flatten)
|
117
|
+
def full_description
|
118
|
+
build_description_from(*container_stack.reverse.map {|a| a[:description_args]}.flatten)
|
97
119
|
end
|
98
120
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
groups
|
109
|
-
end
|
121
|
+
def container_stack
|
122
|
+
@container_stack ||= begin
|
123
|
+
groups = [group = self]
|
124
|
+
while group.has_key?(:example_group)
|
125
|
+
groups << group[:example_group]
|
126
|
+
group = group[:example_group]
|
127
|
+
end
|
128
|
+
groups
|
129
|
+
end
|
110
130
|
end
|
111
131
|
end
|
112
132
|
|
113
133
|
def initialize(parent_group_metadata=nil)
|
114
134
|
if parent_group_metadata
|
115
135
|
update(parent_group_metadata)
|
116
|
-
store(:example_group, {:example_group => parent_group_metadata[:example_group]}.extend(GroupMetadataHash))
|
136
|
+
store(:example_group, {:example_group => parent_group_metadata[:example_group].extend(GroupMetadataHash)}.extend(GroupMetadataHash))
|
117
137
|
else
|
118
138
|
store(:example_group, {}.extend(GroupMetadataHash))
|
119
139
|
end
|
@@ -121,7 +141,7 @@ module RSpec
|
|
121
141
|
yield self if block_given?
|
122
142
|
end
|
123
143
|
|
124
|
-
# @
|
144
|
+
# @private
|
125
145
|
def process(*args)
|
126
146
|
user_metadata = args.last.is_a?(Hash) ? args.pop : {}
|
127
147
|
ensure_valid_keys(user_metadata)
|
@@ -132,36 +152,29 @@ module RSpec
|
|
132
152
|
update(user_metadata)
|
133
153
|
end
|
134
154
|
|
135
|
-
# @
|
155
|
+
# @private
|
136
156
|
def for_example(description, user_metadata)
|
137
157
|
dup.extend(ExampleMetadataHash).configure_for_example(description, user_metadata)
|
138
158
|
end
|
139
159
|
|
140
|
-
# @
|
160
|
+
# @private
|
141
161
|
def any_apply?(filters)
|
142
162
|
filters.any? {|k,v| filter_applies?(k,v)}
|
143
163
|
end
|
144
164
|
|
145
|
-
# @
|
165
|
+
# @private
|
146
166
|
def all_apply?(filters)
|
147
167
|
filters.all? {|k,v| filter_applies?(k,v)}
|
148
168
|
end
|
149
169
|
|
150
|
-
# @
|
170
|
+
# @private
|
151
171
|
def filter_applies?(key, value, metadata=self)
|
172
|
+
return metadata.filter_applies_to_any_value?(key, value) if Array === metadata[key]
|
173
|
+
return metadata.line_number_filter_applies?(value) if key == :line_numbers
|
174
|
+
return metadata.location_filter_applies?(value) if key == :locations
|
175
|
+
return metadata.filters_apply?(key, value) if Hash === value
|
176
|
+
|
152
177
|
case value
|
153
|
-
when Hash
|
154
|
-
if key == :locations
|
155
|
-
file_path = (self[:example_group] || {})[:file_path]
|
156
|
-
expanded_path = file_path && File.expand_path( file_path )
|
157
|
-
if expanded_path && line_numbers = value[expanded_path]
|
158
|
-
filter_applies?(:line_numbers, line_numbers)
|
159
|
-
else
|
160
|
-
true
|
161
|
-
end
|
162
|
-
else
|
163
|
-
value.all? { |k, v| filter_applies?(k, v, metadata[key]) }
|
164
|
-
end
|
165
178
|
when Regexp
|
166
179
|
metadata[key] =~ value
|
167
180
|
when Proc
|
@@ -176,21 +189,35 @@ module RSpec
|
|
176
189
|
else
|
177
190
|
value.call(metadata[key]) rescue false
|
178
191
|
end
|
179
|
-
when String
|
180
|
-
metadata[key].to_s == value.to_s
|
181
|
-
when Enumerable
|
182
|
-
if key == :line_numbers
|
183
|
-
preceding_declaration_lines = value.map{|v| world.preceding_declaration_line(v)}
|
184
|
-
!(relevant_line_numbers(metadata) & preceding_declaration_lines).empty?
|
185
|
-
else
|
186
|
-
metadata[key] == value
|
187
|
-
end
|
188
192
|
else
|
189
193
|
metadata[key].to_s == value.to_s
|
190
194
|
end
|
191
195
|
end
|
192
196
|
|
193
|
-
|
197
|
+
# @private
|
198
|
+
def filters_apply?(key, value)
|
199
|
+
value.all? {|k, v| filter_applies?(k, v, self[key])}
|
200
|
+
end
|
201
|
+
|
202
|
+
# @private
|
203
|
+
def filter_applies_to_any_value?(key, value)
|
204
|
+
self[key].any? {|v| filter_applies?(key, v, {key => value})}
|
205
|
+
end
|
206
|
+
|
207
|
+
# @private
|
208
|
+
def location_filter_applies?(locations)
|
209
|
+
# it ignores location filters for other files
|
210
|
+
line_number = example_group_declaration_line(locations)
|
211
|
+
line_number ? line_number_filter_applies?(line_number) : true
|
212
|
+
end
|
213
|
+
|
214
|
+
# @private
|
215
|
+
def line_number_filter_applies?(line_numbers)
|
216
|
+
preceding_declaration_lines = line_numbers.map {|n| RSpec.world.preceding_declaration_line(n)}
|
217
|
+
!(relevant_line_numbers & preceding_declaration_lines).empty?
|
218
|
+
end
|
219
|
+
|
220
|
+
protected
|
194
221
|
|
195
222
|
def configure_for_example(description, user_metadata)
|
196
223
|
store(:description_args, [description])
|
@@ -198,7 +225,7 @@ module RSpec
|
|
198
225
|
update(user_metadata)
|
199
226
|
end
|
200
227
|
|
201
|
-
|
228
|
+
private
|
202
229
|
|
203
230
|
RESERVED_KEYS = [
|
204
231
|
:description,
|
@@ -212,37 +239,33 @@ module RSpec
|
|
212
239
|
|
213
240
|
def ensure_valid_keys(user_metadata)
|
214
241
|
RESERVED_KEYS.each do |key|
|
215
|
-
if user_metadata.
|
242
|
+
if user_metadata.has_key?(key)
|
216
243
|
raise <<-EOM
|
217
|
-
#{"*"*50}
|
244
|
+
#{"*"*50}
|
218
245
|
:#{key} is not allowed
|
219
246
|
|
220
247
|
RSpec reserves some hash keys for its own internal use,
|
221
248
|
including :#{key}, which is used on:
|
222
249
|
|
223
|
-
|
250
|
+
#{caller(0)[4]}.
|
224
251
|
|
225
252
|
Here are all of RSpec's reserved hash keys:
|
226
253
|
|
227
|
-
|
228
|
-
#{"*"*50}
|
229
|
-
EOM
|
230
|
-
raise ":#{key} is not allowed"
|
254
|
+
#{RESERVED_KEYS.join("\n ")}
|
255
|
+
#{"*"*50}
|
256
|
+
EOM
|
231
257
|
end
|
232
258
|
end
|
233
259
|
end
|
234
260
|
|
235
|
-
def
|
236
|
-
|
261
|
+
def example_group_declaration_line(locations)
|
262
|
+
locations[File.expand_path(self[:example_group][:file_path])] if self[:example_group]
|
237
263
|
end
|
238
264
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
else
|
244
|
-
line_numbers
|
245
|
-
end
|
265
|
+
# TODO - make this a method on metadata - the problem is
|
266
|
+
# metadata[:example_group] is not always a kind of GroupMetadataHash.
|
267
|
+
def relevant_line_numbers(metadata=self)
|
268
|
+
[metadata[:line_number]] + (metadata[:example_group] ? relevant_line_numbers(metadata[:example_group]) : [])
|
246
269
|
end
|
247
270
|
|
248
271
|
end
|