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