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

Sign up to get free protection for your applications and to get access to all the features.
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