rspec-core 3.1.7 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
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