rspec-core 2.0.0.beta.12 → 2.0.0.beta.13

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 (38) hide show
  1. data/.gitignore +1 -0
  2. data/Gemfile +14 -0
  3. data/Rakefile +15 -12
  4. data/VERSION +1 -1
  5. data/features/command_line/example_name_option.feature +17 -3
  6. data/features/command_line/exit_status.feature +49 -0
  7. data/features/hooks/before_and_after_hooks.feature +51 -19
  8. data/features/hooks/halt.feature +1 -1
  9. data/features/support/env.rb +5 -3
  10. data/lib/rspec/core/command_line.rb +14 -5
  11. data/lib/rspec/core/configuration.rb +14 -24
  12. data/lib/rspec/core/configuration_options.rb +13 -8
  13. data/lib/rspec/core/drb_command_line.rb +2 -3
  14. data/lib/rspec/core/example.rb +5 -5
  15. data/lib/rspec/core/example_group.rb +23 -25
  16. data/lib/rspec/core/formatters/base_text_formatter.rb +13 -4
  17. data/lib/rspec/core/hooks.rb +57 -24
  18. data/lib/rspec/core/metadata.rb +1 -1
  19. data/lib/rspec/core/pending.rb +3 -3
  20. data/lib/rspec/core/rake_task.rb +48 -11
  21. data/lib/rspec/core/runner.rb +19 -8
  22. data/lib/rspec/core/subject.rb +3 -3
  23. data/lib/rspec/core/world.rb +3 -7
  24. data/rspec-core.gemspec +16 -12
  25. data/spec/rspec/core/command_line_spec.rb +72 -0
  26. data/spec/rspec/core/configuration_options_spec.rb +12 -3
  27. data/spec/rspec/core/configuration_spec.rb +6 -1
  28. data/spec/rspec/core/deprecations_spec.rb +19 -0
  29. data/spec/rspec/core/drb_command_line_spec.rb +1 -1
  30. data/spec/rspec/core/example_group_spec.rb +120 -12
  31. data/spec/rspec/core/example_spec.rb +27 -17
  32. data/spec/rspec/core/formatters/base_text_formatter_spec.rb +23 -0
  33. data/spec/rspec/core/metadata_spec.rb +32 -0
  34. data/spec/rspec/core/runner_spec.rb +2 -1
  35. data/spec/rspec/core/shared_example_group_spec.rb +1 -1
  36. data/spec/spec_helper.rb +49 -51
  37. data/specs.watchr +1 -1
  38. metadata +31 -27
@@ -2,7 +2,7 @@ module RSpec
2
2
  module Core
3
3
  class Example
4
4
 
5
- attr_reader :metadata, :example_block
5
+ attr_reader :metadata, :example_block, :options
6
6
 
7
7
  def self.delegate_to_metadata(*keys)
8
8
  keys.each do |key|
@@ -33,7 +33,7 @@ module RSpec
33
33
  def run(example_group_instance, reporter)
34
34
  @in_block = false
35
35
  @example_group_instance = example_group_instance
36
- @example_group_instance.running_example = self
36
+ @example_group_instance.example = self
37
37
 
38
38
  run_started
39
39
 
@@ -43,10 +43,10 @@ module RSpec
43
43
  run_before_each
44
44
  pending_declared_in_example = catch(:pending_declared_in_example) do
45
45
  @in_block = true
46
- if @example_group_class.around_eachs.empty?
46
+ if @example_group_class.hooks[:around][:each].empty?
47
47
  @example_group_instance.instance_eval(&example_block) unless pending
48
48
  else
49
- @example_group_class.around_eachs.first.call(AroundProxy.new(self, &example_block))
49
+ @example_group_class.hooks[:around][:each].first.call(AroundProxy.new(self, &example_block))
50
50
  end
51
51
  throw :pending_declared_in_example, false
52
52
  end
@@ -62,7 +62,7 @@ module RSpec
62
62
  rescue Exception => e
63
63
  exception ||= e
64
64
  ensure
65
- @example_group_instance.running_example = nil
65
+ @example_group_instance.example = nil
66
66
  end
67
67
 
68
68
  if exception
@@ -6,7 +6,12 @@ module RSpec
6
6
  include Let
7
7
  include Pending
8
8
 
9
- attr_accessor :running_example
9
+ attr_accessor :example
10
+
11
+ def running_example
12
+ RSpec.deprecate('running_example', 'example')
13
+ example
14
+ end
10
15
 
11
16
  def self.world
12
17
  RSpec.world
@@ -135,36 +140,30 @@ module RSpec
135
140
  @before_all_ivars ||= {}
136
141
  end
137
142
 
138
- def self.eval_before_alls(running_example)
143
+ def self.eval_before_alls(example)
139
144
  return if descendant_filtered_examples.empty?
140
- superclass.before_all_ivars.each { |ivar, val| running_example.instance_variable_set(ivar, val) }
141
- world.run_hook(:before, :all, self, running_example)
145
+ superclass.before_all_ivars.each { |ivar, val| example.instance_variable_set(ivar, val) }
146
+ world.run_hook_filtered(:before, :all, self, example)
142
147
 
143
- until before_alls.empty?
144
- running_example.instance_eval &before_alls.shift
145
- end
146
- running_example.instance_variables.each { |ivar| before_all_ivars[ivar] = running_example.instance_variable_get(ivar) }
148
+ run_hook!(:before, :all, example, :reverse => true)
149
+ example.instance_variables.each { |ivar| before_all_ivars[ivar] = example.instance_variable_get(ivar) }
147
150
  end
148
151
 
149
- def self.eval_before_eachs(running_example)
150
- world.run_hook(:before, :each, self, running_example)
151
- ancestors.reverse.each { |ancestor| ancestor.before_eachs.each { |blk| running_example.instance_eval(&blk) } }
152
+ def self.eval_before_eachs(example)
153
+ world.run_hook_filtered(:before, :each, self, example)
154
+ ancestors.reverse.each { |ancestor| ancestor.run_hook(:before, :each, example) }
152
155
  end
153
156
 
154
- def self.eval_after_eachs(running_example)
155
- ancestors.each { |ancestor| ancestor.after_eachs.reverse.each { |blk| running_example.instance_eval(&blk) } }
156
- world.run_hook(:after, :each, self, running_example)
157
+ def self.eval_after_eachs(example)
158
+ ancestors.each { |ancestor| ancestor.run_hook(:after, :each, example, :reverse => true) }
159
+ world.run_hook_filtered(:after, :each, self, example)
157
160
  end
158
161
 
159
- def self.eval_after_alls(running_example)
162
+ def self.eval_after_alls(example)
160
163
  return if descendant_filtered_examples.empty?
161
- before_all_ivars.each { |ivar, val| running_example.instance_variable_set(ivar, val) }
162
- ancestors.each do |ancestor|
163
- until ancestor.after_alls.empty?
164
- running_example.instance_eval &ancestor.after_alls.pop
165
- end
166
- end
167
- world.run_hook(:after, :all, self, running_example)
164
+ before_all_ivars.each { |ivar, val| example.instance_variable_set(ivar, val) }
165
+ ancestors.each {|ancestor| ancestor.run_hook!(:after, :all, example) }
166
+ world.run_hook_filtered(:after, :all, self, example)
168
167
  end
169
168
 
170
169
  def self.run(reporter)
@@ -172,9 +171,8 @@ module RSpec
172
171
  reporter.add_example_group(self)
173
172
  begin
174
173
  eval_before_alls(example_group_instance)
175
- result_for_this_group = run_examples(example_group_instance, reporter)
176
- results_for_descendants = children.map {|child| child.run(reporter)}
177
- result_for_this_group && (children.empty? ? true : results_for_descendants)
174
+ run_examples(example_group_instance, reporter) &&
175
+ children.map {|child| child.run(reporter)}.all?
178
176
  ensure
179
177
  eval_after_alls(example_group_instance)
180
178
  end
@@ -38,12 +38,10 @@ module RSpec
38
38
  def dump_summary
39
39
  failure_count = failed_examples.size
40
40
  pending_count = pending_examples.size
41
-
42
41
 
43
- output.puts "\nFinished in #{format_seconds(duration)} seconds\n"
42
+ output.puts "\nFinished in #{format_seconds(duration)} seconds\n"
44
43
 
45
- summary = "#{example_count} example#{'s' unless example_count == 1}, #{failure_count} failures"
46
- summary << ", #{pending_count} pending" if pending_count > 0
44
+ summary = summary_line(example_count, failure_count, pending_count)
47
45
 
48
46
  if failure_count == 0
49
47
  if pending_count > 0
@@ -68,6 +66,17 @@ module RSpec
68
66
  output.flush
69
67
  end
70
68
 
69
+ def summary_line(example_count, failure_count, pending_count)
70
+ summary = pluralize(example_count, "example")
71
+ summary << ", " << pluralize(failure_count, "failure")
72
+ summary << ", #{pending_count} pending" if pending_count > 0
73
+ summary
74
+ end
75
+
76
+ def pluralize(count, string)
77
+ "#{count} #{string}#{'s' unless count == 1}"
78
+ end
79
+
71
80
  def format_caller(caller_info)
72
81
  caller_info.to_s.split(':in `block').first
73
82
  end
@@ -1,49 +1,82 @@
1
1
  module RSpec
2
2
  module Core
3
3
  module Hooks
4
- def before_blocks
5
- @before_blocks ||= { :all => [], :each => [] }
6
- end
4
+ class Hook
5
+ attr_reader :options
6
+
7
+ def initialize(options, block)
8
+ @options = options
9
+ @block = block
10
+ end
11
+
12
+ def options_apply?(group)
13
+ !group || group.all_apply?(options)
14
+ end
15
+
16
+ def call
17
+ @block.call
18
+ end
7
19
 
8
- def after_blocks
9
- @after_blocks ||= { :all => [], :each => [] }
20
+ def to_proc
21
+ @block
22
+ end
10
23
  end
11
24
 
12
- def around_blocks
13
- @around_blocks ||= { :each => [] }
25
+ def hooks
26
+ @hooks ||= {
27
+ :around => { :each => [] },
28
+ :before => { :each => [], :all => [], :suite => [] },
29
+ :after => { :each => [], :all => [], :suite => [] }
30
+ }
14
31
  end
15
32
 
16
- def before_eachs
17
- before_blocks[:each]
33
+ def before(scope=:each, options={}, &block)
34
+ hooks[:before][scope] << Hook.new(options, block)
18
35
  end
19
36
 
20
- def before_alls
21
- before_blocks[:all]
37
+ def after(scope=:each, options={}, &block)
38
+ hooks[:after][scope] << Hook.new(options, block)
22
39
  end
23
40
 
24
- def before(type=:each, &block)
25
- before_blocks[type] << block
41
+ def around(scope=:each, &block)
42
+ RSpec::deprecate("around", "before and after")
43
+ hooks[:around][scope] << block
26
44
  end
27
45
 
28
- def after_eachs
29
- after_blocks[:each]
46
+ # Runs all of the blocks stored with the hook in the context of the
47
+ # example. If no example is provided, just calls the hook directly.
48
+ def run_hook(hook, scope, example=nil, options={})
49
+ if options[:reverse]
50
+ hooks[hook][scope].reverse.each &run_hook_in(example)
51
+ else
52
+ hooks[hook][scope].each &run_hook_in(example)
53
+ end
30
54
  end
31
55
 
32
- def after_alls
33
- after_blocks[:all]
56
+ # Just like run_hook, except it removes the blocks as it evalutes them,
57
+ # ensuring that they will only be run once.
58
+ def run_hook!(hook, scope, example, options={})
59
+ until hooks[hook][scope].empty?
60
+ if options[:reverse]
61
+ example.instance_eval &hooks[hook][scope].shift
62
+ else
63
+ example.instance_eval &hooks[hook][scope].pop
64
+ end
65
+ end
34
66
  end
35
67
 
36
- def after(type=:each, &block)
37
- after_blocks[type] << block
68
+ def run_hook_filtered(hook, scope, group, example)
69
+ find_hook(hook, scope, group).each &run_hook_in(example)
38
70
  end
39
71
 
40
- def around_eachs
41
- around_blocks[:each]
72
+ def find_hook(hook, scope, group)
73
+ hooks[hook][scope].select {|hook| hook.options_apply?(group)}
42
74
  end
43
75
 
44
- def around(type=:each, &block)
45
- RSpec::deprecate("around", "before and after")
46
- around_blocks[type] << block
76
+ private
77
+
78
+ def run_hook_in(example)
79
+ lambda {|hook| example ? example.instance_eval(&hook) : hook.call}
47
80
  end
48
81
  end
49
82
  end
@@ -139,7 +139,7 @@ EOM
139
139
  end
140
140
 
141
141
  def described_class_from(args)
142
- if args.first.is_a?(String)
142
+ if args.first.is_a?(String) || args.first.is_a?(Symbol)
143
143
  superclass_metadata[:example_group][:describes]
144
144
  else
145
145
  args.first
@@ -2,12 +2,12 @@ module RSpec
2
2
  module Core
3
3
  module Pending
4
4
  def pending(message = 'No reason given')
5
- running_example.metadata[:pending] = true
6
- running_example.metadata[:execution_result][:pending_message] = message
5
+ example.metadata[:pending] = true
6
+ example.metadata[:execution_result][:pending_message] = message
7
7
  if block_given?
8
8
  begin
9
9
  result = yield
10
- running_example.metadata[:pending] = false
10
+ example.metadata[:pending] = false
11
11
  rescue Exception => e
12
12
  end
13
13
  raise RSpec::Core::PendingExampleFixedError.new if result
@@ -35,16 +35,20 @@ module RSpec
35
35
  # Use rcov for code coverage? defaults to false
36
36
  attr_accessor :rcov
37
37
 
38
+ # Path to rcov. You can set this to 'bundle exec rcov' if you bundle rcov.
39
+ attr_accessor :rcov_path
40
+
38
41
  # The options to pass to rcov. Defaults to blank
39
42
  attr_accessor :rcov_opts
40
43
 
41
44
  def initialize(*args)
42
45
  @name = args.shift || :spec
43
- @pattern, @rcov_opts, @ruby_opts = nil, nil, nil
46
+ @pattern, @rcov_path, @rcov_opts, @ruby_opts = nil, nil, nil, nil
44
47
  @warning, @rcov = false, false
45
48
  @fail_on_error = true
46
49
 
47
50
  yield self if block_given?
51
+ @rcov_path ||= 'rcov'
48
52
  @pattern ||= './spec/**/*_spec.rb'
49
53
  define
50
54
  end
@@ -58,18 +62,30 @@ module RSpec
58
62
  if files_to_run.empty?
59
63
  puts "No examples matching #{pattern} could be found"
60
64
  else
61
- cmd_parts = [rcov ? 'rcov' : RUBY]
62
- cmd_parts += rcov ? [rcov_opts] : [ruby_opts]
63
- cmd_parts << '-Ilib'
64
- cmd_parts << '-Ispec'
65
+ cmd_parts = [ '-Ilib', '-Ispec' ]
65
66
  cmd_parts << "-w" if warning
66
- cmd_parts += files_to_run.collect { |fn| %["#{fn}"] }
67
- cmd = cmd_parts.join(" ")
68
- puts cmd if verbose
69
- unless system(cmd)
70
- STDERR.puts failure_message if failure_message
71
- raise("Command #{cmd} failed") if fail_on_error
67
+
68
+ if rcov
69
+ command_to_run = rcov_command(cmd_parts)
70
+ command_to_run.inspect if verbose
71
+
72
+ unless system(command_to_run)
73
+ STDERR.puts failure_message if failure_message
74
+ raise("#{command_to_run} failed") if fail_on_error
75
+ end
76
+ else
77
+ cmd_parts.concat(files_to_run)
78
+ puts cmd.inspect if verbose
79
+
80
+ require 'rspec/core'
81
+ RSpec::Core::Runner.disable_at_exit_hook!
82
+
83
+ unless RSpec::Core::Runner.run(cmd_parts, $stderr, $stdout)
84
+ STDERR.puts failure_message if failure_message
85
+ raise("RSpec::Core::Runner.run with args #{cmd_parts.inspect} failed") if fail_on_error
86
+ end
72
87
  end
88
+
73
89
  end
74
90
  end
75
91
  end
@@ -81,6 +97,27 @@ module RSpec
81
97
  FileList[ pattern ].to_a
82
98
  end
83
99
 
100
+ private
101
+
102
+ def rcov_command(cmd_parts)
103
+ cmd_parts.unshift runner_options
104
+ cmd_parts.unshift runner
105
+ cmd_parts.unshift bundler
106
+ cmd_parts += files_to_run.map { |fn| %["#{fn}"] }
107
+ cmd_parts.join(" ")
108
+ end
109
+
110
+ def runner
111
+ rcov ? rcov_path : RUBY
112
+ end
113
+
114
+ def runner_options
115
+ rcov ? [rcov_opts] : [ruby_opts]
116
+ end
117
+
118
+ def bundler
119
+ File.exist?("./Gemfile") ? "bundle exec " : ""
120
+ end
84
121
  end
85
122
 
86
123
  end
@@ -4,12 +4,20 @@ module RSpec
4
4
  module Core
5
5
  class Runner
6
6
 
7
+ def self.at_exit_hook_disabled?
8
+ @no_at_exit_hook ||= false
9
+ end
10
+
11
+ def self.disable_at_exit_hook!
12
+ @no_at_exit_hook = true
13
+ end
14
+
7
15
  def self.installed_at_exit?
8
16
  @installed_at_exit ||= false
9
17
  end
10
18
 
11
19
  def self.autorun
12
- return if installed_at_exit? || running_in_drb?
20
+ return if at_exit_hook_disabled? || installed_at_exit? || running_in_drb?
13
21
  @installed_at_exit = true
14
22
  at_exit { run(ARGV, $stderr, $stdout) ? exit(0) : exit(1) }
15
23
  end
@@ -20,19 +28,22 @@ module RSpec
20
28
  end
21
29
 
22
30
  def self.run(args, err, out)
23
- if args.any? {|a| %w[--drb -X].include? a}
24
- run_over_drb(args, err, out) || run_in_process(args, err, out)
31
+ options = ConfigurationOptions.new(args)
32
+ options.parse_options
33
+
34
+ if options.options[:drb]
35
+ run_over_drb(options, err, out) || run_in_process(options, err, out)
25
36
  else
26
- run_in_process(args, err, out)
37
+ run_in_process(options, err, out)
27
38
  end
28
39
  end
29
40
 
30
- def self.run_over_drb(args, err, out)
31
- DRbCommandLine.new(args).run(err, out)
41
+ def self.run_over_drb(options, err, out)
42
+ DRbCommandLine.new(options).run(err, out)
32
43
  end
33
44
 
34
- def self.run_in_process(args, err, out)
35
- CommandLine.new(args).run(err, out)
45
+ def self.run_in_process(options, err, out)
46
+ CommandLine.new(options).run(err, out)
36
47
  end
37
48
 
38
49
  end
@@ -80,12 +80,12 @@ module RSpec
80
80
  end
81
81
 
82
82
  def attribute_of_subject
83
- original_subject.send(running_example.description) if using_attribute?
83
+ original_subject.send(example.description) if using_attribute?
84
84
  end
85
85
 
86
86
  def using_attribute?
87
- running_example.in_block? &&
88
- running_example.metadata[:attribute_of_subject]
87
+ example.in_block? &&
88
+ example.metadata[:attribute_of_subject]
89
89
  end
90
90
 
91
91
  end
@@ -67,15 +67,11 @@ module RSpec
67
67
  end
68
68
  end
69
69
  end
70
-
71
- def run_hook(hook, scope, group, example)
72
- find_hook(hook, scope, group).each { |blk| example.instance_eval(&blk) }
73
- end
70
+
71
+ include RSpec::Core::Hooks
74
72
 
75
73
  def find_hook(hook, scope, group)
76
- RSpec.configuration.hooks[hook][scope].select do |filters, block|
77
- group.all_apply?(filters)
78
- end.map { |filters, block| block }
74
+ RSpec.configuration.find_hook(hook, scope, group)
79
75
  end
80
76
 
81
77
  private