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
@@ -1,5 +1,6 @@
|
|
1
1
|
module RSpec
|
2
2
|
module Core
|
3
|
+
# @private
|
3
4
|
# Manages the filtering of examples and groups by matching tags declared on
|
4
5
|
# the command line or options files, or filters declared via
|
5
6
|
# `RSpec.configure`, with hash key/values submitted within example group
|
@@ -66,149 +67,193 @@ module RSpec
|
|
66
67
|
# @see Configuration#filter_run_including
|
67
68
|
# @see Configuration#filter_run_excluding
|
68
69
|
class FilterManager
|
69
|
-
|
70
|
+
attr_reader :exclusions, :inclusions
|
70
71
|
|
71
|
-
|
72
|
-
|
72
|
+
def initialize
|
73
|
+
@exclusions, @inclusions = FilterRules.build
|
74
|
+
end
|
73
75
|
|
74
|
-
|
75
|
-
|
76
|
+
# @api private
|
77
|
+
#
|
78
|
+
# @param file_path [String]
|
79
|
+
# @param line_numbers [Array]
|
80
|
+
def add_location(file_path, line_numbers)
|
81
|
+
# locations is a hash of expanded paths to arrays of line
|
82
|
+
# numbers to match against. e.g.
|
83
|
+
# { "path/to/file.rb" => [37, 42] }
|
84
|
+
locations = inclusions.delete(:locations) || Hash.new { |h,k| h[k] = [] }
|
85
|
+
locations[File.expand_path(file_path)].push(*line_numbers)
|
86
|
+
inclusions.add_location(locations)
|
87
|
+
end
|
88
|
+
|
89
|
+
def empty?
|
90
|
+
inclusions.empty? && exclusions.empty?
|
76
91
|
end
|
77
92
|
|
78
|
-
|
79
|
-
|
80
|
-
|
93
|
+
def prune(examples)
|
94
|
+
if inclusions.standalone?
|
95
|
+
base_exclusions = ExclusionRules.new
|
96
|
+
examples.select {|e| !base_exclusions.include_example?(e) && include?(e) }
|
97
|
+
else
|
98
|
+
examples.select {|e| !exclude?(e) && include?(e)}
|
81
99
|
end
|
82
100
|
end
|
83
101
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
:unless => lambda { |value| value }
|
88
|
-
}
|
102
|
+
def exclude(*args)
|
103
|
+
exclusions.add(args.last)
|
104
|
+
end
|
89
105
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
end
|
106
|
+
def exclude_only(*args)
|
107
|
+
exclusions.use_only(args.last)
|
108
|
+
end
|
94
109
|
|
95
|
-
|
96
|
-
|
97
|
-
|
110
|
+
def exclude_with_low_priority(*args)
|
111
|
+
exclusions.add_with_low_priority(args.last)
|
112
|
+
end
|
98
113
|
|
99
|
-
|
100
|
-
|
101
|
-
|
114
|
+
def exclude?(example)
|
115
|
+
exclusions.include_example?(example)
|
116
|
+
end
|
102
117
|
|
103
|
-
|
118
|
+
def include(*args)
|
119
|
+
inclusions.add(args.last)
|
120
|
+
end
|
104
121
|
|
105
|
-
|
106
|
-
|
107
|
-
# On 1.8.7, Hash#reject returns a hash but Hash#select returns an array.
|
108
|
-
reject {|k,v| CONDITIONAL_FILTERS[k] == v}
|
109
|
-
end
|
110
|
-
else
|
111
|
-
def without_conditional_filters
|
112
|
-
# On ruby 2.1 #reject on a subclass of Hash emits warnings, but #select does not.
|
113
|
-
select {|k,v| CONDITIONAL_FILTERS[k] != v}
|
114
|
-
end
|
115
|
-
end
|
122
|
+
def include_only(*args)
|
123
|
+
inclusions.use_only(args.last)
|
116
124
|
end
|
117
125
|
|
118
|
-
|
126
|
+
def include_with_low_priority(*args)
|
127
|
+
inclusions.add_with_low_priority(args.last)
|
128
|
+
end
|
119
129
|
|
120
|
-
def
|
121
|
-
|
122
|
-
@inclusions = InclusionFilterHash.new
|
130
|
+
def include?(example)
|
131
|
+
inclusions.include_example?(example)
|
123
132
|
end
|
133
|
+
end
|
124
134
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
135
|
+
# @private
|
136
|
+
class FilterRules
|
137
|
+
PROC_HEX_NUMBER = /0x[0-9a-f]+@/
|
138
|
+
PROJECT_DIR = File.expand_path('.')
|
139
|
+
|
140
|
+
attr_accessor :opposite
|
141
|
+
attr_reader :rules
|
131
142
|
|
132
|
-
|
143
|
+
def self.build
|
144
|
+
exclusions = ExclusionRules.new
|
145
|
+
inclusions = InclusionRules.new
|
146
|
+
exclusions.opposite = inclusions
|
147
|
+
inclusions.opposite = exclusions
|
148
|
+
[exclusions, inclusions]
|
133
149
|
end
|
134
150
|
|
135
|
-
def
|
136
|
-
|
151
|
+
def initialize(*args, &block)
|
152
|
+
@rules = Hash.new(*args, &block)
|
137
153
|
end
|
138
154
|
|
139
|
-
def
|
140
|
-
|
155
|
+
def add(updated)
|
156
|
+
@rules.merge!(updated).each_key { |k| opposite.delete(k) }
|
141
157
|
end
|
142
158
|
|
143
|
-
def
|
144
|
-
merge(@
|
159
|
+
def add_with_low_priority(_updated)
|
160
|
+
updated = _updated.merge(@rules)
|
161
|
+
opposite.each_pair { |k,v| updated.delete(k) if updated[k] == v }
|
162
|
+
@rules.replace(updated)
|
145
163
|
end
|
146
164
|
|
147
|
-
def
|
148
|
-
|
165
|
+
def use_only(updated)
|
166
|
+
updated.each_key { |k| opposite.delete(k) }
|
167
|
+
@rules.replace(updated)
|
149
168
|
end
|
150
169
|
|
151
|
-
def
|
152
|
-
|
170
|
+
def clear
|
171
|
+
@rules.clear
|
153
172
|
end
|
154
173
|
|
155
|
-
def
|
156
|
-
@
|
174
|
+
def delete(key)
|
175
|
+
@rules.delete(key)
|
157
176
|
end
|
158
177
|
|
159
|
-
def
|
160
|
-
|
178
|
+
def fetch(*args, &block)
|
179
|
+
@rules.fetch(*args, &block)
|
161
180
|
end
|
162
181
|
|
163
|
-
def
|
164
|
-
|
182
|
+
def [](key)
|
183
|
+
@rules[key]
|
165
184
|
end
|
166
185
|
|
167
|
-
def
|
168
|
-
|
186
|
+
def empty?
|
187
|
+
rules.empty?
|
169
188
|
end
|
170
189
|
|
171
|
-
def
|
172
|
-
@
|
190
|
+
def each_pair(&block)
|
191
|
+
@rules.each_pair(&block)
|
173
192
|
end
|
174
193
|
|
175
|
-
|
194
|
+
def description
|
195
|
+
rules.inspect.gsub(PROC_HEX_NUMBER, '').gsub(PROJECT_DIR, '.').gsub(' (lambda)','')
|
196
|
+
end
|
197
|
+
end
|
176
198
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
end
|
199
|
+
# @private
|
200
|
+
class InclusionRules < FilterRules
|
201
|
+
STANDALONE_FILTERS = [:locations, :full_description]
|
202
|
+
|
203
|
+
def add_location(locations)
|
204
|
+
replace_filters({ :locations => locations })
|
184
205
|
end
|
185
206
|
|
186
|
-
def
|
187
|
-
|
188
|
-
@exclusions.clear
|
207
|
+
def add(*args)
|
208
|
+
set_standalone_filter(*args) || super
|
189
209
|
end
|
190
210
|
|
191
|
-
def
|
192
|
-
|
211
|
+
def add_with_low_priority(*args)
|
212
|
+
set_standalone_filter(*args) || super
|
193
213
|
end
|
194
214
|
|
195
|
-
def
|
196
|
-
|
197
|
-
orig.replace(updates.last)
|
215
|
+
def use(*args)
|
216
|
+
set_standalone_filter(*args) || super
|
198
217
|
end
|
199
218
|
|
200
|
-
def
|
201
|
-
|
202
|
-
opposite.each_pair {|k,v| updated.delete(k) if updated[k] == v}
|
203
|
-
orig.replace(updated)
|
219
|
+
def include_example?(example)
|
220
|
+
@rules.empty? ? true : example.any_apply?(@rules)
|
204
221
|
end
|
205
222
|
|
206
|
-
def
|
207
|
-
is_standalone_filter?(
|
223
|
+
def standalone?
|
224
|
+
is_standalone_filter?(@rules)
|
208
225
|
end
|
209
226
|
|
210
|
-
|
211
|
-
|
227
|
+
private
|
228
|
+
|
229
|
+
def set_standalone_filter(updated)
|
230
|
+
return true if standalone?
|
231
|
+
|
232
|
+
if is_standalone_filter?(updated)
|
233
|
+
replace_filters(updated)
|
234
|
+
true
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def replace_filters(new_rules)
|
239
|
+
@rules.replace(new_rules)
|
240
|
+
opposite.clear
|
241
|
+
end
|
242
|
+
|
243
|
+
def is_standalone_filter?(rules)
|
244
|
+
STANDALONE_FILTERS.any? { |key| rules.has_key?(key) }
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
# @private
|
249
|
+
class ExclusionRules < FilterRules
|
250
|
+
CONDITIONAL_FILTERS = {
|
251
|
+
:if => lambda { |value| !value },
|
252
|
+
:unless => lambda { |value| value }
|
253
|
+
}.freeze
|
254
|
+
|
255
|
+
def include_example?(example)
|
256
|
+
example.any_apply?(@rules) || example.any_apply?(CONDITIONAL_FILTERS)
|
212
257
|
end
|
213
258
|
end
|
214
259
|
end
|
data/lib/rspec/core/flat_map.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'rspec/core/formatters/legacy_formatter'
|
2
|
-
|
3
1
|
# ## Built-in Formatters
|
4
2
|
#
|
5
3
|
# * progress (default) - prints dots for passing examples, `F` for failures, `*` for pending
|
@@ -56,8 +54,14 @@ module RSpec::Core::Formatters
|
|
56
54
|
autoload :DocumentationFormatter, 'rspec/core/formatters/documentation_formatter'
|
57
55
|
autoload :HtmlFormatter, 'rspec/core/formatters/html_formatter'
|
58
56
|
autoload :ProgressFormatter, 'rspec/core/formatters/progress_formatter'
|
57
|
+
autoload :ProfileFormatter, 'rspec/core/formatters/profile_formatter'
|
59
58
|
autoload :JsonFormatter, 'rspec/core/formatters/json_formatter'
|
60
59
|
|
60
|
+
# Register the formatter class
|
61
|
+
# @param formatter_class [Class] formatter class to register
|
62
|
+
# @param notifications [Symbol, ...] one or more notifications to be registered to the specified formatter
|
63
|
+
#
|
64
|
+
# @see RSpec::Core::Formatters::BaseFormatter
|
61
65
|
def self.register(formatter_class, *notifications)
|
62
66
|
Loader.formatters[formatter_class] = notifications
|
63
67
|
end
|
@@ -80,38 +84,66 @@ module RSpec::Core::Formatters
|
|
80
84
|
def initialize(reporter)
|
81
85
|
@formatters = []
|
82
86
|
@reporter = reporter
|
87
|
+
self.default_formatter = 'progress'
|
83
88
|
end
|
84
|
-
attr_reader :formatters, :reporter
|
85
89
|
|
86
|
-
# @
|
90
|
+
# @return [Array] the loaded formatters
|
91
|
+
attr_reader :formatters
|
92
|
+
|
93
|
+
# @return [Reporter] the reporter
|
94
|
+
attr_reader :reporter
|
95
|
+
|
96
|
+
# @return [String] the default formatter to setup, defaults to `progress`
|
97
|
+
attr_accessor :default_formatter
|
98
|
+
|
99
|
+
# @private
|
87
100
|
def setup_default(output_stream, deprecation_stream)
|
88
101
|
if @formatters.empty?
|
89
|
-
add
|
102
|
+
add default_formatter, output_stream
|
90
103
|
end
|
91
104
|
unless @formatters.any? { |formatter| DeprecationFormatter === formatter }
|
92
105
|
add DeprecationFormatter, deprecation_stream, output_stream
|
93
106
|
end
|
107
|
+
if RSpec.configuration.profile_examples? && !existing_formatter_implements?(:dump_profile)
|
108
|
+
add RSpec::Core::Formatters::ProfileFormatter, output_stream
|
109
|
+
end
|
94
110
|
end
|
95
111
|
|
96
|
-
# @
|
112
|
+
# @private
|
97
113
|
def add(formatter_to_use, *paths)
|
98
114
|
formatter_class = find_formatter(formatter_to_use)
|
99
115
|
|
100
|
-
args = paths.map { |p|
|
116
|
+
args = paths.map { |p| p.respond_to?(:puts) ? p : file_at(p) }
|
101
117
|
|
102
118
|
if !Loader.formatters[formatter_class].nil?
|
103
119
|
formatter = formatter_class.new(*args)
|
104
120
|
@reporter.register_listener formatter, *notifications_for(formatter_class)
|
105
|
-
|
106
|
-
formatter =
|
121
|
+
elsif defined?(RSpec::LegacyFormatters)
|
122
|
+
formatter = RSpec::LegacyFormatters.load_formatter formatter_class, *args
|
107
123
|
@reporter.register_listener formatter, *formatter.notifications
|
108
|
-
|
124
|
+
else
|
125
|
+
line = ::RSpec::CallerFilter.first_non_rspec_line
|
126
|
+
if line
|
127
|
+
call_site = "Formatter added at: #{line}"
|
128
|
+
else
|
129
|
+
call_site = "The formatter was added via command line flag or your "+
|
130
|
+
"`.rspec` file."
|
131
|
+
end
|
109
132
|
|
110
|
-
|
111
|
-
|
112
|
-
|
133
|
+
RSpec.warn_deprecation <<-WARNING.gsub(/\s*\|/,' ')
|
134
|
+
|The #{formatter_class} formatter uses the deprecated formatter
|
135
|
+
|interface not supported directly by RSpec 3.
|
136
|
+
|
|
137
|
+
|To continue to use this formatter you must install the
|
138
|
+
|`rspec-legacy_formatters` gem, which provides support
|
139
|
+
|for legacy formatters or upgrade the formatter to a
|
140
|
+
|compatible version.
|
141
|
+
|
|
142
|
+
|#{call_site}
|
143
|
+
WARNING
|
144
|
+
return
|
113
145
|
end
|
114
|
-
|
146
|
+
@formatters << formatter unless duplicate_formatter_exists?(formatter)
|
115
147
|
formatter
|
116
148
|
end
|
117
149
|
|
@@ -129,6 +161,10 @@ module RSpec::Core::Formatters
|
|
129
161
|
end
|
130
162
|
end
|
131
163
|
|
164
|
+
def existing_formatter_implements?(notification)
|
165
|
+
@reporter.registered_listeners(notification).any?
|
166
|
+
end
|
167
|
+
|
132
168
|
def built_in_formatter(key)
|
133
169
|
case key.to_s
|
134
170
|
when 'd', 'doc', 'documentation'
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
RSpec::Support.require_rspec_core "formatters/helpers"
|
2
2
|
require 'stringio'
|
3
3
|
|
4
4
|
module RSpec
|
@@ -14,22 +14,15 @@ module RSpec
|
|
14
14
|
class BaseFormatter
|
15
15
|
|
16
16
|
# all formatters inheriting from this formatter will receive these notifications
|
17
|
-
Formatters.register self, :start, :example_group_started, :
|
18
|
-
:example_pending, :example_failed, :close
|
19
|
-
include Helpers
|
17
|
+
Formatters.register self, :start, :example_group_started, :close
|
20
18
|
attr_accessor :example_group
|
21
|
-
attr_reader :
|
22
|
-
attr_reader :failed_examples, :pending_examples
|
19
|
+
attr_reader :output
|
23
20
|
|
24
21
|
# @api public
|
25
22
|
#
|
26
|
-
# @param output
|
23
|
+
# @param output [IO] the formatter output
|
27
24
|
def initialize(output)
|
28
25
|
@output = output || StringIO.new
|
29
|
-
@example_count = @pending_count = @failure_count = 0
|
30
|
-
@examples = []
|
31
|
-
@failed_examples = []
|
32
|
-
@pending_examples = []
|
33
26
|
@example_group = nil
|
34
27
|
end
|
35
28
|
|
@@ -42,7 +35,7 @@ module RSpec
|
|
42
35
|
# This will only be invoked once, and the next one to be invoked
|
43
36
|
# is {#example_group_started}.
|
44
37
|
#
|
45
|
-
# @param
|
38
|
+
# @param notification [StartNotification]
|
46
39
|
def start(notification)
|
47
40
|
start_sync_output
|
48
41
|
@example_count = notification.count
|
@@ -52,12 +45,10 @@ module RSpec
|
|
52
45
|
#
|
53
46
|
# This method is invoked at the beginning of the execution of each example group.
|
54
47
|
#
|
55
|
-
# @param example_group subclass of `RSpec::Core::ExampleGroup`
|
56
|
-
#
|
57
48
|
# The next method to be invoked after this is {#example_passed},
|
58
49
|
# {#example_pending}, or {#example_group_finished}.
|
59
50
|
#
|
60
|
-
# @param example_group
|
51
|
+
# @param notification [GroupNotification] containing example_group subclass of `RSpec::Core::ExampleGroup`
|
61
52
|
def example_group_started(notification)
|
62
53
|
@example_group = notification.group
|
63
54
|
end
|
@@ -67,56 +58,47 @@ module RSpec
|
|
67
58
|
#
|
68
59
|
# Invoked at the end of the execution of each example group.
|
69
60
|
#
|
70
|
-
# @param example_group subclass of `RSpec::Core::ExampleGroup`
|
61
|
+
# @param notification [GroupNotification] containing example_group subclass of `RSpec::Core::ExampleGroup`
|
71
62
|
|
63
|
+
# @method example_started
|
72
64
|
# @api public
|
73
65
|
#
|
74
66
|
# Invoked at the beginning of the execution of each example.
|
75
67
|
#
|
76
|
-
# @param
|
77
|
-
# @return [Array]
|
78
|
-
def example_started(notification)
|
79
|
-
examples << notification.example
|
80
|
-
end
|
68
|
+
# @param notification [ExampleNotification] containing example subclass of `RSpec::Core::Example`
|
81
69
|
|
82
70
|
# @method example_passed
|
83
71
|
# @api public
|
84
72
|
#
|
85
73
|
# Invoked when an example passes.
|
86
74
|
#
|
87
|
-
# @param
|
75
|
+
# @param notification [ExampleNotification] containing example subclass of `RSpec::Core::Example`
|
88
76
|
|
77
|
+
# @method example_pending
|
89
78
|
# Invoked when an example is pending.
|
90
79
|
#
|
91
|
-
# @param
|
92
|
-
# @return [Array]
|
93
|
-
def example_pending(notification)
|
94
|
-
@pending_examples << notification.example
|
95
|
-
end
|
80
|
+
# @param notification [ExampleNotification] containing example subclass of `RSpec::Core::Example`
|
96
81
|
|
82
|
+
# @method example_failed
|
97
83
|
# @api public
|
98
84
|
#
|
99
85
|
# Invoked when an example fails.
|
100
86
|
#
|
101
|
-
# @param
|
102
|
-
# @return [Array]
|
103
|
-
def example_failed(notification)
|
104
|
-
@failed_examples << notification.example
|
105
|
-
end
|
87
|
+
# @param notification [ExampleNotification] containing example subclass of `RSpec::Core::Example`
|
106
88
|
|
107
89
|
# @method message
|
108
90
|
# @api public
|
109
91
|
#
|
110
92
|
# Used by the reporter to send messages to the output stream.
|
111
93
|
#
|
112
|
-
# @param [
|
94
|
+
# @param notification [MessageNotification] containing message
|
113
95
|
|
114
96
|
# @method stop
|
115
97
|
# @api public
|
116
98
|
#
|
117
99
|
# Invoked after all examples have executed, before dumping post-run reports.
|
118
100
|
#
|
119
|
-
# @
|
101
|
+
# @param notification [NullNotification]
|
120
102
|
|
121
103
|
# @method start_dump
|
122
104
|
# @api public
|
@@ -125,14 +107,14 @@ module RSpec
|
|
125
107
|
# to be invoked after this one is {#dump_failures}
|
126
108
|
# (BaseTextFormatter then calls {#dump_failure} once for each failed example.)
|
127
109
|
#
|
128
|
-
# @
|
110
|
+
# @param notification [NullNotification]
|
129
111
|
|
130
112
|
# @method dump_failures
|
131
113
|
# @api public
|
132
114
|
#
|
133
115
|
# Dumps detailed information about each example failure.
|
134
116
|
#
|
135
|
-
# @
|
117
|
+
# @param notification [NullNotification]
|
136
118
|
|
137
119
|
# @method dump_summary
|
138
120
|
# @api public
|
@@ -140,73 +122,37 @@ module RSpec
|
|
140
122
|
# This method is invoked after the dumping of examples and failures. Each parameter
|
141
123
|
# is assigned to a corresponding attribute.
|
142
124
|
#
|
143
|
-
# @param duration
|
144
|
-
#
|
145
|
-
# @param failure_count
|
146
|
-
# @param pending_count
|
125
|
+
# @param summary [SummaryNotification] containing duration, example_count,
|
126
|
+
# failure_count and pending_count
|
147
127
|
|
148
|
-
# @method
|
128
|
+
# @method dump_profile
|
149
129
|
# @api public
|
150
130
|
#
|
151
|
-
#
|
152
|
-
#
|
131
|
+
# This method is invoked after the dumping the summary if profiling is
|
132
|
+
# enabled.
|
153
133
|
#
|
154
|
-
# @
|
134
|
+
# @param profile [ProfileNotification] containing duration, slowest_examples
|
135
|
+
# and slowest_example_groups
|
155
136
|
|
156
|
-
# @method
|
137
|
+
# @method dump_pending
|
157
138
|
# @api public
|
158
139
|
#
|
159
|
-
#
|
160
|
-
#
|
140
|
+
# Outputs a report of pending examples. This gets invoked
|
141
|
+
# after the summary if option is set to do so.
|
161
142
|
#
|
162
|
-
# @
|
143
|
+
# @param notification [NullNotification]
|
163
144
|
|
164
145
|
# @api public
|
165
146
|
#
|
166
147
|
# Invoked at the very end, `close` allows the formatter to clean
|
167
148
|
# up resources, e.g. open streams, etc.
|
149
|
+
#
|
150
|
+
# @param notification [NullNotification]
|
168
151
|
def close(notification)
|
169
152
|
restore_sync_output
|
170
153
|
end
|
171
154
|
|
172
|
-
|
173
|
-
#
|
174
|
-
# Formats the given backtrace based on configuration and
|
175
|
-
# the metadata of the given example.
|
176
|
-
def format_backtrace(backtrace, example)
|
177
|
-
configuration.backtrace_formatter.format_backtrace(backtrace, example.metadata)
|
178
|
-
end
|
179
|
-
|
180
|
-
protected
|
181
|
-
|
182
|
-
def configuration
|
183
|
-
RSpec.configuration
|
184
|
-
end
|
185
|
-
|
186
|
-
def read_failed_line(exception, example)
|
187
|
-
unless matching_line = find_failed_line(exception.backtrace, example.file_path)
|
188
|
-
return "Unable to find matching line from backtrace"
|
189
|
-
end
|
190
|
-
|
191
|
-
file_path, line_number = matching_line.match(/(.+?):(\d+)(|:\d+)/)[1..2]
|
192
|
-
|
193
|
-
if File.exist?(file_path)
|
194
|
-
File.readlines(file_path)[line_number.to_i - 1] ||
|
195
|
-
"Unable to find matching line in #{file_path}"
|
196
|
-
else
|
197
|
-
"Unable to find #{file_path} to read failed line"
|
198
|
-
end
|
199
|
-
rescue SecurityError
|
200
|
-
"Unable to read failed line"
|
201
|
-
end
|
202
|
-
|
203
|
-
def find_failed_line(backtrace, path)
|
204
|
-
path = File.expand_path(path)
|
205
|
-
backtrace.detect { |line|
|
206
|
-
match = line.match(/(.+?):(\d+)(|:\d+)/)
|
207
|
-
match && match[1].downcase == path.downcase
|
208
|
-
}
|
209
|
-
end
|
155
|
+
private
|
210
156
|
|
211
157
|
def start_sync_output
|
212
158
|
@old_sync, output.sync = output.sync, true if output_supports_sync
|
@@ -220,58 +166,6 @@ module RSpec
|
|
220
166
|
output.respond_to?(:sync=)
|
221
167
|
end
|
222
168
|
|
223
|
-
def profile_examples?
|
224
|
-
configuration.profile_examples
|
225
|
-
end
|
226
|
-
|
227
|
-
def fail_fast?
|
228
|
-
configuration.fail_fast
|
229
|
-
end
|
230
|
-
|
231
|
-
def color_enabled?
|
232
|
-
configuration.color_enabled?(output)
|
233
|
-
end
|
234
|
-
|
235
|
-
def mute_profile_output?(failure_count)
|
236
|
-
# Don't print out profiled info if there are failures and `--fail-fast` is used, it just clutters the output
|
237
|
-
!profile_examples? || (fail_fast? && failure_count != 0)
|
238
|
-
end
|
239
|
-
|
240
|
-
# @api private
|
241
|
-
def slowest_examples
|
242
|
-
number_of_examples = RSpec.configuration.profile_examples
|
243
|
-
sorted_examples = examples.sort_by {|example|
|
244
|
-
example.execution_result[:run_time] }.reverse.first(number_of_examples)
|
245
|
-
|
246
|
-
total, slows = [examples, sorted_examples].map do |exs|
|
247
|
-
exs.inject(0.0) {|i, e| i + e.execution_result[:run_time] }
|
248
|
-
end
|
249
|
-
{:examples => sorted_examples, :total => total, :slows => slows}
|
250
|
-
end
|
251
|
-
|
252
|
-
# @api private
|
253
|
-
def slowest_groups
|
254
|
-
number_of_examples = RSpec.configuration.profile_examples
|
255
|
-
example_groups = {}
|
256
|
-
|
257
|
-
examples.each do |example|
|
258
|
-
location = example.example_group.parent_groups.last.metadata[:example_group][:location]
|
259
|
-
|
260
|
-
example_groups[location] ||= Hash.new(0)
|
261
|
-
example_groups[location][:total_time] += example.execution_result[:run_time]
|
262
|
-
example_groups[location][:count] += 1
|
263
|
-
example_groups[location][:description] = example.example_group.top_level_description unless example_groups[location].has_key?(:description)
|
264
|
-
end
|
265
|
-
|
266
|
-
# stop if we've only one example group
|
267
|
-
return {} if example_groups.keys.length <= 1
|
268
|
-
|
269
|
-
example_groups.each_value do |hash|
|
270
|
-
hash[:average] = hash[:total_time].to_f / hash[:count]
|
271
|
-
end
|
272
|
-
|
273
|
-
example_groups.sort_by {|_, hash| -hash[:average]}.first(number_of_examples)
|
274
|
-
end
|
275
169
|
end
|
276
170
|
end
|
277
171
|
end
|