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.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.yardopts +1 -0
- data/Changelog.md +297 -57
- data/README.md +16 -13
- data/lib/rspec/core.rb +55 -84
- data/lib/rspec/core/backport_random.rb +35 -3
- data/lib/rspec/core/backtrace_formatter.rb +4 -13
- data/lib/rspec/core/configuration.rb +330 -114
- data/lib/rspec/core/configuration_options.rb +38 -22
- data/lib/rspec/core/drb.rb +111 -0
- data/lib/rspec/core/dsl.rb +8 -2
- data/lib/rspec/core/example.rb +203 -94
- data/lib/rspec/core/example_group.rb +344 -316
- data/lib/rspec/core/filter_manager.rb +135 -90
- data/lib/rspec/core/flat_map.rb +1 -0
- data/lib/rspec/core/formatters.rb +50 -14
- data/lib/rspec/core/formatters/base_formatter.rb +32 -138
- data/lib/rspec/core/formatters/base_text_formatter.rb +32 -253
- data/lib/rspec/core/formatters/console_codes.rb +65 -0
- data/lib/rspec/core/formatters/deprecation_formatter.rb +24 -15
- data/lib/rspec/core/formatters/documentation_formatter.rb +7 -10
- data/lib/rspec/core/formatters/helpers.rb +15 -9
- data/lib/rspec/core/formatters/html_formatter.rb +17 -16
- data/lib/rspec/core/formatters/html_printer.rb +1 -0
- data/lib/rspec/core/formatters/json_formatter.rb +18 -20
- data/lib/rspec/core/formatters/profile_formatter.rb +67 -0
- data/lib/rspec/core/formatters/progress_formatter.rb +6 -7
- data/lib/rspec/core/formatters/snippet_extractor.rb +8 -6
- data/lib/rspec/core/hooks.rb +131 -125
- data/lib/rspec/core/memoized_helpers.rb +31 -26
- data/lib/rspec/core/metadata.rb +277 -184
- data/lib/rspec/core/metadata_filter.rb +86 -0
- data/lib/rspec/core/minitest_assertions_adapter.rb +28 -0
- data/lib/rspec/core/mocking_adapters/flexmock.rb +1 -1
- data/lib/rspec/core/mocking_adapters/mocha.rb +1 -1
- data/lib/rspec/core/mocking_adapters/null.rb +1 -1
- data/lib/rspec/core/mocking_adapters/rr.rb +2 -1
- data/lib/rspec/core/mocking_adapters/rspec.rb +1 -1
- data/lib/rspec/core/notifications.rb +435 -24
- data/lib/rspec/core/option_parser.rb +16 -25
- data/lib/rspec/core/ordering.rb +3 -1
- data/lib/rspec/core/pending.rb +57 -33
- data/lib/rspec/core/project_initializer.rb +2 -0
- data/lib/rspec/core/project_initializer/spec_helper.rb +5 -4
- data/lib/rspec/core/rake_task.rb +45 -20
- data/lib/rspec/core/reporter.rb +50 -22
- data/lib/rspec/core/ruby_project.rb +1 -0
- data/lib/rspec/core/runner.rb +93 -39
- data/lib/rspec/core/shared_context.rb +7 -5
- data/lib/rspec/core/shared_example_group.rb +85 -77
- data/lib/rspec/core/test_unit_assertions_adapter.rb +30 -0
- data/lib/rspec/core/version.rb +3 -1
- data/lib/rspec/core/warnings.rb +35 -17
- data/lib/rspec/core/world.rb +57 -5
- metadata +56 -369
- metadata.gz.sig +3 -3
- data/features/README.md +0 -13
- data/features/Upgrade.md +0 -352
- data/features/command_line/README.md +0 -25
- data/features/command_line/dry_run.feature +0 -29
- data/features/command_line/example_name_option.feature +0 -97
- data/features/command_line/exit_status.feature +0 -82
- data/features/command_line/fail_fast.feature +0 -26
- data/features/command_line/format_option.feature +0 -75
- data/features/command_line/init.feature +0 -57
- data/features/command_line/line_number_appended_to_path.feature +0 -140
- data/features/command_line/line_number_option.feature +0 -58
- data/features/command_line/order.feature +0 -25
- data/features/command_line/pattern_option.feature +0 -49
- data/features/command_line/rake_task.feature +0 -122
- data/features/command_line/randomization.feature +0 -63
- data/features/command_line/require_option.feature +0 -43
- data/features/command_line/ruby.feature +0 -23
- data/features/command_line/tag.feature +0 -98
- data/features/command_line/warnings_option.feature +0 -29
- data/features/configuration/alias_example_to.feature +0 -39
- data/features/configuration/backtrace_exclusion_patterns.feature +0 -105
- data/features/configuration/custom_settings.feature +0 -84
- data/features/configuration/default_path.feature +0 -38
- data/features/configuration/deprecation_stream.feature +0 -58
- data/features/configuration/enable_global_dsl.feature +0 -54
- data/features/configuration/fail_fast.feature +0 -77
- data/features/configuration/failure_exit_code.feature +0 -36
- data/features/configuration/order_and_seed.feature +0 -3
- data/features/configuration/output_stream.feature +0 -24
- data/features/configuration/overriding_global_ordering.feature +0 -93
- data/features/configuration/pattern.feature +0 -38
- data/features/configuration/profile.feature +0 -220
- data/features/configuration/read_options_from_file.feature +0 -90
- data/features/configuration/run_all_when_everything_filtered.feature +0 -76
- data/features/example_groups/aliasing.feature +0 -48
- data/features/example_groups/basic_structure.feature +0 -55
- data/features/example_groups/shared_context.feature +0 -74
- data/features/example_groups/shared_examples.feature +0 -286
- data/features/expectation_framework_integration/configure_expectation_framework.feature +0 -102
- data/features/filtering/exclusion_filters.feature +0 -135
- data/features/filtering/if_and_unless.feature +0 -138
- data/features/filtering/inclusion_filters.feature +0 -101
- data/features/formatters/configurable_colors.feature +0 -31
- data/features/formatters/custom_formatter.feature +0 -68
- data/features/formatters/json_formatter.feature +0 -30
- data/features/formatters/regression_tests.feature +0 -95
- data/features/formatters/text_formatter.feature +0 -46
- data/features/helper_methods/arbitrary_methods.feature +0 -40
- data/features/helper_methods/let.feature +0 -50
- data/features/helper_methods/modules.feature +0 -146
- data/features/hooks/around_hooks.feature +0 -344
- data/features/hooks/before_and_after_hooks.feature +0 -427
- data/features/hooks/filtering.feature +0 -232
- data/features/metadata/current_example.feature +0 -56
- data/features/metadata/described_class.feature +0 -17
- data/features/metadata/user_defined.feature +0 -100
- data/features/mock_framework_integration/use_any_framework.feature +0 -106
- data/features/mock_framework_integration/use_flexmock.feature +0 -94
- data/features/mock_framework_integration/use_mocha.feature +0 -95
- data/features/mock_framework_integration/use_rr.feature +0 -96
- data/features/mock_framework_integration/use_rspec.feature +0 -95
- data/features/pending_and_skipped_examples/README.md +0 -3
- data/features/pending_and_skipped_examples/pending_examples.feature +0 -118
- data/features/pending_and_skipped_examples/skipped_examples.feature +0 -106
- data/features/spec_files/arbitrary_file_suffix.feature +0 -13
- data/features/step_definitions/additional_cli_steps.rb +0 -83
- data/features/subject/explicit_subject.feature +0 -101
- data/features/subject/implicit_subject.feature +0 -63
- data/features/subject/one_liner_syntax.feature +0 -71
- data/features/support/env.rb +0 -21
- data/features/support/require_expect_syntax_in_aruba_specs.rb +0 -16
- data/features/support/rubinius.rb +0 -6
- data/lib/rspec/core/command_line.rb +0 -35
- data/lib/rspec/core/drb_command_line.rb +0 -26
- data/lib/rspec/core/drb_options.rb +0 -87
- data/lib/rspec/core/formatters/legacy_formatter.rb +0 -227
- data/lib/rspec/core/shared_example_group/collection.rb +0 -27
- data/spec/command_line/order_spec.rb +0 -211
- data/spec/rspec/core/backtrace_formatter_spec.rb +0 -230
- data/spec/rspec/core/command_line_spec.rb +0 -112
- data/spec/rspec/core/command_line_spec_output.txt +0 -0
- data/spec/rspec/core/configuration_options_spec.rb +0 -409
- data/spec/rspec/core/configuration_spec.rb +0 -1479
- data/spec/rspec/core/drb_command_line_spec.rb +0 -102
- data/spec/rspec/core/drb_options_spec.rb +0 -193
- data/spec/rspec/core/dsl_spec.rb +0 -88
- data/spec/rspec/core/example_group_spec.rb +0 -1533
- data/spec/rspec/core/example_spec.rb +0 -642
- data/spec/rspec/core/filter_manager_spec.rb +0 -229
- data/spec/rspec/core/formatters/base_formatter_spec.rb +0 -64
- data/spec/rspec/core/formatters/base_text_formatter_spec.rb +0 -303
- data/spec/rspec/core/formatters/deprecation_formatter_spec.rb +0 -208
- data/spec/rspec/core/formatters/documentation_formatter_spec.rb +0 -75
- data/spec/rspec/core/formatters/helpers_spec.rb +0 -104
- data/spec/rspec/core/formatters/html_formatted-2.1.0.html +0 -392
- data/spec/rspec/core/formatters/html_formatted.html +0 -397
- data/spec/rspec/core/formatters/html_formatter_spec.rb +0 -122
- data/spec/rspec/core/formatters/json_formatter_spec.rb +0 -206
- data/spec/rspec/core/formatters/legacy_formatter_spec.rb +0 -137
- data/spec/rspec/core/formatters/progress_formatter_spec.rb +0 -43
- data/spec/rspec/core/formatters/snippet_extractor_spec.rb +0 -26
- data/spec/rspec/core/formatters_spec.rb +0 -120
- data/spec/rspec/core/hooks_filtering_spec.rb +0 -227
- data/spec/rspec/core/hooks_spec.rb +0 -294
- data/spec/rspec/core/memoized_helpers_spec.rb +0 -495
- data/spec/rspec/core/metadata_spec.rb +0 -491
- data/spec/rspec/core/option_parser_spec.rb +0 -262
- data/spec/rspec/core/ordering_spec.rb +0 -102
- data/spec/rspec/core/pending_example_spec.rb +0 -117
- data/spec/rspec/core/pending_spec.rb +0 -8
- data/spec/rspec/core/project_initializer_spec.rb +0 -73
- data/spec/rspec/core/rake_task_spec.rb +0 -146
- data/spec/rspec/core/random_spec.rb +0 -47
- data/spec/rspec/core/reporter_spec.rb +0 -155
- data/spec/rspec/core/resources/a_bar.rb +0 -0
- data/spec/rspec/core/resources/a_foo.rb +0 -0
- data/spec/rspec/core/resources/a_spec.rb +0 -1
- data/spec/rspec/core/resources/custom_example_group_runner.rb +0 -14
- data/spec/rspec/core/resources/formatter_specs.rb +0 -58
- data/spec/rspec/core/resources/utf8_encoded.rb +0 -8
- data/spec/rspec/core/rspec_matchers_spec.rb +0 -45
- data/spec/rspec/core/ruby_project_spec.rb +0 -26
- data/spec/rspec/core/runner_spec.rb +0 -151
- data/spec/rspec/core/shared_context_spec.rb +0 -102
- data/spec/rspec/core/shared_example_group/collection_spec.rb +0 -57
- data/spec/rspec/core/shared_example_group_spec.rb +0 -114
- data/spec/rspec/core/warnings_spec.rb +0 -29
- data/spec/rspec/core/world_spec.rb +0 -142
- data/spec/rspec/core_spec.rb +0 -91
- data/spec/spec_helper.rb +0 -160
- data/spec/support/config_options_helper.rb +0 -13
- data/spec/support/formatter_support.rb +0 -83
- data/spec/support/helper_methods.rb +0 -26
- data/spec/support/isolate_load_path_mutation.rb +0 -5
- data/spec/support/isolated_directory.rb +0 -10
- data/spec/support/isolated_home_directory.rb +0 -16
- data/spec/support/legacy_formatter_using_sub_classing_example.rb +0 -87
- data/spec/support/matchers.rb +0 -85
- data/spec/support/mathn_integration_support.rb +0 -12
- data/spec/support/old_style_formatter_example.rb +0 -69
- data/spec/support/shared_example_groups.rb +0 -13
- data/spec/support/spec_files.rb +0 -44
- 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
|
@@ -1,14 +1,18 @@
|
|
1
|
-
|
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 `
|
7
|
-
#
|
8
|
-
#
|
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]
|
11
|
-
|
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
|
-
|
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]
|
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]
|
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]
|
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]
|
60
|
-
# @attr [
|
61
|
-
# @attr [
|
62
|
-
# @attr [
|
63
|
-
|
64
|
-
|
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
|
68
|
-
def
|
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]
|
81
|
-
# @attr [String]
|
82
|
-
# @attr [String]
|
83
|
-
# @attr [String]
|
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
|
|