rspec-core 3.0.0.beta2 → 3.0.0.rc1

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 (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