rspec 0.8.2 → 0.9.0

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 (245) hide show
  1. data/CHANGES +125 -9
  2. data/EXAMPLES.rd +50 -27
  3. data/README +14 -1
  4. data/Rakefile +95 -42
  5. data/UPGRADE +31 -0
  6. data/bin/spec +0 -1
  7. data/bin/spec_translator +6 -0
  8. data/examples/auto_spec_description_example.rb +19 -0
  9. data/examples/{setup_teardown_example.rb → before_and_after_example.rb} +6 -6
  10. data/examples/behave_as_example.rb +45 -0
  11. data/examples/custom_expectation_matchers.rb +13 -12
  12. data/examples/dynamic_spec.rb +2 -2
  13. data/examples/file_accessor_spec.rb +2 -2
  14. data/examples/greeter_spec.rb +3 -3
  15. data/examples/helper_method_example.rb +2 -2
  16. data/examples/io_processor_spec.rb +4 -4
  17. data/examples/legacy_spec.rb +10 -0
  18. data/examples/mocking_example.rb +5 -5
  19. data/examples/multi_threaded_behaviour_runner.rb +25 -0
  20. data/examples/partial_mock_example.rb +4 -4
  21. data/examples/predicate_example.rb +4 -4
  22. data/examples/priority.txt +1 -0
  23. data/examples/shared_behaviours_example.rb +31 -0
  24. data/examples/stack_spec.rb +52 -69
  25. data/examples/stubbing_example.rb +10 -10
  26. data/examples/test_case_adapter_example.rb +26 -0
  27. data/examples/test_case_spec.rb +6 -6
  28. data/lib/spec.rb +9 -4
  29. data/lib/spec/dsl.rb +10 -0
  30. data/lib/spec/dsl/behaviour.rb +189 -0
  31. data/lib/spec/dsl/behaviour_callbacks.rb +43 -0
  32. data/lib/spec/dsl/behaviour_eval.rb +170 -0
  33. data/lib/spec/dsl/behaviour_factory.rb +32 -0
  34. data/lib/spec/dsl/composite_proc_builder.rb +28 -0
  35. data/lib/spec/dsl/configuration.rb +38 -0
  36. data/lib/spec/dsl/description.rb +34 -0
  37. data/lib/spec/dsl/example.rb +114 -0
  38. data/lib/spec/dsl/example_matcher.rb +28 -0
  39. data/lib/spec/{runner/spec_should_raise_handler.rb → dsl/example_should_raise_handler.rb} +4 -4
  40. data/lib/spec/expectations.rb +0 -3
  41. data/lib/spec/expectations/differs/default.rb +0 -1
  42. data/lib/spec/expectations/extensions.rb +0 -1
  43. data/lib/spec/expectations/extensions/object.rb +10 -53
  44. data/lib/spec/expectations/handler.rb +14 -18
  45. data/lib/spec/extensions.rb +1 -0
  46. data/lib/spec/extensions/object.rb +6 -0
  47. data/lib/spec/matchers.rb +19 -21
  48. data/lib/spec/matchers/be.rb +40 -11
  49. data/lib/spec/matchers/be_close.rb +2 -2
  50. data/lib/spec/matchers/operator_matcher.rb +52 -0
  51. data/lib/spec/matchers/respond_to.rb +21 -11
  52. data/lib/spec/mocks.rb +5 -28
  53. data/lib/spec/mocks/argument_constraint_matchers.rb +12 -0
  54. data/lib/spec/mocks/argument_expectation.rb +7 -4
  55. data/lib/spec/mocks/methods.rb +11 -16
  56. data/lib/spec/mocks/mock.rb +6 -3
  57. data/lib/spec/mocks/{mock_handler.rb → proxy.rb} +4 -7
  58. data/lib/spec/mocks/space.rb +28 -0
  59. data/lib/spec/mocks/spec_methods.rb +30 -0
  60. data/lib/spec/rake/spectask.rb +23 -21
  61. data/lib/spec/rake/verify_rcov.rb +1 -0
  62. data/lib/spec/runner.rb +88 -35
  63. data/lib/spec/runner/backtrace_tweaker.rb +2 -1
  64. data/lib/spec/runner/behaviour_runner.rb +102 -0
  65. data/lib/spec/runner/command_line.rb +5 -17
  66. data/lib/spec/runner/drb_command_line.rb +2 -2
  67. data/lib/spec/runner/extensions/kernel.rb +22 -9
  68. data/lib/spec/runner/formatter.rb +4 -0
  69. data/lib/spec/runner/formatter/base_formatter.rb +63 -0
  70. data/lib/spec/runner/formatter/base_text_formatter.rb +22 -52
  71. data/lib/spec/runner/formatter/failing_behaviours_formatter.rb +25 -0
  72. data/lib/spec/runner/formatter/failing_examples_formatter.rb +22 -0
  73. data/lib/spec/runner/formatter/html_formatter.rb +74 -29
  74. data/lib/spec/runner/formatter/progress_bar_formatter.rb +6 -8
  75. data/lib/spec/runner/formatter/rdoc_formatter.rb +6 -6
  76. data/lib/spec/runner/formatter/snippet_extractor.rb +52 -0
  77. data/lib/spec/runner/formatter/specdoc_formatter.rb +6 -6
  78. data/lib/spec/runner/heckle_runner.rb +8 -7
  79. data/lib/spec/runner/option_parser.rb +136 -55
  80. data/lib/spec/runner/options.rb +26 -0
  81. data/lib/spec/runner/reporter.rb +38 -31
  82. data/lib/spec/runner/spec_parser.rb +22 -13
  83. data/lib/spec/test_case_adapter.rb +10 -0
  84. data/lib/spec/translator.rb +103 -86
  85. data/lib/spec/version.rb +7 -15
  86. data/plugins/mock_frameworks/flexmock.rb +27 -0
  87. data/plugins/mock_frameworks/mocha.rb +21 -0
  88. data/plugins/mock_frameworks/rspec.rb +18 -0
  89. data/spec/spec/dsl/behaviour_eval_spec.rb +49 -0
  90. data/spec/spec/dsl/behaviour_factory_spec.rb +30 -0
  91. data/spec/spec/dsl/behaviour_spec.rb +508 -0
  92. data/spec/spec/dsl/composite_proc_builder_spec.rb +57 -0
  93. data/spec/spec/dsl/configuration_spec.rb +43 -0
  94. data/spec/spec/dsl/description_spec.rb +51 -0
  95. data/spec/spec/dsl/example_class_spec.rb +24 -0
  96. data/spec/spec/dsl/example_instance_spec.rb +140 -0
  97. data/spec/spec/dsl/example_should_raise_spec.rb +137 -0
  98. data/spec/spec/dsl/predicate_matcher_spec.rb +21 -0
  99. data/spec/spec/dsl/shared_behaviour_spec.rb +186 -0
  100. data/spec/spec/expectations/differs/default_spec.rb +12 -12
  101. data/spec/spec/expectations/extensions/object_spec.rb +10 -10
  102. data/spec/spec/expectations/fail_with_spec.rb +20 -20
  103. data/spec/spec/matchers/be_close_spec.rb +37 -31
  104. data/spec/spec/matchers/be_spec.rb +50 -41
  105. data/spec/spec/matchers/change_spec.rb +54 -54
  106. data/spec/spec/matchers/description_generation_spec.rb +43 -31
  107. data/spec/spec/matchers/eql_spec.rb +24 -37
  108. data/spec/spec/matchers/equal_spec.rb +24 -37
  109. data/spec/spec/matchers/exist_spec.rb +48 -0
  110. data/spec/spec/matchers/handler_spec.rb +36 -23
  111. data/spec/spec/matchers/has_spec.rb +8 -8
  112. data/spec/spec/matchers/have_spec.rb +38 -38
  113. data/spec/spec/matchers/include_spec.rb +6 -6
  114. data/spec/spec/matchers/match_spec.rb +8 -8
  115. data/spec/spec/matchers/matcher_methods_spec.rb +24 -31
  116. data/spec/spec/matchers/raise_error_spec.rb +34 -34
  117. data/spec/spec/matchers/respond_to_spec.rb +32 -8
  118. data/spec/spec/matchers/satisfy_spec.rb +6 -6
  119. data/spec/spec/matchers/should_===_spec.rb +38 -0
  120. data/spec/spec/matchers/should_==_spec.rb +37 -0
  121. data/spec/spec/matchers/should_=~_spec.rb +36 -0
  122. data/spec/spec/matchers/throw_symbol_spec.rb +47 -55
  123. data/spec/spec/mocks/any_number_of_times_spec.rb +16 -21
  124. data/spec/spec/mocks/argument_expectation_spec.rb +3 -3
  125. data/spec/spec/mocks/at_least_spec.rb +30 -30
  126. data/spec/spec/mocks/at_most_spec.rb +53 -57
  127. data/spec/spec/mocks/bug_report_10260_spec.rb +8 -0
  128. data/spec/spec/mocks/bug_report_7611_spec.rb +3 -3
  129. data/spec/spec/mocks/bug_report_7805_spec.rb +3 -3
  130. data/spec/spec/mocks/bug_report_8165_spec.rb +5 -5
  131. data/spec/spec/mocks/bug_report_8302_spec.rb +5 -5
  132. data/spec/spec/mocks/failing_mock_argument_constraints_spec.rb +26 -27
  133. data/spec/spec/mocks/mock_ordering_spec.rb +19 -15
  134. data/spec/spec/mocks/mock_space_spec.rb +54 -0
  135. data/spec/spec/mocks/mock_spec.rb +111 -141
  136. data/spec/spec/mocks/multiple_return_value_spec.rb +48 -48
  137. data/spec/spec/mocks/null_object_mock_spec.rb +10 -10
  138. data/spec/spec/mocks/once_counts_spec.rb +32 -35
  139. data/spec/spec/mocks/options_hash_spec.rb +12 -10
  140. data/spec/spec/mocks/partial_mock_spec.rb +15 -15
  141. data/spec/spec/mocks/partial_mock_using_mocks_directly_spec.rb +24 -22
  142. data/spec/spec/mocks/passing_mock_argument_constraints_spec.rb +19 -19
  143. data/spec/spec/mocks/precise_counts_spec.rb +28 -32
  144. data/spec/spec/mocks/record_messages_spec.rb +10 -10
  145. data/spec/spec/mocks/stub_spec.rb +45 -45
  146. data/spec/spec/mocks/twice_counts_spec.rb +21 -21
  147. data/spec/spec/package/bin_spec_spec.rb +12 -0
  148. data/spec/spec/runner/behaviour_runner_spec.rb +114 -0
  149. data/spec/spec/runner/command_line_spec.rb +8 -8
  150. data/spec/spec/runner/context_matching_spec.rb +14 -15
  151. data/spec/spec/runner/drb_command_line_spec.rb +12 -12
  152. data/spec/spec/runner/execution_context_spec.rb +8 -29
  153. data/spec/spec/runner/extensions/kernel_spec.rb +36 -0
  154. data/spec/spec/runner/formatter/failing_behaviours_formatter_spec.rb +27 -0
  155. data/spec/spec/runner/formatter/failing_examples_formatter_spec.rb +28 -0
  156. data/spec/spec/runner/formatter/html_formatter_spec.rb +9 -8
  157. data/spec/spec/runner/formatter/progress_bar_formatter_dry_run_spec.rb +6 -6
  158. data/spec/spec/runner/formatter/progress_bar_formatter_failure_dump_spec.rb +10 -10
  159. data/spec/spec/runner/formatter/progress_bar_formatter_spec.rb +22 -27
  160. data/spec/spec/runner/formatter/rdoc_formatter_dry_run_spec.rb +6 -5
  161. data/spec/spec/runner/formatter/rdoc_formatter_spec.rb +17 -17
  162. data/spec/spec/runner/formatter/snippet_extractor_spec.rb +11 -0
  163. data/spec/spec/runner/formatter/specdoc_formatter_dry_run_spec.rb +6 -6
  164. data/spec/spec/runner/formatter/specdoc_formatter_spec.rb +17 -17
  165. data/spec/spec/runner/heckle_runner_spec.rb +21 -21
  166. data/spec/spec/runner/heckler_spec.rb +5 -5
  167. data/spec/spec/runner/noisy_backtrace_tweaker_spec.rb +12 -12
  168. data/spec/spec/runner/object_ext_spec.rb +3 -3
  169. data/spec/spec/runner/option_parser_spec.rb +171 -102
  170. data/spec/spec/runner/quiet_backtrace_tweaker_spec.rb +21 -12
  171. data/spec/spec/runner/reporter_spec.rb +106 -97
  172. data/spec/spec/runner/spec_matcher_spec.rb +46 -51
  173. data/spec/spec/runner/spec_parser_spec.rb +72 -16
  174. data/spec/spec/spec_classes.rb +12 -3
  175. data/spec/spec/translator_spec.rb +165 -36
  176. metadata +66 -76
  177. data/RELEASE-PLAN +0 -117
  178. data/examples/auto_spec_name_generation_example.rb +0 -18
  179. data/lib/spec/callback.rb +0 -11
  180. data/lib/spec/callback/callback_container.rb +0 -60
  181. data/lib/spec/callback/extensions/module.rb +0 -24
  182. data/lib/spec/callback/extensions/object.rb +0 -37
  183. data/lib/spec/deprecated.rb +0 -3
  184. data/lib/spec/expectations/extensions/proc.rb +0 -57
  185. data/lib/spec/expectations/should.rb +0 -5
  186. data/lib/spec/expectations/should/base.rb +0 -64
  187. data/lib/spec/expectations/should/change.rb +0 -69
  188. data/lib/spec/expectations/should/have.rb +0 -128
  189. data/lib/spec/expectations/should/not.rb +0 -74
  190. data/lib/spec/expectations/should/should.rb +0 -81
  191. data/lib/spec/expectations/sugar.rb +0 -47
  192. data/lib/spec/runner/context.rb +0 -154
  193. data/lib/spec/runner/context_eval.rb +0 -142
  194. data/lib/spec/runner/context_runner.rb +0 -55
  195. data/lib/spec/runner/execution_context.rb +0 -17
  196. data/lib/spec/runner/spec_matcher.rb +0 -25
  197. data/lib/spec/runner/specification.rb +0 -114
  198. data/spec/spec/callback/callback_container_spec.rb +0 -27
  199. data/spec/spec/callback/module_spec.rb +0 -37
  200. data/spec/spec/callback/object_spec.rb +0 -90
  201. data/spec/spec/callback/object_with_class_callback_spec.rb +0 -19
  202. data/spec/spec/expectations/should/should_==_spec.rb +0 -19
  203. data/spec/spec/expectations/should/should_=~_spec.rb +0 -13
  204. data/spec/spec/expectations/should/should_be_a_kind_of_spec.rb +0 -21
  205. data/spec/spec/expectations/should/should_be_an_instance_of_spec.rb +0 -30
  206. data/spec/spec/expectations/should/should_be_arbitrary_predicate_spec.rb +0 -81
  207. data/spec/spec/expectations/should/should_be_close_spec.rb +0 -18
  208. data/spec/spec/expectations/should/should_be_comparison_operator_spec.rb +0 -44
  209. data/spec/spec/expectations/should/should_be_false_spec.rb +0 -39
  210. data/spec/spec/expectations/should/should_be_spec.rb +0 -11
  211. data/spec/spec/expectations/should/should_be_true_spec.rb +0 -27
  212. data/spec/spec/expectations/should/should_change_spec.rb +0 -184
  213. data/spec/spec/expectations/should/should_eql_spec.rb +0 -11
  214. data/spec/spec/expectations/should/should_equal_spec.rb +0 -11
  215. data/spec/spec/expectations/should/should_have_at_least_spec.rb +0 -53
  216. data/spec/spec/expectations/should/should_have_at_most_spec.rb +0 -45
  217. data/spec/spec/expectations/should/should_have_key_spec.rb +0 -21
  218. data/spec/spec/expectations/should/should_have_spec.rb +0 -64
  219. data/spec/spec/expectations/should/should_include_spec.rb +0 -59
  220. data/spec/spec/expectations/should/should_match_spec.rb +0 -25
  221. data/spec/spec/expectations/should/should_not_==_spec.rb +0 -15
  222. data/spec/spec/expectations/should/should_not_be_a_kind_of_spec.rb +0 -21
  223. data/spec/spec/expectations/should/should_not_be_an_instance_of_spec.rb +0 -11
  224. data/spec/spec/expectations/should/should_not_be_arbitrary_predicate_spec.rb +0 -68
  225. data/spec/spec/expectations/should/should_not_be_spec.rb +0 -11
  226. data/spec/spec/expectations/should/should_not_change_spec.rb +0 -24
  227. data/spec/spec/expectations/should/should_not_eql_spec.rb +0 -11
  228. data/spec/spec/expectations/should/should_not_equal_spec.rb +0 -11
  229. data/spec/spec/expectations/should/should_not_have_key_spec.rb +0 -15
  230. data/spec/spec/expectations/should/should_not_include_spec.rb +0 -58
  231. data/spec/spec/expectations/should/should_not_match_spec.rb +0 -11
  232. data/spec/spec/expectations/should/should_not_raise_spec.rb +0 -75
  233. data/spec/spec/expectations/should/should_not_respond_to_spec.rb +0 -15
  234. data/spec/spec/expectations/should/should_not_throw_spec.rb +0 -35
  235. data/spec/spec/expectations/should/should_raise_spec.rb +0 -66
  236. data/spec/spec/expectations/should/should_respond_to_spec.rb +0 -15
  237. data/spec/spec/expectations/should/should_satisfy_spec.rb +0 -35
  238. data/spec/spec/expectations/should/should_throw_spec.rb +0 -27
  239. data/spec/spec/runner/context_runner_spec.rb +0 -100
  240. data/spec/spec/runner/context_spec.rb +0 -405
  241. data/spec/spec/runner/kernel_ext_spec.rb +0 -16
  242. data/spec/spec/runner/spec_name_generation_spec.rb +0 -102
  243. data/spec/spec/runner/specification_class_spec.rb +0 -72
  244. data/spec/spec/runner/specification_instance_spec.rb +0 -160
  245. data/spec/spec/runner/specification_should_raise_spec.rb +0 -136
@@ -2,24 +2,22 @@ module Spec
2
2
  module Runner
3
3
  module Formatter
4
4
  class ProgressBarFormatter < BaseTextFormatter
5
- def add_context(name, first)
6
- @output.puts if first
7
- STDOUT.flush
5
+ def add_behaviour(name)
8
6
  end
9
7
 
10
- def spec_failed(name, counter, failure)
8
+ def example_failed(name, counter, failure)
11
9
  @output.print failure.expectation_not_met? ? red('F') : magenta('F')
12
- STDOUT.flush
10
+ @output.flush
13
11
  end
14
12
 
15
- def spec_passed(name)
13
+ def example_passed(name)
16
14
  @output.print green('.')
17
- STDOUT.flush
15
+ @output.flush
18
16
  end
19
17
 
20
18
  def start_dump
21
19
  @output.puts
22
- STDOUT.flush
20
+ @output.flush
23
21
  end
24
22
  end
25
23
  end
@@ -2,19 +2,19 @@ module Spec
2
2
  module Runner
3
3
  module Formatter
4
4
  class RdocFormatter < BaseTextFormatter
5
- def add_context(name, first)
5
+ def add_behaviour(name)
6
6
  @output.print "# #{name}\n"
7
- STDOUT.flush
7
+ @output.flush
8
8
  end
9
9
 
10
- def spec_passed(name)
10
+ def example_passed(name)
11
11
  @output.print "# * #{name}\n"
12
- STDOUT.flush
12
+ @output.flush
13
13
  end
14
14
 
15
- def spec_failed(name, counter, failure)
15
+ def example_failed(name, counter, failure)
16
16
  @output.print "# * #{name} [#{counter} - FAILED]\n"
17
- STDOUT.flush
17
+ @output.flush
18
18
  end
19
19
  end
20
20
  end
@@ -0,0 +1,52 @@
1
+ module Spec
2
+ module Runner
3
+ module Formatter
4
+ # This class extracts code snippets by looking at the backtrace of the passed error
5
+ class SnippetExtractor #:nodoc:
6
+ class NullConverter; def convert(code, pre); code; end; end #:nodoc:
7
+ begin; require 'rubygems'; require 'syntax/convertors/html'; @@converter = Syntax::Convertors::HTML.for_syntax "ruby"; rescue LoadError => e; @@converter = NullConverter.new; end
8
+
9
+ def snippet(error)
10
+ raw_code, line = snippet_for(error.backtrace[0])
11
+ highlighted = @@converter.convert(raw_code, false)
12
+ highlighted << "\n<span class=\"comment\"># gem install syntax to get syntax highlighting</span>" if @@converter.is_a?(NullConverter)
13
+ post_process(highlighted, line)
14
+ end
15
+
16
+ def snippet_for(error_line)
17
+ if error_line =~ /(.*):(\d+)/
18
+ file = $1
19
+ line = $2.to_i
20
+ [lines_around(file, line), line]
21
+ else
22
+ ["# Couldn't get snippet for #{error_line}", 1]
23
+ end
24
+ end
25
+
26
+ def lines_around(file, line)
27
+ if File.file?(file)
28
+ lines = File.open(file).read.split("\n")
29
+ min = [0, line-3].max
30
+ max = [line+1, lines.length-1].min
31
+ selected_lines = []
32
+ selected_lines.join("\n")
33
+ lines[min..max].join("\n")
34
+ else
35
+ "# Couldn't get snippet for #{file}"
36
+ end
37
+ end
38
+
39
+ def post_process(highlighted, offending_line)
40
+ new_lines = []
41
+ highlighted.split("\n").each_with_index do |line, i|
42
+ new_line = "<span class=\"linenum\">#{offending_line+i-2}</span>#{line}"
43
+ new_line = "<span class=\"offending\">#{new_line}</span>" if i == 2
44
+ new_lines << new_line
45
+ end
46
+ new_lines.join("\n")
47
+ end
48
+
49
+ end
50
+ end
51
+ end
52
+ end
@@ -2,20 +2,20 @@ module Spec
2
2
  module Runner
3
3
  module Formatter
4
4
  class SpecdocFormatter < BaseTextFormatter
5
- def add_context(name, first)
5
+ def add_behaviour(name)
6
6
  @output.puts
7
7
  @output.puts name
8
- STDOUT.flush
8
+ @output.flush
9
9
  end
10
10
 
11
- def spec_failed(name, counter, failure)
11
+ def example_failed(name, counter, failure)
12
12
  @output.puts failure.expectation_not_met? ? red("- #{name} (FAILED - #{counter})") : magenta("- #{name} (ERROR - #{counter})")
13
- STDOUT.flush
13
+ @output.flush
14
14
  end
15
15
 
16
- def spec_passed(name)
16
+ def example_passed(name)
17
17
  @output.print green("- #{name}\n")
18
- STDOUT.flush
18
+ @output.flush
19
19
  end
20
20
  end
21
21
  end
@@ -13,9 +13,9 @@ module Spec
13
13
  @heckle_class = heckle_class
14
14
  end
15
15
 
16
- # Runs all the contexts held by +context_runner+ once for each of the
16
+ # Runs all the contexts held by +behaviour_runner+ once for each of the
17
17
  # methods in the matched classes.
18
- def heckle_with(context_runner)
18
+ def heckle_with(behaviour_runner)
19
19
  if @filter =~ /(.*)[#\.](.*)/
20
20
  heckle_method($1, $2)
21
21
  else
@@ -25,7 +25,7 @@ module Spec
25
25
 
26
26
  def heckle_method(class_name, method_name)
27
27
  verify_constant(class_name)
28
- heckle = @heckle_class.new(class_name, method_name, context_runner)
28
+ heckle = @heckle_class.new(class_name, method_name, behaviour_runner)
29
29
  heckle.validate
30
30
  end
31
31
 
@@ -39,7 +39,7 @@ module Spec
39
39
 
40
40
  classes.each do |klass|
41
41
  klass.instance_methods(false).each do |method_name|
42
- heckle = @heckle_class.new(klass.name, method_name, context_runner)
42
+ heckle = @heckle_class.new(klass.name, method_name, behaviour_runner)
43
43
  heckle.validate
44
44
  end
45
45
  end
@@ -57,13 +57,14 @@ module Spec
57
57
 
58
58
  #Supports Heckle 1.2 and prior (earlier versions used Heckle::Base)
59
59
  class Heckler < (Heckle.const_defined?(:Base) ? Heckle::Base : Heckle)
60
- def initialize(klass_name, method_name, context_runner)
60
+ def initialize(klass_name, method_name, behaviour_runner)
61
61
  super(klass_name, method_name)
62
- @context_runner = context_runner
62
+ @behaviour_runner = behaviour_runner
63
63
  end
64
64
 
65
65
  def tests_pass?
66
- failure_count = @context_runner.run(false)
66
+ paths = [] # We can pass an empty array of paths - our specs are already loaded.
67
+ failure_count = @behaviour_runner.run(paths, false)
67
68
  failure_count == 0
68
69
  end
69
70
  end
@@ -1,27 +1,40 @@
1
- require 'ostruct'
2
1
  require 'optparse'
3
- require 'spec/runner/spec_parser'
4
- require 'spec/runner/formatter'
5
- require 'spec/runner/backtrace_tweaker'
6
- require 'spec/runner/reporter'
7
- require 'spec/runner/context_runner'
2
+ require 'stringio'
8
3
 
9
4
  module Spec
10
5
  module Runner
11
6
  class OptionParser
7
+ BUILT_IN_FORMATTERS = {
8
+ 'specdoc' => Formatter::SpecdocFormatter,
9
+ 's' => Formatter::SpecdocFormatter,
10
+ 'html' => Formatter::HtmlFormatter,
11
+ 'h' => Formatter::HtmlFormatter,
12
+ 'rdoc' => Formatter::RdocFormatter,
13
+ 'r' => Formatter::RdocFormatter,
14
+ 'progress' => Formatter::ProgressBarFormatter,
15
+ 'p' => Formatter::ProgressBarFormatter,
16
+ 'failing_examples' => Formatter::FailingExamplesFormatter,
17
+ 'e' => Formatter::FailingExamplesFormatter,
18
+ 'failing_behaviours' => Formatter::FailingBehavioursFormatter,
19
+ 'b' => Formatter::FailingBehavioursFormatter
20
+ }
21
+
12
22
  def initialize
13
23
  @spec_parser = SpecParser.new
14
24
  @file_factory = File
15
25
  end
16
26
 
17
- def create_context_runner(args, err, out, warn_if_no_files)
27
+ def create_behaviour_runner(args, err, out, warn_if_no_files)
18
28
  options = parse(args, err, out, warn_if_no_files)
19
29
  # Some exit points in parse (--generate-options, --drb) don't return the options,
20
30
  # but hand over control. In that case we don't want to continue.
21
- return nil unless options.is_a?(OpenStruct)
31
+ return nil unless options.is_a?(Options)
22
32
 
23
- formatter = options.formatter_type.new(options.out, options.dry_run, options.colour)
24
- options.reporter = Reporter.new(formatter, options.backtrace_tweaker)
33
+ options.formatters.each do |formatter|
34
+ formatter.colour = options.colour if formatter.respond_to?(:colour=)
35
+ formatter.dry_run = options.dry_run if formatter.respond_to?(:dry_run=)
36
+ end
37
+ options.reporter = Reporter.new(options.formatters, options.backtrace_tweaker)
25
38
 
26
39
  # this doesn't really belong here.
27
40
  # it should, but the way things are coupled, it doesn't
@@ -30,21 +43,24 @@ module Spec
30
43
  end
31
44
 
32
45
  unless options.generate
33
- ContextRunner.new(options)
46
+ if options.runner_type
47
+ options.runner_type.new(options)
48
+ else
49
+ BehaviourRunner.new(options)
50
+ end
34
51
  end
35
52
  end
36
53
 
37
54
  def parse(args, err, out, warn_if_no_files)
38
55
  options_file = nil
39
56
  args_copy = args.dup
40
- options = OpenStruct.new
41
- options.out = (out == STDOUT ? Kernel : out)
42
- options.formatter_type = Formatter::ProgressBarFormatter
57
+ options = Options.new
58
+ options.formatters = []
43
59
  options.backtrace_tweaker = QuietBacktraceTweaker.new
44
- options.spec_name = nil
60
+ options.examples = []
45
61
 
46
62
  opts = ::OptionParser.new do |opts|
47
- opts.banner = "Usage: spec [options] (FILE|DIRECTORY|GLOB)+"
63
+ opts.banner = "Usage: spec (FILE|DIRECTORY|GLOB)+ [options]"
48
64
  opts.separator ""
49
65
 
50
66
  opts.on("-D", "--diff [FORMAT]", "Show diff of objects that are expected to be equal when they are not",
@@ -82,38 +98,74 @@ module Spec
82
98
  options.colour = true
83
99
  end
84
100
 
85
- opts.on("-s", "--spec SPECIFICATION_NAME", "Execute context or specification with matching name") do |spec_name|
86
- options.spec_name = spec_name
101
+ opts.on("-e", "--example [NAME|FILE_NAME]", "Execute example(s) with matching name(s). If the argument is",
102
+ "the path to an existing file (typically generated by a previous",
103
+ "run using --format failing_examples:file.txt), then the examples",
104
+ "on each line of that file will be executed. If the file is empty,",
105
+ "all examples will be run (as if --example was not specified).",
106
+ " ",
107
+ "If the argument is not an existing file, then it is treated as",
108
+ "an example name directly, causing RSpec to run just the example",
109
+ "matching that name") do |example|
110
+ if(File.file?(example))
111
+ options.examples = File.open(example).read.split("\n")
112
+ else
113
+ options.examples = [example]
114
+ end
87
115
  end
88
-
89
- opts.on("-l", "--line LINE_NUMBER", Integer, "Execute context or specification at given line") do |line_number|
116
+
117
+ opts.on("-s", "--spec [NAME]", "DEPRECATED - use -e instead", "(This will be removed when autotest works with -e)") do |example|
118
+ if(File.file?(example))
119
+ options.examples = File.open(example).read.split("\n")
120
+ else
121
+ options.examples = [example]
122
+ end
123
+ end
124
+
125
+ opts.on("-l", "--line LINE_NUMBER", Integer, "Execute behaviour or example at given line.",
126
+ "(does not work for dynamically generated specs)") do |line_number|
90
127
  options.line_number = line_number.to_i
91
128
  end
92
129
 
93
- opts.on("-f", "--format FORMAT", "Builtin formats: specdoc|s|rdoc|r|html|h",
94
- "You can also specify a custom formatter class",
95
- "(in which case you should also specify --require)") do |format|
96
- case format
97
- when 'specdoc', 's'
98
- options.formatter_type = Formatter::SpecdocFormatter
99
- when 'html', 'h'
100
- options.formatter_type = Formatter::HtmlFormatter
101
- when 'rdoc', 'r'
102
- options.formatter_type = Formatter::RdocFormatter
103
- options.dry_run = true
130
+ opts.on("-f", "--format FORMAT[:WHERE]", "Specifies what format to use for output. Specify WHERE to tell",
131
+ "the formatter where to write the output. All built-in formats",
132
+ "expect WHERE to be a file name, and will write to STDOUT if it's",
133
+ "not specified. The --format option may be specified several times",
134
+ "if you want several outputs",
135
+ " ",
136
+ "Builtin formats: ",
137
+ "progress|p : Text progress",
138
+ "specdoc|s : Behaviour doc as text",
139
+ "rdoc|r : Behaviour doc as RDoc",
140
+ "html|h : A nice HTML report",
141
+ "failing_examples|e : Write all failing examples - input for --example",
142
+ "failing_behaviours|b : Write all failing behaviours - input for --example",
143
+ " ",
144
+ "FORMAT can also be the name of a custom formatter class",
145
+ "(in which case you should also specify --require to load it)") do |format|
146
+
147
+ where = out
148
+ # This funky regexp checks whether we have a FILE_NAME or not
149
+ if (format =~ /([a-zA-Z_]+(?:::[a-zA-Z_]+)*):?(.*)/) && ($2 != '')
150
+ format = $1
151
+ where = $2
104
152
  else
105
- begin
106
- options.formatter_type = eval(format)
107
- rescue NameError
108
- err.puts "Couldn't find formatter class #{format}"
109
- err.puts "Make sure the --require option is specified *before* --format"
110
- exit if out == $stdout
111
- end
153
+ raise "When using several --format options only one of them can be without a file" if @out_used
154
+ @out_used = true
155
+ end
156
+
157
+ begin
158
+ formatter_type = BUILT_IN_FORMATTERS[format] || eval(format)
159
+ options.formatters << formatter_type.new(where)
160
+ rescue NameError
161
+ err.puts "Couldn't find formatter class #{format}"
162
+ err.puts "Make sure the --require option is specified *before* --format"
163
+ exit if out == $stdout
112
164
  end
113
165
  end
114
166
 
115
167
  opts.on("-r", "--require FILE", "Require FILE before running specs",
116
- "Useful for loading custom formatters or other extensions",
168
+ "Useful for loading custom formatters or other extensions.",
117
169
  "If this option is used it must come before the others") do |req|
118
170
  req.split(",").each{|file| require file}
119
171
  end
@@ -121,31 +173,45 @@ module Spec
121
173
  opts.on("-b", "--backtrace", "Output full backtrace") do
122
174
  options.backtrace_tweaker = NoisyBacktraceTweaker.new
123
175
  end
176
+
177
+ opts.on("-L", "--loadby STRATEGY", "Specify the strategy by which spec files should be loaded.",
178
+ "STRATEGY can currently only be 'mtime' (File modification time)",
179
+ "By default, spec files are loaded in alphabetical order if --loadby",
180
+ "is not specified.") do |loadby|
181
+ options.loadby = loadby
182
+ end
183
+
184
+ opts.on("-R", "--reverse", "Run examples in reverse order") do
185
+ options.reverse = true
186
+ end
187
+
188
+ opts.on("-t", "--timeout FLOAT", "Interrupt and fail each example that doesn't complete in the",
189
+ "specified time") do |timeout|
190
+ options.timeout = timeout.to_f
191
+ end
124
192
 
125
- opts.on("-H", "--heckle CODE", "If all specs pass, this will run your specs many times, mutating",
126
- "the specced code a little each time. The intent is that specs",
127
- "*should* fail, and RSpec will tell you if they don't.",
128
- "CODE should be either Some::Module, Some::Class or Some::Fabulous#method}") do |heckle|
193
+ opts.on("-H", "--heckle CODE", "If all examples pass, this will mutate the classes and methods",
194
+ "identified by CODE little by little and run all the examples again",
195
+ "for each mutation. The intent is that for each mutation, at least",
196
+ "one example *should* fail, and RSpec will tell you if this is not the",
197
+ "case. CODE should be either Some::Module, Some::Class or",
198
+ "Some::Fabulous#method") do |heckle|
129
199
  heckle_runner = PLATFORM == 'i386-mswin32' ? 'spec/runner/heckle_runner_win' : 'spec/runner/heckle_runner'
130
200
  require heckle_runner
131
201
  options.heckle_runner = HeckleRunner.new(heckle)
132
202
  end
133
203
 
134
- opts.on("-d", "--dry-run", "Don't execute specs") do
204
+ opts.on("-d", "--dry-run", "Invokes formatters without executing the examples.") do
135
205
  options.dry_run = true
136
206
  end
137
207
 
138
- opts.on("-o", "--out OUTPUT_FILE", "Path to output file (defaults to STDOUT)") do |out_file|
139
- options.out = File.new(out_file, 'w')
140
- end
141
-
142
208
  opts.on("-O", "--options PATH", "Read options from a file") do |options_file|
143
209
  # Remove the --options option and the argument before writing to file
144
210
  index = args_copy.index("-O") || args_copy.index("--options")
145
211
  args_copy.delete_at(index)
146
212
  args_copy.delete_at(index)
147
213
 
148
- new_args = args_copy + IO.readlines(options_file).each {|s| s.chomp!}
214
+ new_args = args_copy + IO.readlines(options_file).map {|l| l.chomp.split " "}.flatten
149
215
  return CommandLine.run(new_args, err, out, true, warn_if_no_files)
150
216
  end
151
217
 
@@ -162,12 +228,22 @@ module Spec
162
228
  out.puts "spec --options #{options_file}"
163
229
  options.generate = true
164
230
  end
231
+
232
+ opts.on("-U", "--runner RUNNER", "Use a custom BehaviourRunner.") do |runner|
233
+ begin
234
+ options.runner_type = eval(runner)
235
+ rescue NameError
236
+ err.puts "Couldn't find behaviour runner class #{runner}"
237
+ err.puts "Make sure the --require option is specified."
238
+ exit if out == $stdout
239
+ end
240
+ end
165
241
 
166
- opts.on("-X", "--drb", "Run specs via DRb. (For example against script/rails_spec_server)") do |options_file|
167
- # Remove the --options option and the argument before writing to file
242
+ opts.on("-X", "--drb", "Run examples via DRb. (For example against script/spec_server)") do |options_file|
243
+ # Remove the --drb option
168
244
  index = args_copy.index("-X") || args_copy.index("--drb")
169
245
  args_copy.delete_at(index)
170
-
246
+
171
247
  return DrbCommandLine.run(args_copy, err, out, true, warn_if_no_files)
172
248
  end
173
249
 
@@ -193,16 +269,21 @@ module Spec
193
269
  if options.line_number
194
270
  set_spec_from_line_number(options, args, err)
195
271
  end
272
+
273
+ if options.formatters.empty?
274
+ options.formatters << Formatter::ProgressBarFormatter.new(out)
275
+ end
196
276
 
197
277
  options
198
278
  end
199
279
 
200
280
  def set_spec_from_line_number(options, args, err)
201
- unless options.spec_name
281
+ if options.examples.empty?
202
282
  if args.length == 1
203
283
  if @file_factory.file?(args[0])
204
284
  source = @file_factory.open(args[0])
205
- options.spec_name = @spec_parser.spec_name_for(source, options.line_number)
285
+ example = @spec_parser.spec_name_for(source, options.line_number)
286
+ options.examples = [example]
206
287
  elsif @file_factory.directory?(args[0])
207
288
  err.puts "You must specify one file, not a directory when using the --line option"
208
289
  exit(1) if err == $stderr
@@ -215,7 +296,7 @@ module Spec
215
296
  exit(3) if err == $stderr
216
297
  end
217
298
  else
218
- err.puts "You cannot use both --line and --spec"
299
+ err.puts "You cannot use both --line and --example"
219
300
  exit(4) if err == $stderr
220
301
  end
221
302
  end