rspec-core 3.0.0.beta1 → 3.0.0.beta2
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.
- data.tar.gz.sig +0 -0
- data/Changelog.md +137 -0
- data/README.md +2 -2
- data/exe/rspec +2 -23
- data/features/README.md +1 -5
- data/features/command_line/README.md +7 -10
- data/features/command_line/exit_status.feature +1 -1
- data/features/command_line/format_option.feature +1 -1
- data/features/command_line/init.feature +40 -1
- data/features/command_line/line_number_option.feature +2 -2
- data/features/command_line/ruby.feature +5 -4
- data/features/configuration/enable_global_dsl.feature +54 -0
- data/features/example_groups/aliasing.feature +48 -0
- data/features/example_groups/basic_structure.feature +1 -1
- data/features/expectation_framework_integration/configure_expectation_framework.feature +1 -1
- data/features/filtering/if_and_unless.feature +0 -30
- data/features/formatters/custom_formatter.feature +32 -0
- data/features/formatters/regression_tests.feature +95 -0
- data/features/hooks/around_hooks.feature +1 -0
- data/features/hooks/before_and_after_hooks.feature +2 -2
- data/features/mock_framework_integration/use_flexmock.feature +11 -13
- data/features/mock_framework_integration/use_mocha.feature +11 -13
- data/features/mock_framework_integration/use_rr.feature +11 -13
- data/features/mock_framework_integration/use_rspec.feature +11 -13
- data/features/pending_and_skipped_examples/README.md +3 -0
- data/features/pending_and_skipped_examples/pending_examples.feature +118 -0
- data/features/pending_and_skipped_examples/skipped_examples.feature +106 -0
- data/features/step_definitions/additional_cli_steps.rb +34 -0
- data/features/subject/explicit_subject.feature +1 -1
- data/features/subject/one_liner_syntax.feature +71 -0
- data/lib/rspec/core.rb +6 -14
- data/lib/rspec/core/backtrace_formatter.rb +16 -4
- data/lib/rspec/core/command_line.rb +2 -3
- data/lib/rspec/core/configuration.rb +114 -125
- data/lib/rspec/core/configuration_options.rb +32 -18
- data/lib/rspec/core/dsl.rb +80 -18
- data/lib/rspec/core/example.rb +84 -33
- data/lib/rspec/core/example_group.rb +95 -43
- data/lib/rspec/core/filter_manager.rb +31 -40
- data/lib/rspec/core/formatters.rb +137 -0
- data/lib/rspec/core/formatters/base_formatter.rb +28 -41
- data/lib/rspec/core/formatters/base_text_formatter.rb +26 -37
- data/lib/rspec/core/formatters/deprecation_formatter.rb +48 -27
- data/lib/rspec/core/formatters/documentation_formatter.rb +27 -22
- data/lib/rspec/core/formatters/html_formatter.rb +48 -56
- data/lib/rspec/core/formatters/html_printer.rb +11 -18
- data/lib/rspec/core/formatters/json_formatter.rb +18 -22
- data/lib/rspec/core/formatters/legacy_formatter.rb +227 -0
- data/lib/rspec/core/formatters/progress_formatter.rb +7 -10
- data/lib/rspec/core/hooks.rb +250 -217
- data/lib/rspec/core/memoized_helpers.rb +43 -9
- data/lib/rspec/core/mocking_adapters/flexmock.rb +29 -0
- data/lib/rspec/core/{mocking/with_mocha.rb → mocking_adapters/mocha.rb} +19 -16
- data/lib/rspec/core/mocking_adapters/null.rb +12 -0
- data/lib/rspec/core/mocking_adapters/rr.rb +28 -0
- data/lib/rspec/core/mocking_adapters/rspec.rb +30 -0
- data/lib/rspec/core/notifications.rb +100 -0
- data/lib/rspec/core/option_parser.rb +11 -18
- data/lib/rspec/core/pending.rb +78 -47
- data/lib/rspec/core/project_initializer.rb +2 -49
- data/lib/rspec/core/project_initializer/dot_rspec +3 -0
- data/lib/rspec/core/project_initializer/spec_helper.rb +82 -0
- data/lib/rspec/core/rake_task.rb +5 -14
- data/lib/rspec/core/reporter.rb +24 -32
- data/lib/rspec/core/ruby_project.rb +1 -1
- data/lib/rspec/core/runner.rb +14 -4
- data/lib/rspec/core/shared_example_group.rb +40 -13
- data/lib/rspec/core/version.rb +1 -1
- data/spec/command_line/order_spec.rb +15 -15
- data/spec/rspec/core/backtrace_formatter_spec.rb +15 -1
- data/spec/rspec/core/command_line_spec.rb +18 -17
- data/spec/rspec/core/configuration_options_spec.rb +57 -34
- data/spec/rspec/core/configuration_spec.rb +162 -184
- data/spec/rspec/core/drb_command_line_spec.rb +5 -7
- data/spec/rspec/core/drb_options_spec.rb +2 -2
- data/spec/rspec/core/dsl_spec.rb +79 -15
- data/spec/rspec/core/example_group_spec.rb +253 -39
- data/spec/rspec/core/example_spec.rb +149 -33
- data/spec/rspec/core/filter_manager_spec.rb +9 -26
- data/spec/rspec/core/formatters/base_formatter_spec.rb +2 -5
- data/spec/rspec/core/formatters/base_text_formatter_spec.rb +42 -145
- data/spec/rspec/core/formatters/deprecation_formatter_spec.rb +64 -34
- data/spec/rspec/core/formatters/documentation_formatter_spec.rb +15 -28
- data/spec/rspec/core/formatters/helpers_spec.rb +2 -2
- data/spec/rspec/core/formatters/{html_formatted-1.8.7.html → html_formatted-2.1.0.html} +22 -44
- data/spec/rspec/core/formatters/{html_formatted-1.8.7-jruby.html → html_formatted.html} +30 -49
- data/spec/rspec/core/formatters/html_formatter_spec.rb +35 -19
- data/spec/rspec/core/formatters/json_formatter_spec.rb +42 -40
- data/spec/rspec/core/formatters/legacy_formatter_spec.rb +137 -0
- data/spec/rspec/core/formatters/progress_formatter_spec.rb +38 -25
- data/spec/rspec/core/formatters/snippet_extractor_spec.rb +1 -1
- data/spec/rspec/core/formatters_spec.rb +120 -0
- data/spec/rspec/core/hooks_filtering_spec.rb +1 -1
- data/spec/rspec/core/hooks_spec.rb +13 -2
- data/spec/rspec/core/memoized_helpers_spec.rb +17 -8
- data/spec/rspec/core/metadata_spec.rb +3 -3
- data/spec/rspec/core/option_parser_spec.rb +53 -46
- data/spec/rspec/core/ordering_spec.rb +4 -4
- data/spec/rspec/core/pending_example_spec.rb +23 -126
- data/spec/rspec/core/pending_spec.rb +8 -0
- data/spec/rspec/core/project_initializer_spec.rb +8 -41
- data/spec/rspec/core/rake_task_spec.rb +15 -4
- data/spec/rspec/core/random_spec.rb +1 -1
- data/spec/rspec/core/reporter_spec.rb +50 -37
- data/spec/rspec/core/resources/formatter_specs.rb +9 -11
- data/spec/rspec/core/rspec_matchers_spec.rb +1 -1
- data/spec/rspec/core/ruby_project_spec.rb +3 -3
- data/spec/rspec/core/runner_spec.rb +65 -23
- data/spec/rspec/core/shared_context_spec.rb +4 -4
- data/spec/rspec/core/shared_example_group/collection_spec.rb +1 -1
- data/spec/rspec/core/shared_example_group_spec.rb +20 -11
- data/spec/rspec/core/warnings_spec.rb +1 -1
- data/spec/rspec/core/world_spec.rb +10 -10
- data/spec/rspec/core_spec.rb +2 -2
- data/spec/spec_helper.rb +12 -24
- data/spec/support/config_options_helper.rb +1 -3
- data/spec/support/formatter_support.rb +83 -0
- data/spec/support/isolate_load_path_mutation.rb +1 -2
- data/spec/support/isolated_directory.rb +1 -1
- data/spec/support/isolated_home_directory.rb +1 -1
- data/spec/support/legacy_formatter_using_sub_classing_example.rb +87 -0
- data/spec/support/matchers.rb +20 -0
- data/spec/support/mathn_integration_support.rb +2 -2
- data/spec/support/old_style_formatter_example.rb +69 -0
- data/spec/support/shared_example_groups.rb +1 -1
- data/spec/support/spec_files.rb +3 -3
- metadata +192 -69
- metadata.gz.sig +3 -1
- checksums.yaml +0 -15
- checksums.yaml.gz.sig +0 -2
- data/features/configuration/show_failures_in_pending_blocks.feature +0 -61
- data/features/pending/pending_examples.feature +0 -229
- data/features/subject/implicit_receiver.feature +0 -29
- data/lib/rspec/core/mocking/with_absolutely_nothing.rb +0 -11
- data/lib/rspec/core/mocking/with_flexmock.rb +0 -27
- data/lib/rspec/core/mocking/with_rr.rb +0 -27
- data/lib/rspec/core/mocking/with_rspec.rb +0 -27
- data/spec/rspec/core/formatters/html_formatted-1.8.7-rbx.html +0 -477
- data/spec/rspec/core/formatters/html_formatted-1.9.2.html +0 -425
- data/spec/rspec/core/formatters/html_formatted-1.9.3-jruby.html +0 -416
- data/spec/rspec/core/formatters/html_formatted-1.9.3-rbx.html +0 -477
- data/spec/rspec/core/formatters/html_formatted-1.9.3.html +0 -419
- data/spec/rspec/core/formatters/html_formatted-2.0.0.html +0 -425
- data/spec/support/in_sub_process.rb +0 -37
- data/spec/support/sandboxed_mock_space.rb +0 -100
|
@@ -4,8 +4,9 @@ require 'json'
|
|
|
4
4
|
module RSpec
|
|
5
5
|
module Core
|
|
6
6
|
module Formatters
|
|
7
|
-
|
|
8
7
|
class JsonFormatter < BaseFormatter
|
|
8
|
+
Formatters.register self, :message, :dump_summary, :stop, :close,
|
|
9
|
+
:dump_profile
|
|
9
10
|
|
|
10
11
|
attr_reader :output_hash
|
|
11
12
|
|
|
@@ -14,32 +15,23 @@ module RSpec
|
|
|
14
15
|
@output_hash = {}
|
|
15
16
|
end
|
|
16
17
|
|
|
17
|
-
def message(
|
|
18
|
-
(@output_hash[:messages] ||= []) << message
|
|
18
|
+
def message(notification)
|
|
19
|
+
(@output_hash[:messages] ||= []) << notification.message
|
|
19
20
|
end
|
|
20
21
|
|
|
21
|
-
def dump_summary(
|
|
22
|
-
super(duration, example_count, failure_count, pending_count)
|
|
22
|
+
def dump_summary(summary)
|
|
23
23
|
@output_hash[:summary] = {
|
|
24
|
-
:duration => duration,
|
|
25
|
-
:example_count => example_count,
|
|
26
|
-
:failure_count => failure_count,
|
|
27
|
-
:pending_count => pending_count
|
|
24
|
+
:duration => summary.duration,
|
|
25
|
+
:example_count => summary.example_count,
|
|
26
|
+
:failure_count => summary.failure_count,
|
|
27
|
+
:pending_count => summary.pending_count
|
|
28
28
|
}
|
|
29
|
-
@output_hash[:summary_line] = summary_line
|
|
30
|
-
|
|
31
|
-
dump_profile unless mute_profile_output?(failure_count)
|
|
32
|
-
end
|
|
29
|
+
@output_hash[:summary_line] = summary.summary_line
|
|
33
30
|
|
|
34
|
-
|
|
35
|
-
summary = pluralize(example_count, "example")
|
|
36
|
-
summary << ", " << pluralize(failure_count, "failure")
|
|
37
|
-
summary << ", #{pending_count} pending" if pending_count > 0
|
|
38
|
-
summary
|
|
31
|
+
dump_profile unless mute_profile_output?(summary.failure_count)
|
|
39
32
|
end
|
|
40
33
|
|
|
41
|
-
def stop
|
|
42
|
-
super
|
|
34
|
+
def stop(notification)
|
|
43
35
|
@output_hash[:examples] = examples.map do |example|
|
|
44
36
|
format_example(example).tap do |hash|
|
|
45
37
|
if e=example.exception
|
|
@@ -53,7 +45,7 @@ module RSpec
|
|
|
53
45
|
end
|
|
54
46
|
end
|
|
55
47
|
|
|
56
|
-
def close
|
|
48
|
+
def close(notification)
|
|
57
49
|
output.write @output_hash.to_json
|
|
58
50
|
output.close if IO === output && output != $stdout
|
|
59
51
|
end
|
|
@@ -64,6 +56,7 @@ module RSpec
|
|
|
64
56
|
dump_profile_slowest_example_groups
|
|
65
57
|
end
|
|
66
58
|
|
|
59
|
+
# @api private
|
|
67
60
|
def dump_profile_slowest_examples
|
|
68
61
|
@output_hash[:profile] = {}
|
|
69
62
|
sorted_examples = slowest_examples
|
|
@@ -76,6 +69,7 @@ module RSpec
|
|
|
76
69
|
@output_hash[:profile][:total] = sorted_examples[:total]
|
|
77
70
|
end
|
|
78
71
|
|
|
72
|
+
# @api private
|
|
79
73
|
def dump_profile_slowest_example_groups
|
|
80
74
|
@output_hash[:profile] ||= {}
|
|
81
75
|
@output_hash[:profile][:groups] = slowest_groups.map do |loc, hash|
|
|
@@ -84,13 +78,15 @@ module RSpec
|
|
|
84
78
|
end
|
|
85
79
|
|
|
86
80
|
private
|
|
81
|
+
|
|
87
82
|
def format_example(example)
|
|
88
83
|
{
|
|
89
84
|
:description => example.description,
|
|
90
85
|
:full_description => example.full_description,
|
|
91
86
|
:status => example.execution_result[:status],
|
|
92
87
|
:file_path => example.metadata[:file_path],
|
|
93
|
-
:line_number => example.metadata[:line_number]
|
|
88
|
+
:line_number => example.metadata[:line_number],
|
|
89
|
+
:run_time => example.execution_result[:run_time]
|
|
94
90
|
}
|
|
95
91
|
end
|
|
96
92
|
end
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
require 'rspec/core/formatters/helpers'
|
|
2
|
+
require 'stringio'
|
|
3
|
+
|
|
4
|
+
module RSpec
|
|
5
|
+
module Core
|
|
6
|
+
module Formatters
|
|
7
|
+
|
|
8
|
+
# The `LegacyFormatter` is used to wrap older RSpec 2.x style formatters
|
|
9
|
+
# for the new 3.x implementation. It takes care of registering all the
|
|
10
|
+
# old notifications and translating them to the older formatter.
|
|
11
|
+
#
|
|
12
|
+
# @see RSpec::Core::Formatters::BaseFormatter
|
|
13
|
+
class LegacyFormatter
|
|
14
|
+
NOTIFICATIONS = %W[start message example_group_started example_group_finished example_started
|
|
15
|
+
example_passed example_failed example_pending start_dump dump_pending
|
|
16
|
+
dump_failures dump_summary seed close stop deprecation deprecation_summary]
|
|
17
|
+
|
|
18
|
+
module LegacyInterface
|
|
19
|
+
|
|
20
|
+
def start(count)
|
|
21
|
+
super Notifications::CountNotification.new(count)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def example_group_started(group)
|
|
25
|
+
super Notifications::GroupNotification.new(group) if defined?(super)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def example_group_finished(group)
|
|
29
|
+
super Notifications::GroupNotification.new(group) if defined?(super)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def example_started(example)
|
|
33
|
+
super Notifications::ExampleNotification.new(example) if defined?(super)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def example_passed(example)
|
|
37
|
+
super Notifications::ExampleNotification.new(example) if defined?(super)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def example_pending(example)
|
|
41
|
+
super Notifications::ExampleNotification.new(example) if defined?(super)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def example_failed(example)
|
|
45
|
+
super Notifications::ExampleNotification.new(example) if defined?(super)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def message(message)
|
|
49
|
+
super Notifications::MessageNotification.new(message) if defined?(super)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
attr_reader :duration, :example_count, :failure_count, :pending_count
|
|
53
|
+
def dump_summary(duration, examples, failures, pending)
|
|
54
|
+
@duration = duration
|
|
55
|
+
@example_count = examples
|
|
56
|
+
@failure_count = failures
|
|
57
|
+
@pending_count = pending
|
|
58
|
+
super Notifications::SummaryNotification.new(duration, examples, failures, pending) if defined?(super)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def seed(seed)
|
|
62
|
+
super Notifications::SeedNotification.new(seed, true) if defined?(super)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def start_dump
|
|
67
|
+
super(Notifications::NullNotification) if defined?(super)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def dump_failures
|
|
71
|
+
super(Notifications::NullNotification) if defined?(super)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def dump_pending
|
|
75
|
+
super(Notifications::NullNotification) if defined?(super)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def dump_profile
|
|
79
|
+
super(Notifications::NullNotification) if defined?(super)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def close
|
|
83
|
+
super(Notifications::NullNotification) if defined?(super)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def stop
|
|
87
|
+
super(Notifications::NullNotification) if defined?(super)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# @api private
|
|
92
|
+
attr_reader :formatter
|
|
93
|
+
|
|
94
|
+
# @api public
|
|
95
|
+
#
|
|
96
|
+
# @param formatter
|
|
97
|
+
def initialize(formatter_class, *args)
|
|
98
|
+
if formatter_class.ancestors.include?(BaseFormatter)
|
|
99
|
+
formatter_class.class_eval do
|
|
100
|
+
include LegacyInterface
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
@formatter = formatter_class.new(*args)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# @api public
|
|
107
|
+
#
|
|
108
|
+
# This method is invoked during the setup phase to register
|
|
109
|
+
# a formatters with the reporter
|
|
110
|
+
#
|
|
111
|
+
def notifications
|
|
112
|
+
@notifications ||= NOTIFICATIONS.select { |m| @formatter.respond_to? m }
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# @api public
|
|
116
|
+
#
|
|
117
|
+
# @param example_count
|
|
118
|
+
def start(notification)
|
|
119
|
+
@formatter.start notification.count
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# @api public
|
|
123
|
+
#
|
|
124
|
+
# @param example_group
|
|
125
|
+
def example_group_started(notification)
|
|
126
|
+
@formatter.example_group_started notification.group
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# @api public
|
|
130
|
+
#
|
|
131
|
+
# @param example_group
|
|
132
|
+
def example_group_finished(notification)
|
|
133
|
+
@formatter.example_group_finished notification.group
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# @api public
|
|
137
|
+
#
|
|
138
|
+
# @param example
|
|
139
|
+
def example_started(notification)
|
|
140
|
+
@formatter.example_started notification.example
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# @api public
|
|
144
|
+
#
|
|
145
|
+
# @param example
|
|
146
|
+
def example_passed(notification)
|
|
147
|
+
@formatter.example_passed notification.example
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# @api public
|
|
151
|
+
#
|
|
152
|
+
# @param example
|
|
153
|
+
def example_pending(notification)
|
|
154
|
+
@formatter.example_pending notification.example
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# @api public
|
|
158
|
+
#
|
|
159
|
+
# @param example
|
|
160
|
+
def example_failed(notification)
|
|
161
|
+
@formatter.example_failed notification.example
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
# @api public
|
|
165
|
+
#
|
|
166
|
+
# @param message
|
|
167
|
+
def message(notification)
|
|
168
|
+
@formatter.message notification.message
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# @api public
|
|
172
|
+
#
|
|
173
|
+
def stop(notification)
|
|
174
|
+
@formatter.stop
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# @api public
|
|
178
|
+
#
|
|
179
|
+
def start_dump(notification)
|
|
180
|
+
@formatter.start_dump
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# @api public
|
|
184
|
+
#
|
|
185
|
+
def dump_failures(notification)
|
|
186
|
+
@formatter.dump_failures
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# @api public
|
|
190
|
+
#
|
|
191
|
+
# @param duration
|
|
192
|
+
# @param example_count
|
|
193
|
+
# @param failure_count
|
|
194
|
+
# @param pending_count
|
|
195
|
+
def dump_summary(summary)
|
|
196
|
+
@formatter.dump_summary summary.duration, summary.example_count, summary.failure_count, summary.pending_count
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# @api public
|
|
200
|
+
#
|
|
201
|
+
def dump_pending(notification)
|
|
202
|
+
@formatter.dump_pending
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
# @api public
|
|
206
|
+
#
|
|
207
|
+
def dump_profile(notification)
|
|
208
|
+
@formatter.dump_profile
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# @api public
|
|
212
|
+
#
|
|
213
|
+
# @param seed
|
|
214
|
+
def seed(notification)
|
|
215
|
+
@formatter.seed notification.seed
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# @api public
|
|
219
|
+
#
|
|
220
|
+
def close(notification)
|
|
221
|
+
@formatter.close
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
@@ -2,31 +2,28 @@ require 'rspec/core/formatters/base_text_formatter'
|
|
|
2
2
|
module RSpec
|
|
3
3
|
module Core
|
|
4
4
|
module Formatters
|
|
5
|
-
|
|
6
5
|
class ProgressFormatter < BaseTextFormatter
|
|
6
|
+
Formatters.register self, :example_passed, :example_pending, :example_failed, :start_dump
|
|
7
7
|
|
|
8
|
-
def example_passed(
|
|
9
|
-
super(example)
|
|
8
|
+
def example_passed(notification)
|
|
10
9
|
output.print success_color('.')
|
|
11
10
|
end
|
|
12
11
|
|
|
13
|
-
def example_pending(
|
|
14
|
-
super
|
|
12
|
+
def example_pending(notification)
|
|
13
|
+
super
|
|
15
14
|
output.print pending_color('*')
|
|
16
15
|
end
|
|
17
16
|
|
|
18
|
-
def example_failed(
|
|
19
|
-
super
|
|
17
|
+
def example_failed(notification)
|
|
18
|
+
super
|
|
20
19
|
output.print failure_color('F')
|
|
21
20
|
end
|
|
22
21
|
|
|
23
|
-
def start_dump
|
|
24
|
-
super()
|
|
22
|
+
def start_dump(notification)
|
|
25
23
|
output.puts
|
|
26
24
|
end
|
|
27
25
|
|
|
28
26
|
end
|
|
29
|
-
|
|
30
27
|
end
|
|
31
28
|
end
|
|
32
29
|
end
|
data/lib/rspec/core/hooks.rb
CHANGED
|
@@ -1,167 +1,6 @@
|
|
|
1
1
|
module RSpec
|
|
2
2
|
module Core
|
|
3
3
|
module Hooks
|
|
4
|
-
class Hook
|
|
5
|
-
attr_reader :block, :options
|
|
6
|
-
|
|
7
|
-
def initialize(block, options)
|
|
8
|
-
@block = block
|
|
9
|
-
@options = options
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def options_apply?(example_or_group)
|
|
13
|
-
example_or_group.all_apply?(options)
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
class BeforeHook < Hook
|
|
18
|
-
def run(example)
|
|
19
|
-
example.instance_exec(example, &block)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def display_name
|
|
23
|
-
"before hook"
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
class AfterHook < Hook
|
|
28
|
-
def run(example)
|
|
29
|
-
example.instance_exec_with_rescue("in an after hook", &block)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def display_name
|
|
33
|
-
"after hook"
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
class AfterAllHook < Hook
|
|
38
|
-
def run(example)
|
|
39
|
-
example.instance_exec(example, &block)
|
|
40
|
-
rescue Exception => e
|
|
41
|
-
# TODO: come up with a better solution for this.
|
|
42
|
-
RSpec.configuration.reporter.message <<-EOS
|
|
43
|
-
|
|
44
|
-
An error occurred in an after(:all) hook.
|
|
45
|
-
#{e.class}: #{e.message}
|
|
46
|
-
occurred at #{e.backtrace.first}
|
|
47
|
-
|
|
48
|
-
EOS
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def display_name
|
|
52
|
-
"after(:all) hook"
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
class AroundHook < Hook
|
|
57
|
-
def display_name
|
|
58
|
-
"around hook"
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
class BaseHookCollection
|
|
63
|
-
Array.public_instance_methods(false).each do |name|
|
|
64
|
-
define_method(name) { |*a, &b| hooks.__send__(name, *a, &b) }
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
attr_reader :hooks
|
|
68
|
-
protected :hooks
|
|
69
|
-
|
|
70
|
-
alias append push
|
|
71
|
-
alias prepend unshift
|
|
72
|
-
|
|
73
|
-
def initialize(hooks=[])
|
|
74
|
-
@hooks = hooks
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
class HookCollection < BaseHookCollection
|
|
79
|
-
def for(example_or_group)
|
|
80
|
-
self.class.
|
|
81
|
-
new(hooks.select {|hook| hook.options_apply?(example_or_group)}).
|
|
82
|
-
with(example_or_group)
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def with(example)
|
|
86
|
-
@example = example
|
|
87
|
-
self
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def run
|
|
91
|
-
hooks.each {|h| h.run(@example)}
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
class AroundHookCollection < BaseHookCollection
|
|
96
|
-
def for(example, initial_procsy=nil)
|
|
97
|
-
self.class.new(hooks.select {|hook| hook.options_apply?(example)}).
|
|
98
|
-
with(example, initial_procsy)
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def with(example, initial_procsy)
|
|
102
|
-
@example = example
|
|
103
|
-
@initial_procsy = initial_procsy
|
|
104
|
-
self
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def run
|
|
108
|
-
hooks.reduce(@initial_procsy) do |procsy, around_hook|
|
|
109
|
-
procsy.wrap do
|
|
110
|
-
@example.instance_exec(procsy, &around_hook.block)
|
|
111
|
-
end
|
|
112
|
-
end.call
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
class GroupHookCollection < BaseHookCollection
|
|
117
|
-
def for(group)
|
|
118
|
-
@group = group
|
|
119
|
-
self
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
def run
|
|
123
|
-
hooks.shift.run(@group) until hooks.empty?
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
class HookCollections
|
|
128
|
-
def initialize(data)
|
|
129
|
-
@data = data
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
def [](key)
|
|
133
|
-
@data[key]
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
def register_globals(host, globals)
|
|
137
|
-
process(host, globals, :before, :each)
|
|
138
|
-
process(host, globals, :after, :each)
|
|
139
|
-
process(host, globals, :around, :each)
|
|
140
|
-
|
|
141
|
-
process(host, globals, :before, :all)
|
|
142
|
-
process(host, globals, :after, :all)
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
private
|
|
146
|
-
|
|
147
|
-
def process(host, globals, position, scope)
|
|
148
|
-
globals[position][scope].each do |hook|
|
|
149
|
-
next unless scope == :each || hook.options_apply?(host)
|
|
150
|
-
next if host.parent_groups.any? {|a| a.hooks[position][scope].include?(hook)}
|
|
151
|
-
self[position][scope] << hook
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
# @private
|
|
157
|
-
def hooks
|
|
158
|
-
@hooks ||= HookCollections.new(
|
|
159
|
-
:around => { :each => AroundHookCollection.new },
|
|
160
|
-
:before => { :each => HookCollection.new, :all => HookCollection.new, :suite => HookCollection.new },
|
|
161
|
-
:after => { :each => HookCollection.new, :all => HookCollection.new, :suite => HookCollection.new }
|
|
162
|
-
)
|
|
163
|
-
end
|
|
164
|
-
|
|
165
4
|
# @api public
|
|
166
5
|
# @overload before(&block)
|
|
167
6
|
# @overload before(scope, &block)
|
|
@@ -329,7 +168,7 @@ EOS
|
|
|
329
168
|
# end
|
|
330
169
|
# end
|
|
331
170
|
def before(*args, &block)
|
|
332
|
-
|
|
171
|
+
hooks.register :append, :before, *args, &block
|
|
333
172
|
end
|
|
334
173
|
|
|
335
174
|
alias_method :append_before, :before
|
|
@@ -339,7 +178,7 @@ EOS
|
|
|
339
178
|
#
|
|
340
179
|
# See #before for scoping semantics.
|
|
341
180
|
def prepend_before(*args, &block)
|
|
342
|
-
|
|
181
|
+
hooks.register :prepend, :before, *args, &block
|
|
343
182
|
end
|
|
344
183
|
|
|
345
184
|
# @api public
|
|
@@ -391,7 +230,7 @@ EOS
|
|
|
391
230
|
# Similarly, if more than one `after` is declared within any one scope,
|
|
392
231
|
# they are run in reverse order of that in which they are declared.
|
|
393
232
|
def after(*args, &block)
|
|
394
|
-
|
|
233
|
+
hooks.register :prepend, :after, *args, &block
|
|
395
234
|
end
|
|
396
235
|
|
|
397
236
|
alias_method :prepend_after, :after
|
|
@@ -401,7 +240,7 @@ EOS
|
|
|
401
240
|
#
|
|
402
241
|
# See #after for scoping semantics.
|
|
403
242
|
def append_after(*args, &block)
|
|
404
|
-
|
|
243
|
+
hooks.register :append, :after, *args, &block
|
|
405
244
|
end
|
|
406
245
|
|
|
407
246
|
# @api public
|
|
@@ -449,85 +288,279 @@ EOS
|
|
|
449
288
|
# around(:each) {|ex| FakeFS(&ex)}
|
|
450
289
|
#
|
|
451
290
|
def around(*args, &block)
|
|
452
|
-
|
|
291
|
+
hooks.register :prepend, :around, *args, &block
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
# @api private
|
|
295
|
+
# Holds the various registered hooks.
|
|
296
|
+
def hooks
|
|
297
|
+
@hooks ||= HookCollections.new(self,
|
|
298
|
+
:around => { :each => AroundHookCollection.new },
|
|
299
|
+
:before => { :each => HookCollection.new, :all => HookCollection.new, :suite => HookCollection.new },
|
|
300
|
+
:after => { :each => HookCollection.new, :all => HookCollection.new, :suite => HookCollection.new }
|
|
301
|
+
)
|
|
453
302
|
end
|
|
454
303
|
|
|
304
|
+
private
|
|
305
|
+
|
|
455
306
|
# @private
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
# example. If no example is provided, just calls the hook directly.
|
|
459
|
-
def run_hook(hook, scope, example_or_group=ExampleGroup.new, initial_procsy=nil)
|
|
460
|
-
return if RSpec.configuration.dry_run?
|
|
307
|
+
class Hook
|
|
308
|
+
attr_reader :block, :options
|
|
461
309
|
|
|
462
|
-
|
|
310
|
+
def initialize(block, options)
|
|
311
|
+
@block = block
|
|
312
|
+
@options = options
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def options_apply?(example_or_group)
|
|
316
|
+
example_or_group.all_apply?(options)
|
|
317
|
+
end
|
|
463
318
|
end
|
|
464
319
|
|
|
465
320
|
# @private
|
|
466
|
-
|
|
467
|
-
|
|
321
|
+
class BeforeHook < Hook
|
|
322
|
+
def run(example)
|
|
323
|
+
example.instance_exec(example, &block)
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
def display_name
|
|
327
|
+
"before hook"
|
|
328
|
+
end
|
|
468
329
|
end
|
|
469
330
|
|
|
470
|
-
|
|
331
|
+
# @private
|
|
332
|
+
class AfterHook < Hook
|
|
333
|
+
def run(example)
|
|
334
|
+
example.instance_exec_with_rescue("in an after hook", &block)
|
|
335
|
+
end
|
|
471
336
|
|
|
472
|
-
|
|
337
|
+
def display_name
|
|
338
|
+
"after hook"
|
|
339
|
+
end
|
|
340
|
+
end
|
|
473
341
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
342
|
+
# @private
|
|
343
|
+
class AfterAllHook < Hook
|
|
344
|
+
def run(example)
|
|
345
|
+
example.instance_exec(example, &block)
|
|
346
|
+
rescue Exception => e
|
|
347
|
+
# TODO: come up with a better solution for this.
|
|
348
|
+
RSpec.configuration.reporter.message <<-EOS
|
|
479
349
|
|
|
480
|
-
|
|
350
|
+
An error occurred in an after(:all) hook.
|
|
351
|
+
#{e.class}: #{e.message}
|
|
352
|
+
occurred at #{e.backtrace.first}
|
|
481
353
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
end
|
|
354
|
+
EOS
|
|
355
|
+
end
|
|
485
356
|
|
|
486
|
-
|
|
487
|
-
|
|
357
|
+
def display_name
|
|
358
|
+
"after(:all) hook"
|
|
359
|
+
end
|
|
488
360
|
end
|
|
489
361
|
|
|
490
|
-
|
|
491
|
-
|
|
362
|
+
# @private
|
|
363
|
+
class AroundHook < Hook
|
|
364
|
+
def display_name
|
|
365
|
+
"around hook"
|
|
366
|
+
end
|
|
492
367
|
end
|
|
493
368
|
|
|
494
|
-
|
|
495
|
-
|
|
369
|
+
# @private
|
|
370
|
+
class BaseHookCollection
|
|
371
|
+
Array.public_instance_methods(false).each do |name|
|
|
372
|
+
define_method(name) { |*a, &b| hooks.__send__(name, *a, &b) }
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
attr_reader :hooks
|
|
376
|
+
protected :hooks
|
|
377
|
+
|
|
378
|
+
alias append push
|
|
379
|
+
alias prepend unshift
|
|
380
|
+
|
|
381
|
+
def initialize(hooks=[])
|
|
382
|
+
@hooks = hooks
|
|
383
|
+
end
|
|
496
384
|
end
|
|
497
385
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
386
|
+
# @private
|
|
387
|
+
class HookCollection < BaseHookCollection
|
|
388
|
+
def for(example_or_group)
|
|
389
|
+
self.class.
|
|
390
|
+
new(hooks.select {|hook| hook.options_apply?(example_or_group)}).
|
|
391
|
+
with(example_or_group)
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
def with(example)
|
|
395
|
+
@example = example
|
|
396
|
+
self
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
def run
|
|
400
|
+
hooks.each {|h| h.run(@example)}
|
|
401
|
+
end
|
|
501
402
|
end
|
|
502
403
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
404
|
+
# @private
|
|
405
|
+
class AroundHookCollection < BaseHookCollection
|
|
406
|
+
def for(example, initial_procsy=nil)
|
|
407
|
+
self.class.new(hooks.select {|hook| hook.options_apply?(example)}).
|
|
408
|
+
with(example, initial_procsy)
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
def with(example, initial_procsy)
|
|
412
|
+
@example = example
|
|
413
|
+
@initial_procsy = initial_procsy
|
|
414
|
+
self
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
def run
|
|
418
|
+
hooks.inject(@initial_procsy) do |procsy, around_hook|
|
|
419
|
+
procsy.wrap do
|
|
420
|
+
@example.instance_exec(procsy, &around_hook.block)
|
|
421
|
+
end
|
|
422
|
+
end.call
|
|
517
423
|
end
|
|
518
424
|
end
|
|
519
425
|
|
|
520
|
-
|
|
521
|
-
|
|
426
|
+
# @private
|
|
427
|
+
class GroupHookCollection < BaseHookCollection
|
|
428
|
+
def for(group)
|
|
429
|
+
@group = group
|
|
430
|
+
self
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
def run
|
|
434
|
+
hooks.shift.run(@group) until hooks.empty?
|
|
435
|
+
end
|
|
522
436
|
end
|
|
523
437
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
438
|
+
# @private
|
|
439
|
+
class HookCollections
|
|
440
|
+
def initialize(owner, data)
|
|
441
|
+
@owner = owner
|
|
442
|
+
@data = data
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
def [](key)
|
|
446
|
+
@data[key]
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def register_globals(host, globals)
|
|
450
|
+
process(host, globals, :before, :each)
|
|
451
|
+
process(host, globals, :after, :each)
|
|
452
|
+
process(host, globals, :around, :each)
|
|
453
|
+
|
|
454
|
+
process(host, globals, :before, :all)
|
|
455
|
+
process(host, globals, :after, :all)
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
def around_each_hooks_for(example, initial_procsy=nil)
|
|
459
|
+
AroundHookCollection.new(FlatMap.flat_map(@owner.parent_groups) do |a|
|
|
460
|
+
a.hooks[:around][:each]
|
|
461
|
+
end).for(example, initial_procsy)
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
def register(prepend_or_append, hook, *args, &block)
|
|
465
|
+
scope, options = scope_and_options_from(*args)
|
|
466
|
+
self[hook][scope].__send__(prepend_or_append, HOOK_TYPES[hook][scope].new(block, options))
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
# @private
|
|
470
|
+
#
|
|
471
|
+
# Runs all of the blocks stored with the hook in the context of the
|
|
472
|
+
# example. If no example is provided, just calls the hook directly.
|
|
473
|
+
def run(hook, scope, example_or_group=ExampleGroup.new, initial_procsy=nil)
|
|
474
|
+
return if RSpec.configuration.dry_run?
|
|
475
|
+
|
|
476
|
+
find_hook(hook, scope, example_or_group, initial_procsy).run
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
SCOPES = [:each, :all, :suite]
|
|
480
|
+
|
|
481
|
+
SCOPE_ALIASES = {
|
|
482
|
+
:example => :each,
|
|
483
|
+
:context => :all,
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
HOOK_TYPES = {
|
|
487
|
+
:before => Hash.new { BeforeHook },
|
|
488
|
+
:after => Hash.new { AfterHook },
|
|
489
|
+
:around => Hash.new { AroundHook }
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
HOOK_TYPES[:after][:all] = AfterAllHook
|
|
493
|
+
|
|
494
|
+
private
|
|
495
|
+
|
|
496
|
+
def process(host, globals, position, scope)
|
|
497
|
+
globals[position][scope].each do |hook|
|
|
498
|
+
next unless scope == :each || hook.options_apply?(host)
|
|
499
|
+
next if host.parent_groups.any? {|a| a.hooks[position][scope].include?(hook)}
|
|
500
|
+
self[position][scope] << hook
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
def scope_and_options_from(*args)
|
|
505
|
+
return extract_scope_from(args), Metadata.build_hash_from(args)
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
def extract_scope_from(args)
|
|
509
|
+
if known_scope?(args.first)
|
|
510
|
+
normalized_scope_for(args.shift)
|
|
511
|
+
elsif args.any? { |a| a.is_a?(Symbol) }
|
|
512
|
+
error_message = "You must explicitly give a scope (#{SCOPES.join(", ")}) or scope alias (#{SCOPE_ALIASES.keys.join(", ")}) when using symbols as metadata for a hook."
|
|
513
|
+
raise ArgumentError.new error_message
|
|
514
|
+
else
|
|
515
|
+
:each
|
|
516
|
+
end
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
# @api private
|
|
520
|
+
def known_scope?(scope)
|
|
521
|
+
SCOPES.include?(scope) || SCOPE_ALIASES.keys.include?(scope)
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
# @api private
|
|
525
|
+
def normalized_scope_for(scope)
|
|
526
|
+
SCOPE_ALIASES[scope] || scope
|
|
527
|
+
end
|
|
528
|
+
|
|
529
|
+
def find_hook(hook, scope, example_or_group, initial_procsy)
|
|
530
|
+
case [hook, scope]
|
|
531
|
+
when [:before, :all]
|
|
532
|
+
before_all_hooks_for(example_or_group)
|
|
533
|
+
when [:after, :all]
|
|
534
|
+
after_all_hooks_for(example_or_group)
|
|
535
|
+
when [:around, :each]
|
|
536
|
+
around_each_hooks_for(example_or_group, initial_procsy)
|
|
537
|
+
when [:before, :each]
|
|
538
|
+
before_each_hooks_for(example_or_group)
|
|
539
|
+
when [:after, :each]
|
|
540
|
+
after_each_hooks_for(example_or_group)
|
|
541
|
+
when [:before, :suite], [:after, :suite]
|
|
542
|
+
self[hook][:suite].with(example_or_group)
|
|
543
|
+
end
|
|
544
|
+
end
|
|
545
|
+
|
|
546
|
+
def before_all_hooks_for(group)
|
|
547
|
+
GroupHookCollection.new(self[:before][:all]).for(group)
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
def after_all_hooks_for(group)
|
|
551
|
+
GroupHookCollection.new(self[:after][:all]).for(group)
|
|
552
|
+
end
|
|
553
|
+
|
|
554
|
+
def before_each_hooks_for(example)
|
|
555
|
+
HookCollection.new(FlatMap.flat_map(@owner.parent_groups.reverse) do |a|
|
|
556
|
+
a.hooks[:before][:each]
|
|
557
|
+
end).for(example)
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
def after_each_hooks_for(example)
|
|
561
|
+
HookCollection.new(FlatMap.flat_map(@owner.parent_groups) do |a|
|
|
562
|
+
a.hooks[:after][:each]
|
|
563
|
+
end).for(example)
|
|
531
564
|
end
|
|
532
565
|
end
|
|
533
566
|
end
|