rspec-core 3.0.0.beta2 → 3.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (201) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.yardopts +1 -0
  5. data/Changelog.md +297 -57
  6. data/README.md +16 -13
  7. data/lib/rspec/core.rb +55 -84
  8. data/lib/rspec/core/backport_random.rb +35 -3
  9. data/lib/rspec/core/backtrace_formatter.rb +4 -13
  10. data/lib/rspec/core/configuration.rb +330 -114
  11. data/lib/rspec/core/configuration_options.rb +38 -22
  12. data/lib/rspec/core/drb.rb +111 -0
  13. data/lib/rspec/core/dsl.rb +8 -2
  14. data/lib/rspec/core/example.rb +203 -94
  15. data/lib/rspec/core/example_group.rb +344 -316
  16. data/lib/rspec/core/filter_manager.rb +135 -90
  17. data/lib/rspec/core/flat_map.rb +1 -0
  18. data/lib/rspec/core/formatters.rb +50 -14
  19. data/lib/rspec/core/formatters/base_formatter.rb +32 -138
  20. data/lib/rspec/core/formatters/base_text_formatter.rb +32 -253
  21. data/lib/rspec/core/formatters/console_codes.rb +65 -0
  22. data/lib/rspec/core/formatters/deprecation_formatter.rb +24 -15
  23. data/lib/rspec/core/formatters/documentation_formatter.rb +7 -10
  24. data/lib/rspec/core/formatters/helpers.rb +15 -9
  25. data/lib/rspec/core/formatters/html_formatter.rb +17 -16
  26. data/lib/rspec/core/formatters/html_printer.rb +1 -0
  27. data/lib/rspec/core/formatters/json_formatter.rb +18 -20
  28. data/lib/rspec/core/formatters/profile_formatter.rb +67 -0
  29. data/lib/rspec/core/formatters/progress_formatter.rb +6 -7
  30. data/lib/rspec/core/formatters/snippet_extractor.rb +8 -6
  31. data/lib/rspec/core/hooks.rb +131 -125
  32. data/lib/rspec/core/memoized_helpers.rb +31 -26
  33. data/lib/rspec/core/metadata.rb +277 -184
  34. data/lib/rspec/core/metadata_filter.rb +86 -0
  35. data/lib/rspec/core/minitest_assertions_adapter.rb +28 -0
  36. data/lib/rspec/core/mocking_adapters/flexmock.rb +1 -1
  37. data/lib/rspec/core/mocking_adapters/mocha.rb +1 -1
  38. data/lib/rspec/core/mocking_adapters/null.rb +1 -1
  39. data/lib/rspec/core/mocking_adapters/rr.rb +2 -1
  40. data/lib/rspec/core/mocking_adapters/rspec.rb +1 -1
  41. data/lib/rspec/core/notifications.rb +435 -24
  42. data/lib/rspec/core/option_parser.rb +16 -25
  43. data/lib/rspec/core/ordering.rb +3 -1
  44. data/lib/rspec/core/pending.rb +57 -33
  45. data/lib/rspec/core/project_initializer.rb +2 -0
  46. data/lib/rspec/core/project_initializer/spec_helper.rb +5 -4
  47. data/lib/rspec/core/rake_task.rb +45 -20
  48. data/lib/rspec/core/reporter.rb +50 -22
  49. data/lib/rspec/core/ruby_project.rb +1 -0
  50. data/lib/rspec/core/runner.rb +93 -39
  51. data/lib/rspec/core/shared_context.rb +7 -5
  52. data/lib/rspec/core/shared_example_group.rb +85 -77
  53. data/lib/rspec/core/test_unit_assertions_adapter.rb +30 -0
  54. data/lib/rspec/core/version.rb +3 -1
  55. data/lib/rspec/core/warnings.rb +35 -17
  56. data/lib/rspec/core/world.rb +57 -5
  57. metadata +56 -369
  58. metadata.gz.sig +3 -3
  59. data/features/README.md +0 -13
  60. data/features/Upgrade.md +0 -352
  61. data/features/command_line/README.md +0 -25
  62. data/features/command_line/dry_run.feature +0 -29
  63. data/features/command_line/example_name_option.feature +0 -97
  64. data/features/command_line/exit_status.feature +0 -82
  65. data/features/command_line/fail_fast.feature +0 -26
  66. data/features/command_line/format_option.feature +0 -75
  67. data/features/command_line/init.feature +0 -57
  68. data/features/command_line/line_number_appended_to_path.feature +0 -140
  69. data/features/command_line/line_number_option.feature +0 -58
  70. data/features/command_line/order.feature +0 -25
  71. data/features/command_line/pattern_option.feature +0 -49
  72. data/features/command_line/rake_task.feature +0 -122
  73. data/features/command_line/randomization.feature +0 -63
  74. data/features/command_line/require_option.feature +0 -43
  75. data/features/command_line/ruby.feature +0 -23
  76. data/features/command_line/tag.feature +0 -98
  77. data/features/command_line/warnings_option.feature +0 -29
  78. data/features/configuration/alias_example_to.feature +0 -39
  79. data/features/configuration/backtrace_exclusion_patterns.feature +0 -105
  80. data/features/configuration/custom_settings.feature +0 -84
  81. data/features/configuration/default_path.feature +0 -38
  82. data/features/configuration/deprecation_stream.feature +0 -58
  83. data/features/configuration/enable_global_dsl.feature +0 -54
  84. data/features/configuration/fail_fast.feature +0 -77
  85. data/features/configuration/failure_exit_code.feature +0 -36
  86. data/features/configuration/order_and_seed.feature +0 -3
  87. data/features/configuration/output_stream.feature +0 -24
  88. data/features/configuration/overriding_global_ordering.feature +0 -93
  89. data/features/configuration/pattern.feature +0 -38
  90. data/features/configuration/profile.feature +0 -220
  91. data/features/configuration/read_options_from_file.feature +0 -90
  92. data/features/configuration/run_all_when_everything_filtered.feature +0 -76
  93. data/features/example_groups/aliasing.feature +0 -48
  94. data/features/example_groups/basic_structure.feature +0 -55
  95. data/features/example_groups/shared_context.feature +0 -74
  96. data/features/example_groups/shared_examples.feature +0 -286
  97. data/features/expectation_framework_integration/configure_expectation_framework.feature +0 -102
  98. data/features/filtering/exclusion_filters.feature +0 -135
  99. data/features/filtering/if_and_unless.feature +0 -138
  100. data/features/filtering/inclusion_filters.feature +0 -101
  101. data/features/formatters/configurable_colors.feature +0 -31
  102. data/features/formatters/custom_formatter.feature +0 -68
  103. data/features/formatters/json_formatter.feature +0 -30
  104. data/features/formatters/regression_tests.feature +0 -95
  105. data/features/formatters/text_formatter.feature +0 -46
  106. data/features/helper_methods/arbitrary_methods.feature +0 -40
  107. data/features/helper_methods/let.feature +0 -50
  108. data/features/helper_methods/modules.feature +0 -146
  109. data/features/hooks/around_hooks.feature +0 -344
  110. data/features/hooks/before_and_after_hooks.feature +0 -427
  111. data/features/hooks/filtering.feature +0 -232
  112. data/features/metadata/current_example.feature +0 -56
  113. data/features/metadata/described_class.feature +0 -17
  114. data/features/metadata/user_defined.feature +0 -100
  115. data/features/mock_framework_integration/use_any_framework.feature +0 -106
  116. data/features/mock_framework_integration/use_flexmock.feature +0 -94
  117. data/features/mock_framework_integration/use_mocha.feature +0 -95
  118. data/features/mock_framework_integration/use_rr.feature +0 -96
  119. data/features/mock_framework_integration/use_rspec.feature +0 -95
  120. data/features/pending_and_skipped_examples/README.md +0 -3
  121. data/features/pending_and_skipped_examples/pending_examples.feature +0 -118
  122. data/features/pending_and_skipped_examples/skipped_examples.feature +0 -106
  123. data/features/spec_files/arbitrary_file_suffix.feature +0 -13
  124. data/features/step_definitions/additional_cli_steps.rb +0 -83
  125. data/features/subject/explicit_subject.feature +0 -101
  126. data/features/subject/implicit_subject.feature +0 -63
  127. data/features/subject/one_liner_syntax.feature +0 -71
  128. data/features/support/env.rb +0 -21
  129. data/features/support/require_expect_syntax_in_aruba_specs.rb +0 -16
  130. data/features/support/rubinius.rb +0 -6
  131. data/lib/rspec/core/command_line.rb +0 -35
  132. data/lib/rspec/core/drb_command_line.rb +0 -26
  133. data/lib/rspec/core/drb_options.rb +0 -87
  134. data/lib/rspec/core/formatters/legacy_formatter.rb +0 -227
  135. data/lib/rspec/core/shared_example_group/collection.rb +0 -27
  136. data/spec/command_line/order_spec.rb +0 -211
  137. data/spec/rspec/core/backtrace_formatter_spec.rb +0 -230
  138. data/spec/rspec/core/command_line_spec.rb +0 -112
  139. data/spec/rspec/core/command_line_spec_output.txt +0 -0
  140. data/spec/rspec/core/configuration_options_spec.rb +0 -409
  141. data/spec/rspec/core/configuration_spec.rb +0 -1479
  142. data/spec/rspec/core/drb_command_line_spec.rb +0 -102
  143. data/spec/rspec/core/drb_options_spec.rb +0 -193
  144. data/spec/rspec/core/dsl_spec.rb +0 -88
  145. data/spec/rspec/core/example_group_spec.rb +0 -1533
  146. data/spec/rspec/core/example_spec.rb +0 -642
  147. data/spec/rspec/core/filter_manager_spec.rb +0 -229
  148. data/spec/rspec/core/formatters/base_formatter_spec.rb +0 -64
  149. data/spec/rspec/core/formatters/base_text_formatter_spec.rb +0 -303
  150. data/spec/rspec/core/formatters/deprecation_formatter_spec.rb +0 -208
  151. data/spec/rspec/core/formatters/documentation_formatter_spec.rb +0 -75
  152. data/spec/rspec/core/formatters/helpers_spec.rb +0 -104
  153. data/spec/rspec/core/formatters/html_formatted-2.1.0.html +0 -392
  154. data/spec/rspec/core/formatters/html_formatted.html +0 -397
  155. data/spec/rspec/core/formatters/html_formatter_spec.rb +0 -122
  156. data/spec/rspec/core/formatters/json_formatter_spec.rb +0 -206
  157. data/spec/rspec/core/formatters/legacy_formatter_spec.rb +0 -137
  158. data/spec/rspec/core/formatters/progress_formatter_spec.rb +0 -43
  159. data/spec/rspec/core/formatters/snippet_extractor_spec.rb +0 -26
  160. data/spec/rspec/core/formatters_spec.rb +0 -120
  161. data/spec/rspec/core/hooks_filtering_spec.rb +0 -227
  162. data/spec/rspec/core/hooks_spec.rb +0 -294
  163. data/spec/rspec/core/memoized_helpers_spec.rb +0 -495
  164. data/spec/rspec/core/metadata_spec.rb +0 -491
  165. data/spec/rspec/core/option_parser_spec.rb +0 -262
  166. data/spec/rspec/core/ordering_spec.rb +0 -102
  167. data/spec/rspec/core/pending_example_spec.rb +0 -117
  168. data/spec/rspec/core/pending_spec.rb +0 -8
  169. data/spec/rspec/core/project_initializer_spec.rb +0 -73
  170. data/spec/rspec/core/rake_task_spec.rb +0 -146
  171. data/spec/rspec/core/random_spec.rb +0 -47
  172. data/spec/rspec/core/reporter_spec.rb +0 -155
  173. data/spec/rspec/core/resources/a_bar.rb +0 -0
  174. data/spec/rspec/core/resources/a_foo.rb +0 -0
  175. data/spec/rspec/core/resources/a_spec.rb +0 -1
  176. data/spec/rspec/core/resources/custom_example_group_runner.rb +0 -14
  177. data/spec/rspec/core/resources/formatter_specs.rb +0 -58
  178. data/spec/rspec/core/resources/utf8_encoded.rb +0 -8
  179. data/spec/rspec/core/rspec_matchers_spec.rb +0 -45
  180. data/spec/rspec/core/ruby_project_spec.rb +0 -26
  181. data/spec/rspec/core/runner_spec.rb +0 -151
  182. data/spec/rspec/core/shared_context_spec.rb +0 -102
  183. data/spec/rspec/core/shared_example_group/collection_spec.rb +0 -57
  184. data/spec/rspec/core/shared_example_group_spec.rb +0 -114
  185. data/spec/rspec/core/warnings_spec.rb +0 -29
  186. data/spec/rspec/core/world_spec.rb +0 -142
  187. data/spec/rspec/core_spec.rb +0 -91
  188. data/spec/spec_helper.rb +0 -160
  189. data/spec/support/config_options_helper.rb +0 -13
  190. data/spec/support/formatter_support.rb +0 -83
  191. data/spec/support/helper_methods.rb +0 -26
  192. data/spec/support/isolate_load_path_mutation.rb +0 -5
  193. data/spec/support/isolated_directory.rb +0 -10
  194. data/spec/support/isolated_home_directory.rb +0 -16
  195. data/spec/support/legacy_formatter_using_sub_classing_example.rb +0 -87
  196. data/spec/support/matchers.rb +0 -85
  197. data/spec/support/mathn_integration_support.rb +0 -12
  198. data/spec/support/old_style_formatter_example.rb +0 -69
  199. data/spec/support/shared_example_groups.rb +0 -13
  200. data/spec/support/spec_files.rb +0 -44
  201. data/spec/support/stderr_splitter.rb +0 -36
@@ -0,0 +1,86 @@
1
+ module RSpec
2
+ module Core
3
+ # Contains metadata filtering logic. This has been extracted from
4
+ # the metadata classes because it operates ON a metadata hash but
5
+ # does not manage any of the state in the hash. We're moving towards
6
+ # having metadata be a raw hash (not a custom subclass), so externalizing
7
+ # this filtering logic helps us move in that direction.
8
+ module MetadataFilter
9
+ extend self
10
+
11
+ # @private
12
+ def any_apply?(filters, metadata)
13
+ filters.any? { |k, v| filter_applies?(k, v, metadata) }
14
+ end
15
+
16
+ # @private
17
+ def all_apply?(filters, metadata)
18
+ filters.all? { |k, v| filter_applies?(k, v, metadata) }
19
+ end
20
+
21
+ # @private
22
+ def filter_applies?(key, value, metadata)
23
+ return filter_applies_to_any_value?(key, value, metadata) if Array === metadata[key] && !(Proc === value)
24
+ return location_filter_applies?(value, metadata) if key == :locations
25
+ return filters_apply?(key, value, metadata) if Hash === value
26
+
27
+ return false unless metadata.has_key?(key)
28
+
29
+ case value
30
+ when Regexp
31
+ metadata[key] =~ value
32
+ when Proc
33
+ case value.arity
34
+ when 0 then value.call
35
+ when 2 then value.call(metadata[key], metadata)
36
+ else value.call(metadata[key])
37
+ end
38
+ else
39
+ metadata[key].to_s == value.to_s
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def filter_applies_to_any_value?(key, value, metadata)
46
+ metadata[key].any? {|v| filter_applies?(key, v, {key => value})}
47
+ end
48
+
49
+ def location_filter_applies?(locations, metadata)
50
+ # it ignores location filters for other files
51
+ line_number = example_group_declaration_line(locations, metadata)
52
+ line_number ? line_number_filter_applies?(line_number, metadata) : true
53
+ end
54
+
55
+ def line_number_filter_applies?(line_numbers, metadata)
56
+ preceding_declaration_lines = line_numbers.map {|n| RSpec.world.preceding_declaration_line(n)}
57
+ !(relevant_line_numbers(metadata) & preceding_declaration_lines).empty?
58
+ end
59
+
60
+ def relevant_line_numbers(metadata)
61
+ return [] unless metadata
62
+ [metadata[:line_number]].compact + (relevant_line_numbers(parent_of metadata))
63
+ end
64
+
65
+ def example_group_declaration_line(locations, metadata)
66
+ parent = parent_of(metadata)
67
+ return nil unless parent
68
+ locations[File.expand_path(parent[:file_path])]
69
+ end
70
+
71
+ def filters_apply?(key, value, metadata)
72
+ subhash = metadata[key]
73
+ return false unless Hash === subhash || HashImitatable === subhash
74
+ value.all? { |k, v| filter_applies?(k, v, subhash) }
75
+ end
76
+
77
+ def parent_of(metadata)
78
+ if metadata.has_key?(:parent_example_group)
79
+ metadata[:parent_example_group]
80
+ else
81
+ metadata[:example_group]
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,28 @@
1
+ begin
2
+ # Only the minitest 5.x gem includes the minitest.rb and assertions.rb files
3
+ require 'minitest'
4
+ require 'minitest/assertions'
5
+ rescue LoadError => _ignored
6
+ # We must be using Ruby Core's MiniTest or the Minitest gem 4.x
7
+ require 'minitest/unit'
8
+ Minitest = MiniTest
9
+ end
10
+
11
+ module RSpec
12
+ module Core
13
+ # @private
14
+ module MinitestAssertionsAdapter
15
+ include ::Minitest::Assertions
16
+
17
+ # Minitest 5.x requires this accessor to be available. See
18
+ # https://github.com/seattlerb/minitest/blob/38f0a5fcbd9c37c3f80a3eaad4ba84d3fc9947a0/lib/minitest/assertions.rb#L8
19
+ #
20
+ # It is not required for other extension libraries, and RSpec does not
21
+ # report or make this information available to formatters.
22
+ attr_writer :assertions
23
+ def assertions
24
+ @assertions ||= 0
25
+ end
26
+ end
27
+ end
28
+ end
@@ -6,7 +6,7 @@ require 'flexmock/rspec'
6
6
  module RSpec
7
7
  module Core
8
8
  module MockingAdapters
9
- # @api private
9
+ # @private
10
10
  module Flexmock
11
11
  include ::FlexMock::MockContainer
12
12
 
@@ -27,7 +27,7 @@ end
27
27
  module RSpec
28
28
  module Core
29
29
  module MockingAdapters
30
- # @api private
30
+ # @private
31
31
  module Mocha
32
32
  def self.framework_name; :mocha end
33
33
 
@@ -1,7 +1,7 @@
1
1
  module RSpec
2
2
  module Core
3
3
  module MockingAdapters
4
- # @api private
4
+ # @private
5
5
  module Null
6
6
  def setup_mocks_for_rspec; end
7
7
  def verify_mocks_for_rspec; end
@@ -4,8 +4,9 @@ RSpec.configuration.backtrace_exclusion_patterns.push(RR::Errors::BACKTRACE_IDEN
4
4
 
5
5
  module RSpec
6
6
  module Core
7
+ # @private
7
8
  module MockingAdapters
8
- # @api private
9
+ # @private
9
10
  module RR
10
11
  def self.framework_name; :rr end
11
12
 
@@ -3,7 +3,7 @@ require 'rspec/mocks'
3
3
  module RSpec
4
4
  module Core
5
5
  module MockingAdapters
6
- # @api private
6
+ # @private
7
7
  module RSpec
8
8
  include ::RSpec::Mocks::ExampleMethods
9
9
 
@@ -1,14 +1,18 @@
1
- require 'rspec/core/formatters/helpers'
1
+ RSpec::Support.require_rspec_core "formatters/helpers"
2
2
 
3
3
  module RSpec::Core
4
+ # Notifications are value objects passed to formatters to provide them
5
+ # with information about a particular event of interest.
4
6
  module Notifications
5
7
 
6
- # The `CountNotification` represents notifications sent by the formatter
7
- # which a single numerical count attribute. Currently used to notify
8
- # formatters of the expected number of examples.
8
+ # The `StartNotification` represents a notification sent by the reporter
9
+ # when the suite is started. It contains the expected amount of examples
10
+ # to be executed, and the load time of RSpec.
9
11
  #
10
- # @attr [Fixnum] count the number counted
11
- CountNotification = Struct.new(:count)
12
+ # @attr count [Fixnum] the number counted
13
+ # @attr load_time [Float] the number of seconds taken to boot RSpec
14
+ # and load the spec files
15
+ StartNotification = Struct.new(:count, :load_time)
12
16
 
13
17
  # The `ExampleNotification` represents notifications sent by the reporter
14
18
  # which contain information about the current (or soon to be) example.
@@ -19,8 +23,264 @@ module RSpec::Core
19
23
  # puts "Hey I started #{notification.example.description}"
20
24
  # end
21
25
  #
26
+ # @attr example [RSpec::Core::Example] the current example
27
+ ExampleNotification = Struct.new(:example) do
28
+ # @private
29
+ def self.for(example)
30
+ if example.execution_result.pending_fixed?
31
+ PendingExampleFixedNotification.new(example)
32
+ elsif example.execution_result.status == :failed
33
+ FailedExampleNotification.new(example)
34
+ else
35
+ new(example)
36
+ end
37
+ end
38
+ private_class_method :new
39
+ end
40
+
41
+ # The `ExamplesNotification` represents notifications sent by the reporter
42
+ # which contain information about the suites examples.
43
+ #
44
+ # @example
45
+ # def stop(notification)
46
+ # puts "Hey I ran #{notification.examples.size}"
47
+ # end
48
+ #
49
+ class ExamplesNotification
50
+
51
+ def initialize(reporter)
52
+ @reporter = reporter
53
+ end
54
+
55
+ # @return [Array(RSpec::Core::Example)] list of examples
56
+ def examples
57
+ @reporter.examples
58
+ end
59
+
60
+ # @return [Array(RSpec::Core::Example)] list of failed examples
61
+ def failed_examples
62
+ @reporter.failed_examples
63
+ end
64
+
65
+ # @return [Array(RSpec::Core::Example)] list of pending examples
66
+ def pending_examples
67
+ @reporter.pending_examples
68
+ end
69
+
70
+ # @return [Array(Rspec::Core::Notifications::ExampleNotification]
71
+ # returns examples as notifications
72
+ def notifications
73
+ @notifications ||= format(examples)
74
+ end
75
+
76
+ # @return [Array(Rspec::Core::Notifications::FailedExampleNotification]
77
+ # returns failed examples as notifications
78
+ def failure_notifications
79
+ @failed_notifications ||= format(failed_examples)
80
+ end
81
+
82
+ # @return [String] The list of failed examples, fully formatted in the way that
83
+ # RSpec's built-in formatters emit.
84
+ def fully_formatted_failed_examples(colorizer = ::RSpec::Core::Formatters::ConsoleCodes)
85
+ formatted = "\nFailures:\n"
86
+
87
+ failure_notifications.each_with_index do |failure, index|
88
+ formatted << failure.fully_formatted(index.next, colorizer)
89
+ end
90
+
91
+ formatted
92
+ end
93
+
94
+ # @return [String] The list of pending examples, fully formatted in the way that
95
+ # RSpec's built-in formatters emit.
96
+ def fully_formatted_pending_examples(colorizer = ::RSpec::Core::Formatters::ConsoleCodes)
97
+ formatted = "\nPending:\n"
98
+
99
+ pending_examples.each do |example|
100
+ formatted_caller = RSpec.configuration.backtrace_formatter.backtrace_line(example.location)
101
+
102
+ formatted <<
103
+ " #{colorizer.wrap(example.full_description, :pending)}\n" <<
104
+ " # #{colorizer.wrap(example.execution_result.pending_message, :detail)}\n" <<
105
+ " # #{colorizer.wrap(formatted_caller, :detail)}\n"
106
+ end
107
+
108
+ formatted
109
+ end
110
+
111
+ private
112
+
113
+ def format(examples)
114
+ examples.map do |example|
115
+ ExampleNotification.for(example)
116
+ end
117
+ end
118
+
119
+ end
120
+
121
+ # The `FailedExampleNotification` extends `ExampleNotification` with
122
+ # things useful for failed specs.
123
+ #
124
+ # @example
125
+ # def example_failed(notification)
126
+ # puts "Hey I failed :("
127
+ # puts "Here's my stack trace"
128
+ # puts notification.exception.backtrace.join("\n")
129
+ # end
130
+ #
131
+ # @attr [RSpec::Core::Example] example the current example
132
+ # @see ExampleNotification
133
+ class FailedExampleNotification < ExampleNotification
134
+ public_class_method :new
135
+
136
+ # @return [Exception] The example failure
137
+ def exception
138
+ example.execution_result.exception
139
+ end
140
+
141
+ # @return [String] The example description
142
+ def description
143
+ example.full_description
144
+ end
145
+
146
+ # Returns the message generated for this failure line by line.
147
+ #
148
+ # @return [Array(String)] The example failure message
149
+ def message_lines
150
+ @lines ||=
151
+ begin
152
+ lines = ["Failure/Error: #{read_failed_line.strip}"]
153
+ lines << "#{exception_class_name}:" unless exception_class_name =~ /RSpec/
154
+ exception.message.to_s.split("\n").each do |line|
155
+ lines << " #{line}" if exception.message
156
+ end
157
+ if shared_group
158
+ lines << "Shared Example Group: \"#{shared_group.metadata[:shared_group_name]}\"" +
159
+ " called from #{backtrace_formatter.backtrace_line(shared_group.location)}"
160
+ end
161
+ lines
162
+ end
163
+ end
164
+
165
+ # Returns the message generated for this failure colorized line by line.
166
+ #
167
+ # @param colorizer [#wrap] An object to colorize the message_lines by
168
+ # @return [Array(String)] The example failure message colorized
169
+ def colorized_message_lines(colorizer = ::RSpec::Core::Formatters::ConsoleCodes)
170
+ message_lines.map do |line|
171
+ colorizer.wrap line, RSpec.configuration.failure_color
172
+ end
173
+ end
174
+
175
+ # Returns the failures formatted backtrace.
176
+ #
177
+ # @return [Array(String)] the examples backtrace lines
178
+ def formatted_backtrace
179
+ backtrace_formatter.format_backtrace(exception.backtrace, example.metadata)
180
+ end
181
+
182
+ # Returns the failures colorized formatted backtrace.
183
+ #
184
+ # @param colorizer [#wrap] An object to colorize the message_lines by
185
+ # @return [Array(String)] the examples colorized backtrace lines
186
+ def colorized_formatted_backtrace(colorizer = ::RSpec::Core::Formatters::ConsoleCodes)
187
+ formatted_backtrace.map do |backtrace_info|
188
+ colorizer.wrap "# #{backtrace_info}", RSpec.configuration.detail_color
189
+ end
190
+ end
191
+
192
+ # @return [String] The failure information fully formatted in the way that
193
+ # RSpec's built-in formatters emit.
194
+ def fully_formatted(failure_number, colorizer = ::RSpec::Core::Formatters::ConsoleCodes)
195
+ formatted = "\n #{failure_number}) #{description}\n"
196
+
197
+ colorized_message_lines(colorizer).each do |line|
198
+ formatted << " #{line}\n"
199
+ end
200
+
201
+ colorized_formatted_backtrace(colorizer).each do |line|
202
+ formatted << " #{line}\n"
203
+ end
204
+
205
+ formatted
206
+ end
207
+
208
+ private
209
+
210
+ def backtrace_formatter
211
+ RSpec.configuration.backtrace_formatter
212
+ end
213
+
214
+ def exception_class_name
215
+ name = exception.class.name.to_s
216
+ name ="(anonymous error class)" if name == ''
217
+ name
218
+ end
219
+
220
+ def shared_group
221
+ @shared_group ||= group_and_parent_groups.find { |group| group.metadata[:shared_group_name] }
222
+ end
223
+
224
+ def group_and_parent_groups
225
+ example.example_group.parent_groups + [example.example_group]
226
+ end
227
+
228
+ def read_failed_line
229
+ unless matching_line = find_failed_line
230
+ return "Unable to find matching line from backtrace"
231
+ end
232
+
233
+ file_path, line_number = matching_line.match(/(.+?):(\d+)(|:\d+)/)[1..2]
234
+
235
+ if File.exist?(file_path)
236
+ File.readlines(file_path)[line_number.to_i - 1] ||
237
+ "Unable to find matching line in #{file_path}"
238
+ else
239
+ "Unable to find #{file_path} to read failed line"
240
+ end
241
+ rescue SecurityError
242
+ "Unable to read failed line"
243
+ end
244
+
245
+ def find_failed_line
246
+ path = File.expand_path(example.file_path)
247
+ exception.backtrace.detect do |line|
248
+ match = line.match(/(.+?):(\d+)(|:\d+)/)
249
+ match && match[1].downcase == path.downcase
250
+ end
251
+ end
252
+ end
253
+
254
+ # The `PendingExampleFixedNotification` extends `ExampleNotification` with
255
+ # things useful for specs that pass when they are expected to fail.
256
+ #
22
257
  # @attr [RSpec::Core::Example] example the current example
23
- ExampleNotification = Struct.new(:example)
258
+ # @see ExampleNotification
259
+ class PendingExampleFixedNotification < FailedExampleNotification
260
+ public_class_method :new
261
+
262
+ # Returns the examples description
263
+ #
264
+ # @return [String] The example description
265
+ def description
266
+ "#{example.full_description} FIXED"
267
+ end
268
+
269
+ # Returns the message generated for this failure line by line.
270
+ #
271
+ # @return [Array(String)] The example failure message
272
+ def message_lines
273
+ ["Expected pending '#{example.execution_result.pending_message}' to fail. No Error was raised."]
274
+ end
275
+
276
+ # Returns the message generated for this failure colorized line by line.
277
+ #
278
+ # @param colorizer [#wrap] An object to colorize the message_lines by
279
+ # @return [Array(String)] The example failure message colorized
280
+ def colorized_message_lines(colorizer = ::RSpec::Core::Formatters::ConsoleCodes)
281
+ message_lines.map { |line| colorizer.wrap(line, RSpec.configuration.fixed_color) }
282
+ end
283
+ end
24
284
 
25
285
  # The `GroupNotification` represents notifications sent by the reporter which
26
286
  # contain information about the currently running (or soon to be) example group
@@ -30,19 +290,20 @@ module RSpec::Core
30
290
  # def example_group_started(notification)
31
291
  # puts "Hey I started #{notification.group.description}"
32
292
  # end
33
- # @attr [RSpec::Core::ExampleGroup] group the current group
293
+ # @attr group [RSpec::Core::ExampleGroup] the current group
34
294
  GroupNotification = Struct.new(:group)
35
295
 
36
296
  # The `MessageNotification` encapsulates generic messages that the reporter
37
297
  # sends to formatters.
38
298
  #
39
- # @attr [String] message the message
299
+ # @attr message [String] the message
40
300
  MessageNotification = Struct.new(:message)
41
301
 
42
302
  # The `SeedNotification` holds the seed used to randomize examples and
43
303
  # wether that seed has been used or not.
44
304
  #
45
- # @attr [Fixnum] seed the seed used to randomize ordering
305
+ # @attr seed [Fixnum] the seed used to randomize ordering
306
+ # @attr used [Boolean] wether the seed has been used or not
46
307
  SeedNotification = Struct.new(:seed, :used) do
47
308
  # @api
48
309
  # @return [Boolean] has the seed been used?
@@ -50,37 +311,187 @@ module RSpec::Core
50
311
  !!used
51
312
  end
52
313
  private :used
314
+
315
+ # @return [String] The seed information fully formatted in the way that
316
+ # RSpec's built-in formatters emit.
317
+ def fully_formatted
318
+ "\nRandomized with seed #{seed}\n\n"
319
+ end
53
320
  end
54
321
 
55
322
  # The `SummaryNotification` holds information about the results of running
56
323
  # a test suite. It is used by formatters to provide information at the end
57
324
  # of the test run.
58
325
  #
59
- # @attr [Float] duration the time taken (in seconds) to run the suite
60
- # @attr [Fixnum] example_count the number of examples run
61
- # @attr [Fixnum] failure_count the number of failed examples
62
- # @attr [Fixnum] pending_count the number of pending examples
63
- class SummaryNotification < Struct.new(:duration, :example_count, :failure_count, :pending_count)
64
- include Formatters::Helpers
326
+ # @attr duration [Float] the time taken (in seconds) to run the suite
327
+ # @attr examples [Array(RSpec::Core::Example)] the examples run
328
+ # @attr failed_examples [Array(RSpec::Core::Example)] the failed examples
329
+ # @attr pending_examples [Array(RSpec::Core::Example)] the pending examples
330
+ # @attr load_time [Float] the number of seconds taken to boot RSpec
331
+ # and load the spec files
332
+ SummaryNotification = Struct.new(:duration, :examples, :failed_examples, :pending_examples, :load_time) do
333
+
334
+ # @api
335
+ # @return [Fixnum] the number of examples run
336
+ def example_count
337
+ @example_count ||= examples.size
338
+ end
339
+
340
+ # @api
341
+ # @return [Fixnum] the number of failed examples
342
+ def failure_count
343
+ @failure_count ||= failed_examples.size
344
+ end
345
+
346
+ # @api
347
+ # @return [Fixnum] the number of pending examples
348
+ def pending_count
349
+ @pending_count ||= pending_examples.size
350
+ end
65
351
 
66
352
  # @api
67
- # @return [String] A line summarising the results of the spec run.
68
- def summary_line
69
- summary = pluralize(example_count, "example")
70
- summary << ", " << pluralize(failure_count, "failure")
353
+ # @return [String] A line summarising the result totals of the spec run.
354
+ def totals_line
355
+ summary = Formatters::Helpers.pluralize(example_count, "example")
356
+ summary << ", " << Formatters::Helpers.pluralize(failure_count, "failure")
71
357
  summary << ", #{pending_count} pending" if pending_count > 0
72
358
  summary
73
359
  end
360
+
361
+ # @api public
362
+ #
363
+ # Wraps the results line with colors based on the configured
364
+ # colors for failure, pending, and success. Defaults to red,
365
+ # yellow, green accordingly.
366
+ #
367
+ # @param colorizer [#wrap] An object which supports wrapping text with
368
+ # specific colors.
369
+ # @return [String] A colorized results line.
370
+ def colorized_totals_line(colorizer = ::RSpec::Core::Formatters::ConsoleCodes)
371
+ if failure_count > 0
372
+ colorizer.wrap(totals_line, RSpec.configuration.failure_color)
373
+ elsif pending_count > 0
374
+ colorizer.wrap(totals_line, RSpec.configuration.pending_color)
375
+ else
376
+ colorizer.wrap(totals_line, RSpec.configuration.success_color)
377
+ end
378
+ end
379
+
380
+ # @api public
381
+ #
382
+ # Formats failures into a rerunable command format.
383
+ #
384
+ # @param colorizer [#wrap] An object which supports wrapping text with
385
+ # specific colors.
386
+ # @return [String] A colorized summary line.
387
+ def colorized_rerun_commands(colorizer = ::RSpec::Core::Formatters::ConsoleCodes)
388
+ "\nFailed examples:\n\n" +
389
+ failed_examples.map do |example|
390
+ colorizer.wrap("rspec #{example.location}", RSpec.configuration.failure_color) + " " +
391
+ colorizer.wrap("# #{example.full_description}", RSpec.configuration.detail_color)
392
+ end.join("\n")
393
+ end
394
+
395
+ # @return [String] a formatted version of the time it took to run the suite
396
+ def formatted_duration
397
+ Formatters::Helpers.format_duration(duration)
398
+ end
399
+
400
+ # @return [String] a formatted version of the time it took to boot RSpec and
401
+ # load the spec files
402
+ def formatted_load_time
403
+ Formatters::Helpers.format_duration(load_time)
404
+ end
405
+
406
+ # @return [String] The summary information fully formatted in the way that
407
+ # RSpec's built-in formatters emit.
408
+ def fully_formatted(colorizer = ::RSpec::Core::Formatters::ConsoleCodes)
409
+ formatted = "\nFinished in #{formatted_duration} " \
410
+ "(files took #{formatted_load_time} to load)\n" \
411
+ "#{colorized_totals_line(colorizer)}\n"
412
+
413
+ unless failed_examples.empty?
414
+ formatted << colorized_rerun_commands(colorizer) << "\n"
415
+ end
416
+
417
+ formatted
418
+ end
419
+ end
420
+
421
+ # The `ProfileNotification` holds information about the results of running
422
+ # a test suite when profiling is enabled. It is used by formatters to provide
423
+ # information at the end of the test run for profiling information.
424
+ #
425
+ # @attr duration [Float] the time taken (in seconds) to run the suite
426
+ # @attr examples [Array(RSpec::Core::Example)] the examples run
427
+ # @attr number_of_examples [Fixnum] the number of examples to profile
428
+ ProfileNotification = Struct.new(:duration, :examples, :number_of_examples) do
429
+
430
+ # @return [Array(RSpec::Core::Example)] the slowest examples
431
+ def slowest_examples
432
+ @slowest_examples ||=
433
+ examples.sort_by do |example|
434
+ -example.execution_result.run_time
435
+ end.first(number_of_examples)
436
+ end
437
+
438
+ # @return [Float] the time taken (in seconds) to run the slowest examples
439
+ def slow_duration
440
+ @slow_duration ||=
441
+ slowest_examples.inject(0.0) do |i, e|
442
+ i + e.execution_result.run_time
443
+ end
444
+ end
445
+
446
+ # @return [String] the percentage of total time taken
447
+ def percentage
448
+ @percentage ||=
449
+ begin
450
+ time_taken = slow_duration / duration
451
+ '%.1f' % ((time_taken.nan? ? 0.0 : time_taken) * 100)
452
+ end
453
+ end
454
+
455
+ # @return [Array(RSpec::Core::Example)] the slowest example groups
456
+ def slowest_groups
457
+ @slowest_groups ||= calculate_slowest_groups
458
+ end
459
+
460
+ private
461
+
462
+ def calculate_slowest_groups
463
+ example_groups = {}
464
+
465
+ examples.each do |example|
466
+ location = example.example_group.parent_groups.last.metadata[:location]
467
+
468
+ location_hash = example_groups[location] ||= Hash.new(0)
469
+ location_hash[:total_time] += example.execution_result.run_time
470
+ location_hash[:count] += 1
471
+ unless location_hash.has_key?(:description)
472
+ location_hash[:description] = example.example_group.top_level_description
473
+ end
474
+ end
475
+
476
+ # stop if we've only one example group
477
+ return {} if example_groups.keys.length <= 1
478
+
479
+ example_groups.each_value do |hash|
480
+ hash[:average] = hash[:total_time].to_f / hash[:count]
481
+ end
482
+
483
+ example_groups.sort_by { |_, hash| -hash[:average] }.first(number_of_examples)
484
+ end
74
485
  end
75
486
 
76
487
  # The `DeprecationNotification` is issued by the reporter when a deprecated
77
488
  # part of RSpec is encountered. It represents information about the deprecated
78
489
  # call site.
79
490
  #
80
- # @attr [String] message A custom message about the deprecation
81
- # @attr [String] deprecated A custom message about the deprecation (alias of message)
82
- # @attr [String] replacement An optional replacement for the deprecation
83
- # @attr [String] call_site An optional call site from which the deprecation was issued
491
+ # @attr message [String] A custom message about the deprecation
492
+ # @attr deprecated [String] A custom message about the deprecation (alias of message)
493
+ # @attr replacement [String] An optional replacement for the deprecation
494
+ # @attr call_site [String] An optional call site from which the deprecation was issued
84
495
  DeprecationNotification = Struct.new(:deprecated, :message, :replacement, :call_site) do
85
496
  private_class_method :new
86
497