rspec-core 2.3.1 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.markdown +22 -0
- data/Rakefile +2 -2
- data/features/command_line/README.md +6 -0
- data/features/command_line/configure.feature +16 -14
- data/features/command_line/example_name_option.feature +3 -3
- data/features/command_line/format_option.feature +73 -0
- data/features/command_line/line_number_appended_to_path.feature +1 -1
- data/features/command_line/line_number_option.feature +2 -2
- data/features/command_line/tag.feature +7 -7
- data/features/configuration/read_options_from_file.feature +29 -16
- data/features/hooks/before_and_after_hooks.feature +9 -14
- data/features/hooks/filtering.feature +174 -0
- data/features/step_definitions/additional_cli_steps.rb +4 -0
- data/features/subject/attribute_of_subject.feature +68 -18
- data/lib/rspec/core/command_line_configuration.rb +16 -16
- data/lib/rspec/core/configuration.rb +14 -15
- data/lib/rspec/core/configuration_options.rb +46 -22
- data/lib/rspec/core/example.rb +16 -6
- data/lib/rspec/core/example_group.rb +11 -11
- data/lib/rspec/core/formatters/base_text_formatter.rb +2 -1
- data/lib/rspec/core/hooks.rb +8 -8
- data/lib/rspec/core/option_parser.rb +13 -3
- data/lib/rspec/core/pending.rb +2 -0
- data/lib/rspec/core/rake_task.rb +1 -1
- data/lib/rspec/core/subject.rb +2 -0
- data/lib/rspec/core/version.rb +1 -1
- data/lib/rspec/core/world.rb +2 -2
- data/spec/rspec/core/configuration_options_spec.rb +147 -151
- data/spec/rspec/core/configuration_spec.rb +67 -19
- data/spec/rspec/core/example_spec.rb +12 -10
- data/spec/rspec/core/formatters/base_text_formatter_spec.rb +25 -1
- data/spec/rspec/core/formatters/html_formatted-1.8.6.html +5 -5
- data/spec/rspec/core/formatters/html_formatted-1.8.7-jruby.html +37 -24
- data/spec/rspec/core/formatters/html_formatted-1.8.7.html +5 -5
- data/spec/rspec/core/formatters/html_formatted-1.9.1.html +5 -5
- data/spec/rspec/core/formatters/html_formatted-1.9.2.html +5 -5
- data/spec/rspec/core/formatters/html_formatter_spec.rb +7 -7
- data/spec/rspec/core/formatters/text_mate_formatted-1.8.6.html +19 -19
- data/spec/rspec/core/formatters/text_mate_formatted-1.8.7-jruby.html +51 -33
- data/spec/rspec/core/formatters/text_mate_formatted-1.8.7.html +19 -19
- data/spec/rspec/core/formatters/text_mate_formatted-1.9.1.html +26 -26
- data/spec/rspec/core/formatters/text_mate_formatted-1.9.2.html +26 -26
- data/spec/rspec/core/formatters/text_mate_formatter_spec.rb +7 -7
- data/spec/rspec/core/hooks_filtering_spec.rb +54 -0
- data/spec/rspec/core/option_parser_spec.rb +53 -17
- data/spec/rspec/core/rake_task_spec.rb +21 -0
- data/spec/spec_helper.rb +1 -1
- metadata +14 -8
@@ -14,3 +14,7 @@ Then /^the example(s)? should( all)? pass$/ do |*|
|
|
14
14
|
Then %q{the output should contain "0 failures"}
|
15
15
|
Then %q{the exit status should be 0}
|
16
16
|
end
|
17
|
+
|
18
|
+
Then /^the file "([^"]*)" should contain:$/ do |file, partial_content|
|
19
|
+
check_file_content(file, partial_content, true)
|
20
|
+
end
|
@@ -1,29 +1,43 @@
|
|
1
1
|
Feature: attribute of subject
|
2
2
|
|
3
3
|
Use the its() method as a short-hand to generate a nested example group with
|
4
|
-
a single example that specifies the expected value of an attribute of the
|
5
|
-
This can be used with an implicit or explicit subject.
|
4
|
+
a single example that specifies the expected value of an attribute of the
|
5
|
+
subject. This can be used with an implicit or explicit subject.
|
6
6
|
|
7
|
-
its() accepts a symbol or a string, and a block representing the example.
|
8
|
-
a string with dots to specify a nested attribute (i.e. an attribute of the
|
9
|
-
attribute of the subject).
|
7
|
+
its() accepts a symbol or a string, and a block representing the example.
|
10
8
|
|
11
|
-
|
9
|
+
its(:size) { should eq(1) }
|
10
|
+
its("length") { should eq(1) }
|
11
|
+
|
12
|
+
You can use a string with dots to specify a nested attribute (i.e. an
|
13
|
+
attribute of the attribute of the subject).
|
14
|
+
|
15
|
+
its("phone_numbers.size") { should eq(2) }
|
16
|
+
|
17
|
+
When the subject is a hash, you can pass in an array with a single key to
|
18
|
+
access the value at that key in the hash.
|
19
|
+
|
20
|
+
its([:key]) { should eq(value) }
|
21
|
+
|
22
|
+
Scenario: specify value of an attribute
|
12
23
|
Given a file named "example_spec.rb" with:
|
13
24
|
"""
|
14
25
|
describe Array do
|
15
|
-
|
26
|
+
context "when first created" do
|
27
|
+
its(:size) { should eq(0) }
|
28
|
+
end
|
16
29
|
end
|
17
30
|
"""
|
18
31
|
When I run "rspec example_spec.rb --format documentation"
|
19
32
|
Then the output should contain:
|
20
33
|
"""
|
21
34
|
Array
|
22
|
-
|
23
|
-
|
35
|
+
when first created
|
36
|
+
size
|
37
|
+
should == 0
|
24
38
|
"""
|
25
39
|
|
26
|
-
Scenario: nested attribute
|
40
|
+
Scenario: specify value of a nested attribute
|
27
41
|
Given a file named "example_spec.rb" with:
|
28
42
|
"""
|
29
43
|
class Person
|
@@ -34,19 +48,55 @@ Feature: attribute of subject
|
|
34
48
|
end
|
35
49
|
|
36
50
|
describe Person do
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
51
|
+
context "with one phone number (555-1212)"do
|
52
|
+
subject do
|
53
|
+
person = Person.new
|
54
|
+
person.phone_numbers << "555-1212"
|
55
|
+
person
|
56
|
+
end
|
42
57
|
|
43
|
-
|
58
|
+
its("phone_numbers.first") { should eq("555-1212") }
|
59
|
+
end
|
44
60
|
end
|
45
61
|
"""
|
46
62
|
When I run "rspec example_spec.rb --format documentation"
|
47
63
|
Then the output should contain:
|
48
64
|
"""
|
49
65
|
Person
|
50
|
-
|
51
|
-
|
66
|
+
with one phone number (555-1212)
|
67
|
+
phone_numbers.first
|
68
|
+
should == 555-1212
|
69
|
+
"""
|
70
|
+
|
71
|
+
Scenario: specify value of an attribute of a hash
|
72
|
+
Given a file named "example_spec.rb" with:
|
73
|
+
"""
|
74
|
+
describe Hash do
|
75
|
+
context "with two items" do
|
76
|
+
subject do
|
77
|
+
{:one => 'one', :two => 'two'}
|
78
|
+
end
|
79
|
+
|
80
|
+
its(:size) { should eq(2) }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
"""
|
84
|
+
When I run "rspec example_spec.rb"
|
85
|
+
Then the output should contain "1 example, 0 failures"
|
86
|
+
|
87
|
+
Scenario: specify value for key in a hash
|
88
|
+
Given a file named "example_spec.rb" with:
|
89
|
+
"""
|
90
|
+
describe Hash do
|
91
|
+
context "with keys :one and 'two'" do
|
92
|
+
subject do
|
93
|
+
{:one => 1, "two" => 2}
|
94
|
+
end
|
95
|
+
|
96
|
+
its([:one]) { should eq(1) }
|
97
|
+
its(["two"]) { should eq(2) }
|
98
|
+
end
|
99
|
+
end
|
52
100
|
"""
|
101
|
+
When I run "rspec example_spec.rb"
|
102
|
+
Then the output should contain "2 examples, 0 failures"
|
@@ -16,7 +16,7 @@ module RSpec
|
|
16
16
|
"#{@command}" is not valid a valid argument to "rspec --configure".
|
17
17
|
Supported options are:
|
18
18
|
|
19
|
-
rspec --configure autotest # generates
|
19
|
+
rspec --configure autotest # generates .rspec file
|
20
20
|
|
21
21
|
#{"*"*50}
|
22
22
|
MESSAGE
|
@@ -26,26 +26,26 @@ MESSAGE
|
|
26
26
|
class Autotest
|
27
27
|
class << self
|
28
28
|
def generate
|
29
|
-
|
30
|
-
|
31
|
-
puts "autotest/discover.rb has been added"
|
29
|
+
create_dot_rspec_file
|
30
|
+
remove_autotest_dir_if_present
|
32
31
|
end
|
33
32
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
file << 'Autotest.add_discovery { "rspec2" }'
|
33
|
+
def create_dot_rspec_file
|
34
|
+
puts "Autotest loads RSpec's Autotest subclass when there is a .rspec file in the project's root directory."
|
35
|
+
if File.exist?('./.rspec')
|
36
|
+
puts ".rspec file already exists, so nothing was changed."
|
37
|
+
else
|
38
|
+
FileUtils.touch('./.rspec')
|
39
|
+
puts ".rspec file did not exist, so it was created."
|
42
40
|
end
|
43
41
|
end
|
44
42
|
|
45
|
-
def
|
46
|
-
|
47
|
-
|
48
|
-
|
43
|
+
def remove_autotest_dir_if_present
|
44
|
+
if discover_file_exists?
|
45
|
+
print "Delete obsolete autotest/discover.rb [y/n]? "
|
46
|
+
exit if gets !~ /y/i
|
47
|
+
FileUtils.rm_rf(discover_file_path)
|
48
|
+
end
|
49
49
|
end
|
50
50
|
|
51
51
|
def discover_file_exists?
|
@@ -24,7 +24,7 @@ module RSpec
|
|
24
24
|
add_setting :drb
|
25
25
|
add_setting :drb_port
|
26
26
|
add_setting :profile_examples
|
27
|
-
add_setting :fail_fast
|
27
|
+
add_setting :fail_fast
|
28
28
|
add_setting :run_all_when_everything_filtered
|
29
29
|
add_setting :filter
|
30
30
|
add_setting :exclusion_filter
|
@@ -240,6 +240,7 @@ module RSpec
|
|
240
240
|
return unless bool
|
241
241
|
begin
|
242
242
|
require 'ruby-debug'
|
243
|
+
Debugger.start
|
243
244
|
rescue LoadError
|
244
245
|
raise <<-EOM
|
245
246
|
|
@@ -262,28 +263,26 @@ EOM
|
|
262
263
|
filter_run({ :full_description => /#{description}/ }, true)
|
263
264
|
end
|
264
265
|
|
265
|
-
|
266
|
-
|
267
|
-
def formatter_class
|
268
|
-
@formatter_class ||= begin
|
269
|
-
require 'rspec/core/formatters/progress_formatter'
|
270
|
-
RSpec::Core::Formatters::ProgressFormatter
|
271
|
-
end
|
272
|
-
end
|
273
|
-
|
274
|
-
def formatter=(formatter_to_use)
|
275
|
-
self.formatter_class =
|
266
|
+
def add_formatter(formatter_to_use, output=nil)
|
267
|
+
formatter_class =
|
276
268
|
built_in_formatter(formatter_to_use) ||
|
277
269
|
custom_formatter(formatter_to_use) ||
|
278
270
|
(raise ArgumentError, "Formatter '#{formatter_to_use}' unknown - maybe you meant 'documentation' or 'progress'?.")
|
271
|
+
|
272
|
+
formatters << formatter_class.new(output ? File.new(output, 'w') : self.output)
|
279
273
|
end
|
280
274
|
|
281
|
-
|
282
|
-
|
275
|
+
alias_method :formatter=, :add_formatter
|
276
|
+
|
277
|
+
def formatters
|
278
|
+
@formatters ||= []
|
283
279
|
end
|
284
280
|
|
285
281
|
def reporter
|
286
|
-
@reporter ||=
|
282
|
+
@reporter ||= begin
|
283
|
+
add_formatter('progress') if formatters.empty?
|
284
|
+
Reporter.new(*formatters)
|
285
|
+
end
|
287
286
|
end
|
288
287
|
|
289
288
|
def files_or_directories_to_run=(*files)
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require 'optparse'
|
2
1
|
# http://www.ruby-doc.org/stdlib/libdoc/optparse/rdoc/classes/OptionParser.html
|
2
|
+
require 'optparse'
|
3
3
|
|
4
4
|
module RSpec
|
5
5
|
module Core
|
@@ -18,8 +18,14 @@ module RSpec
|
|
18
18
|
keys = options.keys
|
19
19
|
keys.unshift(:requires) if keys.delete(:requires)
|
20
20
|
keys.unshift(:libs) if keys.delete(:libs)
|
21
|
+
formatters = options[:formatters] if keys.delete(:formatters)
|
21
22
|
keys.each do |key|
|
22
|
-
config.send("#{key}=", options[key])
|
23
|
+
config.send("#{key}=", options[key]) if config.respond_to?("#{key}=")
|
24
|
+
end
|
25
|
+
if formatters
|
26
|
+
formatters.each do |pair|
|
27
|
+
config.add_formatter(*pair)
|
28
|
+
end
|
23
29
|
end
|
24
30
|
end
|
25
31
|
|
@@ -30,9 +36,17 @@ module RSpec
|
|
30
36
|
argv << "--backtrace" if options[:full_backtrace]
|
31
37
|
argv << "--tty" if options[:tty]
|
32
38
|
argv << "--fail-fast" if options[:fail_fast]
|
33
|
-
argv << "--format" << options[:formatter] if options[:formatter]
|
34
39
|
argv << "--line_number" << options[:line_number] if options[:line_number]
|
40
|
+
argv << "--options" << options[:custom_options_file] if options[:custom_options_file]
|
35
41
|
argv << "--example" << options[:full_description].source if options[:full_description]
|
42
|
+
if options[:formatters]
|
43
|
+
options[:formatters].each do |pair|
|
44
|
+
argv << "--format" << pair.shift
|
45
|
+
unless pair.empty?
|
46
|
+
argv << "--out" << pair.shift
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
36
50
|
(options[:libs] || []).each do |path|
|
37
51
|
argv << "-I" << path
|
38
52
|
end
|
@@ -44,12 +58,17 @@ module RSpec
|
|
44
58
|
|
45
59
|
def parse_options
|
46
60
|
@options = begin
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
61
|
+
options_to_merge = []
|
62
|
+
if custom_options_file
|
63
|
+
options_to_merge << custom_options
|
64
|
+
else
|
65
|
+
options_to_merge << global_options
|
66
|
+
options_to_merge << local_options
|
67
|
+
end
|
68
|
+
options_to_merge << env_options
|
69
|
+
options_to_merge << command_line_options
|
51
70
|
|
52
|
-
|
71
|
+
options_to_merge.inject do |merged, options|
|
53
72
|
merged.merge(options)
|
54
73
|
end
|
55
74
|
end
|
@@ -57,28 +76,34 @@ module RSpec
|
|
57
76
|
|
58
77
|
private
|
59
78
|
|
60
|
-
def
|
79
|
+
def env_options
|
61
80
|
ENV["SPEC_OPTS"] ? Parser.parse!(ENV["SPEC_OPTS"].split) : {}
|
62
81
|
end
|
63
82
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
83
|
+
def command_line_options
|
84
|
+
@command_line_options ||= begin
|
85
|
+
options = Parser.parse!(@args)
|
86
|
+
options[:files_or_directories_to_run] = @args
|
87
|
+
options
|
88
|
+
end
|
68
89
|
end
|
69
90
|
|
70
|
-
def
|
71
|
-
|
91
|
+
def custom_options
|
92
|
+
options_from(custom_options_file)
|
72
93
|
end
|
73
94
|
|
74
|
-
def
|
75
|
-
|
95
|
+
def local_options
|
96
|
+
@local_options ||= options_from(LOCAL_OPTIONS_FILE)
|
76
97
|
end
|
77
98
|
|
78
|
-
def
|
99
|
+
def global_options
|
100
|
+
@global_options ||= options_from(GLOBAL_OPTIONS_FILE)
|
101
|
+
end
|
102
|
+
|
103
|
+
def options_from(path)
|
79
104
|
Parser.parse(args_from_options_file(path))
|
80
105
|
end
|
81
|
-
|
106
|
+
|
82
107
|
def args_from_options_file(path)
|
83
108
|
return [] unless File.exist?(path)
|
84
109
|
config_string = options_file_as_erb_string(path)
|
@@ -90,9 +115,8 @@ module RSpec
|
|
90
115
|
ERB.new(IO.read(path)).result(binding)
|
91
116
|
end
|
92
117
|
|
93
|
-
def
|
94
|
-
|
95
|
-
LOCAL_OPTIONS_FILE
|
118
|
+
def custom_options_file
|
119
|
+
command_line_options[:custom_options_file]
|
96
120
|
end
|
97
121
|
end
|
98
122
|
end
|
data/lib/rspec/core/example.rb
CHANGED
@@ -2,7 +2,7 @@ module RSpec
|
|
2
2
|
module Core
|
3
3
|
class Example
|
4
4
|
|
5
|
-
attr_reader :metadata, :options
|
5
|
+
attr_reader :metadata, :options, :example_group_instance
|
6
6
|
|
7
7
|
def self.delegate_to_metadata(*keys)
|
8
8
|
keys.each do |key|
|
@@ -23,6 +23,15 @@ module RSpec
|
|
23
23
|
@example_group_class
|
24
24
|
end
|
25
25
|
|
26
|
+
def around_hooks
|
27
|
+
@around_hooks ||= example_group.around_hooks_for(self)
|
28
|
+
end
|
29
|
+
|
30
|
+
def apply?(predicate, filters)
|
31
|
+
@metadata.apply?(predicate, filters) ||
|
32
|
+
@example_group_class.apply?(predicate, filters)
|
33
|
+
end
|
34
|
+
|
26
35
|
alias_method :pending?, :pending
|
27
36
|
|
28
37
|
def run(example_group_instance, reporter)
|
@@ -69,8 +78,9 @@ module RSpec
|
|
69
78
|
class Procsy < Proc
|
70
79
|
attr_reader :metadata
|
71
80
|
alias_method :run, :call
|
72
|
-
def initialize(metadata)
|
81
|
+
def initialize(metadata, &block)
|
73
82
|
@metadata = metadata
|
83
|
+
super(&block)
|
74
84
|
end
|
75
85
|
end
|
76
86
|
|
@@ -84,10 +94,10 @@ module RSpec
|
|
84
94
|
end
|
85
95
|
|
86
96
|
def with_around_hooks
|
87
|
-
if
|
97
|
+
if around_hooks.empty?
|
88
98
|
yield
|
89
99
|
else
|
90
|
-
@example_group_class.eval_around_eachs(
|
100
|
+
@example_group_class.eval_around_eachs(self, Procsy.new(metadata)).call
|
91
101
|
end
|
92
102
|
end
|
93
103
|
|
@@ -123,11 +133,11 @@ module RSpec
|
|
123
133
|
|
124
134
|
def run_before_each
|
125
135
|
@example_group_instance.setup_mocks_for_rspec if @example_group_instance.respond_to?(:setup_mocks_for_rspec)
|
126
|
-
@example_group_class.eval_before_eachs(
|
136
|
+
@example_group_class.eval_before_eachs(self)
|
127
137
|
end
|
128
138
|
|
129
139
|
def run_after_each
|
130
|
-
@example_group_class.eval_after_eachs(
|
140
|
+
@example_group_class.eval_after_eachs(self)
|
131
141
|
@example_group_instance.verify_mocks_for_rspec if @example_group_instance.respond_to?(:verify_mocks_for_rspec)
|
132
142
|
ensure
|
133
143
|
@example_group_instance.teardown_mocks_for_rspec if @example_group_instance.respond_to?(:teardown_mocks_for_rspec)
|
@@ -177,22 +177,22 @@ module RSpec
|
|
177
177
|
store_before_all_ivars(example_group_instance)
|
178
178
|
end
|
179
179
|
|
180
|
-
def self.eval_around_eachs(
|
181
|
-
around_hooks.reverse.inject(initial_procsy) do |procsy, around_hook|
|
180
|
+
def self.eval_around_eachs(example, initial_procsy)
|
181
|
+
example.around_hooks.reverse.inject(initial_procsy) do |procsy, around_hook|
|
182
182
|
Example::Procsy.new(procsy.metadata) do
|
183
|
-
example_group_instance.instance_eval_with_args(procsy, &around_hook)
|
183
|
+
example.example_group_instance.instance_eval_with_args(procsy, &around_hook)
|
184
184
|
end
|
185
185
|
end
|
186
186
|
end
|
187
187
|
|
188
|
-
def self.eval_before_eachs(
|
189
|
-
world.run_hook_filtered(:before, :each, self, example_group_instance)
|
190
|
-
ancestors.reverse.each { |ancestor| ancestor.run_hook(:before, :each, example_group_instance) }
|
188
|
+
def self.eval_before_eachs(example)
|
189
|
+
world.run_hook_filtered(:before, :each, self, example.example_group_instance, example)
|
190
|
+
ancestors.reverse.each { |ancestor| ancestor.run_hook(:before, :each, example.example_group_instance) }
|
191
191
|
end
|
192
192
|
|
193
|
-
def self.eval_after_eachs(
|
194
|
-
ancestors.each { |ancestor| ancestor.run_hook(:after, :each, example_group_instance) }
|
195
|
-
world.run_hook_filtered(:after, :each, self, example_group_instance)
|
193
|
+
def self.eval_after_eachs(example)
|
194
|
+
ancestors.each { |ancestor| ancestor.run_hook(:after, :each, example.example_group_instance) }
|
195
|
+
world.run_hook_filtered(:after, :each, self, example.example_group_instance, example)
|
196
196
|
end
|
197
197
|
|
198
198
|
def self.eval_after_alls(example_group_instance)
|
@@ -215,8 +215,8 @@ An error occurred in an after(:all) hook.
|
|
215
215
|
world.run_hook_filtered(:after, :all, self, example_group_instance) if top_level?
|
216
216
|
end
|
217
217
|
|
218
|
-
def self.
|
219
|
-
|
218
|
+
def self.around_hooks_for(example)
|
219
|
+
world.find_hook(:around, :each, self, example) + ancestors.reverse.inject([]){|l,a| l + a.find_hook(:around, :each, self, example)}
|
220
220
|
end
|
221
221
|
|
222
222
|
def self.run(reporter)
|