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.
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)