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