rspec-core 2.0.0.beta.20 → 2.0.0.beta.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/.rspec +1 -1
  2. data/Gemfile +7 -6
  3. data/History.md +30 -0
  4. data/Rakefile +3 -43
  5. data/bin/rspec +2 -1
  6. data/features/configuration/{options_file.feature → read_options_from_file.feature} +29 -25
  7. data/features/example_groups/shared_example_group.feature +10 -6
  8. data/features/hooks/before_and_after_hooks.feature +38 -0
  9. data/lib/autotest/rspec2.rb +10 -2
  10. data/lib/rspec/core.rb +8 -0
  11. data/lib/rspec/core/configuration.rb +16 -10
  12. data/lib/rspec/core/configuration_options.rb +7 -3
  13. data/lib/rspec/core/example.rb +7 -0
  14. data/lib/rspec/core/example_group.rb +15 -2
  15. data/lib/rspec/core/extensions/module_eval_with_args.rb +9 -29
  16. data/lib/rspec/core/extensions/object.rb +0 -2
  17. data/lib/rspec/core/formatters/base_formatter.rb +8 -6
  18. data/lib/rspec/core/formatters/base_text_formatter.rb +18 -10
  19. data/lib/rspec/core/formatters/documentation_formatter.rb +9 -9
  20. data/lib/rspec/core/option_parser.rb +0 -4
  21. data/lib/rspec/core/rake_task.rb +85 -39
  22. data/lib/rspec/core/reporter.rb +18 -5
  23. data/lib/rspec/core/runner.rb +8 -18
  24. data/lib/rspec/core/shared_example_group.rb +2 -1
  25. data/lib/rspec/core/version.rb +1 -1
  26. data/rspec-core.gemspec +33 -233
  27. data/spec/autotest/failed_results_re_spec.rb +1 -2
  28. data/spec/autotest/rspec_spec.rb +62 -42
  29. data/spec/rspec/core/configuration_options_spec.rb +12 -29
  30. data/spec/rspec/core/configuration_spec.rb +8 -8
  31. data/spec/rspec/core/example_group_spec.rb +38 -7
  32. data/spec/rspec/core/example_spec.rb +16 -1
  33. data/spec/rspec/core/formatters/base_formatter_spec.rb +6 -0
  34. data/spec/rspec/core/formatters/base_text_formatter_spec.rb +125 -10
  35. data/spec/rspec/core/formatters/documentation_formatter_spec.rb +36 -0
  36. data/spec/rspec/core/formatters/html_formatted-1.8.7-jruby.html +282 -0
  37. data/spec/rspec/core/formatters/html_formatted-1.9.1.html +22 -2
  38. data/spec/rspec/core/formatters/text_mate_formatted-1.8.7-jruby.html +280 -0
  39. data/spec/rspec/core/formatters/text_mate_formatted-1.9.1.html +280 -0
  40. data/spec/rspec/core/rake_task_spec.rb +128 -0
  41. data/spec/rspec/core/reporter_spec.rb +36 -0
  42. data/spec/rspec/core/runner_spec.rb +0 -18
  43. data/spec/rspec/core/shared_example_group_spec.rb +22 -2
  44. data/spec/rspec/core/world_spec.rb +13 -15
  45. data/spec/spec_helper.rb +2 -1
  46. metadata +110 -13
  47. data/VERSION +0 -1
  48. data/lib/rspec/autorun.rb +0 -2
@@ -11,42 +11,22 @@ module RSpec
11
11
  # If there are no args and the block doesn't expect any, there's no
12
12
  # need to fake module_exec with our hack below.
13
13
  # Notes:
14
- # * lambda { }.arity # => -1
15
- # * lambda { || }.arity # => 0
16
- # * lambda { |*a| }.arity # -1
14
+ # * lambda { }.arity # => -1
15
+ # * lambda { || }.arity # => 0
16
+ # * lambda { |*a| }.arity # => -1
17
17
  return module_eval(&block) if block.arity < 1 && args.size.zero?
18
18
 
19
+ orig_singleton_methods = singleton_methods
19
20
  instance_eval_with_args(*args, &block)
20
21
 
21
22
  # The only difference between instance_eval and module_eval is static method defs.
22
23
  # * `def foo` in instance_eval defines a singleton method on the instance
23
24
  # * `def foo` in class/module_eval defines an instance method for the class/module
24
- # Here we deal with this difference by defining instance methods on the
25
- # class/module and removing the singleton definitions.
26
- singleton_class = class << self; self; end
27
- extract_static_instance_method_defs_from(block).each do |m_name, m_def|
28
- define_method(m_name, &m_def)
29
- singleton_class.send(:remove_method, m_name)
30
- end
31
- end
32
-
33
- private
34
-
35
- def extract_static_instance_method_defs_from(block)
36
- klass = Class.new do
37
- # swallow any missing class method errors;
38
- # we only care to capture the raw method definitions here.
39
- def self.method_missing(*a); end
40
-
41
- # skip any dynamic method definitions
42
- def self.define_method(*a); end
43
-
44
- # run the block so our instance methods get defined
45
- class_eval(&block)
46
- end
47
-
48
- instance = klass.new
49
- klass.instance_methods(false).inject({}) { |h, m| h[m] = instance.method(m); h }
25
+ # Here we deal with this difference by defining an instance method for
26
+ # each new singleton method.
27
+ # This has the side effect of duplicating methods (all new class methods will
28
+ # become instance methods and vice versa), but I don't see a way around it...
29
+ (singleton_methods - orig_singleton_methods).each { |m| define_method(m, &method(m)) }
50
30
  end
51
31
  end
52
32
  end
@@ -6,8 +6,6 @@ module RSpec
6
6
  args.last.update :caller => caller(1)
7
7
  RSpec::Core::ExampleGroup.describe(*args, &example_group_block)
8
8
  end
9
-
10
- alias :context :describe
11
9
  end
12
10
  end
13
11
  end
@@ -38,6 +38,11 @@ module RSpec
38
38
  @example_group = example_group
39
39
  end
40
40
 
41
+ # This method is invoked at the end of the execution of each example group.
42
+ # +example_group+ is the example_group.
43
+ def example_group_finished(example_group)
44
+ end
45
+
41
46
  def add_example_group(example_group)
42
47
  RSpec.deprecate("add_example_group", "example_group_started")
43
48
  example_group_started(example_group)
@@ -93,10 +98,7 @@ module RSpec
93
98
  def format_backtrace(backtrace, example)
94
99
  return "" unless backtrace
95
100
  return backtrace if example.metadata[:full_backtrace] == true
96
-
97
- cleansed = backtrace.select { |line| backtrace_line(line) }
98
- # Kick the describe stack info off the list, just keep the line the problem happened on from that file
99
- # cleansed = [cleansed.detect { |line| line.split(':').first == example.metadata[:caller].split(':').first }] if cleansed.size > 1
101
+ cleansed = backtrace.map { |line| backtrace_line(line) }.compact
100
102
  cleansed.empty? ? backtrace : cleansed
101
103
  end
102
104
 
@@ -108,8 +110,8 @@ module RSpec
108
110
 
109
111
  def backtrace_line(line)
110
112
  return nil if configuration.cleaned_from_backtrace?(line)
111
- line.sub!(File.expand_path("."), ".")
112
- line.sub!(/\A([^:]+:\d+)$/, '\\1')
113
+ line = line.sub(File.expand_path("."), ".")
114
+ line = line.sub(/\A([^:]+:\d+)$/, '\\1')
113
115
  return nil if line == '-e:1'
114
116
  line
115
117
  end
@@ -22,10 +22,18 @@ module RSpec
22
22
  output.puts "#{padding}Expected pending '#{example.metadata[:execution_result][:pending_message]}' to fail. No Error was raised."
23
23
  else
24
24
  output.puts "#{short_padding}#{index.next}) #{example.full_description}"
25
- output.puts "#{padding}Failure/Error: #{read_failed_line(exception, example).strip}"
25
+ output.puts "#{padding}#{red("Failure/Error:")} #{red(read_failed_line(exception, example).strip)}"
26
26
  exception.message.split("\n").each do |line|
27
27
  output.puts "#{padding}#{red(line)}"
28
28
  end
29
+
30
+ example.example_group.ancestors.push(example.example_group).each do |group|
31
+ if group.metadata[:shared_group_name]
32
+ output.puts "#{padding}Shared Example Group: \"#{group.metadata[:shared_group_name]}\" called from " +
33
+ "#{backtrace_line(group.metadata[:example_group][:location])}"
34
+ break
35
+ end
36
+ end
29
37
  end
30
38
 
31
39
  format_backtrace(exception.backtrace, example).each do |backtrace_info|
@@ -48,18 +56,18 @@ module RSpec
48
56
 
49
57
  def dump_summary(duration, example_count, failure_count, pending_count)
50
58
  super(duration, example_count, failure_count, pending_count)
59
+ # Don't print out profiled info if there are failures, it just clutters the output
60
+ dump_profile if profile_examples? && failure_count == 0
51
61
  output.puts "\nFinished in #{format_seconds(duration)} seconds\n"
52
-
53
62
  output.puts colorise_summary(summary_line(example_count, failure_count, pending_count))
63
+ end
54
64
 
55
- # Don't print out profiled info if there are failures, it just clutters the output
56
- if profile_examples? && failure_count == 0
57
- sorted_examples = examples.sort_by { |example| example.execution_result[:run_time] }.reverse.first(10)
58
- output.puts "\nTop #{sorted_examples.size} slowest examples:\n"
59
- sorted_examples.each do |example|
60
- output.puts " (#{format_seconds(example.execution_result[:run_time])} seconds) #{example}"
61
- output.puts grey(" # #{format_caller(example.metadata[:location])}")
62
- end
65
+ def dump_profile
66
+ sorted_examples = examples.sort_by { |example| example.execution_result[:run_time] }.reverse.first(10)
67
+ output.puts "\nTop #{sorted_examples.size} slowest examples:\n"
68
+ sorted_examples.each do |example|
69
+ output.puts " #{example.full_description}"
70
+ output.puts grey(" #{red(format_seconds(example.execution_result[:run_time]))} #{red("seconds")} #{format_caller(example.metadata[:location])}")
63
71
  end
64
72
  end
65
73
 
@@ -6,20 +6,20 @@ module RSpec
6
6
 
7
7
  def initialize(output)
8
8
  super(output)
9
- @previous_nested_example_groups = []
9
+ @group_level = 0
10
10
  end
11
11
 
12
12
  def example_group_started(example_group)
13
13
  super(example_group)
14
14
 
15
- example_group_chain.each_with_index do |nested_example_group, i|
16
- unless nested_example_group == @previous_nested_example_groups[i]
17
- output.puts if i == 0
18
- output.puts "#{' ' * i}#{nested_example_group.description}"
19
- end
20
- end
15
+ output.puts if @group_level == 0
16
+ output.puts "#{' ' * @group_level}#{example_group.description}"
21
17
 
22
- @previous_nested_example_groups = example_group_chain
18
+ @group_level += 1
19
+ end
20
+
21
+ def example_group_finished(example_group)
22
+ @group_level -= 1
23
23
  end
24
24
 
25
25
  def example_passed(example)
@@ -55,7 +55,7 @@ module RSpec
55
55
  end
56
56
 
57
57
  def current_indentation
58
- ' ' * @previous_nested_example_groups.size
58
+ ' ' * @group_level
59
59
  end
60
60
 
61
61
  def example_group_chain
@@ -64,10 +64,6 @@ module RSpec::Core
64
64
  options[:line_number] = o
65
65
  end
66
66
 
67
- parser.on('-o', '--options PATH', 'Read configuration options from a file path. (Defaults to .rspec)') do |o|
68
- options[:options_file] = o || local_options_file
69
- end
70
-
71
67
  parser.on('-p', '--profile', 'Enable profiling of examples with output of the top 10 slowest examples') do |o|
72
68
  options[:profile_examples] = o
73
69
  end
@@ -8,57 +8,94 @@ module RSpec
8
8
 
9
9
  class RakeTask < ::Rake::TaskLib
10
10
 
11
- # Name of task. (default is :spec)
11
+ # Name of task.
12
+ #
13
+ # default:
14
+ # :spec
12
15
  attr_accessor :name
13
16
 
14
- # If true, requests that the specs be run with the warning flag set.
15
- # E.g. warning=true implies "ruby -w" used to run the specs. Defaults to false.
16
- attr_accessor :warning
17
-
18
- # Glob pattern to match files. (default is 'spec/**/*_spec.rb')
17
+ # Glob pattern to match files.
18
+ #
19
+ # default:
20
+ # 'spec/**/*_spec.rb'
19
21
  attr_accessor :pattern
20
22
 
21
- # Array of commandline options to pass to RSpec. Defaults to [].
22
- attr_accessor :spec_opts
23
-
24
- # The options to pass to ruby. Defaults to blank
25
- attr_accessor :ruby_opts
23
+ # Deprecated. Use ruby_opts="-w" instead.
24
+ # When true, requests that the specs be run with the warning flag set.
25
+ # e.g. "ruby -w"
26
+ #
27
+ # default:
28
+ # false
29
+ attr_reader :warning
30
+
31
+ def warning=(true_or_false)
32
+ RSpec.deprecate("warning", 'ruby_opts="-w"')
33
+ @warning = true_or_false
34
+ end
26
35
 
27
36
  # Whether or not to fail Rake when an error occurs (typically when examples fail).
28
- # Defaults to true.
37
+ #
38
+ # default:
39
+ # true
29
40
  attr_accessor :fail_on_error
30
41
 
31
42
  # A message to print to stderr when there are failures.
32
43
  attr_accessor :failure_message
33
44
 
34
- # Use verbose output. If this is set to true, the task will print
35
- # the executed spec command to stdout. Defaults to false.
45
+ # Use verbose output. If this is set to true, the task will print the
46
+ # executed spec command to stdout.
47
+ #
48
+ # default:
49
+ # false
36
50
  attr_accessor :verbose
37
51
 
38
- # Use rcov for code coverage? defaults to false
52
+ # Use rcov for code coverage?
53
+ #
54
+ # default:
55
+ # false
39
56
  attr_accessor :rcov
40
57
 
41
- # Path to rcov. You can set this to 'bundle exec rcov' if you bundle rcov.
58
+ # Path to rcov.
59
+ #
60
+ # defaults:
61
+ # 'rcov'
42
62
  attr_accessor :rcov_path
43
63
 
44
- # The options to pass to rcov. Defaults to blank
64
+ # Command line options to pass to rcov.
65
+ #
66
+ # default:
67
+ # nil
45
68
  attr_accessor :rcov_opts
46
69
 
70
+ # Command line options to pass to ruby.
71
+ #
72
+ # default:
73
+ # nil
74
+ attr_accessor :ruby_opts
75
+
76
+ # Command line options to pass to rspec.
77
+ #
78
+ # default:
79
+ # nil
80
+ attr_accessor :rspec_opts
81
+
82
+ # Deprecated. Use rspec_opts instead.
83
+ def spec_opts=(opts)
84
+ RSpec.deprecate("spec_opts","rspec_opts")
85
+ @rspec_opts = opts
86
+ end
87
+
47
88
  def initialize(*args)
48
89
  @name = args.shift || :spec
49
- @pattern, @rcov_path, @rcov_opts, @ruby_opts = nil, nil, nil, nil
90
+ @pattern, @rcov_path, @rcov_opts, @ruby_opts, @rspec_opts = nil, nil, nil, nil, nil
50
91
  @warning, @rcov = false, false
51
92
  @fail_on_error = true
52
- @spec_opts = []
53
93
 
54
94
  yield self if block_given?
95
+
55
96
  @rcov_path ||= 'rcov'
56
97
  @pattern ||= './spec/**/*_spec.rb'
57
- define
58
- end
59
98
 
60
- def define # :nodoc:
61
- actual_name = Hash === name ? name.keys.first : name
62
99
  desc("Run RSpec code examples") unless ::Rake.application.last_comment
63
100
 
64
101
  task name do
@@ -67,47 +104,56 @@ module RSpec
67
104
  puts "No examples matching #{pattern} could be found"
68
105
  else
69
106
  puts spec_command.inspect if verbose
70
- unless ruby("-S #{spec_command}")
107
+ unless ruby(spec_command)
71
108
  STDERR.puts failure_message if failure_message
72
109
  raise("#{spec_command} failed") if fail_on_error
73
110
  end
74
111
  end
75
112
  end
76
113
  end
77
-
78
- self
79
114
  end
80
115
 
81
116
  def files_to_run # :nodoc:
82
- FileList[ pattern ].to_a
117
+ FileList[ pattern ].map { |f| %["#{f}"] }
83
118
  end
84
119
 
85
120
  private
86
121
 
87
122
  def spec_command
88
123
  @spec_command ||= begin
89
- cmd_parts = %w[-Ilib -Ispec]
90
- cmd_parts << "-w" if warning
91
- cmd_parts.unshift runner_options
92
- cmd_parts.unshift runner
93
- cmd_parts.unshift bundler
94
- cmd_parts += files_to_run.map { |fn| %["#{fn}"] }
95
- cmd_parts << spec_opts.join(" ")
96
- cmd_parts.join(" ")
124
+ cmd_parts = [ruby_opts]
125
+ cmd_parts << "-w" if warning?
126
+ cmd_parts << "-S"
127
+ cmd_parts << "bundle exec" if bundler?
128
+ cmd_parts << runner
129
+ cmd_parts << runner_options
130
+ cmd_parts << files_to_run
131
+ cmd_parts.flatten.compact.reject(&blank).join(" ")
97
132
  end
98
133
  end
99
134
 
135
+ private
136
+
100
137
  def runner
101
- rcov ? rcov_path : RUBY
138
+ rcov ? rcov_path : 'rspec'
102
139
  end
103
140
 
104
141
  def runner_options
105
- rcov ? [rcov_opts] : [ruby_opts]
142
+ rcov ? [rcov_opts] : [rspec_opts]
106
143
  end
107
144
 
108
- def bundler
109
- File.exist?("./Gemfile") ? "bundle exec " : ""
145
+ def bundler?
146
+ File.exist?("./Gemfile")
110
147
  end
148
+
149
+ def warning?
150
+ warning
151
+ end
152
+
153
+ def blank
154
+ lambda {|s| s == ""}
155
+ end
156
+
111
157
  end
112
158
 
113
159
  end
@@ -2,13 +2,20 @@ module RSpec::Core
2
2
  class Reporter
3
3
  def initialize(*formatters)
4
4
  @formatters = formatters
5
- @failure_count = @pending_count = 0
5
+ @example_count = @failure_count = @pending_count = 0
6
6
  end
7
7
 
8
8
  def report(count)
9
9
  start(count)
10
10
  begin
11
11
  yield self
12
+ ensure
13
+ conclude
14
+ end
15
+ end
16
+
17
+ def conclude
18
+ begin
12
19
  stop
13
20
  notify :start_dump
14
21
  notify :dump_pending
@@ -19,10 +26,11 @@ module RSpec::Core
19
26
  end
20
27
  end
21
28
 
22
- def start(example_count)
23
- @example_count = example_count
29
+ alias_method :abort, :conclude
30
+
31
+ def start(expected_example_count)
24
32
  @start = Time.now
25
- notify :start, example_count
33
+ notify :start, expected_example_count
26
34
  end
27
35
 
28
36
  def message(message)
@@ -33,7 +41,12 @@ module RSpec::Core
33
41
  notify :example_group_started, group
34
42
  end
35
43
 
44
+ def example_group_finished(group)
45
+ notify :example_group_finished, group
46
+ end
47
+
36
48
  def example_started(example)
49
+ @example_count += 1
37
50
  notify :example_started, example
38
51
  end
39
52
 
@@ -52,7 +65,7 @@ module RSpec::Core
52
65
  end
53
66
 
54
67
  def stop
55
- @duration = Time.now - @start
68
+ @duration = Time.now - @start if @start
56
69
  notify :stop
57
70
  end
58
71
 
@@ -4,30 +4,20 @@ module RSpec
4
4
  module Core
5
5
  class Runner
6
6
 
7
- def self.autorun
8
- return if autorun_disabled? || installed_at_exit? || running_in_drb?
9
- @installed_at_exit = true
10
- at_exit { run(ARGV, $stderr, $stdout) ? exit(0) : exit(1) }
11
- end
12
-
13
- def self.autorun_disabled?
14
- @autorun_disabled ||= false
15
- end
16
-
17
7
  def self.disable_autorun!
18
- @autorun_disabled = true
8
+ RSpec.deprecate("disable_autorun!")
19
9
  end
20
10
 
21
- def self.installed_at_exit?
22
- @installed_at_exit ||= false
23
- end
24
-
25
- def self.running_in_drb?
26
- (DRb.current_server rescue false) &&
27
- !!((DRb.current_server.uri) =~ /druby\:\/\/127.0.0.1\:/)
11
+ def self.trap_interrupt
12
+ trap('INT') do
13
+ exit!(1) if RSpec.wants_to_quit
14
+ RSpec.wants_to_quit = true
15
+ STDERR.puts "\nExiting... Interrupt again to exit immediately."
16
+ end
28
17
  end
29
18
 
30
19
  def self.run(args, err, out)
20
+ trap_interrupt
31
21
  options = ConfigurationOptions.new(args)
32
22
  options.parse_options
33
23