rspec 1.1.2 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. data/CHANGES +17 -0
  2. data/Rakefile +7 -4
  3. data/failing_examples/README.txt +7 -0
  4. data/failing_examples/diffing_spec.rb +36 -0
  5. data/failing_examples/failing_autogenerated_docstrings_example.rb +19 -0
  6. data/failing_examples/failure_in_setup.rb +10 -0
  7. data/failing_examples/failure_in_teardown.rb +10 -0
  8. data/failing_examples/mocking_example.rb +40 -0
  9. data/failing_examples/mocking_with_flexmock.rb +26 -0
  10. data/failing_examples/mocking_with_mocha.rb +25 -0
  11. data/failing_examples/mocking_with_rr.rb +27 -0
  12. data/failing_examples/partial_mock_example.rb +20 -0
  13. data/failing_examples/predicate_example.rb +29 -0
  14. data/failing_examples/raising_example.rb +47 -0
  15. data/failing_examples/spec_helper.rb +3 -0
  16. data/failing_examples/syntax_error_example.rb +7 -0
  17. data/failing_examples/team_spec.rb +44 -0
  18. data/failing_examples/timeout_behaviour.rb +7 -0
  19. data/lib/autotest/rspec.rb +21 -35
  20. data/lib/spec.rb +0 -7
  21. data/lib/spec/example/example_group_methods.rb +10 -4
  22. data/lib/spec/example/example_methods.rb +4 -0
  23. data/lib/spec/interop/test.rb +3 -1
  24. data/lib/spec/interop/test/unit/ui/console/testrunner.rb +1 -0
  25. data/lib/spec/matchers/raise_error.rb +19 -15
  26. data/lib/spec/runner.rb +14 -0
  27. data/lib/spec/runner/formatter/story/html_formatter.rb +3 -0
  28. data/lib/spec/runner/formatter/story/plain_text_formatter.rb +4 -1
  29. data/lib/spec/runner/option_parser.rb +5 -33
  30. data/lib/spec/runner/options.rb +51 -18
  31. data/lib/spec/runner/spec_parser.rb +49 -31
  32. data/lib/spec/story/runner.rb +0 -2
  33. data/lib/spec/story/step.rb +8 -6
  34. data/lib/spec/story/world.rb +1 -0
  35. data/lib/spec/version.rb +22 -22
  36. data/pre_commit/lib/pre_commit.rb +4 -0
  37. data/pre_commit/lib/pre_commit/core.rb +50 -0
  38. data/pre_commit/lib/pre_commit/pre_commit.rb +54 -0
  39. data/pre_commit/lib/pre_commit/rspec.rb +111 -0
  40. data/pre_commit/lib/pre_commit/rspec_on_rails.rb +313 -0
  41. data/pre_commit/spec/pre_commit/pre_commit_spec.rb +15 -0
  42. data/pre_commit/spec/pre_commit/rspec_on_rails_spec.rb +36 -0
  43. data/pre_commit/spec/spec_helper.rb +3 -0
  44. data/pre_commit/spec/spec_suite.rb +11 -0
  45. data/rake_tasks/examples.rake +7 -0
  46. data/rake_tasks/examples_with_rcov.rake +9 -0
  47. data/rake_tasks/failing_examples_with_html.rake +9 -0
  48. data/rake_tasks/verify_rcov.rake +7 -0
  49. data/spec/README.jruby +15 -0
  50. data/spec/autotest/rspec_spec.rb +11 -80
  51. data/spec/autotest_helper.rb +2 -1
  52. data/spec/autotest_matchers.rb +47 -0
  53. data/spec/rspec_suite.rb +1 -1
  54. data/spec/spec.opts +6 -0
  55. data/spec/spec/example/example_group_methods_spec.rb +11 -2
  56. data/spec/spec/example/example_methods_spec.rb +69 -56
  57. data/spec/spec/interop/test/unit/resources/spec_that_fails.rb +10 -0
  58. data/spec/spec/interop/test/unit/resources/spec_that_passes.rb +10 -0
  59. data/spec/spec/interop/test/unit/resources/spec_with_errors.rb +10 -0
  60. data/spec/spec/interop/test/unit/resources/test_case_that_fails.rb +10 -0
  61. data/spec/spec/interop/test/unit/resources/test_case_that_passes.rb +10 -0
  62. data/spec/spec/interop/test/unit/resources/test_case_with_errors.rb +10 -0
  63. data/spec/spec/interop/test/unit/resources/testsuite_adapter_spec_with_test_unit.rb +38 -0
  64. data/spec/spec/interop/test/unit/spec_spec.rb +45 -0
  65. data/spec/spec/interop/test/unit/testcase_spec.rb +39 -4
  66. data/spec/spec/interop/test/unit/testsuite_adapter_spec.rb +1 -1
  67. data/spec/spec/matchers/raise_error_spec.rb +7 -1
  68. data/spec/spec/mocks/bug_report_10263.rb +1 -1
  69. data/spec/spec/runner/command_line_spec.rb +3 -2
  70. data/spec/spec/runner/empty_file.txt +0 -0
  71. data/spec/spec/runner/examples.txt +2 -0
  72. data/spec/spec/runner/failed.txt +3 -0
  73. data/spec/spec/runner/formatter/html_formatted-1.8.4.html +365 -0
  74. data/spec/spec/runner/formatter/html_formatted-1.8.5-jruby.html +387 -0
  75. data/spec/spec/runner/formatter/html_formatted-1.8.5.html +371 -0
  76. data/spec/spec/runner/formatter/html_formatted-1.8.6-jruby.html +381 -0
  77. data/spec/spec/runner/formatter/html_formatted-1.8.6.html +365 -0
  78. data/spec/spec/runner/formatter/story/plain_text_formatter_spec.rb +54 -54
  79. data/spec/spec/runner/formatter/text_mate_formatted-1.8.4.html +365 -0
  80. data/spec/spec/runner/formatter/text_mate_formatted-1.8.6.html +365 -0
  81. data/spec/spec/runner/option_parser_spec.rb +50 -49
  82. data/spec/spec/runner/options_spec.rb +72 -2
  83. data/spec/spec/runner/resources/a_bar.rb +0 -0
  84. data/spec/spec/runner/resources/a_foo.rb +0 -0
  85. data/spec/spec/runner/resources/a_spec.rb +1 -0
  86. data/spec/spec/runner/spec.opts +2 -0
  87. data/spec/spec/runner/spec_parser/spec_parser_fixture.rb +70 -0
  88. data/spec/spec/runner/spec_parser_spec.rb +31 -76
  89. data/spec/spec/runner/spec_spaced.opts +2 -0
  90. data/spec/spec/spec_classes.rb +4 -0
  91. data/spec/spec/story/step_spec.rb +22 -0
  92. data/spec/spec/story/world_spec.rb +7 -0
  93. data/stories/interop/test_case_with_should_methods +1 -1
  94. metadata +85 -5
  95. data/spec/spec/interop/test/unit/testcase_spec_with_test_unit.rb +0 -20
  96. data/spec/spec/interop/test/unit/testsuite_adapter_spec_with_test_unit.rb +0 -34
data/lib/spec.rb CHANGED
@@ -27,11 +27,4 @@ module Spec
27
27
  !Object.const_defined?(:Test) || Test::Unit.run?; \
28
28
  end
29
29
  end
30
- end
31
-
32
- at_exit do \
33
- unless $! || Spec.run?; \
34
- success = Spec.run; \
35
- exit success if Spec.exit?; \
36
- end \
37
30
  end
@@ -11,13 +11,14 @@ module Spec
11
11
  end
12
12
  end
13
13
 
14
- attr_reader :description_text, :description_args, :description_options, :spec_path
14
+ attr_reader :description_text, :description_args, :description_options, :spec_path, :registration_binding_block
15
15
 
16
16
  def inherited(klass)
17
17
  super
18
- klass.register
18
+ klass.register {}
19
+ Spec::Runner.register_at_exit_hook
19
20
  end
20
-
21
+
21
22
  # Makes the describe/it syntax available from a class. For example:
22
23
  #
23
24
  # class StackSpec < Spec::ExampleGroup
@@ -236,7 +237,8 @@ module Spec
236
237
  @after_each_parts = nil
237
238
  end
238
239
 
239
- def register
240
+ def register(&registration_binding_block)
241
+ @registration_binding_block = registration_binding_block
240
242
  rspec_options.add_example_group self
241
243
  end
242
244
 
@@ -244,6 +246,10 @@ module Spec
244
246
  rspec_options.remove_example_group self
245
247
  end
246
248
 
249
+ def registration_backtrace
250
+ eval("caller", registration_binding_block.binding)
251
+ end
252
+
247
253
  def run_before_each(example)
248
254
  execute_in_class_hierarchy do |example_group|
249
255
  example.eval_each_fail_fast(example_group.before_each_parts)
@@ -81,6 +81,10 @@ module Spec
81
81
  Spec::Matchers.clear_generated_description
82
82
  end
83
83
  end
84
+
85
+ def implementation_backtrace
86
+ eval("caller", @_implementation)
87
+ end
84
88
 
85
89
  protected
86
90
  include Matchers
@@ -7,4 +7,6 @@ require 'spec/interop/test/unit/autorunner'
7
7
  require 'spec/interop/test/unit/testresult'
8
8
  require 'spec/interop/test/unit/ui/console/testrunner'
9
9
 
10
- Spec::Example::ExampleGroupFactory.default(Test::Unit::TestCase)
10
+ Spec::Example::ExampleGroupFactory.default(Test::Unit::TestCase)
11
+
12
+ Test::Unit.run = true
@@ -36,6 +36,7 @@ module Test
36
36
 
37
37
  alias_method :finished_without_rspec, :finished
38
38
  def finished_with_rspec(elapsed_time)
39
+ @ran_test ||= false
39
40
  if @ran_test
40
41
  finished_without_rspec(elapsed_time)
41
42
  end
@@ -21,27 +21,31 @@ module Spec
21
21
  if @expected_message.nil?
22
22
  @raised_expected_error = true
23
23
  else
24
- case @expected_message
25
- when Regexp
26
- if @expected_message =~ @actual_error.message
27
- @raised_expected_error = true
28
- else
29
- @raised_other = true
30
- end
31
- else
32
- if @expected_message == @actual_error.message
33
- @raised_expected_error = true
34
- else
35
- @raised_other = true
36
- end
37
- end
24
+ verify_message
38
25
  end
39
- rescue => @actual_error
26
+ rescue Exception => @actual_error
40
27
  @raised_other = true
41
28
  ensure
42
29
  return @raised_expected_error
43
30
  end
44
31
  end
32
+
33
+ def verify_message
34
+ case @expected_message
35
+ when Regexp
36
+ if @expected_message =~ @actual_error.message
37
+ @raised_expected_error = true
38
+ else
39
+ @raised_other = true
40
+ end
41
+ else
42
+ if @expected_message == @actual_error.message
43
+ @raised_expected_error = true
44
+ else
45
+ @raised_other = true
46
+ end
47
+ end
48
+ end
45
49
 
46
50
  def failure_message
47
51
  return "expected #{expected_error}#{actual_error}" if @raised_other || !@raised_expected_error
data/lib/spec/runner.rb CHANGED
@@ -183,6 +183,20 @@ module Spec
183
183
  def configure
184
184
  yield configuration
185
185
  end
186
+
187
+ def register_at_exit_hook # :nodoc:
188
+ $spec_runner_at_exit_hook_registered ||= nil
189
+ unless $spec_runner_at_exit_hook_registered
190
+ at_exit do
191
+ unless $! || Spec.run?; \
192
+ success = Spec.run; \
193
+ exit success if Spec.exit?; \
194
+ end
195
+ end
196
+ $spec_runner_at_exit_hook_registered = true
197
+ end
198
+ end
199
+
186
200
  end
187
201
  end
188
202
  end
@@ -98,6 +98,9 @@ EOF
98
98
  scenario_ended
99
99
  end
100
100
 
101
+ def step_upcoming(type, description, *args)
102
+ end
103
+
101
104
  def step_succeeded(type, description, *args)
102
105
  print_step('passed', type, description, *args) # TODO: uses succeeded CSS class
103
106
  end
@@ -76,7 +76,10 @@ module Spec
76
76
  end
77
77
  end
78
78
  end
79
-
79
+
80
+ def step_upcoming(type, description, *args)
81
+ end
82
+
80
83
  def step_succeeded(type, description, *args)
81
84
  found_step(type, description, false, *args)
82
85
  end
@@ -15,6 +15,10 @@ module Spec
15
15
  attr_reader :options
16
16
 
17
17
  OPTIONS = {
18
+ :pattern => ["-p", "--pattern [PATTERN]","Limit files loaded to those matching this pattern. Defaults to '**/*_spec.rb'",
19
+ "Separate multiple patterns with commas.",
20
+ "Applies only to directories named on the command line (files",
21
+ "named explicitly on the command line will be loaded regardless)."],
18
22
  :diff => ["-D", "--diff [FORMAT]", "Show diff of objects that are expected to be equal when they are not",
19
23
  "Builtin formats: unified|u|context|c",
20
24
  "You can also specify a custom differ class",
@@ -84,11 +88,11 @@ module Spec
84
88
  @out_stream = out
85
89
  @options = Options.new(@error_stream, @out_stream)
86
90
 
87
- @spec_parser = SpecParser.new
88
91
  @file_factory = File
89
92
 
90
93
  self.banner = "Usage: spec (FILE|DIRECTORY|GLOB)+ [options]"
91
94
  self.separator ""
95
+ on(*OPTIONS[:pattern]) {|pattern| @options.filename_pattern = pattern}
92
96
  on(*OPTIONS[:diff]) {|diff| @options.parse_diff(diff)}
93
97
  on(*OPTIONS[:colour]) {@options.colour = true}
94
98
  on(*OPTIONS[:example]) {|example| @options.parse_example(example)}
@@ -124,10 +128,6 @@ module Spec
124
128
  blk.call(file) if blk
125
129
  end
126
130
 
127
- if @options.line_number
128
- set_spec_from_line_number
129
- end
130
-
131
131
  @options
132
132
  end
133
133
 
@@ -193,37 +193,9 @@ module Spec
193
193
  exit if stdout?
194
194
  end
195
195
 
196
- def set_spec_from_line_number
197
- if @options.examples.empty?
198
- if @options.files.length == 1
199
- if @file_factory.file?(@options.files[0])
200
- source = @file_factory.open(@options.files[0])
201
- example = @spec_parser.spec_name_for(source, @options.line_number)
202
- @options.parse_example(example)
203
- elsif @file_factory.directory?(@options.files[0])
204
- @error_stream.puts "You must specify one file, not a directory when using the --line option"
205
- exit(1) if stderr?
206
- else
207
- @error_stream.puts "#{@options.files[0]} does not exist"
208
- exit(2) if stderr?
209
- end
210
- else
211
- @error_stream.puts "Only one file can be specified when using the --line option: #{@options.files.inspect}"
212
- exit(3) if stderr?
213
- end
214
- else
215
- @error_stream.puts "You cannot use both --line and --example"
216
- exit(4) if stderr?
217
- end
218
- end
219
-
220
196
  def stdout?
221
197
  @out_stream == $stdout
222
198
  end
223
-
224
- def stderr?
225
- @error_stream == $stderr
226
- end
227
199
  end
228
200
  end
229
201
  end
@@ -29,6 +29,7 @@ module Spec
29
29
  }
30
30
 
31
31
  attr_accessor(
32
+ :filename_pattern,
32
33
  :backtrace_tweaker,
33
34
  :context_lines,
34
35
  :diff_format,
@@ -53,6 +54,7 @@ module Spec
53
54
  def initialize(error_stream, output_stream)
54
55
  @error_stream = error_stream
55
56
  @output_stream = output_stream
57
+ @filename_pattern = "**/*_spec.rb"
56
58
  @backtrace_tweaker = QuietBacktraceTweaker.new
57
59
  @examples = []
58
60
  @colour = false
@@ -84,6 +86,7 @@ module Spec
84
86
  if example_groups.empty?
85
87
  true
86
88
  else
89
+ set_spec_from_line_number if line_number
87
90
  success = runner.run
88
91
  @examples_run = true
89
92
  heckle if heckle_runner
@@ -101,10 +104,14 @@ module Spec
101
104
 
102
105
  def colour=(colour)
103
106
  @colour = colour
104
- begin; \
105
- require 'Win32/Console/ANSI' if @colour && PLATFORM =~ /win32/; \
106
- rescue LoadError ; \
107
- raise "You must gem install win32console to use colour on Windows" ; \
107
+ if @colour && RUBY_PLATFORM =~ /win32/ ;\
108
+ begin ;\
109
+ require 'rubygems' ;\
110
+ require 'Win32/Console/ANSI' ;\
111
+ rescue LoadError ;\
112
+ warn "You must 'gem install win32console' to use colour on Windows" ;\
113
+ @colour = false ;\
114
+ end
108
115
  end
109
116
  end
110
117
 
@@ -175,6 +182,22 @@ module Spec
175
182
  end
176
183
  end
177
184
 
185
+ def files_to_load
186
+ result = []
187
+ sorted_files.each do |file|
188
+ if File.directory?(file)
189
+ filename_pattern.split(",").each do |pattern|
190
+ result += Dir[File.expand_path("#{file}/#{pattern.strip}")]
191
+ end
192
+ elsif File.file?(file)
193
+ result << file
194
+ else
195
+ raise "File or directory not found: #{file}"
196
+ end
197
+ end
198
+ result
199
+ end
200
+
178
201
  protected
179
202
  def examples_should_be_run?
180
203
  return @examples_should_be_run unless @examples_should_be_run.nil?
@@ -205,20 +228,6 @@ module Spec
205
228
  end
206
229
  end
207
230
 
208
- def files_to_load
209
- result = []
210
- sorted_files.each do |file|
211
- if test ?d, file
212
- result += Dir[File.expand_path("#{file}/**/*.rb")]
213
- elsif test ?f, file
214
- result << file
215
- else
216
- raise "File or directory not found: #{file}"
217
- end
218
- end
219
- result
220
- end
221
-
222
231
  def custom_runner
223
232
  return nil unless custom_runner?
224
233
  klass_name, arg = ClassAndArgumentsParser.parse(user_input_for_runner)
@@ -248,6 +257,30 @@ module Spec
248
257
  require 'spec/expectations/differs/default'
249
258
  self.differ_class = Spec::Expectations::Differs::Default
250
259
  end
260
+
261
+ def set_spec_from_line_number
262
+ if examples.empty?
263
+ if files.length == 1
264
+ if File.directory?(files[0])
265
+ error_stream.puts "You must specify one file, not a directory when using the --line option"
266
+ exit(1) if stderr?
267
+ else
268
+ example = SpecParser.new.spec_name_for(files[0], line_number)
269
+ @examples = [example]
270
+ end
271
+ else
272
+ error_stream.puts "Only one file can be specified when using the --line option: #{files.inspect}"
273
+ exit(3) if stderr?
274
+ end
275
+ else
276
+ error_stream.puts "You cannot use both --line and --example"
277
+ exit(4) if stderr?
278
+ end
279
+ end
280
+
281
+ def stderr?
282
+ @error_stream == $stderr
283
+ end
251
284
  end
252
285
  end
253
286
  end
@@ -2,14 +2,28 @@ module Spec
2
2
  module Runner
3
3
  # Parses a spec file and finds the nearest example for a given line number.
4
4
  class SpecParser
5
- def spec_name_for(io, line_number)
6
- source = io.read
7
- example_group, example_group_line = example_group_at_line(source, line_number)
8
- example, example_line = example_at_line(source, line_number)
9
- if example_group && example && (example_group_line < example_line)
10
- "#{example_group} #{example}"
11
- elsif example_group
12
- example_group
5
+ attr_reader :best_match
6
+
7
+ def initialize
8
+ @best_match = {}
9
+ end
10
+
11
+ def spec_name_for(file, line_number)
12
+ best_match.clear
13
+ file = File.expand_path(file)
14
+ rspec_options.example_groups.each do |example_group|
15
+ consider_example_groups_for_best_match example_group, file, line_number
16
+
17
+ example_group.examples.each do |example|
18
+ consider_example_for_best_match example, example_group, file, line_number
19
+ end
20
+ end
21
+ if best_match[:example_group]
22
+ if best_match[:example]
23
+ "#{best_match[:example_group].description} #{best_match[:example].description}"
24
+ else
25
+ best_match[:example_group].description
26
+ end
13
27
  else
14
28
  nil
15
29
  end
@@ -17,36 +31,40 @@ module Spec
17
31
 
18
32
  protected
19
33
 
20
- def example_group_at_line(source, line_number)
21
- find_above(source, line_number, /^\s*(context|describe)\s+(.*)\s+do/)
22
- end
23
-
24
- def example_at_line(source, line_number)
25
- find_above(source, line_number, /^\s*(specify|it)\s+(.*)\s+do/)
34
+ def consider_example_groups_for_best_match(example_group, file, line_number)
35
+ parsed_backtrace = parse_backtrace(example_group.registration_backtrace)
36
+ parsed_backtrace.each do |example_file, example_line|
37
+ if is_best_match?(file, line_number, example_file, example_line)
38
+ best_match.clear
39
+ best_match[:example_group] = example_group
40
+ best_match[:line] = example_line
41
+ end
42
+ end
26
43
  end
27
44
 
28
- # Returns the context/describe or specify/it name and the line number
29
- def find_above(source, line_number, pattern)
30
- lines_above_reversed(source, line_number).each_with_index do |line, n|
31
- return [parse_description($2), line_number-n] if line =~ pattern
45
+ def consider_example_for_best_match(example, example_group, file, line_number)
46
+ parsed_backtrace = parse_backtrace(example.implementation_backtrace)
47
+ parsed_backtrace.each do |example_file, example_line|
48
+ if is_best_match?(file, line_number, example_file, example_line)
49
+ best_match.clear
50
+ best_match[:example_group] = example_group
51
+ best_match[:example] = example
52
+ best_match[:line] = example_line
53
+ end
32
54
  end
33
- nil
34
55
  end
35
56
 
36
- def lines_above_reversed(source, line_number)
37
- lines = source.split("\n")
38
- lines[0...line_number].reverse
57
+ def is_best_match?(file, line_number, example_file, example_line)
58
+ file == File.expand_path(example_file) &&
59
+ example_line <= line_number &&
60
+ example_line > best_match[:line].to_i
39
61
  end
40
-
41
- def parse_description(str)
42
- return str[1..-2] if str =~ /^['"].*['"]$/
43
- if matches = /^['"](.*)['"](,.*)?$/.match(str)
44
- return ::Spec::Example::ExampleGroupMethods.description_text(matches[1])
45
- end
46
- if matches = /^(.*)\s*,\s*['"](.*)['"](,.*)?$/.match(str)
47
- return ::Spec::Example::ExampleGroupMethods.description_text(matches[1], matches[2])
62
+
63
+ def parse_backtrace(backtrace)
64
+ backtrace.collect do |trace_line|
65
+ split_line = trace_line.split(':')
66
+ [split_line[0], Integer(split_line[1])]
48
67
  end
49
- return str
50
68
  end
51
69
  end
52
70
  end