rspec-core 2.3.1 → 2.4.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 (48) hide show
  1. data/History.markdown +22 -0
  2. data/Rakefile +2 -2
  3. data/features/command_line/README.md +6 -0
  4. data/features/command_line/configure.feature +16 -14
  5. data/features/command_line/example_name_option.feature +3 -3
  6. data/features/command_line/format_option.feature +73 -0
  7. data/features/command_line/line_number_appended_to_path.feature +1 -1
  8. data/features/command_line/line_number_option.feature +2 -2
  9. data/features/command_line/tag.feature +7 -7
  10. data/features/configuration/read_options_from_file.feature +29 -16
  11. data/features/hooks/before_and_after_hooks.feature +9 -14
  12. data/features/hooks/filtering.feature +174 -0
  13. data/features/step_definitions/additional_cli_steps.rb +4 -0
  14. data/features/subject/attribute_of_subject.feature +68 -18
  15. data/lib/rspec/core/command_line_configuration.rb +16 -16
  16. data/lib/rspec/core/configuration.rb +14 -15
  17. data/lib/rspec/core/configuration_options.rb +46 -22
  18. data/lib/rspec/core/example.rb +16 -6
  19. data/lib/rspec/core/example_group.rb +11 -11
  20. data/lib/rspec/core/formatters/base_text_formatter.rb +2 -1
  21. data/lib/rspec/core/hooks.rb +8 -8
  22. data/lib/rspec/core/option_parser.rb +13 -3
  23. data/lib/rspec/core/pending.rb +2 -0
  24. data/lib/rspec/core/rake_task.rb +1 -1
  25. data/lib/rspec/core/subject.rb +2 -0
  26. data/lib/rspec/core/version.rb +1 -1
  27. data/lib/rspec/core/world.rb +2 -2
  28. data/spec/rspec/core/configuration_options_spec.rb +147 -151
  29. data/spec/rspec/core/configuration_spec.rb +67 -19
  30. data/spec/rspec/core/example_spec.rb +12 -10
  31. data/spec/rspec/core/formatters/base_text_formatter_spec.rb +25 -1
  32. data/spec/rspec/core/formatters/html_formatted-1.8.6.html +5 -5
  33. data/spec/rspec/core/formatters/html_formatted-1.8.7-jruby.html +37 -24
  34. data/spec/rspec/core/formatters/html_formatted-1.8.7.html +5 -5
  35. data/spec/rspec/core/formatters/html_formatted-1.9.1.html +5 -5
  36. data/spec/rspec/core/formatters/html_formatted-1.9.2.html +5 -5
  37. data/spec/rspec/core/formatters/html_formatter_spec.rb +7 -7
  38. data/spec/rspec/core/formatters/text_mate_formatted-1.8.6.html +19 -19
  39. data/spec/rspec/core/formatters/text_mate_formatted-1.8.7-jruby.html +51 -33
  40. data/spec/rspec/core/formatters/text_mate_formatted-1.8.7.html +19 -19
  41. data/spec/rspec/core/formatters/text_mate_formatted-1.9.1.html +26 -26
  42. data/spec/rspec/core/formatters/text_mate_formatted-1.9.2.html +26 -26
  43. data/spec/rspec/core/formatters/text_mate_formatter_spec.rb +7 -7
  44. data/spec/rspec/core/hooks_filtering_spec.rb +54 -0
  45. data/spec/rspec/core/option_parser_spec.rb +53 -17
  46. data/spec/rspec/core/rake_task_spec.rb +21 -0
  47. data/spec/spec_helper.rb +1 -1
  48. 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 subject.
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. Use
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
- Scenario: simple attribute
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
- its(:size) { should == 0 }
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
- size
23
- should == 0
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
- subject do
38
- person = Person.new
39
- person.phone_numbers << "555-1212"
40
- person
41
- end
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
- its("phone_numbers.first") { should == "555-1212" }
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
- phone_numbers.first
51
- should == "555-1212"
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 configuration to run autotest with rspec
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
- create_autotest_directory
30
- create_discover_file
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 create_autotest_directory
35
- Dir.mkdir('autotest') unless File.exist?('autotest')
36
- end
37
-
38
- def create_discover_file
39
- optionally_remove_discover_file if discover_file_exists?
40
- File.open(discover_file_path, 'w') do |file|
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 optionally_remove_discover_file
46
- print "Discover file already exists, overwrite [y/N]? "
47
- exit if gets !~ /y/i
48
- FileUtils.rm_rf(discover_file_path)
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, :default => false
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
- attr_writer :formatter_class
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
- def formatter
282
- @formatter ||= formatter_class.new(output)
275
+ alias_method :formatter=, :add_formatter
276
+
277
+ def formatters
278
+ @formatters ||= []
283
279
  end
284
280
 
285
281
  def reporter
286
- @reporter ||= Reporter.new(formatter)
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
- command_line_options = parse_command_line_options
48
- local_options = parse_local_options(command_line_options)
49
- global_options = parse_global_options
50
- env_options = parse_env_options
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
- [global_options, local_options, command_line_options, env_options].inject do |merged, options|
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 parse_env_options
79
+ def env_options
61
80
  ENV["SPEC_OPTS"] ? Parser.parse!(ENV["SPEC_OPTS"].split) : {}
62
81
  end
63
82
 
64
- def parse_command_line_options
65
- options = Parser.parse!(@args)
66
- options[:files_or_directories_to_run] = @args
67
- options
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 parse_local_options(options)
71
- parse_options_file(local_options_file(options))
91
+ def custom_options
92
+ options_from(custom_options_file)
72
93
  end
73
94
 
74
- def parse_global_options
75
- parse_options_file(GLOBAL_OPTIONS_FILE)
95
+ def local_options
96
+ @local_options ||= options_from(LOCAL_OPTIONS_FILE)
76
97
  end
77
98
 
78
- def parse_options_file(path)
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 local_options_file(options)
94
- return options[:options_file] if options[:options_file]
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
@@ -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 @example_group_class.around_hooks.empty?
97
+ if around_hooks.empty?
88
98
  yield
89
99
  else
90
- @example_group_class.eval_around_eachs(@example_group_instance, Procsy.new(metadata)).call
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(@example_group_instance)
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(@example_group_instance)
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(example_group_instance, initial_procsy)
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(example_group_instance)
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(example_group_instance)
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.around_hooks
219
- @around_hooks ||= (world.find_hook(:around, :each, self) + ancestors.reverse.inject([]){|l,a| l + a.find_hook(:around, :each, self)})
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)