rspec-core 3.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.document +5 -0
  5. data/.yardopts +8 -0
  6. data/Changelog.md +2243 -0
  7. data/LICENSE.md +26 -0
  8. data/README.md +384 -0
  9. data/exe/rspec +4 -0
  10. data/lib/rspec/autorun.rb +3 -0
  11. data/lib/rspec/core.rb +185 -0
  12. data/lib/rspec/core/backtrace_formatter.rb +65 -0
  13. data/lib/rspec/core/bisect/coordinator.rb +62 -0
  14. data/lib/rspec/core/bisect/example_minimizer.rb +173 -0
  15. data/lib/rspec/core/bisect/fork_runner.rb +134 -0
  16. data/lib/rspec/core/bisect/server.rb +61 -0
  17. data/lib/rspec/core/bisect/shell_command.rb +126 -0
  18. data/lib/rspec/core/bisect/shell_runner.rb +73 -0
  19. data/lib/rspec/core/bisect/utilities.rb +58 -0
  20. data/lib/rspec/core/configuration.rb +2308 -0
  21. data/lib/rspec/core/configuration_options.rb +233 -0
  22. data/lib/rspec/core/drb.rb +113 -0
  23. data/lib/rspec/core/dsl.rb +98 -0
  24. data/lib/rspec/core/example.rb +656 -0
  25. data/lib/rspec/core/example_group.rb +889 -0
  26. data/lib/rspec/core/example_status_persister.rb +235 -0
  27. data/lib/rspec/core/filter_manager.rb +231 -0
  28. data/lib/rspec/core/flat_map.rb +20 -0
  29. data/lib/rspec/core/formatters.rb +269 -0
  30. data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
  31. data/lib/rspec/core/formatters/base_formatter.rb +70 -0
  32. data/lib/rspec/core/formatters/base_text_formatter.rb +75 -0
  33. data/lib/rspec/core/formatters/bisect_drb_formatter.rb +29 -0
  34. data/lib/rspec/core/formatters/bisect_progress_formatter.rb +157 -0
  35. data/lib/rspec/core/formatters/console_codes.rb +68 -0
  36. data/lib/rspec/core/formatters/deprecation_formatter.rb +223 -0
  37. data/lib/rspec/core/formatters/documentation_formatter.rb +70 -0
  38. data/lib/rspec/core/formatters/exception_presenter.rb +508 -0
  39. data/lib/rspec/core/formatters/fallback_message_formatter.rb +28 -0
  40. data/lib/rspec/core/formatters/helpers.rb +110 -0
  41. data/lib/rspec/core/formatters/html_formatter.rb +153 -0
  42. data/lib/rspec/core/formatters/html_printer.rb +414 -0
  43. data/lib/rspec/core/formatters/html_snippet_extractor.rb +120 -0
  44. data/lib/rspec/core/formatters/json_formatter.rb +102 -0
  45. data/lib/rspec/core/formatters/profile_formatter.rb +68 -0
  46. data/lib/rspec/core/formatters/progress_formatter.rb +29 -0
  47. data/lib/rspec/core/formatters/protocol.rb +182 -0
  48. data/lib/rspec/core/formatters/snippet_extractor.rb +134 -0
  49. data/lib/rspec/core/formatters/syntax_highlighter.rb +91 -0
  50. data/lib/rspec/core/hooks.rb +624 -0
  51. data/lib/rspec/core/invocations.rb +87 -0
  52. data/lib/rspec/core/memoized_helpers.rb +554 -0
  53. data/lib/rspec/core/metadata.rb +498 -0
  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 +309 -0
  63. data/lib/rspec/core/ordering.rb +158 -0
  64. data/lib/rspec/core/output_wrapper.rb +29 -0
  65. data/lib/rspec/core/pending.rb +165 -0
  66. data/lib/rspec/core/profiler.rb +34 -0
  67. data/lib/rspec/core/project_initializer.rb +48 -0
  68. data/lib/rspec/core/project_initializer/.rspec +1 -0
  69. data/lib/rspec/core/project_initializer/spec/spec_helper.rb +100 -0
  70. data/lib/rspec/core/rake_task.rb +168 -0
  71. data/lib/rspec/core/reporter.rb +257 -0
  72. data/lib/rspec/core/ruby_project.rb +53 -0
  73. data/lib/rspec/core/runner.rb +199 -0
  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 +55 -0
  77. data/lib/rspec/core/shared_example_group.rb +269 -0
  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 +9 -0
  81. data/lib/rspec/core/warnings.rb +40 -0
  82. data/lib/rspec/core/world.rb +275 -0
  83. metadata +292 -0
  84. metadata.gz.sig +0 -0
@@ -0,0 +1,29 @@
1
+ require 'drb/drb'
2
+ RSpec::Support.require_rspec_core "formatters/base_bisect_formatter"
3
+
4
+ module RSpec
5
+ module Core
6
+ module Formatters
7
+ # Used by `--bisect`. When it shells out and runs a portion of the suite, it uses
8
+ # this formatter as a means to have the status reported back to it, via DRb.
9
+ #
10
+ # Note that since DRb calls carry considerable overhead compared to normal
11
+ # method calls, we try to minimize the number of DRb calls for perf reasons,
12
+ # opting to communicate only at the start and the end of the run, rather than
13
+ # after each example.
14
+ # @private
15
+ class BisectDRbFormatter < BaseBisectFormatter
16
+ def initialize(_output)
17
+ drb_uri = "druby://localhost:#{RSpec.configuration.drb_port}"
18
+ @bisect_server = DRbObject.new_with_uri(drb_uri)
19
+ RSpec.configuration.files_or_directories_to_run = @bisect_server.files_or_directories_to_run
20
+ super(Set.new(@bisect_server.expected_failures))
21
+ end
22
+
23
+ def notify_results(results)
24
+ @bisect_server.latest_run_results = results
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,157 @@
1
+ RSpec::Support.require_rspec_core "formatters/base_text_formatter"
2
+
3
+ module RSpec
4
+ module Core
5
+ module Formatters
6
+ # @private
7
+ # Produces progress output while bisecting.
8
+ class BisectProgressFormatter < BaseTextFormatter
9
+ def initialize(output, bisect_runner)
10
+ super(output)
11
+ @bisect_runner = bisect_runner
12
+ end
13
+
14
+ def bisect_starting(notification)
15
+ @round_count = 0
16
+ output.puts bisect_started_message(notification)
17
+ output.print "Running suite to find failures..."
18
+ end
19
+
20
+ def bisect_original_run_complete(notification)
21
+ failures = Helpers.pluralize(notification.failed_example_ids.size, "failing example")
22
+ non_failures = Helpers.pluralize(notification.non_failing_example_ids.size, "non-failing example")
23
+
24
+ output.puts " (#{Helpers.format_duration(notification.duration)})"
25
+ output.puts "Starting bisect with #{failures} and #{non_failures}."
26
+ end
27
+
28
+ def bisect_dependency_check_started(_notification)
29
+ output.print "Checking that failure(s) are order-dependent.."
30
+ end
31
+
32
+ def bisect_dependency_check_passed(_notification)
33
+ output.puts " failure appears to be order-dependent"
34
+ end
35
+
36
+ def bisect_dependency_check_failed(_notification)
37
+ output.puts " failure(s) do not require any non-failures to run first"
38
+
39
+ if @bisect_runner == :fork
40
+ output.puts
41
+ output.puts "=" * 80
42
+ output.puts "NOTE: this bisect run used `config.bisect_runner = :fork`, which generally"
43
+ output.puts "provides significantly faster bisection runs than the old shell-based runner,"
44
+ output.puts "but may inaccurately report that no non-failures are required. If this result"
45
+ output.puts "is unexpected, consider setting `config.bisect_runner = :shell` and trying again."
46
+ output.puts "=" * 80
47
+ end
48
+ end
49
+
50
+ def bisect_round_started(notification, include_trailing_space=true)
51
+ @round_count += 1
52
+ range_desc = notification.candidate_range.description
53
+
54
+ output.print "\nRound #{@round_count}: bisecting over non-failing #{range_desc}"
55
+ output.print " " if include_trailing_space
56
+ end
57
+
58
+ def bisect_round_ignoring_ids(notification)
59
+ range_desc = notification.ignore_range.description
60
+
61
+ output.print " ignoring #{range_desc}"
62
+ output.print " (#{Helpers.format_duration(notification.duration)})"
63
+ end
64
+
65
+ def bisect_round_detected_multiple_culprits(notification)
66
+ output.print " multiple culprits detected - splitting candidates"
67
+ output.print " (#{Helpers.format_duration(notification.duration)})"
68
+ end
69
+
70
+ def bisect_individual_run_complete(_)
71
+ output.print '.'
72
+ end
73
+
74
+ def bisect_complete(notification)
75
+ output.puts "\nBisect complete! Reduced necessary non-failing examples " \
76
+ "from #{notification.original_non_failing_count} to " \
77
+ "#{notification.remaining_count} in " \
78
+ "#{Helpers.format_duration(notification.duration)}."
79
+ end
80
+
81
+ def bisect_repro_command(notification)
82
+ output.puts "\nThe minimal reproduction command is:\n #{notification.repro}"
83
+ end
84
+
85
+ def bisect_failed(notification)
86
+ output.puts "\nBisect failed! #{notification.failure_explanation}"
87
+ end
88
+
89
+ def bisect_aborted(notification)
90
+ output.puts "\n\nBisect aborted!"
91
+ output.puts "\nThe most minimal reproduction command discovered so far is:\n #{notification.repro}"
92
+ end
93
+
94
+ private
95
+
96
+ def bisect_started_message(notification)
97
+ options = notification.original_cli_args.join(' ')
98
+ "Bisect started using options: #{options.inspect}"
99
+ end
100
+ end
101
+
102
+ # @private
103
+ # Produces detailed debug output while bisecting. Used when bisect is
104
+ # performed with `--bisect=verbose`. Designed to provide details for
105
+ # us when we need to troubleshoot bisect bugs.
106
+ class BisectDebugFormatter < BisectProgressFormatter
107
+ def bisect_original_run_complete(notification)
108
+ output.puts " (#{Helpers.format_duration(notification.duration)})"
109
+
110
+ output.puts " - #{describe_ids 'Failing examples', notification.failed_example_ids}"
111
+ output.puts " - #{describe_ids 'Non-failing examples', notification.non_failing_example_ids}"
112
+ end
113
+
114
+ def bisect_individual_run_start(notification)
115
+ output.print "\n - Running: #{notification.command}"
116
+ end
117
+
118
+ def bisect_individual_run_complete(notification)
119
+ output.print " (#{Helpers.format_duration(notification.duration)})"
120
+ end
121
+
122
+ def bisect_dependency_check_passed(_notification)
123
+ output.print "\n - Failure appears to be order-dependent"
124
+ end
125
+
126
+ def bisect_dependency_check_failed(_notification)
127
+ output.print "\n - Failure is not order-dependent"
128
+ end
129
+
130
+ def bisect_round_started(notification)
131
+ super(notification, false)
132
+ end
133
+
134
+ def bisect_round_ignoring_ids(notification)
135
+ output.print "\n - #{describe_ids 'Examples we can safely ignore', notification.ids_to_ignore}"
136
+ output.print "\n - #{describe_ids 'Remaining non-failing examples', notification.remaining_ids}"
137
+ end
138
+
139
+ def bisect_round_detected_multiple_culprits(_notification)
140
+ output.print "\n - Multiple culprits detected - splitting candidates"
141
+ end
142
+
143
+ private
144
+
145
+ def describe_ids(description, ids)
146
+ organized_ids = Formatters::Helpers.organize_ids(ids)
147
+ formatted_ids = organized_ids.map { |id| " - #{id}" }.join("\n")
148
+ "#{description} (#{ids.size}):\n#{formatted_ids}"
149
+ end
150
+
151
+ def bisect_started_message(notification)
152
+ "#{super} and bisect runner: #{notification.bisect_runner.inspect}"
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,68 @@
1
+ module RSpec
2
+ module Core
3
+ module Formatters
4
+ # ConsoleCodes provides helpers for formatting console output
5
+ # with ANSI codes, e.g. color's and bold.
6
+ module ConsoleCodes
7
+ # @private
8
+ VT100_CODES =
9
+ {
10
+ :black => 30,
11
+ :red => 31,
12
+ :green => 32,
13
+ :yellow => 33,
14
+ :blue => 34,
15
+ :magenta => 35,
16
+ :cyan => 36,
17
+ :white => 37,
18
+ :bold => 1,
19
+ }
20
+ # @private
21
+ VT100_CODE_VALUES = VT100_CODES.invert
22
+
23
+ module_function
24
+
25
+ # @private
26
+ def config_colors_to_methods
27
+ @config_colors_to_methods ||=
28
+ Configuration.instance_methods.grep(/_color\z/).inject({}) do |hash, method|
29
+ hash[method.to_s.sub(/_color\z/, '').to_sym] = method
30
+ hash
31
+ end
32
+ end
33
+
34
+ # Fetches the correct code for the supplied symbol, or checks
35
+ # that a code is valid. Defaults to white (37).
36
+ #
37
+ # @param code_or_symbol [Symbol, Fixnum] Symbol or code to check
38
+ # @return [Fixnum] a console code
39
+ def console_code_for(code_or_symbol)
40
+ if (config_method = config_colors_to_methods[code_or_symbol])
41
+ console_code_for RSpec.configuration.__send__(config_method)
42
+ elsif VT100_CODE_VALUES.key?(code_or_symbol)
43
+ code_or_symbol
44
+ else
45
+ VT100_CODES.fetch(code_or_symbol) do
46
+ console_code_for(:white)
47
+ end
48
+ end
49
+ end
50
+
51
+ # Wraps a piece of text in ANSI codes with the supplied code. Will
52
+ # only apply the control code if `RSpec.configuration.color_enabled?`
53
+ # returns true.
54
+ #
55
+ # @param text [String] the text to wrap
56
+ # @param code_or_symbol [Symbol, Fixnum] the desired control code
57
+ # @return [String] the wrapped text
58
+ def wrap(text, code_or_symbol)
59
+ if RSpec.configuration.color_enabled?
60
+ "\e[#{console_code_for(code_or_symbol)}m#{text}\e[0m"
61
+ else
62
+ text
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,223 @@
1
+ RSpec::Support.require_rspec_core "formatters/helpers"
2
+
3
+ module RSpec
4
+ module Core
5
+ module Formatters
6
+ # @private
7
+ class DeprecationFormatter
8
+ Formatters.register self, :deprecation, :deprecation_summary
9
+
10
+ attr_reader :count, :deprecation_stream, :summary_stream
11
+
12
+ def initialize(deprecation_stream, summary_stream)
13
+ @deprecation_stream = deprecation_stream
14
+ @summary_stream = summary_stream
15
+ @seen_deprecations = Set.new
16
+ @count = 0
17
+ end
18
+ alias :output :deprecation_stream
19
+
20
+ def printer
21
+ @printer ||= case deprecation_stream
22
+ when File
23
+ ImmediatePrinter.new(FileStream.new(deprecation_stream),
24
+ summary_stream, self)
25
+ when RaiseErrorStream
26
+ ImmediatePrinter.new(deprecation_stream, summary_stream, self)
27
+ else
28
+ DelayedPrinter.new(deprecation_stream, summary_stream, self)
29
+ end
30
+ end
31
+
32
+ def deprecation(notification)
33
+ return if @seen_deprecations.include? notification
34
+
35
+ @count += 1
36
+ printer.print_deprecation_message notification
37
+ @seen_deprecations << notification
38
+ end
39
+
40
+ def deprecation_summary(_notification)
41
+ printer.deprecation_summary
42
+ end
43
+
44
+ def deprecation_message_for(data)
45
+ if data.message
46
+ SpecifiedDeprecationMessage.new(data)
47
+ else
48
+ GeneratedDeprecationMessage.new(data)
49
+ end
50
+ end
51
+
52
+ RAISE_ERROR_CONFIG_NOTICE = <<-EOS.gsub(/^\s+\|/, '')
53
+ |
54
+ |If you need more of the backtrace for any of these deprecations to
55
+ |identify where to make the necessary changes, you can configure
56
+ |`config.raise_errors_for_deprecations!`, and it will turn the
57
+ |deprecation warnings into errors, giving you the full backtrace.
58
+ EOS
59
+
60
+ DEPRECATION_STREAM_NOTICE = "Pass `--deprecation-out` or set " \
61
+ "`config.deprecation_stream` to a file for full output."
62
+ TOO_MANY_WARNINGS_NOTICE = "Too many similar deprecation messages " \
63
+ "reported, disregarding further reports. #{DEPRECATION_STREAM_NOTICE}"
64
+
65
+ # @private
66
+ SpecifiedDeprecationMessage = Struct.new(:type) do
67
+ def initialize(data)
68
+ @message = data.message
69
+ super deprecation_type_for(data)
70
+ end
71
+
72
+ def to_s
73
+ output_formatted @message
74
+ end
75
+
76
+ def too_many_warnings_message
77
+ TOO_MANY_WARNINGS_NOTICE
78
+ end
79
+
80
+ private
81
+
82
+ def output_formatted(str)
83
+ return str unless str.lines.count > 1
84
+ separator = '-' * 80
85
+ "#{separator}\n#{str.chomp}\n#{separator}"
86
+ end
87
+
88
+ def deprecation_type_for(data)
89
+ data.message.gsub(/(\w+\/)+\w+\.rb:\d+/, '')
90
+ end
91
+ end
92
+
93
+ # @private
94
+ GeneratedDeprecationMessage = Struct.new(:type) do
95
+ def initialize(data)
96
+ @data = data
97
+ super data.deprecated
98
+ end
99
+
100
+ def to_s
101
+ msg = String.new("#{@data.deprecated} is deprecated.")
102
+ msg << " Use #{@data.replacement} instead." if @data.replacement
103
+ msg << " Called from #{@data.call_site}." if @data.call_site
104
+ msg
105
+ end
106
+
107
+ def too_many_warnings_message
108
+ "Too many uses of deprecated '#{type}'. #{DEPRECATION_STREAM_NOTICE}"
109
+ end
110
+ end
111
+
112
+ # @private
113
+ class ImmediatePrinter
114
+ attr_reader :deprecation_stream, :summary_stream, :deprecation_formatter
115
+
116
+ def initialize(deprecation_stream, summary_stream, deprecation_formatter)
117
+ @deprecation_stream = deprecation_stream
118
+
119
+ @summary_stream = summary_stream
120
+ @deprecation_formatter = deprecation_formatter
121
+ end
122
+
123
+ def print_deprecation_message(data)
124
+ deprecation_message = deprecation_formatter.deprecation_message_for(data)
125
+ deprecation_stream.puts deprecation_message.to_s
126
+ end
127
+
128
+ def deprecation_summary
129
+ return if deprecation_formatter.count.zero?
130
+ deprecation_stream.summarize(summary_stream, deprecation_formatter.count)
131
+ end
132
+ end
133
+
134
+ # @private
135
+ class DelayedPrinter
136
+ TOO_MANY_USES_LIMIT = 4
137
+
138
+ attr_reader :deprecation_stream, :summary_stream, :deprecation_formatter
139
+
140
+ def initialize(deprecation_stream, summary_stream, deprecation_formatter)
141
+ @deprecation_stream = deprecation_stream
142
+ @summary_stream = summary_stream
143
+ @deprecation_formatter = deprecation_formatter
144
+ @seen_deprecations = Hash.new { 0 }
145
+ @deprecation_messages = Hash.new { |h, k| h[k] = [] }
146
+ end
147
+
148
+ def print_deprecation_message(data)
149
+ deprecation_message = deprecation_formatter.deprecation_message_for(data)
150
+ @seen_deprecations[deprecation_message] += 1
151
+
152
+ stash_deprecation_message(deprecation_message)
153
+ end
154
+
155
+ def stash_deprecation_message(deprecation_message)
156
+ if @seen_deprecations[deprecation_message] < TOO_MANY_USES_LIMIT
157
+ @deprecation_messages[deprecation_message] << deprecation_message.to_s
158
+ elsif @seen_deprecations[deprecation_message] == TOO_MANY_USES_LIMIT
159
+ @deprecation_messages[deprecation_message] << deprecation_message.too_many_warnings_message
160
+ end
161
+ end
162
+
163
+ def deprecation_summary
164
+ return unless @deprecation_messages.any?
165
+
166
+ print_deferred_deprecation_warnings
167
+ deprecation_stream.puts RAISE_ERROR_CONFIG_NOTICE
168
+
169
+ summary_stream.puts "\n#{Helpers.pluralize(deprecation_formatter.count, 'deprecation warning')} total"
170
+ end
171
+
172
+ def print_deferred_deprecation_warnings
173
+ deprecation_stream.puts "\nDeprecation Warnings:\n\n"
174
+ @deprecation_messages.keys.sort_by(&:type).each do |deprecation|
175
+ messages = @deprecation_messages[deprecation]
176
+ messages.each { |msg| deprecation_stream.puts msg }
177
+ deprecation_stream.puts
178
+ end
179
+ end
180
+ end
181
+
182
+ # @private
183
+ # Not really a stream, but is usable in place of one.
184
+ class RaiseErrorStream
185
+ def puts(message)
186
+ raise DeprecationError, message
187
+ end
188
+
189
+ def summarize(summary_stream, deprecation_count)
190
+ summary_stream.puts "\n#{Helpers.pluralize(deprecation_count, 'deprecation')} found."
191
+ end
192
+ end
193
+
194
+ # @private
195
+ # Wraps a File object and provides file-specific operations.
196
+ class FileStream
197
+ def initialize(file)
198
+ @file = file
199
+
200
+ # In one of my test suites, I got lots of duplicate output in the
201
+ # deprecation file (e.g. 200 of the same deprecation, even though
202
+ # the `puts` below was only called 6 times). Setting `sync = true`
203
+ # fixes this (but we really have no idea why!).
204
+ @file.sync = true
205
+ end
206
+
207
+ def puts(*args)
208
+ @file.puts(*args)
209
+ end
210
+
211
+ def summarize(summary_stream, deprecation_count)
212
+ path = @file.respond_to?(:path) ? @file.path : @file.inspect
213
+ summary_stream.puts "\n#{Helpers.pluralize(deprecation_count, 'deprecation')} logged to #{path}"
214
+ puts RAISE_ERROR_CONFIG_NOTICE
215
+ end
216
+ end
217
+ end
218
+ end
219
+
220
+ # Deprecation Error.
221
+ DeprecationError = Class.new(StandardError)
222
+ end
223
+ end