rspec 1.1.4 → 1.1.5

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 (157) hide show
  1. data/{CHANGES → History.txt} +116 -64
  2. data/Manifest.txt +403 -0
  3. data/{MIT-LICENSE → README.txt} +43 -0
  4. data/Rakefile +39 -212
  5. data/{TODO → TODO.txt} +0 -0
  6. data/bin/autospec +4 -0
  7. data/bin/spec +1 -1
  8. data/examples/pure/yielding_example.rb +33 -0
  9. data/examples/stories/game-of-life/.loadpath +5 -0
  10. data/examples/stories/game-of-life/behaviour/everything.rb +1 -1
  11. data/examples/stories/game-of-life/behaviour/stories/CellsWithMoreThanThreeNeighboursDie.story +17 -17
  12. data/init.rb +9 -0
  13. data/lib/autotest/discover.rb +1 -1
  14. data/lib/autotest/rspec.rb +3 -29
  15. data/lib/spec.rb +10 -12
  16. data/lib/spec/adapters.rb +1 -0
  17. data/lib/spec/adapters/ruby_engine.rb +26 -0
  18. data/lib/spec/adapters/ruby_engine/mri.rb +8 -0
  19. data/lib/spec/adapters/ruby_engine/rubinius.rb +8 -0
  20. data/lib/spec/example/errors.rb +6 -0
  21. data/lib/spec/example/example_group_methods.rb +17 -14
  22. data/lib/spec/example/example_matcher.rb +2 -0
  23. data/lib/spec/example/example_methods.rb +4 -9
  24. data/lib/spec/example/module_inclusion_warnings.rb +2 -1
  25. data/lib/spec/expectations/extensions/object.rb +2 -2
  26. data/lib/spec/expectations/handler.rb +8 -16
  27. data/lib/spec/extensions/main.rb +2 -17
  28. data/lib/spec/matchers.rb +8 -2
  29. data/lib/spec/matchers/be.rb +0 -3
  30. data/lib/spec/matchers/change.rb +44 -40
  31. data/lib/spec/matchers/has.rb +1 -1
  32. data/lib/spec/matchers/have.rb +17 -12
  33. data/lib/spec/matchers/operator_matcher.rb +10 -4
  34. data/lib/spec/matchers/simple_matcher.rb +113 -10
  35. data/lib/spec/mocks.rb +1 -1
  36. data/lib/spec/mocks/argument_constraints.rb +185 -0
  37. data/lib/spec/mocks/argument_expectation.rb +35 -173
  38. data/lib/spec/mocks/framework.rb +1 -1
  39. data/lib/spec/mocks/message_expectation.rb +30 -5
  40. data/lib/spec/mocks/methods.rb +14 -2
  41. data/lib/spec/mocks/mock.rb +4 -0
  42. data/lib/spec/mocks/proxy.rb +46 -5
  43. data/lib/spec/mocks/spec_methods.rb +9 -1
  44. data/lib/spec/rake/spectask.rb +14 -22
  45. data/lib/spec/rake/verify_rcov.rb +3 -3
  46. data/lib/spec/runner.rb +18 -6
  47. data/lib/spec/runner/backtrace_tweaker.rb +6 -7
  48. data/lib/spec/runner/command_line.rb +6 -17
  49. data/lib/spec/runner/drb_command_line.rb +1 -1
  50. data/lib/spec/runner/formatter/base_formatter.rb +3 -1
  51. data/lib/spec/runner/formatter/base_text_formatter.rb +5 -9
  52. data/lib/spec/runner/formatter/html_formatter.rb +1 -1
  53. data/lib/spec/runner/formatter/nested_text_formatter.rb +1 -1
  54. data/lib/spec/runner/formatter/progress_bar_formatter.rb +2 -2
  55. data/lib/spec/runner/formatter/specdoc_formatter.rb +1 -1
  56. data/lib/spec/runner/formatter/story/html_formatter.rb +62 -16
  57. data/lib/spec/runner/formatter/story/plain_text_formatter.rb +68 -16
  58. data/lib/spec/runner/formatter/story/progress_bar_formatter.rb +42 -0
  59. data/lib/spec/runner/heckle_runner.rb +2 -2
  60. data/lib/spec/runner/option_parser.rb +2 -1
  61. data/lib/spec/runner/options.rb +18 -9
  62. data/lib/spec/runner/reporter.rb +24 -4
  63. data/lib/spec/runner/spec_parser.rb +1 -1
  64. data/lib/spec/story/runner.rb +1 -2
  65. data/lib/spec/story/runner/story_mediator.rb +14 -0
  66. data/lib/spec/story/runner/story_parser.rb +20 -0
  67. data/lib/spec/story/step.rb +40 -28
  68. data/lib/spec/story/step_mother.rb +2 -1
  69. data/lib/spec/story/world.rb +6 -2
  70. data/lib/spec/version.rb +13 -22
  71. data/rake_tasks/failing_examples_with_html.rake +1 -1
  72. data/rake_tasks/verify_rcov.rake +2 -2
  73. data/rspec.gemspec +33 -0
  74. data/spec/autotest/rspec_spec.rb +90 -141
  75. data/spec/spec/adapters/ruby_engine_spec.rb +16 -0
  76. data/spec/spec/example/base_formatter_spec.rb +112 -0
  77. data/spec/spec/example/example_group_factory_spec.rb +2 -2
  78. data/spec/spec/example/example_group_methods_spec.rb +55 -4
  79. data/spec/spec/example/example_group_spec.rb +4 -3
  80. data/spec/spec/example/example_methods_spec.rb +18 -14
  81. data/spec/spec/example/pending_module_spec.rb +38 -0
  82. data/spec/spec/example/shared_example_group_spec.rb +1 -1
  83. data/spec/spec/expectations/extensions/object_spec.rb +0 -12
  84. data/spec/spec/extensions/main_spec.rb +3 -8
  85. data/spec/spec/matchers/change_spec.rb +16 -6
  86. data/spec/spec/matchers/handler_spec.rb +58 -37
  87. data/spec/spec/matchers/has_spec.rb +10 -0
  88. data/spec/spec/matchers/have_spec.rb +105 -2
  89. data/spec/spec/matchers/operator_matcher_spec.rb +35 -2
  90. data/spec/spec/matchers/simple_matcher_spec.rb +64 -2
  91. data/spec/spec/mocks/any_number_of_times_spec.rb +7 -0
  92. data/spec/spec/mocks/bug_report_496.rb +17 -0
  93. data/spec/spec/mocks/failing_mock_argument_constraints_spec.rb +7 -1
  94. data/spec/spec/mocks/hash_including_matcher_spec.rb +45 -24
  95. data/spec/spec/mocks/mock_spec.rb +55 -10
  96. data/spec/spec/mocks/nil_expectation_warning_spec.rb +54 -0
  97. data/spec/spec/mocks/null_object_mock_spec.rb +14 -0
  98. data/spec/spec/mocks/options_hash_spec.rb +18 -28
  99. data/spec/spec/mocks/partial_mock_spec.rb +2 -0
  100. data/spec/spec/mocks/passing_mock_argument_constraints_spec.rb +20 -6
  101. data/spec/spec/mocks/stub_spec.rb +7 -0
  102. data/spec/spec/runner/command_line_spec.rb +5 -12
  103. data/spec/spec/runner/drb_command_line_spec.rb +13 -6
  104. data/spec/spec/runner/formatter/html_formatter_spec.rb +2 -1
  105. data/spec/spec/runner/formatter/nested_text_formatter_spec.rb +3 -3
  106. data/spec/spec/runner/formatter/progress_bar_formatter_spec.rb +20 -2
  107. data/spec/spec/runner/formatter/spec_mate_formatter_spec.rb +2 -1
  108. data/spec/spec/runner/formatter/specdoc_formatter_spec.rb +3 -3
  109. data/spec/spec/runner/formatter/story/html_formatter_spec.rb +76 -2
  110. data/spec/spec/runner/formatter/story/plain_text_formatter_spec.rb +161 -0
  111. data/spec/spec/runner/formatter/story/progress_bar_formatter_spec.rb +82 -0
  112. data/spec/spec/runner/heckle_runner_spec.rb +8 -8
  113. data/spec/spec/runner/option_parser_spec.rb +21 -6
  114. data/spec/spec/runner/output_one_time_fixture_runner.rb +1 -1
  115. data/spec/spec/runner/quiet_backtrace_tweaker_spec.rb +6 -0
  116. data/spec/spec/runner/reporter_spec.rb +51 -5
  117. data/spec/spec/runner/spec_parser_spec.rb +4 -4
  118. data/spec/spec/story/runner/plain_text_story_runner_spec.rb +2 -5
  119. data/spec/spec/story/runner/story_mediator_spec.rb +10 -0
  120. data/spec/spec/story/runner/story_parser_spec.rb +23 -6
  121. data/spec/spec/story/scenario_spec.rb +1 -3
  122. data/spec/spec/story/step_mother_spec.rb +12 -0
  123. data/spec/spec/story/step_spec.rb +57 -4
  124. data/spec/spec/story/story_spec.rb +1 -3
  125. data/spec/spec/story/world_spec.rb +1 -1
  126. data/spec/spec_helper.rb +21 -68
  127. data/stories/all.rb +1 -1
  128. data/stories/configuration/before_blocks.story +21 -0
  129. data/stories/configuration/stories.rb +7 -0
  130. data/stories/example_groups/stories.rb +3 -4
  131. data/stories/resources/spec/before_blocks_example.rb +32 -0
  132. data/stories/stories/multiline_steps.story +23 -0
  133. data/stories/stories/steps/multiline_steps.rb +13 -0
  134. data/stories/stories/stories.rb +6 -0
  135. data/story_server/prototype/javascripts/builder.js +136 -0
  136. data/story_server/prototype/javascripts/controls.js +972 -0
  137. data/story_server/prototype/javascripts/dragdrop.js +976 -0
  138. data/story_server/prototype/javascripts/effects.js +1117 -0
  139. data/story_server/prototype/javascripts/prototype.js +4140 -0
  140. data/story_server/prototype/javascripts/rspec.js +149 -0
  141. data/story_server/prototype/javascripts/scriptaculous.js +58 -0
  142. data/story_server/prototype/javascripts/slider.js +276 -0
  143. data/story_server/prototype/javascripts/sound.js +55 -0
  144. data/story_server/prototype/javascripts/unittest.js +568 -0
  145. data/story_server/prototype/lib/server.rb +24 -0
  146. data/story_server/prototype/stories.html +176 -0
  147. data/story_server/prototype/stylesheets/rspec.css +136 -0
  148. data/story_server/prototype/stylesheets/test.css +90 -0
  149. metadata +166 -166
  150. data/README +0 -36
  151. data/UPGRADE +0 -7
  152. data/bin/spec_translator +0 -8
  153. data/lib/spec/mocks/argument_constraint_matchers.rb +0 -31
  154. data/lib/spec/translator.rb +0 -114
  155. data/spec/spec/example/example_spec.rb +0 -53
  156. data/spec/spec/runner/execution_context_spec.rb +0 -37
  157. data/spec/spec/translator_spec.rb +0 -265
@@ -9,8 +9,12 @@ module Spec
9
9
  __mock_proxy.add_negative_message_expectation(caller(1)[0], sym.to_sym, &block)
10
10
  end
11
11
 
12
- def stub!(sym, opts={})
13
- __mock_proxy.add_stub(caller(1)[0], sym.to_sym, opts)
12
+ def stub!(sym_or_hash, opts={})
13
+ if Hash === sym_or_hash
14
+ sym_or_hash.each {|method, value| stub!(method).and_return value }
15
+ else
16
+ __mock_proxy.add_stub(caller(1)[0], sym_or_hash.to_sym, opts)
17
+ end
14
18
  end
15
19
 
16
20
  def received_message?(sym, *args, &block) #:nodoc:
@@ -24,6 +28,14 @@ module Spec
24
28
  def rspec_reset #:nodoc:
25
29
  __mock_proxy.reset
26
30
  end
31
+
32
+ def as_null_object
33
+ __mock_proxy.act_as_null_object
34
+ end
35
+
36
+ def null_object?
37
+ __mock_proxy.null_object?
38
+ end
27
39
 
28
40
  private
29
41
 
@@ -36,6 +36,10 @@ module Spec
36
36
  "#<#{self.class}:#{sprintf '0x%x', self.object_id} @name=#{@name.inspect}>"
37
37
  end
38
38
 
39
+ def to_s
40
+ inspect.gsub('<','[').gsub('>',']')
41
+ end
42
+
39
43
  private
40
44
 
41
45
  def parse_options(options)
@@ -4,6 +4,16 @@ module Spec
4
4
  DEFAULT_OPTIONS = {
5
5
  :null_object => false,
6
6
  }
7
+
8
+ @@warn_about_expectations_on_nil = true
9
+
10
+ def self.allow_message_expectations_on_nil
11
+ @@warn_about_expectations_on_nil = false
12
+
13
+ # ensure nil.rspec_verify is called even if an expectation is not set in the example
14
+ # otherwise the allowance would effect subsequent examples
15
+ $rspec_mocks.add(nil) unless $rspec_mocks.nil?
16
+ end
7
17
 
8
18
  def initialize(target, name, options={})
9
19
  @target = target
@@ -20,15 +30,27 @@ module Spec
20
30
  def null_object?
21
31
  @options[:null_object]
22
32
  end
33
+
34
+ def act_as_null_object
35
+ @options[:null_object] = true
36
+ @target
37
+ end
23
38
 
24
- def add_message_expectation(expected_from, sym, opts={}, &block)
39
+ def add_message_expectation(expected_from, sym, opts={}, &block)
25
40
  __add sym
26
- @expectations << MessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, block_given? ? block : nil, 1, opts)
41
+ warn_if_nil_class sym
42
+ if existing_stub = @stubs.detect {|s| s.sym == sym }
43
+ expectation = existing_stub.build_child(expected_from, block_given?? block : nil, 1, opts)
44
+ else
45
+ expectation = MessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, block_given? ? block : nil, 1, opts)
46
+ end
47
+ @expectations << expectation
27
48
  @expectations.last
28
49
  end
29
50
 
30
51
  def add_negative_message_expectation(expected_from, sym, &block)
31
52
  __add sym
53
+ warn_if_nil_class sym
32
54
  @expectations << NegativeMessageExpectation.new(@error_generator, @expectation_ordering, expected_from, sym, block_given? ? block : nil)
33
55
  @expectations.last
34
56
  end
@@ -50,6 +72,7 @@ module Spec
50
72
  clear_stubs
51
73
  reset_proxied_methods
52
74
  clear_proxied_methods
75
+ reset_nil_expectations_warning
53
76
  end
54
77
 
55
78
  def received_message?(sym, *args, &block)
@@ -61,13 +84,17 @@ module Spec
61
84
  end
62
85
 
63
86
  def message_received(sym, *args, &block)
64
- if expectation = find_matching_expectation(sym, *args)
65
- expectation.invoke(args, block)
66
- elsif (stub = find_matching_method_stub(sym, *args))
87
+ expectation = find_matching_expectation(sym, *args)
88
+ stub = find_matching_method_stub(sym, *args)
89
+
90
+ if (stub && expectation && expectation.called_max_times?) ||
91
+ (stub && !expectation)
67
92
  if expectation = find_almost_matching_expectation(sym, *args)
68
93
  expectation.advise(args, block) unless expectation.expected_messages_received?
69
94
  end
70
95
  stub.invoke([], block)
96
+ elsif expectation
97
+ expectation.invoke(args, block)
71
98
  elsif expectation = find_almost_matching_expectation(sym, *args)
72
99
  expectation.advise(args, block) if null_object? unless expectation.expected_messages_received?
73
100
  raise_unexpected_message_args_error(expectation, *args) unless (has_negative_expectation?(sym) or null_object?)
@@ -91,6 +118,12 @@ module Spec
91
118
  define_expected_method(sym)
92
119
  end
93
120
 
121
+ def warn_if_nil_class(sym)
122
+ if proxy_for_nil_class? && @@warn_about_expectations_on_nil
123
+ Kernel.warn("An expectation of :#{sym} was set on nil. Called from #{caller[2]}. Use allow_message_expectations_on_nil to disable warnings.")
124
+ end
125
+ end
126
+
94
127
  def define_expected_method(sym)
95
128
  visibility_string = "#{visibility(sym)} :#{sym}"
96
129
  if target_responds_to?(sym) && !target_metaclass.method_defined?(munge(sym))
@@ -166,6 +199,14 @@ module Spec
166
199
  end
167
200
  end
168
201
  end
202
+
203
+ def proxy_for_nil_class?
204
+ @name == "NilClass"
205
+ end
206
+
207
+ def reset_nil_expectations_warning
208
+ @@warn_about_expectations_on_nil = true if proxy_for_nil_class?
209
+ end
169
210
 
170
211
  def find_matching_expectation(sym, *args)
171
212
  @expectations.find {|expectation| expectation.matches(sym, args)}
@@ -1,7 +1,7 @@
1
1
  module Spec
2
2
  module Mocks
3
3
  module ExampleMethods
4
- include Spec::Mocks::ArgumentConstraintMatchers
4
+ include Spec::Mocks::ArgumentConstraints
5
5
 
6
6
  # Shortcut for creating an instance of Spec::Mocks::Mock.
7
7
  #
@@ -32,6 +32,14 @@ module Spec
32
32
  def stub_everything(name = 'stub')
33
33
  mock(name, :null_object => true)
34
34
  end
35
+
36
+ # Disables warning messages about expectations being set on nil.
37
+ #
38
+ # By default warning messages are issued when expectations are set on nil. This is to
39
+ # prevent false-positives and to catch potential bugs early on.
40
+ def allow_message_expectations_on_nil
41
+ Proxy.allow_message_expectations_on_nil
42
+ end
35
43
 
36
44
  end
37
45
  end
@@ -155,30 +155,23 @@ module Spec
155
155
  # ruby [ruby_opts] -Ilib -S rcov [rcov_opts] bin/spec -- examples [spec_opts]
156
156
  # or
157
157
  # ruby [ruby_opts] -Ilib bin/spec examples [spec_opts]
158
- cmd = "#{File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])} "
159
-
160
- rb_opts = ruby_opts.clone
161
- rb_opts << "-I\"#{lib_path}\""
162
- rb_opts << "-S rcov" if rcov
163
- rb_opts << "-w" if warning
164
- cmd << rb_opts.join(" ")
165
- cmd << " "
166
- cmd << rcov_option_list
167
- cmd << %[ -o "#{rcov_dir}" ] if rcov
168
- cmd << %Q|"#{spec_script}"|
169
- cmd << " "
170
- cmd << "-- " if rcov
171
- cmd << spec_file_list.collect { |fn| %["#{fn}"] }.join(' ')
172
- cmd << " "
173
- cmd << spec_option_list
158
+ cmd_parts = [RUBY]
159
+ cmd_parts += ruby_opts
160
+ cmd_parts << %[-I"#{lib_path}"]
161
+ cmd_parts << "-S rcov" if rcov
162
+ cmd_parts << "-w" if warning
163
+ cmd_parts << rcov_option_list
164
+ cmd_parts << %[-o "#{rcov_dir}"] if rcov
165
+ cmd_parts << %["#{spec_script}"]
166
+ cmd_parts << "--" if rcov
167
+ cmd_parts += spec_file_list.collect { |fn| %["#{fn}"] }
168
+ cmd_parts << spec_option_list
174
169
  if out
175
- cmd << " "
176
- cmd << %Q| > "#{out}"|
170
+ cmd_parts << %[> "#{out}"]
177
171
  STDERR.puts "The Spec::Rake::SpecTask#out attribute is DEPRECATED and will be removed in a future version. Use --format FORMAT:WHERE instead."
178
172
  end
179
- if verbose
180
- puts cmd
181
- end
173
+ cmd = cmd_parts.join(" ")
174
+ puts cmd if verbose
182
175
  unless system(cmd)
183
176
  STDERR.puts failure_message if failure_message
184
177
  raise("Command #{cmd} failed") if fail_on_error
@@ -232,4 +225,3 @@ module Spec
232
225
  end
233
226
  end
234
227
  end
235
-
@@ -35,11 +35,11 @@ module RCov
35
35
  def define
36
36
  desc "Verify that rcov coverage is at least #{threshold}%"
37
37
  task @name do
38
- total_coverage = nil
38
+ total_coverage = 0
39
39
 
40
40
  File.open(index_html).each_line do |line|
41
- if line =~ /<tt class='coverage_total'>(\d+\.\d+)%<\/tt>/
42
- total_coverage = eval($1)
41
+ if line =~ /<tt class='coverage_total'>\s*(\d+\.\d+)%\s*<\/tt>/
42
+ total_coverage = $1.to_f
43
43
  break
44
44
  end
45
45
  end
@@ -185,18 +185,30 @@ module Spec
185
185
  end
186
186
 
187
187
  def register_at_exit_hook # :nodoc:
188
- $spec_runner_at_exit_hook_registered ||= nil
189
- unless $spec_runner_at_exit_hook_registered
188
+ @spec_runner_at_exit_hook_registered ||= nil
189
+ unless @spec_runner_at_exit_hook_registered
190
190
  at_exit do
191
- unless $! || Spec.run?; \
192
- success = Spec.run; \
193
- exit success if Spec.exit?; \
191
+ unless $! || Spec.run?
192
+ success = Spec.run
193
+ exit success if Spec.exit?
194
194
  end
195
195
  end
196
- $spec_runner_at_exit_hook_registered = true
196
+ @spec_runner_at_exit_hook_registered = true
197
+ end
198
+ end
199
+
200
+ def options # :nodoc:
201
+ @options ||= begin
202
+ parser = ::Spec::Runner::OptionParser.new(STDERR, STDOUT)
203
+ parser.order!(ARGV)
204
+ parser.options
197
205
  end
198
206
  end
199
207
 
208
+ def use options
209
+ @options = options
210
+ end
211
+
200
212
  end
201
213
  end
202
214
  end
@@ -40,15 +40,14 @@ module Spec
40
40
 
41
41
  def tweak_backtrace(error)
42
42
  return if error.backtrace.nil?
43
- error.backtrace.collect! do |line|
44
- clean_up_double_slashes(line)
45
- IGNORE_PATTERNS.each do |ignore|
46
- if line =~ ignore
47
- line = nil
48
- break
43
+ error.backtrace.collect! do |message|
44
+ clean_up_double_slashes(message)
45
+ kept_lines = message.split("\n").select do |line|
46
+ IGNORE_PATTERNS.each do |ignore|
47
+ break if line =~ ignore
49
48
  end
50
49
  end
51
- line
50
+ kept_lines.empty?? nil : kept_lines.join("\n")
52
51
  end
53
52
  error.backtrace.compact!
54
53
  end
@@ -2,25 +2,14 @@ require 'spec/runner/option_parser'
2
2
 
3
3
  module Spec
4
4
  module Runner
5
- # Facade to run specs without having to fork a new ruby process (using `spec ...`)
6
5
  class CommandLine
7
6
  class << self
8
- # Runs specs. +argv+ is the commandline args as per the spec commandline API, +err+
9
- # and +out+ are the streams output will be written to.
10
- def run(instance_rspec_options)
11
- # NOTE - this call to init_rspec_options is not spec'd, but neither is any of this
12
- # swapping of $rspec_options. That is all here to enable rspec to run against itself
13
- # and maintain coverage in a single process. Therefore, DO NOT mess with this stuff
14
- # unless you know what you are doing!
15
- init_rspec_options(instance_rspec_options)
16
- orig_rspec_options = rspec_options
17
- begin
18
- $rspec_options = instance_rspec_options
19
- return $rspec_options.run_examples
20
- ensure
21
- ::Spec.run = true
22
- $rspec_options = orig_rspec_options
23
- end
7
+ def run(tmp_options=Spec::Runner.options)
8
+ orig_options = Spec::Runner.options
9
+ Spec::Runner.use tmp_options
10
+ tmp_options.run_examples
11
+ ensure
12
+ Spec::Runner.use orig_options
24
13
  end
25
14
  end
26
15
  end
@@ -9,7 +9,7 @@ module Spec
9
9
  def self.run(options)
10
10
  begin
11
11
  DRb.start_service
12
- spec_server = DRbObject.new_with_uri("druby://localhost:8989")
12
+ spec_server = DRbObject.new_with_uri("druby://127.0.0.1:8989")
13
13
  spec_server.run(options.argv, options.error_stream, options.output_stream)
14
14
  rescue DRb::DRbConnError => e
15
15
  options.error_stream.puts "No server is running"
@@ -45,7 +45,9 @@ module Spec
45
45
  # been provided a block), or when an ExamplePendingError is raised.
46
46
  # +message+ is the message from the ExamplePendingError, if it exists, or the
47
47
  # default value of "Not Yet Implemented"
48
- def example_pending(example, message)
48
+ # +pending_caller+ is the file and line number of the spec which
49
+ # has called the pending method
50
+ def example_pending(example, message, pending_caller)
49
51
  end
50
52
 
51
53
  # This method is invoked after all of the examples have executed. The next method
@@ -15,19 +15,14 @@ module Spec
15
15
  super
16
16
  if where.is_a?(String)
17
17
  @output = File.open(where, 'w')
18
- elsif where == STDOUT
19
- @output = Kernel
20
- def @output.flush
21
- STDOUT.flush
22
- end
23
18
  else
24
19
  @output = where
25
20
  end
26
21
  @pending_examples = []
27
22
  end
28
23
 
29
- def example_pending(example, message)
30
- @pending_examples << [example.__full_description, message]
24
+ def example_pending(example, message, pending_caller)
25
+ @pending_examples << [example.__full_description, message, pending_caller]
31
26
  end
32
27
 
33
28
  def dump_failure(counter, failure)
@@ -75,13 +70,14 @@ module Spec
75
70
  @output.puts "Pending:"
76
71
  @pending_examples.each do |pending_example|
77
72
  @output.puts "#{pending_example[0]} (#{pending_example[1]})"
73
+ @output.puts " Called from #{pending_example[2]}"
78
74
  end
79
75
  end
80
76
  @output.flush
81
77
  end
82
78
 
83
79
  def close
84
- if IO === @output
80
+ if IO === @output && @output != STDOUT
85
81
  @output.close
86
82
  end
87
83
  end
@@ -112,7 +108,7 @@ module Spec
112
108
 
113
109
  def output_to_tty?
114
110
  begin
115
- @output == Kernel || @output.tty?
111
+ @output.tty? || ENV.has_key?("AUTOTEST")
116
112
  rescue NoMethodError
117
113
  false
118
114
  end
@@ -85,7 +85,7 @@ module Spec
85
85
  @output.flush
86
86
  end
87
87
 
88
- def example_pending(example, message)
88
+ def example_pending(example, message, pending_caller)
89
89
  @output.puts " <script type=\"text/javascript\">makeYellow('rspec-header');</script>" unless @header_red
90
90
  @output.puts " <script type=\"text/javascript\">makeYellow('example_group_#{example_group_number}');</script>" unless @example_group_red
91
91
  move_progress
@@ -40,7 +40,7 @@ module Spec
40
40
  output.flush
41
41
  end
42
42
 
43
- def example_pending(example, message)
43
+ def example_pending(example, message, pending_caller)
44
44
  super
45
45
  output.puts yellow("#{current_indentation}#{example.description} (PENDING: #{message})")
46
46
  output.flush
@@ -14,9 +14,9 @@ module Spec
14
14
  @output.flush
15
15
  end
16
16
 
17
- def example_pending(example, message)
17
+ def example_pending(example, message, pending_caller)
18
18
  super
19
- @output.print yellow('P')
19
+ @output.print yellow('*')
20
20
  @output.flush
21
21
  end
22
22
 
@@ -28,7 +28,7 @@ module Spec
28
28
  output.flush
29
29
  end
30
30
 
31
- def example_pending(example, message)
31
+ def example_pending(example, message, pending_caller)
32
32
  super
33
33
  output.puts yellow("- #{example.description} (PENDING: #{message})")
34
34
  output.flush
@@ -8,6 +8,15 @@ module Spec
8
8
  class HtmlFormatter < BaseTextFormatter
9
9
  include ERB::Util
10
10
 
11
+ def initialize(options, where)
12
+ super
13
+ @previous_type = nil
14
+ @scenario_text = ""
15
+ @story_text = ""
16
+ @scenario_failed = false
17
+ @story_failed = false
18
+ end
19
+
11
20
  def run_started(count)
12
21
  @output.puts <<-EOF
13
22
  <?xml version="1.0" encoding="UTF-8"?>
@@ -49,8 +58,8 @@ EOF
49
58
  end
50
59
 
51
60
  def story_started(title, narrative)
52
- @output.puts <<-EOF
53
- <dl class="story passed">
61
+ @story_failed = false
62
+ @story_text = <<-EOF
54
63
  <dt>Story: #{h title}</dt>
55
64
  <dd>
56
65
  <p>
@@ -59,27 +68,49 @@ EOF
59
68
  EOF
60
69
  end
61
70
 
62
- def story_ended(title, narrative)
63
- @output.puts <<-EOF
71
+ def story_ended(title, narrative)
72
+ if @story_failed
73
+ @output.puts <<-EOF
74
+ <dl class="story failed">
75
+ EOF
76
+ else
77
+ @output.puts <<-EOF
78
+ <dl class="story passed">
79
+ EOF
80
+ end
81
+ @output.puts <<-EOF
82
+ #{@story_text}
64
83
  </dd>
65
84
  </dl>
66
85
  EOF
67
86
  end
68
-
87
+
69
88
  def scenario_started(story_title, scenario_name)
70
- @output.puts <<-EOF
71
- <dl class="passed">
72
- <dt>Scenario: #{h scenario_name}</dt>
73
- <dd>
74
- <ul class="steps">
89
+ @previous_type = nil
90
+ @scenario_failed = false
91
+ @scenario_text = <<-EOF
92
+ <dt>Scenario: #{h scenario_name}</dt>
93
+ <dd>
94
+ <ul class="steps">
75
95
  EOF
76
96
  end
77
97
 
78
98
  def scenario_ended
79
- @output.puts <<-EOF
80
- </ul>
81
- </dd>
82
- </dl>
99
+ if @scenario_failed
100
+ @story_text += <<-EOF
101
+ <dl class="failed">
102
+ EOF
103
+ else
104
+ @story_text += <<-EOF
105
+ <dl class="passed">
106
+ EOF
107
+ end
108
+
109
+ @story_text += <<-EOF
110
+ #{@scenario_text}
111
+ </ul>
112
+ </dd>
113
+ </dl>
83
114
  EOF
84
115
  end
85
116
 
@@ -95,6 +126,8 @@ EOF
95
126
  end
96
127
 
97
128
  def scenario_failed(story_title, scenario_name, err)
129
+ @scenario_failed = true
130
+ @story_failed = true
98
131
  scenario_ended
99
132
  end
100
133
 
@@ -117,9 +150,22 @@ EOF
117
150
  spans = args.map { |arg| "<span class=\"param\">#{arg}</span>" }
118
151
  desc_string = description.step_name
119
152
  arg_regexp = description.arg_regexp
153
+ inner = if(type == @previous_type)
154
+ "And "
155
+ else
156
+ "#{type.to_s.capitalize} "
157
+ end
120
158
  i = -1
121
- inner = type.to_s.capitalize + ' ' + desc_string.gsub(arg_regexp) { |param| spans[i+=1] }
122
- @output.puts " <li class=\"#{klass}\">#{inner}</li>"
159
+ inner += desc_string.gsub(arg_regexp) { |param| spans[i+=1] }
160
+
161
+ @scenario_text += " <li class=\"#{klass}\">#{inner}</li>\n"
162
+
163
+ if type == :'given scenario'
164
+ @previous_type = :given
165
+ else
166
+ @previous_type = type
167
+ end
168
+
123
169
  end
124
170
  end
125
171
  end