rspec-core 3.1.7 → 3.2.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 (51) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.yardopts +1 -0
  5. data/Changelog.md +84 -0
  6. data/README.md +10 -1
  7. data/lib/rspec/core.rb +28 -8
  8. data/lib/rspec/core/backport_random.rb +12 -9
  9. data/lib/rspec/core/configuration.rb +350 -112
  10. data/lib/rspec/core/configuration_options.rb +14 -7
  11. data/lib/rspec/core/dsl.rb +7 -4
  12. data/lib/rspec/core/example.rb +86 -50
  13. data/lib/rspec/core/example_group.rb +247 -86
  14. data/lib/rspec/core/filter_manager.rb +38 -93
  15. data/lib/rspec/core/flat_map.rb +4 -4
  16. data/lib/rspec/core/formatters.rb +10 -6
  17. data/lib/rspec/core/formatters/base_formatter.rb +7 -4
  18. data/lib/rspec/core/formatters/base_text_formatter.rb +12 -12
  19. data/lib/rspec/core/formatters/console_codes.rb +8 -7
  20. data/lib/rspec/core/formatters/deprecation_formatter.rb +5 -3
  21. data/lib/rspec/core/formatters/documentation_formatter.rb +10 -4
  22. data/lib/rspec/core/formatters/helpers.rb +6 -4
  23. data/lib/rspec/core/formatters/html_formatter.rb +13 -8
  24. data/lib/rspec/core/formatters/html_printer.rb +26 -10
  25. data/lib/rspec/core/formatters/profile_formatter.rb +10 -7
  26. data/lib/rspec/core/formatters/protocol.rb +27 -18
  27. data/lib/rspec/core/formatters/snippet_extractor.rb +14 -7
  28. data/lib/rspec/core/hooks.rb +252 -211
  29. data/lib/rspec/core/memoized_helpers.rb +16 -16
  30. data/lib/rspec/core/metadata.rb +67 -28
  31. data/lib/rspec/core/metadata_filter.rb +151 -24
  32. data/lib/rspec/core/minitest_assertions_adapter.rb +5 -2
  33. data/lib/rspec/core/mocking_adapters/flexmock.rb +1 -1
  34. data/lib/rspec/core/mocking_adapters/mocha.rb +8 -8
  35. data/lib/rspec/core/notifications.rb +155 -94
  36. data/lib/rspec/core/option_parser.rb +16 -10
  37. data/lib/rspec/core/pending.rb +11 -9
  38. data/lib/rspec/core/project_initializer.rb +1 -1
  39. data/lib/rspec/core/project_initializer/spec/spec_helper.rb +10 -8
  40. data/lib/rspec/core/rake_task.rb +37 -52
  41. data/lib/rspec/core/reporter.rb +30 -7
  42. data/lib/rspec/core/ruby_project.rb +12 -4
  43. data/lib/rspec/core/runner.rb +5 -8
  44. data/lib/rspec/core/sandbox.rb +37 -0
  45. data/lib/rspec/core/shared_example_group.rb +41 -15
  46. data/lib/rspec/core/test_unit_assertions_adapter.rb +3 -3
  47. data/lib/rspec/core/version.rb +1 -1
  48. data/lib/rspec/core/warnings.rb +2 -2
  49. data/lib/rspec/core/world.rb +12 -28
  50. metadata +44 -31
  51. metadata.gz.sig +0 -0
@@ -1,71 +1,6 @@
1
1
  module RSpec
2
2
  module Core
3
3
  # @private
4
- # Manages the filtering of examples and groups by matching tags declared on
5
- # the command line or options files, or filters declared via
6
- # `RSpec.configure`, with hash key/values submitted within example group
7
- # and/or example declarations. For example, given this declaration:
8
- #
9
- # describe Thing, :awesome => true do
10
- # it "does something" do
11
- # # ...
12
- # end
13
- # end
14
- #
15
- # That group (or any other with `:awesome => true`) would be filtered in
16
- # with any of the following commands:
17
- #
18
- # rspec --tag awesome:true
19
- # rspec --tag awesome
20
- # rspec -t awesome:true
21
- # rspec -t awesome
22
- #
23
- # Prefixing the tag names with `~` negates the tags, thus excluding this group with
24
- # any of:
25
- #
26
- # rspec --tag ~awesome:true
27
- # rspec --tag ~awesome
28
- # rspec -t ~awesome:true
29
- # rspec -t ~awesome
30
- #
31
- # ## Options files and command line overrides
32
- #
33
- # Tag declarations can be stored in `.rspec`, `~/.rspec`, or a custom
34
- # options file. This is useful for storing defaults. For example, let's
35
- # say you've got some slow specs that you want to suppress most of the
36
- # time. You can tag them like this:
37
- #
38
- # describe Something, :slow => true do
39
- #
40
- # And then store this in `.rspec`:
41
- #
42
- # --tag ~slow:true
43
- #
44
- # Now when you run `rspec`, that group will be excluded.
45
- #
46
- # ## Overriding
47
- #
48
- # Of course, you probably want to run them sometimes, so you can override
49
- # this tag on the command line like this:
50
- #
51
- # rspec --tag slow:true
52
- #
53
- # ## RSpec.configure
54
- #
55
- # You can also store default tags with `RSpec.configure`. We use `tag` on
56
- # the command line (and in options files like `.rspec`), but for historical
57
- # reasons we use the term `filter` in `RSpec.configure:
58
- #
59
- # RSpec.configure do |c|
60
- # c.filter_run_including :foo => :bar
61
- # c.filter_run_excluding :foo => :bar
62
- # end
63
- #
64
- # These declarations can also be overridden from the command line.
65
- #
66
- # @see RSpec.configure
67
- # @see Configuration#filter_run_including
68
- # @see Configuration#filter_run_excluding
69
4
  class FilterManager
70
5
  attr_reader :exclusions, :inclusions
71
6
 
@@ -83,7 +18,7 @@ module RSpec
83
18
  # { "path/to/file.rb" => [37, 42] }
84
19
  locations = inclusions.delete(:locations) || Hash.new { |h, k| h[k] = [] }
85
20
  locations[File.expand_path(file_path)].push(*line_numbers)
86
- inclusions.add_location(locations)
21
+ inclusions.add(:locations => locations)
87
22
  end
88
23
 
89
24
  def empty?
@@ -91,11 +26,13 @@ module RSpec
91
26
  end
92
27
 
93
28
  def prune(examples)
29
+ examples = prune_conditionally_filtered_examples(examples)
30
+
94
31
  if inclusions.standalone?
95
- base_exclusions = ExclusionRules.new
96
- examples.select { |e| !base_exclusions.include_example?(e) && include?(e) }
32
+ examples.select { |e| include?(e) }
97
33
  else
98
- examples.select { |e| !exclude?(e) && include?(e) }
34
+ locations = inclusions.fetch(:locations) { Hash.new([]) }
35
+ examples.select { |e| priority_include?(e, locations) || (!exclude?(e) && include?(e)) }
99
36
  end
100
37
  end
101
38
 
@@ -111,10 +48,6 @@ module RSpec
111
48
  exclusions.add_with_low_priority(args.last)
112
49
  end
113
50
 
114
- def exclude?(example)
115
- exclusions.include_example?(example)
116
- end
117
-
118
51
  def include(*args)
119
52
  inclusions.add(args.last)
120
53
  end
@@ -127,9 +60,32 @@ module RSpec
127
60
  inclusions.add_with_low_priority(args.last)
128
61
  end
129
62
 
63
+ private
64
+
65
+ def exclude?(example)
66
+ exclusions.include_example?(example)
67
+ end
68
+
130
69
  def include?(example)
131
70
  inclusions.include_example?(example)
132
71
  end
72
+
73
+ def prune_conditionally_filtered_examples(examples)
74
+ examples.reject do |ex|
75
+ meta = ex.metadata
76
+ !meta.fetch(:if, true) || meta[:unless]
77
+ end
78
+ end
79
+
80
+ # When a user specifies a particular spec location, that takes priority
81
+ # over any exclusion filters (such as if the spec is tagged with `:slow`
82
+ # and there is a `:slow => true` exclusion filter), but only for specs
83
+ # defined in the same file as the location filters. Excluded specs in
84
+ # other files should still be excluded.
85
+ def priority_include?(example, locations)
86
+ return false if locations[example.metadata[:absolute_file_path]].empty?
87
+ MetadataFilter.filter_applies?(:locations, locations, example.metadata)
88
+ end
133
89
  end
134
90
 
135
91
  # @private
@@ -194,16 +150,17 @@ module RSpec
194
150
  def description
195
151
  rules.inspect.gsub(PROC_HEX_NUMBER, '').gsub(PROJECT_DIR, '.').gsub(' (lambda)', '')
196
152
  end
153
+
154
+ def include_example?(example)
155
+ MetadataFilter.apply?(:any?, @rules, example.metadata)
156
+ end
197
157
  end
198
158
 
199
159
  # @private
200
- class InclusionRules < FilterRules
201
- STANDALONE_FILTERS = [:locations, :full_description]
202
-
203
- def add_location(locations)
204
- replace_filters(:locations => locations)
205
- end
160
+ ExclusionRules = FilterRules
206
161
 
162
+ # @private
163
+ class InclusionRules < FilterRules
207
164
  def add(*args)
208
165
  apply_standalone_filter(*args) || super
209
166
  end
@@ -217,7 +174,7 @@ module RSpec
217
174
  end
218
175
 
219
176
  def include_example?(example)
220
- @rules.empty? ? true : example.any_apply?(@rules)
177
+ @rules.empty? || super
221
178
  end
222
179
 
223
180
  def standalone?
@@ -240,19 +197,7 @@ module RSpec
240
197
  end
241
198
 
242
199
  def is_standalone_filter?(rules)
243
- STANDALONE_FILTERS.any? { |key| rules.key?(key) }
244
- end
245
- end
246
-
247
- # @private
248
- class ExclusionRules < FilterRules
249
- CONDITIONAL_FILTERS = {
250
- :if => lambda { |value| !value },
251
- :unless => lambda { |value| value }
252
- }.freeze
253
-
254
- def include_example?(example)
255
- example.any_apply?(@rules) || example.any_apply?(CONDITIONAL_FILTERS)
200
+ rules.key?(:full_description)
256
201
  end
257
202
  end
258
203
  end
@@ -3,12 +3,12 @@ module RSpec
3
3
  # @private
4
4
  module FlatMap
5
5
  if [].respond_to?(:flat_map)
6
- def flat_map(array)
7
- array.flat_map { |item| yield item }
6
+ def flat_map(array, &block)
7
+ array.flat_map(&block)
8
8
  end
9
9
  else # for 1.8.7
10
- def flat_map(array)
11
- array.map { |item| yield item }.flatten
10
+ def flat_map(array, &block)
11
+ array.map(&block).flatten(1)
12
12
  end
13
13
  end
14
14
 
@@ -1,10 +1,12 @@
1
1
  RSpec::Support.require_rspec_support "directory_maker"
2
2
  # ## Built-in Formatters
3
3
  #
4
- # * progress (default) - prints dots for passing examples, `F` for failures, `*` for pending
5
- # * documentation - prints the docstrings passed to `describe` and `it` methods (and their aliases)
4
+ # * progress (default) - Prints dots for passing examples, `F` for failures, `*`
5
+ # for pending.
6
+ # * documentation - Prints the docstrings passed to `describe` and `it` methods
7
+ # (and their aliases).
6
8
  # * html
7
- # * json - useful for archiving data for subsequent analysis
9
+ # * json - Useful for archiving data for subsequent analysis.
8
10
  #
9
11
  # The progress formatter is the default, but you can choose any one or more of
10
12
  # the other formatters by passing with the `--format` (or `-f` for short)
@@ -72,7 +74,8 @@ module RSpec::Core::Formatters
72
74
 
73
75
  # Register the formatter class
74
76
  # @param formatter_class [Class] formatter class to register
75
- # @param notifications [Symbol, ...] one or more notifications to be registered to the specified formatter
77
+ # @param notifications [Symbol, ...] one or more notifications to be
78
+ # registered to the specified formatter
76
79
  #
77
80
  # @see RSpec::Core::Formatters::BaseFormatter
78
81
  def self.register(formatter_class, *notifications)
@@ -88,7 +91,7 @@ module RSpec::Core::Formatters
88
91
  class Loader
89
92
  # @api private
90
93
  #
91
- # Internal formatters are stored here when loaded
94
+ # Internal formatters are stored here when loaded.
92
95
  def self.formatters
93
96
  @formatters ||= {}
94
97
  end
@@ -165,7 +168,8 @@ module RSpec::Core::Formatters
165
168
  def find_formatter(formatter_to_use)
166
169
  built_in_formatter(formatter_to_use) ||
167
170
  custom_formatter(formatter_to_use) ||
168
- (raise ArgumentError, "Formatter '#{formatter_to_use}' unknown - maybe you meant 'documentation' or 'progress'?.")
171
+ (raise ArgumentError, "Formatter '#{formatter_to_use}' unknown - " \
172
+ "maybe you meant 'documentation' or 'progress'?.")
169
173
  end
170
174
 
171
175
  def duplicate_formatter_exists?(new_formatter)
@@ -4,13 +4,15 @@ require 'stringio'
4
4
  module RSpec
5
5
  module Core
6
6
  module Formatters
7
- # RSpec's built-in formatters are all subclasses of RSpec::Core::Formatters::BaseTextFormatter.
7
+ # RSpec's built-in formatters are all subclasses of
8
+ # RSpec::Core::Formatters::BaseTextFormatter.
8
9
  #
9
10
  # @see RSpec::Core::Formatters::BaseTextFormatter
10
11
  # @see RSpec::Core::Reporter
11
12
  # @see RSpec::Core::Formatters::Protocol
12
13
  class BaseFormatter
13
- # all formatters inheriting from this formatter will receive these notifications
14
+ # All formatters inheriting from this formatter will receive these
15
+ # notifications.
14
16
  Formatters.register self, :start, :example_group_started, :close
15
17
  attr_accessor :example_group
16
18
  attr_reader :output
@@ -34,7 +36,8 @@ module RSpec
34
36
 
35
37
  # @api public
36
38
  #
37
- # @param notification [GroupNotification] containing example_group subclass of `RSpec::Core::ExampleGroup`
39
+ # @param notification [GroupNotification] containing example_group
40
+ # subclass of `RSpec::Core::ExampleGroup`
38
41
  # @see RSpec::Core::Formatters::Protocol#example_group_started
39
42
  def example_group_started(notification)
40
43
  @example_group = notification.group
@@ -42,7 +45,7 @@ module RSpec
42
45
 
43
46
  # @api public
44
47
  #
45
- # @param notification [NullNotification]
48
+ # @param _notification [NullNotification] (Ignored)
46
49
  # @see RSpec::Core::Formatters::Protocol#close
47
50
  def close(_notification)
48
51
  restore_sync_output
@@ -4,8 +4,9 @@ RSpec::Support.require_rspec_core "formatters/console_codes"
4
4
  module RSpec
5
5
  module Core
6
6
  module Formatters
7
- # Base for all of RSpec's built-in formatters. See RSpec::Core::Formatters::BaseFormatter
8
- # to learn more about all of the methods called by the reporter.
7
+ # Base for all of RSpec's built-in formatters. See
8
+ # RSpec::Core::Formatters::BaseFormatter to learn more about all of the
9
+ # methods called by the reporter.
9
10
  #
10
11
  # @see RSpec::Core::Formatters::BaseFormatter
11
12
  # @see RSpec::Core::Reporter
@@ -13,7 +14,6 @@ module RSpec
13
14
  Formatters.register self,
14
15
  :message, :dump_summary, :dump_failures, :dump_pending, :seed
15
16
 
16
- # @method message
17
17
  # @api public
18
18
  #
19
19
  # Used by the reporter to send messages to the output stream.
@@ -23,7 +23,6 @@ module RSpec
23
23
  output.puts notification.message
24
24
  end
25
25
 
26
- # @method dump_failures
27
26
  # @api public
28
27
  #
29
28
  # Dumps detailed information about each example failure.
@@ -34,14 +33,13 @@ module RSpec
34
33
  output.puts notification.fully_formatted_failed_examples
35
34
  end
36
35
 
37
- # @method dump_summary
38
36
  # @api public
39
37
  #
40
- # This method is invoked after the dumping of examples and failures. Each parameter
41
- # is assigned to a corresponding attribute.
38
+ # This method is invoked after the dumping of examples and failures.
39
+ # Each parameter is assigned to a corresponding attribute.
42
40
  #
43
- # @param summary [SummaryNotification] containing duration, example_count,
44
- # failure_count and pending_count
41
+ # @param summary [SummaryNotification] containing duration,
42
+ # example_count, failure_count and pending_count
45
43
  def dump_summary(summary)
46
44
  output.puts summary.fully_formatted
47
45
  end
@@ -63,12 +61,14 @@ module RSpec
63
61
  # Invoked at the very end, `close` allows the formatter to clean
64
62
  # up resources, e.g. open streams, etc.
65
63
  #
66
- # @param notification [NullNotification]
64
+ # @param _notification [NullNotification] (Ignored)
67
65
  def close(_notification)
68
66
  return unless IO === output
69
- return if output.closed? || output == $stdout
67
+ return if output.closed?
68
+
69
+ output.puts
70
70
 
71
- output.close
71
+ output.close unless output == $stdout
72
72
  end
73
73
  end
74
74
  end
@@ -22,14 +22,20 @@ module RSpec
22
22
 
23
23
  module_function
24
24
 
25
+ # @private
26
+ CONFIG_COLORS_TO_METHODS = Configuration.instance_methods.grep(/_color\z/).inject({}) do |hash, method|
27
+ hash[method.to_s.sub(/_color\z/, '').to_sym] = method
28
+ hash
29
+ end
30
+
25
31
  # Fetches the correct code for the supplied symbol, or checks
26
32
  # that a code is valid. Defaults to white (37).
27
33
  #
28
34
  # @param code_or_symbol [Symbol, Fixnum] Symbol or code to check
29
35
  # @return [Fixnum] a console code
30
36
  def console_code_for(code_or_symbol)
31
- if RSpec.configuration.respond_to?(:"#{code_or_symbol}_color")
32
- console_code_for configuration_color(code_or_symbol)
37
+ if (config_method = CONFIG_COLORS_TO_METHODS[code_or_symbol])
38
+ console_code_for RSpec.configuration.__send__(config_method)
33
39
  elsif VT100_CODE_VALUES.key?(code_or_symbol)
34
40
  code_or_symbol
35
41
  else
@@ -53,11 +59,6 @@ module RSpec
53
59
  text
54
60
  end
55
61
  end
56
-
57
- # @private
58
- def configuration_color(code)
59
- RSpec.configuration.__send__(:"#{code}_color")
60
- end
61
62
  end
62
63
  end
63
64
  end
@@ -21,7 +21,8 @@ module RSpec
21
21
  def printer
22
22
  @printer ||= case deprecation_stream
23
23
  when File
24
- ImmediatePrinter.new(FileStream.new(deprecation_stream), summary_stream, self)
24
+ ImmediatePrinter.new(FileStream.new(deprecation_stream),
25
+ summary_stream, self)
25
26
  when RaiseErrorStream
26
27
  ImmediatePrinter.new(deprecation_stream, summary_stream, self)
27
28
  else
@@ -209,14 +210,15 @@ module RSpec
209
210
  end
210
211
 
211
212
  def summarize(summary_stream, deprecation_count)
212
- summary_stream.puts "\n#{Helpers.pluralize(deprecation_count, 'deprecation')} logged to #{@file.path}"
213
+ path = @file.respond_to?(:path) ? @file.path : @file.inspect
214
+ summary_stream.puts "\n#{Helpers.pluralize(deprecation_count, 'deprecation')} logged to #{path}"
213
215
  puts RAISE_ERROR_CONFIG_NOTICE
214
216
  end
215
217
  end
216
218
  end
217
219
  end
218
220
 
219
- # Deprecation Error
221
+ # Deprecation Error.
220
222
  DeprecationError = Class.new(StandardError)
221
223
  end
222
224
  end
@@ -29,11 +29,13 @@ module RSpec
29
29
  end
30
30
 
31
31
  def example_pending(pending)
32
- output.puts pending_output(pending.example, pending.example.execution_result.pending_message)
32
+ output.puts pending_output(pending.example,
33
+ pending.example.execution_result.pending_message)
33
34
  end
34
35
 
35
36
  def example_failed(failure)
36
- output.puts failure_output(failure.example, failure.example.execution_result.exception)
37
+ output.puts failure_output(failure.example,
38
+ failure.example.execution_result.exception)
37
39
  end
38
40
 
39
41
  private
@@ -43,11 +45,15 @@ module RSpec
43
45
  end
44
46
 
45
47
  def pending_output(example, message)
46
- ConsoleCodes.wrap("#{current_indentation}#{example.description.strip} (PENDING: #{message})", :pending)
48
+ ConsoleCodes.wrap("#{current_indentation}#{example.description.strip} " \
49
+ "(PENDING: #{message})",
50
+ :pending)
47
51
  end
48
52
 
49
53
  def failure_output(example, _exception)
50
- ConsoleCodes.wrap("#{current_indentation}#{example.description.strip} (FAILED - #{next_failure_index})", :failure)
54
+ ConsoleCodes.wrap("#{current_indentation}#{example.description.strip} " \
55
+ "(FAILED - #{next_failure_index})",
56
+ :failure)
51
57
  end
52
58
 
53
59
  def next_failure_index