rspec-core 2.11.1 → 3.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (222) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/.document +1 -1
  4. data/.yardopts +3 -1
  5. data/Changelog.md +1814 -29
  6. data/{License.txt → LICENSE.md} +6 -4
  7. data/README.md +197 -48
  8. data/exe/rspec +2 -23
  9. data/lib/rspec/autorun.rb +1 -0
  10. data/lib/rspec/core/backtrace_formatter.rb +65 -0
  11. data/lib/rspec/core/bisect/coordinator.rb +62 -0
  12. data/lib/rspec/core/bisect/example_minimizer.rb +173 -0
  13. data/lib/rspec/core/bisect/fork_runner.rb +138 -0
  14. data/lib/rspec/core/bisect/server.rb +61 -0
  15. data/lib/rspec/core/bisect/shell_command.rb +126 -0
  16. data/lib/rspec/core/bisect/shell_runner.rb +73 -0
  17. data/lib/rspec/core/bisect/utilities.rb +69 -0
  18. data/lib/rspec/core/configuration.rb +1846 -407
  19. data/lib/rspec/core/configuration_options.rb +154 -50
  20. data/lib/rspec/core/did_you_mean.rb +46 -0
  21. data/lib/rspec/core/drb.rb +120 -0
  22. data/lib/rspec/core/dsl.rb +90 -18
  23. data/lib/rspec/core/example.rb +488 -152
  24. data/lib/rspec/core/example_group.rb +733 -294
  25. data/lib/rspec/core/example_status_persister.rb +235 -0
  26. data/lib/rspec/core/filter_manager.rb +175 -147
  27. data/lib/rspec/core/flat_map.rb +20 -0
  28. data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
  29. data/lib/rspec/core/formatters/base_formatter.rb +32 -130
  30. data/lib/rspec/core/formatters/base_text_formatter.rb +62 -190
  31. data/lib/rspec/core/formatters/bisect_drb_formatter.rb +29 -0
  32. data/lib/rspec/core/formatters/bisect_progress_formatter.rb +157 -0
  33. data/lib/rspec/core/formatters/console_codes.rb +76 -0
  34. data/lib/rspec/core/formatters/deprecation_formatter.rb +223 -0
  35. data/lib/rspec/core/formatters/documentation_formatter.rb +62 -27
  36. data/lib/rspec/core/formatters/exception_presenter.rb +521 -0
  37. data/lib/rspec/core/formatters/failure_list_formatter.rb +23 -0
  38. data/lib/rspec/core/formatters/fallback_message_formatter.rb +28 -0
  39. data/lib/rspec/core/formatters/helpers.rb +93 -14
  40. data/lib/rspec/core/formatters/html_formatter.rb +104 -415
  41. data/lib/rspec/core/formatters/html_printer.rb +414 -0
  42. data/lib/rspec/core/formatters/html_snippet_extractor.rb +120 -0
  43. data/lib/rspec/core/formatters/json_formatter.rb +102 -0
  44. data/lib/rspec/core/formatters/profile_formatter.rb +68 -0
  45. data/lib/rspec/core/formatters/progress_formatter.rb +12 -15
  46. data/lib/rspec/core/formatters/protocol.rb +182 -0
  47. data/lib/rspec/core/formatters/snippet_extractor.rb +115 -39
  48. data/lib/rspec/core/formatters/syntax_highlighter.rb +91 -0
  49. data/lib/rspec/core/formatters.rb +279 -0
  50. data/lib/rspec/core/hooks.rb +451 -300
  51. data/lib/rspec/core/invocations.rb +87 -0
  52. data/lib/rspec/core/memoized_helpers.rb +580 -0
  53. data/lib/rspec/core/metadata.rb +395 -173
  54. data/lib/rspec/core/metadata_filter.rb +255 -0
  55. data/lib/rspec/core/minitest_assertions_adapter.rb +31 -0
  56. data/lib/rspec/core/mocking_adapters/flexmock.rb +31 -0
  57. data/lib/rspec/core/mocking_adapters/mocha.rb +57 -0
  58. data/lib/rspec/core/mocking_adapters/null.rb +14 -0
  59. data/lib/rspec/core/mocking_adapters/rr.rb +31 -0
  60. data/lib/rspec/core/mocking_adapters/rspec.rb +32 -0
  61. data/lib/rspec/core/notifications.rb +521 -0
  62. data/lib/rspec/core/option_parser.rb +208 -64
  63. data/lib/rspec/core/ordering.rb +169 -0
  64. data/lib/rspec/core/output_wrapper.rb +29 -0
  65. data/lib/rspec/core/pending.rb +115 -59
  66. data/lib/rspec/core/profiler.rb +34 -0
  67. data/lib/rspec/core/project_initializer/.rspec +1 -0
  68. data/lib/rspec/core/project_initializer/spec/spec_helper.rb +98 -0
  69. data/lib/rspec/core/project_initializer.rb +26 -65
  70. data/lib/rspec/core/rake_task.rb +140 -131
  71. data/lib/rspec/core/reporter.rb +207 -44
  72. data/lib/rspec/core/ruby_project.rb +15 -6
  73. data/lib/rspec/core/runner.rb +180 -44
  74. data/lib/rspec/core/sandbox.rb +37 -0
  75. data/lib/rspec/core/set.rb +54 -0
  76. data/lib/rspec/core/shared_context.rb +25 -19
  77. data/lib/rspec/core/shared_example_group.rb +229 -54
  78. data/lib/rspec/core/shell_escape.rb +49 -0
  79. data/lib/rspec/core/test_unit_assertions_adapter.rb +30 -0
  80. data/lib/rspec/core/version.rb +3 -1
  81. data/lib/rspec/core/warnings.rb +40 -0
  82. data/lib/rspec/core/world.rb +208 -49
  83. data/lib/rspec/core.rb +166 -80
  84. data.tar.gz.sig +0 -0
  85. metadata +230 -445
  86. metadata.gz.sig +0 -0
  87. data/exe/autospec +0 -13
  88. data/features/Autotest.md +0 -38
  89. data/features/README.md +0 -17
  90. data/features/Upgrade.md +0 -364
  91. data/features/command_line/README.md +0 -28
  92. data/features/command_line/example_name_option.feature +0 -101
  93. data/features/command_line/exit_status.feature +0 -83
  94. data/features/command_line/format_option.feature +0 -81
  95. data/features/command_line/init.feature +0 -18
  96. data/features/command_line/line_number_appended_to_path.feature +0 -140
  97. data/features/command_line/line_number_option.feature +0 -58
  98. data/features/command_line/order.feature +0 -29
  99. data/features/command_line/pattern_option.feature +0 -31
  100. data/features/command_line/rake_task.feature +0 -68
  101. data/features/command_line/ruby.feature +0 -22
  102. data/features/command_line/tag.feature +0 -91
  103. data/features/configuration/alias_example_to.feature +0 -48
  104. data/features/configuration/custom_settings.feature +0 -84
  105. data/features/configuration/default_path.feature +0 -38
  106. data/features/configuration/fail_fast.feature +0 -77
  107. data/features/configuration/read_options_from_file.feature +0 -87
  108. data/features/example_groups/basic_structure.feature +0 -55
  109. data/features/example_groups/shared_context.feature +0 -74
  110. data/features/example_groups/shared_examples.feature +0 -204
  111. data/features/expectation_framework_integration/configure_expectation_framework.feature +0 -102
  112. data/features/filtering/exclusion_filters.feature +0 -139
  113. data/features/filtering/if_and_unless.feature +0 -168
  114. data/features/filtering/inclusion_filters.feature +0 -105
  115. data/features/filtering/run_all_when_everything_filtered.feature +0 -46
  116. data/features/formatters/custom_formatter.feature +0 -36
  117. data/features/formatters/text_formatter.feature +0 -46
  118. data/features/helper_methods/arbitrary_methods.feature +0 -40
  119. data/features/helper_methods/let.feature +0 -50
  120. data/features/helper_methods/modules.feature +0 -149
  121. data/features/hooks/around_hooks.feature +0 -343
  122. data/features/hooks/before_and_after_hooks.feature +0 -423
  123. data/features/hooks/filtering.feature +0 -234
  124. data/features/metadata/current_example.feature +0 -17
  125. data/features/metadata/described_class.feature +0 -17
  126. data/features/metadata/user_defined.feature +0 -113
  127. data/features/mock_framework_integration/use_any_framework.feature +0 -106
  128. data/features/mock_framework_integration/use_flexmock.feature +0 -96
  129. data/features/mock_framework_integration/use_mocha.feature +0 -97
  130. data/features/mock_framework_integration/use_rr.feature +0 -98
  131. data/features/mock_framework_integration/use_rspec.feature +0 -97
  132. data/features/pending/pending_examples.feature +0 -229
  133. data/features/spec_files/arbitrary_file_suffix.feature +0 -13
  134. data/features/step_definitions/additional_cli_steps.rb +0 -30
  135. data/features/subject/attribute_of_subject.feature +0 -124
  136. data/features/subject/explicit_subject.feature +0 -82
  137. data/features/subject/implicit_receiver.feature +0 -29
  138. data/features/subject/implicit_subject.feature +0 -63
  139. data/features/support/env.rb +0 -12
  140. data/lib/autotest/discover.rb +0 -1
  141. data/lib/autotest/rspec2.rb +0 -73
  142. data/lib/rspec/core/backward_compatibility.rb +0 -65
  143. data/lib/rspec/core/command_line.rb +0 -36
  144. data/lib/rspec/core/deprecation.rb +0 -36
  145. data/lib/rspec/core/drb_command_line.rb +0 -26
  146. data/lib/rspec/core/drb_options.rb +0 -87
  147. data/lib/rspec/core/extensions/instance_eval_with_args.rb +0 -44
  148. data/lib/rspec/core/extensions/kernel.rb +0 -9
  149. data/lib/rspec/core/extensions/module_eval_with_args.rb +0 -38
  150. data/lib/rspec/core/extensions/ordered.rb +0 -21
  151. data/lib/rspec/core/extensions.rb +0 -4
  152. data/lib/rspec/core/formatters/text_mate_formatter.rb +0 -34
  153. data/lib/rspec/core/let.rb +0 -110
  154. data/lib/rspec/core/load_path.rb +0 -3
  155. data/lib/rspec/core/metadata_hash_builder.rb +0 -97
  156. data/lib/rspec/core/mocking/with_absolutely_nothing.rb +0 -11
  157. data/lib/rspec/core/mocking/with_flexmock.rb +0 -27
  158. data/lib/rspec/core/mocking/with_mocha.rb +0 -29
  159. data/lib/rspec/core/mocking/with_rr.rb +0 -27
  160. data/lib/rspec/core/mocking/with_rspec.rb +0 -23
  161. data/lib/rspec/core/subject.rb +0 -219
  162. data/spec/autotest/discover_spec.rb +0 -19
  163. data/spec/autotest/failed_results_re_spec.rb +0 -45
  164. data/spec/autotest/rspec_spec.rb +0 -123
  165. data/spec/command_line/order_spec.rb +0 -137
  166. data/spec/rspec/core/command_line_spec.rb +0 -108
  167. data/spec/rspec/core/command_line_spec_output.txt +0 -0
  168. data/spec/rspec/core/configuration_options_spec.rb +0 -377
  169. data/spec/rspec/core/configuration_spec.rb +0 -1196
  170. data/spec/rspec/core/deprecations_spec.rb +0 -66
  171. data/spec/rspec/core/drb_command_line_spec.rb +0 -108
  172. data/spec/rspec/core/drb_options_spec.rb +0 -180
  173. data/spec/rspec/core/dsl_spec.rb +0 -17
  174. data/spec/rspec/core/example_group_spec.rb +0 -1098
  175. data/spec/rspec/core/example_spec.rb +0 -370
  176. data/spec/rspec/core/filter_manager_spec.rb +0 -256
  177. data/spec/rspec/core/formatters/base_formatter_spec.rb +0 -80
  178. data/spec/rspec/core/formatters/base_text_formatter_spec.rb +0 -363
  179. data/spec/rspec/core/formatters/documentation_formatter_spec.rb +0 -88
  180. data/spec/rspec/core/formatters/helpers_spec.rb +0 -66
  181. data/spec/rspec/core/formatters/html_formatted-1.8.7-jruby.html +0 -410
  182. data/spec/rspec/core/formatters/html_formatted-1.8.7.html +0 -409
  183. data/spec/rspec/core/formatters/html_formatted-1.9.2.html +0 -416
  184. data/spec/rspec/core/formatters/html_formatted-1.9.3.html +0 -416
  185. data/spec/rspec/core/formatters/html_formatter_spec.rb +0 -82
  186. data/spec/rspec/core/formatters/progress_formatter_spec.rb +0 -30
  187. data/spec/rspec/core/formatters/snippet_extractor_spec.rb +0 -18
  188. data/spec/rspec/core/formatters/text_mate_formatted-1.8.7-jruby.html +0 -410
  189. data/spec/rspec/core/formatters/text_mate_formatted-1.8.7.html +0 -409
  190. data/spec/rspec/core/formatters/text_mate_formatted-1.9.2.html +0 -416
  191. data/spec/rspec/core/formatters/text_mate_formatted-1.9.3.html +0 -416
  192. data/spec/rspec/core/formatters/text_mate_formatter_spec.rb +0 -83
  193. data/spec/rspec/core/hooks_filtering_spec.rb +0 -227
  194. data/spec/rspec/core/hooks_spec.rb +0 -250
  195. data/spec/rspec/core/kernel_extensions_spec.rb +0 -9
  196. data/spec/rspec/core/let_spec.rb +0 -55
  197. data/spec/rspec/core/metadata_spec.rb +0 -447
  198. data/spec/rspec/core/option_parser_spec.rb +0 -166
  199. data/spec/rspec/core/pending_example_spec.rb +0 -220
  200. data/spec/rspec/core/project_initializer_spec.rb +0 -130
  201. data/spec/rspec/core/rake_task_spec.rb +0 -138
  202. data/spec/rspec/core/reporter_spec.rb +0 -103
  203. data/spec/rspec/core/resources/a_bar.rb +0 -0
  204. data/spec/rspec/core/resources/a_foo.rb +0 -0
  205. data/spec/rspec/core/resources/a_spec.rb +0 -1
  206. data/spec/rspec/core/resources/custom_example_group_runner.rb +0 -14
  207. data/spec/rspec/core/resources/formatter_specs.rb +0 -60
  208. data/spec/rspec/core/resources/utf8_encoded.rb +0 -8
  209. data/spec/rspec/core/rspec_matchers_spec.rb +0 -45
  210. data/spec/rspec/core/ruby_project_spec.rb +0 -24
  211. data/spec/rspec/core/runner_spec.rb +0 -81
  212. data/spec/rspec/core/shared_context_spec.rb +0 -67
  213. data/spec/rspec/core/shared_example_group_spec.rb +0 -84
  214. data/spec/rspec/core/subject_spec.rb +0 -244
  215. data/spec/rspec/core/world_spec.rb +0 -144
  216. data/spec/rspec/core_spec.rb +0 -35
  217. data/spec/spec_helper.rb +0 -98
  218. data/spec/support/config_options_helper.rb +0 -24
  219. data/spec/support/helper_methods.rb +0 -5
  220. data/spec/support/matchers.rb +0 -65
  221. data/spec/support/shared_example_groups.rb +0 -41
  222. data/spec/support/spec_files.rb +0 -44
@@ -1,178 +1,187 @@
1
- require 'rspec/core'
2
- require 'rspec/core/deprecation'
3
1
  require 'rake'
4
2
  require 'rake/tasklib'
3
+ require 'rspec/support'
4
+
5
+ RSpec::Support.require_rspec_support "ruby_features"
6
+
7
+ # :nocov:
8
+ unless RSpec::Support.respond_to?(:require_rspec_core)
9
+ RSpec::Support.define_optimized_require_for_rspec(:core) { |f| require_relative "../#{f}" }
10
+ end
11
+ # :nocov:
12
+
13
+ RSpec::Support.require_rspec_core "shell_escape"
5
14
 
6
15
  module RSpec
7
16
  module Core
17
+ # RSpec rake task
18
+ #
19
+ # @see Rakefile
8
20
  class RakeTask < ::Rake::TaskLib
9
21
  include ::Rake::DSL if defined?(::Rake::DSL)
22
+ include RSpec::Core::ShellEscape
10
23
 
11
- # Name of task.
12
- #
13
- # default:
14
- # :spec
15
- attr_accessor :name
24
+ # Default path to the RSpec executable.
25
+ DEFAULT_RSPEC_PATH = File.expand_path('../../../../exe/rspec', __FILE__)
16
26
 
17
- # Glob pattern to match files.
18
- #
19
- # default:
20
- # 'spec/**/*_spec.rb'
21
- attr_accessor :pattern
27
+ # Default pattern for spec files.
28
+ DEFAULT_PATTERN = 'spec/**{,/*/**}/*_spec.rb'
22
29
 
23
- # @deprecated
24
- # Has no effect. The rake task now checks ENV['BUNDLE_GEMFILE'] instead.
25
- def skip_bundler=(*)
26
- RSpec.deprecate("RSpec::Core::RakeTask#skip_bundler=")
27
- end
30
+ # Name of task. Defaults to `:spec`.
31
+ attr_accessor :name
28
32
 
29
- # @deprecated
30
- # Has no effect. The rake task now checks ENV['BUNDLE_GEMFILE'] instead.
31
- def gemfile=(*)
32
- RSpec.deprecate("RSpec::Core::RakeTask#gemfile=", 'ENV["BUNDLE_GEMFILE"]')
33
- end
33
+ # Files matching this pattern will be loaded.
34
+ # Defaults to `'spec/**{,/*/**}/*_spec.rb'`.
35
+ attr_accessor :pattern
34
36
 
35
- # @deprecated
36
- # Use ruby_opts="-w" instead.
37
- #
38
- # When true, requests that the specs be run with the warning flag set.
39
- # e.g. "ruby -w"
40
- #
41
- # default:
42
- # false
43
- def warning=(true_or_false)
44
- RSpec.deprecate("RSpec::Core::RakeTask#warning=", 'ruby_opts="-w"')
45
- @warning = true_or_false
46
- end
37
+ # Files matching this pattern will be excluded.
38
+ # Defaults to `nil`.
39
+ attr_accessor :exclude_pattern
47
40
 
48
- # Whether or not to fail Rake when an error occurs (typically when examples fail).
49
- #
50
- # default:
51
- # true
41
+ # Whether or not to fail Rake when an error occurs (typically when
42
+ # examples fail). Defaults to `true`.
52
43
  attr_accessor :fail_on_error
53
44
 
54
45
  # A message to print to stderr when there are failures.
55
46
  attr_accessor :failure_message
56
47
 
48
+ if RUBY_VERSION < "1.9.0" || Support::Ruby.jruby?
49
+ # Run RSpec with a clean (empty) environment is not supported
50
+ def with_clean_environment=(_value)
51
+ raise ArgumentError, "Running in a clean environment is not supported on Ruby versions before 1.9.0"
52
+ end
53
+
54
+ # Run RSpec with a clean (empty) environment is not supported
55
+ def with_clean_environment
56
+ false
57
+ end
58
+ else
59
+ # Run RSpec with a clean (empty) environment.
60
+ attr_accessor :with_clean_environment
61
+ end
62
+
57
63
  # Use verbose output. If this is set to true, the task will print the
58
- # executed spec command to stdout.
59
- #
60
- # default:
61
- # true
64
+ # executed spec command to stdout. Defaults to `true`.
62
65
  attr_accessor :verbose
63
66
 
64
- # Use rcov for code coverage?
65
- #
66
- # default:
67
- # false
68
- attr_accessor :rcov
69
-
70
- # Path to rcov.
71
- #
72
- # default:
73
- # 'rcov'
74
- attr_accessor :rcov_path
75
-
76
- # Command line options to pass to rcov.
77
- #
78
- # default:
79
- # nil
80
- attr_accessor :rcov_opts
81
-
82
- # Command line options to pass to ruby.
83
- #
84
- # default:
85
- # nil
67
+ # Command line options to pass to ruby. Defaults to `nil`.
86
68
  attr_accessor :ruby_opts
87
69
 
88
- # Path to rspec
89
- #
90
- # default:
91
- # 'rspec'
70
+ # Path to RSpec. Defaults to the absolute path to the
71
+ # rspec binary from the loaded rspec-core gem.
92
72
  attr_accessor :rspec_path
93
73
 
94
- # Command line options to pass to rspec.
95
- #
96
- # default:
97
- # nil
74
+ # Command line options to pass to RSpec. Defaults to `nil`.
98
75
  attr_accessor :rspec_opts
99
76
 
100
- # @deprecated
101
- # Use rspec_opts instead.
102
- #
103
- # Command line options to pass to rspec.
104
- #
105
- # default:
106
- # nil
107
- def spec_opts=(opts)
108
- RSpec.deprecate('RSpec::Core::RakeTask#spec_opts=', 'rspec_opts=')
109
- @rspec_opts = opts
77
+ def initialize(*args, &task_block)
78
+ @name = args.shift || :spec
79
+ @ruby_opts = nil
80
+ @rspec_opts = nil
81
+ @verbose = true
82
+ @fail_on_error = true
83
+ @rspec_path = DEFAULT_RSPEC_PATH
84
+ @pattern = DEFAULT_PATTERN
85
+
86
+ define(args, &task_block)
110
87
  end
111
88
 
112
- def initialize(*args)
113
- @name = args.shift || :spec
114
- @pattern, @rcov_path, @rcov_opts, @ruby_opts, @rspec_opts = nil, nil, nil, nil, nil
115
- @warning, @rcov = false, false
116
- @verbose, @fail_on_error = true, true
117
-
118
- yield self if block_given?
119
-
120
- @rcov_path ||= 'rcov'
121
- @rspec_path ||= 'rspec'
122
- @pattern ||= './spec{,/*/**}/*_spec.rb'
123
-
124
- desc("Run RSpec code examples") unless ::Rake.application.last_comment
125
-
126
- task name do
127
- RakeFileUtils.send(:verbose, verbose) do
128
- if files_to_run.empty?
129
- puts "No examples matching #{pattern} could be found"
130
- else
131
- begin
132
- puts spec_command if verbose
133
- success = system(spec_command)
134
- rescue
135
- puts failure_message if failure_message
136
- end
137
- raise("#{spec_command} failed") if fail_on_error unless success
138
- end
139
- end
89
+ # @private
90
+ def run_task(verbose)
91
+ command = spec_command
92
+ puts command if verbose
93
+
94
+ if with_clean_environment
95
+ return if system({}, command, :unsetenv_others => true)
96
+ else
97
+ return if system(command)
140
98
  end
99
+
100
+ puts failure_message if failure_message
101
+
102
+ return unless fail_on_error
103
+ $stderr.puts "#{command} failed" if verbose
104
+ exit $?.exitstatus || 1
141
105
  end
142
106
 
143
107
  private
144
108
 
145
- def files_to_run
109
+ # @private
110
+ def define(args, &task_block)
111
+ desc "Run RSpec code examples" unless ::Rake.application.last_description
112
+
113
+ task name, *args do |_, task_args|
114
+ RakeFileUtils.__send__(:verbose, verbose) do
115
+ task_block.call(*[self, task_args].slice(0, task_block.arity)) if task_block
116
+ run_task verbose
117
+ end
118
+ end
119
+ end
120
+
121
+ def file_inclusion_specification
146
122
  if ENV['SPEC']
147
- FileList[ ENV['SPEC'] ]
123
+ FileList[ENV['SPEC']].sort
124
+ elsif String === pattern && !File.exist?(pattern)
125
+ return if [*rspec_opts].any? { |opt| opt =~ /--pattern/ }
126
+ "--pattern #{escape pattern}"
148
127
  else
149
- FileList[ pattern ].map { |f| f.gsub(/"/, '\"').gsub(/'/, "\\\\'") }
128
+ # Before RSpec 3.1, we used `FileList` to get the list of matched
129
+ # files, and then pass that along to the `rspec` command. Starting
130
+ # with 3.1, we prefer to pass along the pattern as-is to the `rspec`
131
+ # command, for 3 reasons:
132
+ #
133
+ # * It's *much* less verbose to pass one `--pattern` option than a
134
+ # long list of files.
135
+ # * It ensures `task.pattern` and `--pattern` have the same
136
+ # behavior.
137
+ # * It fixes a bug, where
138
+ # `task.pattern = pattern_that_matches_no_files` would run *all*
139
+ # files because it would cause no pattern or file args to get
140
+ # passed to `rspec`, which causes all files to get run.
141
+ #
142
+ # However, `FileList` is *far* more flexible than the `--pattern`
143
+ # option. Specifically, it supports individual files and directories,
144
+ # as well as arrays of files, directories and globs, as well as other
145
+ # `FileList` objects.
146
+ #
147
+ # For backwards compatibility, we have to fall back to using FileList
148
+ # if the user has passed a `pattern` option that will not work with
149
+ # `--pattern`.
150
+ #
151
+ # TODO: consider deprecating support for this and removing it in
152
+ # RSpec 4.
153
+ FileList[pattern].sort.map { |file| escape file }
150
154
  end
151
155
  end
152
156
 
153
- def spec_command
154
- @spec_command ||= begin
155
- cmd_parts = []
156
- cmd_parts << RUBY
157
- cmd_parts << ruby_opts
158
- cmd_parts << "-w" if @warning
159
- cmd_parts << "-S" << runner
160
- cmd_parts << "-Ispec:lib" << rcov_opts if rcov
161
- cmd_parts << files_to_run
162
- cmd_parts << "--" if rcov && rspec_opts
163
- cmd_parts << rspec_opts
164
- cmd_parts.flatten.reject(&blank).join(" ")
165
- end
157
+ def file_exclusion_specification
158
+ " --exclude-pattern #{escape exclude_pattern}" if exclude_pattern
166
159
  end
167
160
 
168
- private
169
-
170
- def runner
171
- rcov ? rcov_path : rspec_path
161
+ def spec_command
162
+ cmd_parts = []
163
+ cmd_parts << RUBY
164
+ cmd_parts << ruby_opts
165
+ cmd_parts << rspec_load_path
166
+ cmd_parts << escape(rspec_path)
167
+ cmd_parts << file_inclusion_specification
168
+ cmd_parts << file_exclusion_specification
169
+ cmd_parts << rspec_opts
170
+ cmd_parts.flatten.reject(&blank).join(" ")
172
171
  end
173
172
 
174
173
  def blank
175
- lambda {|s| s.nil? || s == ""}
174
+ lambda { |s| s.nil? || s == "" }
175
+ end
176
+
177
+ def rspec_load_path
178
+ @rspec_load_path ||= begin
179
+ core_and_support = $LOAD_PATH.grep(
180
+ /#{File::SEPARATOR}rspec-(core|support)[^#{File::SEPARATOR}]*#{File::SEPARATOR}lib/
181
+ ).uniq
182
+
183
+ "-I#{core_and_support.map { |file| escape file }.join(File::PATH_SEPARATOR)}"
184
+ end
176
185
  end
177
186
  end
178
187
  end
@@ -1,102 +1,265 @@
1
1
  module RSpec::Core
2
+ # A reporter will send notifications to listeners, usually formatters for the
3
+ # spec suite run.
2
4
  class Reporter
3
- def initialize(*formatters)
4
- @formatters = formatters
5
- @example_count = @failure_count = @pending_count = 0
6
- @duration = @start = nil
5
+ # @private
6
+ RSPEC_NOTIFICATIONS = Set.new(
7
+ [
8
+ :close, :deprecation, :deprecation_summary, :dump_failures, :dump_pending,
9
+ :dump_profile, :dump_summary, :example_failed, :example_group_finished,
10
+ :example_group_started, :example_passed, :example_pending, :example_started,
11
+ :message, :seed, :start, :start_dump, :stop, :example_finished
12
+ ])
13
+
14
+ def initialize(configuration)
15
+ @configuration = configuration
16
+ @listeners = Hash.new { |h, k| h[k] = Set.new }
17
+ @examples = []
18
+ @failed_examples = []
19
+ @pending_examples = []
20
+ @duration = @start = @load_time = nil
21
+ @non_example_exception_count = 0
22
+ @setup_default = lambda {}
23
+ @setup = false
24
+ @profiler = nil
7
25
  end
8
26
 
9
- # @api
27
+ # @private
28
+ attr_reader :examples, :failed_examples, :pending_examples
29
+
30
+ # Registers a listener to a list of notifications. The reporter will send
31
+ # notification of events to all registered listeners.
32
+ #
33
+ # @param listener [Object] An obect that wishes to be notified of reporter
34
+ # events
35
+ # @param notifications [Array] Array of symbols represents the events a
36
+ # listener wishes to subscribe too
37
+ def register_listener(listener, *notifications)
38
+ notifications.each do |notification|
39
+ @listeners[notification.to_sym] << listener
40
+ end
41
+ true
42
+ end
43
+
44
+ # @private
45
+ def prepare_default(loader, output_stream, deprecation_stream)
46
+ @setup_default = lambda do
47
+ loader.setup_default output_stream, deprecation_stream
48
+ end
49
+ end
50
+
51
+ # @private
52
+ def registered_listeners(notification)
53
+ @listeners[notification].to_a
54
+ end
55
+
56
+ # @overload report(count, &block)
10
57
  # @overload report(count, &block)
11
- # @overload report(count, seed, &block)
12
- # @param [Integer] count the number of examples being run
13
- # @param [Integer] seed the seed used to randomize the spec run
14
- # @param [Block] block yields itself for further reporting.
58
+ # @param expected_example_count [Integer] the number of examples being run
59
+ # @yield [Block] block yields itself for further reporting.
15
60
  #
16
61
  # Initializes the report run and yields itself for further reporting. The
17
62
  # block is required, so that the reporter can manage cleaning up after the
18
63
  # run.
19
64
  #
20
- # ### Warning:
21
- #
22
- # The `seed` argument is an internal API and is not guaranteed to be
23
- # supported in the future.
24
- #
25
65
  # @example
26
66
  #
27
67
  # reporter.report(group.examples.size) do |r|
28
68
  # example_groups.map {|g| g.run(r) }
29
69
  # end
30
70
  #
31
- def report(expected_example_count, seed=nil)
71
+ def report(expected_example_count)
32
72
  start(expected_example_count)
33
73
  begin
34
74
  yield self
35
75
  ensure
36
- finish(seed)
76
+ finish
37
77
  end
38
78
  end
39
79
 
40
- def start(expected_example_count)
41
- @start = Time.now
42
- notify :start, expected_example_count
80
+ # @param exit_code [Integer] the exit_code to be return by the reporter
81
+ #
82
+ # Reports a run that exited early without having run any examples.
83
+ #
84
+ def exit_early(exit_code)
85
+ report(0) { exit_code }
43
86
  end
44
87
 
88
+ # @private
89
+ def start(expected_example_count, time=RSpec::Core::Time.now)
90
+ @start = time
91
+ @load_time = (@start - @configuration.start_time).to_f
92
+ notify :seed, Notifications::SeedNotification.new(@configuration.seed, seed_used?)
93
+ notify :start, Notifications::StartNotification.new(expected_example_count, @load_time)
94
+ end
95
+
96
+ # @param message [#to_s] A message object to send to formatters
97
+ #
98
+ # Send a custom message to supporting formatters.
45
99
  def message(message)
46
- notify :message, message
100
+ notify :message, Notifications::MessageNotification.new(message)
47
101
  end
48
102
 
103
+ # @param event [Symbol] Name of the custom event to trigger on formatters
104
+ # @param options [Hash] Hash of arguments to provide via `CustomNotification`
105
+ #
106
+ # Publish a custom event to supporting registered formatters.
107
+ # @see RSpec::Core::Notifications::CustomNotification
108
+ def publish(event, options={})
109
+ if RSPEC_NOTIFICATIONS.include? event
110
+ raise "RSpec::Core::Reporter#publish is intended for sending custom " \
111
+ "events not internal RSpec ones, please rename your custom event."
112
+ end
113
+ notify event, Notifications::CustomNotification.for(options)
114
+ end
115
+
116
+ # @private
49
117
  def example_group_started(group)
50
- notify :example_group_started, group unless group.descendant_filtered_examples.empty?
118
+ notify :example_group_started, Notifications::GroupNotification.new(group) unless group.descendant_filtered_examples.empty?
51
119
  end
52
120
 
121
+ # @private
53
122
  def example_group_finished(group)
54
- notify :example_group_finished, group unless group.descendant_filtered_examples.empty?
123
+ notify :example_group_finished, Notifications::GroupNotification.new(group) unless group.descendant_filtered_examples.empty?
55
124
  end
56
125
 
126
+ # @private
57
127
  def example_started(example)
58
- @example_count += 1
59
- notify :example_started, example
128
+ @examples << example
129
+ notify :example_started, Notifications::ExampleNotification.for(example)
60
130
  end
61
131
 
132
+ # @private
133
+ def example_finished(example)
134
+ notify :example_finished, Notifications::ExampleNotification.for(example)
135
+ end
136
+
137
+ # @private
62
138
  def example_passed(example)
63
- notify :example_passed, example
139
+ notify :example_passed, Notifications::ExampleNotification.for(example)
64
140
  end
65
141
 
142
+ # @private
66
143
  def example_failed(example)
67
- @failure_count += 1
68
- notify :example_failed, example
144
+ @failed_examples << example
145
+ notify :example_failed, Notifications::ExampleNotification.for(example)
69
146
  end
70
147
 
148
+ # @private
71
149
  def example_pending(example)
72
- @pending_count += 1
73
- notify :example_pending, example
150
+ @pending_examples << example
151
+ notify :example_pending, Notifications::ExampleNotification.for(example)
74
152
  end
75
153
 
76
- def finish(seed)
77
- begin
154
+ # @private
155
+ def deprecation(hash)
156
+ notify :deprecation, Notifications::DeprecationNotification.from_hash(hash)
157
+ end
158
+
159
+ # @private
160
+ # Provides a way to notify of an exception that is not tied to any
161
+ # particular example (such as an exception encountered in a :suite hook).
162
+ # Exceptions will be formatted the same way they normally are.
163
+ def notify_non_example_exception(exception, context_description)
164
+ @configuration.world.non_example_failure = true
165
+ @non_example_exception_count += 1
166
+
167
+ example = Example.new(AnonymousExampleGroup, context_description, {})
168
+ presenter = Formatters::ExceptionPresenter.new(exception, example, :indentation => 0)
169
+ message presenter.fully_formatted(nil)
170
+ end
171
+
172
+ # @private
173
+ def finish
174
+ close_after do
78
175
  stop
79
- notify :start_dump
80
- notify :dump_pending
81
- notify :dump_failures
82
- notify :dump_summary, @duration, @example_count, @failure_count, @pending_count
83
- notify :seed, seed if seed
84
- ensure
85
- notify :close
176
+ notify :start_dump, Notifications::NullNotification
177
+ notify :dump_pending, Notifications::ExamplesNotification.new(self)
178
+ notify :dump_failures, Notifications::ExamplesNotification.new(self)
179
+ notify :deprecation_summary, Notifications::NullNotification
180
+ unless mute_profile_output?
181
+ notify :dump_profile, Notifications::ProfileNotification.new(@duration, @examples,
182
+ @configuration.profile_examples,
183
+ @profiler.example_groups)
184
+ end
185
+ notify :dump_summary, Notifications::SummaryNotification.new(@duration, @examples, @failed_examples,
186
+ @pending_examples, @load_time,
187
+ @non_example_exception_count)
188
+ notify :seed, Notifications::SeedNotification.new(@configuration.seed, seed_used?)
86
189
  end
87
190
  end
88
191
 
89
- alias_method :abort, :finish
192
+ # @private
193
+ def close_after
194
+ yield
195
+ ensure
196
+ close
197
+ end
90
198
 
199
+ # @private
91
200
  def stop
92
- @duration = Time.now - @start if @start
93
- notify :stop
201
+ @duration = (RSpec::Core::Time.now - @start).to_f if @start
202
+ notify :stop, Notifications::ExamplesNotification.new(self)
94
203
  end
95
204
 
96
- def notify(method, *args, &block)
97
- @formatters.each do |formatter|
98
- formatter.send method, *args, &block
205
+ # @private
206
+ def notify(event, notification)
207
+ ensure_listeners_ready
208
+ registered_listeners(event).each do |formatter|
209
+ formatter.__send__(event, notification)
210
+ end
211
+ end
212
+
213
+ # @private
214
+ def abort_with(msg, exit_status)
215
+ message(msg)
216
+ close
217
+ exit!(exit_status)
218
+ end
219
+
220
+ # @private
221
+ def fail_fast_limit_met?
222
+ return false unless (fail_fast = @configuration.fail_fast)
223
+
224
+ if fail_fast == true
225
+ @failed_examples.any?
226
+ else
227
+ fail_fast <= @failed_examples.size
99
228
  end
100
229
  end
230
+
231
+ private
232
+
233
+ def ensure_listeners_ready
234
+ return if @setup
235
+
236
+ @setup_default.call
237
+ @profiler = Profiler.new
238
+ register_listener @profiler, *Profiler::NOTIFICATIONS
239
+ @setup = true
240
+ end
241
+
242
+ def close
243
+ notify :close, Notifications::NullNotification
244
+ end
245
+
246
+ def mute_profile_output?
247
+ # Don't print out profiled info if there are failures and `--fail-fast` is
248
+ # used, it just clutters the output.
249
+ !@configuration.profile_examples? || fail_fast_limit_met?
250
+ end
251
+
252
+ def seed_used?
253
+ @configuration.seed && @configuration.seed_used?
254
+ end
255
+ end
256
+
257
+ # @private
258
+ # # Used in place of a {Reporter} for situations where we don't want reporting output.
259
+ class NullReporter
260
+ def self.method_missing(*)
261
+ # ignore
262
+ end
263
+ private_class_method :method_missing
101
264
  end
102
265
  end
@@ -1,14 +1,12 @@
1
1
  # This is borrowed (slightly modified) from Scott Taylor's
2
2
  # project_path project:
3
3
  # http://github.com/smtlaissezfaire/project_path
4
-
5
- require 'pathname'
6
-
7
4
  module RSpec
8
5
  module Core
6
+ # @private
9
7
  module RubyProject
10
8
  def add_to_load_path(*dirs)
11
- dirs.map {|dir| add_dir_to_load_path(File.join(root, dir))}
9
+ dirs.each { |dir| add_dir_to_load_path(File.join(root, dir)) }
12
10
  end
13
11
 
14
12
  def add_dir_to_load_path(dir)
@@ -24,12 +22,23 @@ module RSpec
24
22
  end
25
23
 
26
24
  def find_first_parent_containing(dir)
27
- ascend_until {|path| File.exists?(File.join(path, dir))}
25
+ ascend_until { |path| File.exist?(File.join(path, dir)) }
28
26
  end
29
27
 
30
28
  def ascend_until
31
- Pathname(File.expand_path('.')).ascend do |path|
29
+ fs = File::SEPARATOR
30
+ escaped_slash = "\\#{fs}"
31
+ special = "_RSPEC_ESCAPED_SLASH_"
32
+ project_path = File.expand_path(".")
33
+ parts = project_path.gsub(escaped_slash, special).squeeze(fs).split(fs).map do |x|
34
+ x.gsub(special, escaped_slash)
35
+ end
36
+
37
+ until parts.empty?
38
+ path = parts.join(fs)
39
+ path = fs if path == ""
32
40
  return path if yield(path)
41
+ parts.pop
33
42
  end
34
43
  end
35
44