rspec-legacy_formatters 1.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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +1 -0
  4. data/.gitignore +11 -0
  5. data/.rspec +2 -0
  6. data/.travis.yml +16 -0
  7. data/.yardopts +7 -0
  8. data/Changelog.md +3 -0
  9. data/Gemfile +30 -0
  10. data/License.txt +22 -0
  11. data/README.md +41 -0
  12. data/Rakefile +27 -0
  13. data/cucumber.yml +6 -0
  14. data/features/custom_formatter.feature +28 -0
  15. data/features/regression_tests_for_built_in_formatters.feature +86 -0
  16. data/features/regression_tests_for_custom_formatters.feature +94 -0
  17. data/features/step_definitions/additional_cli_steps.rb +4 -0
  18. data/features/support/env.rb +13 -0
  19. data/lib/rspec/legacy_formatters.rb +59 -0
  20. data/lib/rspec/legacy_formatters/adaptor.rb +230 -0
  21. data/lib/rspec/legacy_formatters/base_formatter.rb +248 -0
  22. data/lib/rspec/legacy_formatters/base_text_formatter.rb +330 -0
  23. data/lib/rspec/legacy_formatters/documentation_formatter.rb +69 -0
  24. data/lib/rspec/legacy_formatters/helpers.rb +108 -0
  25. data/lib/rspec/legacy_formatters/html_formatter.rb +157 -0
  26. data/lib/rspec/legacy_formatters/html_printer.rb +412 -0
  27. data/lib/rspec/legacy_formatters/json_formatter.rb +71 -0
  28. data/lib/rspec/legacy_formatters/progress_formatter.rb +31 -0
  29. data/lib/rspec/legacy_formatters/snippet_extractor.rb +92 -0
  30. data/lib/rspec/legacy_formatters/version.rb +9 -0
  31. data/maintenance-branch +1 -0
  32. data/rspec-legacy_formatters.gemspec +43 -0
  33. data/script/functions.sh +144 -0
  34. data/script/run_build +13 -0
  35. data/spec/rspec/legacy_formatters_spec.rb +184 -0
  36. data/spec/spec_helper.rb +7 -0
  37. data/spec/support/formatter_support.rb +83 -0
  38. data/spec/support/legacy_formatter_using_sub_classing_example.rb +87 -0
  39. data/spec/support/old_style_formatter_example.rb +69 -0
  40. metadata +243 -0
  41. metadata.gz.sig +2 -0
@@ -0,0 +1,330 @@
1
+ require 'rspec/legacy_formatters/base_formatter'
2
+ require 'set'
3
+
4
+ module RSpec
5
+ module Core
6
+ module Formatters
7
+ remove_const :BaseTextFormatter
8
+
9
+ # Base for all of RSpec's built-in formatters. See RSpec::Core::Formatters::BaseFormatter
10
+ # to learn more about all of the methods called by the reporter.
11
+ #
12
+ # @see RSpec::Core::Formatters::BaseFormatter
13
+ # @see RSpec::Core::Reporter
14
+ class BaseTextFormatter < BaseFormatter
15
+ def message(message)
16
+ output.puts message
17
+ end
18
+
19
+ def dump_failures
20
+ return if failed_examples.empty?
21
+ output.puts
22
+ output.puts "Failures:"
23
+ failed_examples.each_with_index do |example, index|
24
+ output.puts
25
+ pending_fixed?(example) ? dump_pending_fixed(example, index) : dump_failure(example, index)
26
+ dump_backtrace(example)
27
+ end
28
+ end
29
+
30
+ # @api public
31
+ #
32
+ # Colorizes the output red for failure, yellow for
33
+ # pending, and green otherwise.
34
+ #
35
+ # @param [String] string
36
+ def colorise_summary(summary)
37
+ if failure_count > 0
38
+ color(summary, RSpec.configuration.failure_color)
39
+ elsif pending_count > 0
40
+ color(summary, RSpec.configuration.pending_color)
41
+ else
42
+ color(summary, RSpec.configuration.success_color)
43
+ end
44
+ end
45
+
46
+ def dump_summary(duration, example_count, failure_count, pending_count)
47
+ super(duration, example_count, failure_count, pending_count)
48
+ dump_profile unless mute_profile_output?(failure_count)
49
+ output.puts "\nFinished in #{format_duration(duration)}\n"
50
+ output.puts colorise_summary(summary_line(example_count, failure_count, pending_count))
51
+ dump_commands_to_rerun_failed_examples
52
+ end
53
+
54
+ # @api public
55
+ #
56
+ # Outputs commands which can be used to re-run failed examples.
57
+ #
58
+ def dump_commands_to_rerun_failed_examples
59
+ return if failed_examples.empty?
60
+ output.puts
61
+ output.puts("Failed examples:")
62
+ output.puts
63
+
64
+ failed_examples.each do |example|
65
+ output.puts(failure_color("rspec #{RSpec::Core::Metadata::relative_path(example.location)}") + " " + detail_color("# #{example.full_description}"))
66
+ end
67
+ end
68
+
69
+ # @api public
70
+ #
71
+ # Outputs the slowest examples and example groups in a report when using `--profile COUNT` (default 10).
72
+ #
73
+ def dump_profile
74
+ dump_profile_slowest_examples
75
+ dump_profile_slowest_example_groups
76
+ end
77
+
78
+ def dump_profile_slowest_examples
79
+ number_of_examples = RSpec.configuration.profile_examples
80
+ sorted_examples = examples.sort_by {|example|
81
+ example.execution_result.run_time }.reverse.first(number_of_examples)
82
+
83
+ total, slows = [examples, sorted_examples].map {|exs|
84
+ exs.inject(0.0) {|i, e| i + e.execution_result.run_time }}
85
+
86
+ time_taken = slows / total
87
+ percentage = '%.1f' % ((time_taken.nan? ? 0.0 : time_taken) * 100)
88
+
89
+ output.puts "\nTop #{sorted_examples.size} slowest examples (#{format_seconds(slows)} seconds, #{percentage}% of total time):\n"
90
+
91
+ sorted_examples.each do |example|
92
+ output.puts " #{example.full_description}"
93
+ output.puts detail_color(" #{failure_color(format_seconds(example.execution_result.run_time))} #{failure_color("seconds")} #{format_caller(example.location)}")
94
+ end
95
+ end
96
+
97
+ def dump_profile_slowest_example_groups
98
+ number_of_examples = RSpec.configuration.profile_examples
99
+ example_groups = {}
100
+
101
+ examples.each do |example|
102
+ location = example.example_group.parent_groups.last.metadata[:location]
103
+
104
+ example_groups[location] ||= Hash.new(0)
105
+ example_groups[location][:total_time] += example.execution_result.run_time
106
+ example_groups[location][:count] += 1
107
+ example_groups[location][:description] = example.example_group.top_level_description unless example_groups[location].has_key?(:description)
108
+ end
109
+
110
+ # stop if we've only one example group
111
+ return if example_groups.keys.length <= 1
112
+
113
+ example_groups.each do |loc, hash|
114
+ hash[:average] = hash[:total_time].to_f / hash[:count]
115
+ end
116
+
117
+ sorted_groups = example_groups.sort_by {|_, hash| -hash[:average]}.first(number_of_examples)
118
+
119
+ output.puts "\nTop #{sorted_groups.size} slowest example groups:"
120
+ sorted_groups.each do |loc, hash|
121
+ average = "#{failure_color(format_seconds(hash[:average]))} #{failure_color("seconds")} average"
122
+ total = "#{format_seconds(hash[:total_time])} seconds"
123
+ count = pluralize(hash[:count], "example")
124
+ output.puts " #{hash[:description]}"
125
+ output.puts detail_color(" #{average} (#{total} / #{count}) #{loc}")
126
+ end
127
+ end
128
+
129
+ # @api public
130
+ #
131
+ # Outputs summary with number of examples, failures and pending.
132
+ #
133
+ def summary_line(example_count, failure_count, pending_count)
134
+ summary = pluralize(example_count, "example")
135
+ summary << ", " << pluralize(failure_count, "failure")
136
+ summary << ", #{pending_count} pending" if pending_count > 0
137
+ summary
138
+ end
139
+
140
+ def dump_pending
141
+ unless pending_examples.empty?
142
+ output.puts
143
+ output.puts "Pending:"
144
+ pending_examples.each do |pending_example|
145
+ output.puts pending_color(" #{pending_example.full_description}")
146
+ output.puts detail_color(" # #{pending_example.execution_result.pending_message}")
147
+ output.puts detail_color(" # #{format_caller(pending_example.location)}")
148
+ if pending_example.execution_result.exception \
149
+ && RSpec.configuration.show_failures_in_pending_blocks?
150
+ dump_failure_info(pending_example)
151
+ dump_backtrace(pending_example)
152
+ end
153
+ end
154
+ end
155
+ end
156
+
157
+ def seed(number)
158
+ output.puts
159
+ output.puts "Randomized with seed #{number}"
160
+ output.puts
161
+ end
162
+
163
+ def close
164
+ output.close if IO === output && output != $stdout
165
+ end
166
+
167
+ VT100_COLORS = {
168
+ :black => 30,
169
+ :red => 31,
170
+ :green => 32,
171
+ :yellow => 33,
172
+ :blue => 34,
173
+ :magenta => 35,
174
+ :cyan => 36,
175
+ :white => 37
176
+ }
177
+
178
+ VT100_COLOR_CODES = VT100_COLORS.values.to_set
179
+
180
+ def color_code_for(code_or_symbol)
181
+ if VT100_COLOR_CODES.include?(code_or_symbol)
182
+ code_or_symbol
183
+ else
184
+ VT100_COLORS.fetch(code_or_symbol) do
185
+ color_code_for(:white)
186
+ end
187
+ end
188
+ end
189
+
190
+ def colorize(text, code_or_symbol)
191
+ "\e[#{color_code_for(code_or_symbol)}m#{text}\e[0m"
192
+ end
193
+
194
+ protected
195
+
196
+ def bold(text)
197
+ color_enabled? ? "\e[1m#{text}\e[0m" : text
198
+ end
199
+
200
+ def color(text, color_code)
201
+ color_enabled? ? colorize(text, color_code) : text
202
+ end
203
+
204
+ def failure_color(text)
205
+ color(text, RSpec.configuration.failure_color)
206
+ end
207
+
208
+ def success_color(text)
209
+ color(text, RSpec.configuration.success_color)
210
+ end
211
+
212
+ def pending_color(text)
213
+ color(text, RSpec.configuration.pending_color)
214
+ end
215
+
216
+ def fixed_color(text)
217
+ color(text, RSpec.configuration.fixed_color)
218
+ end
219
+
220
+ def detail_color(text)
221
+ color(text, RSpec.configuration.detail_color)
222
+ end
223
+
224
+ def default_color(text)
225
+ color(text, RSpec.configuration.default_color)
226
+ end
227
+
228
+ def red(text)
229
+ RSpec.deprecate("RSpec::Core::Formatters::BaseTextFormatter#red", :replacement => "#failure_color")
230
+ color(text, :red)
231
+ end
232
+
233
+ def green(text)
234
+ RSpec.deprecate("RSpec::Core::Formatters::BaseTextFormatter#green", :replacement => "#success_color")
235
+ color(text, :green)
236
+ end
237
+
238
+ def yellow(text)
239
+ RSpec.deprecate("RSpec::Core::Formatters::BaseTextFormatter#yellow", :replacement => "#pending_color")
240
+ color(text, :yellow)
241
+ end
242
+
243
+ def blue(text)
244
+ RSpec.deprecate("RSpec::Core::Formatters::BaseTextFormatter#blue", :replacement => "#fixed_color")
245
+ color(text, :blue)
246
+ end
247
+
248
+ def magenta(text)
249
+ RSpec.deprecate("RSpec::Core::Formatters::BaseTextFormatter#magenta")
250
+ color(text, :magenta)
251
+ end
252
+
253
+ def cyan(text)
254
+ RSpec.deprecate("RSpec::Core::Formatters::BaseTextFormatter#cyan", :replacement => "#detail_color")
255
+ color(text, :cyan)
256
+ end
257
+
258
+ def white(text)
259
+ RSpec.deprecate("RSpec::Core::Formatters::BaseTextFormatter#white", :replacement => "#default_color")
260
+ color(text, :white)
261
+ end
262
+
263
+ def short_padding
264
+ ' '
265
+ end
266
+
267
+ def long_padding
268
+ ' '
269
+ end
270
+
271
+ private
272
+
273
+ def format_caller(caller_info)
274
+ backtrace_line(caller_info.to_s.split(':in `block').first)
275
+ end
276
+
277
+ def dump_backtrace(example)
278
+ format_backtrace(example.execution_result.exception.backtrace, example).each do |backtrace_info|
279
+ output.puts detail_color("#{long_padding}# #{backtrace_info}")
280
+ end
281
+ end
282
+
283
+ def dump_pending_fixed(example, index)
284
+ output.puts "#{short_padding}#{index.next}) #{example.full_description} FIXED"
285
+ output.puts fixed_color("#{long_padding}Expected pending '#{example.execution_result.pending_message}' to fail. No Error was raised.")
286
+ end
287
+
288
+ def pending_fixed?(example)
289
+ example.execution_result.pending_fixed?
290
+ end
291
+
292
+ def dump_failure(example, index)
293
+ output.puts "#{short_padding}#{index.next}) #{example.full_description}"
294
+ dump_failure_info(example)
295
+ end
296
+
297
+ def dump_failure_info(example)
298
+ exception = example.execution_result.exception
299
+ exception_class_name = exception_class_name_for(exception)
300
+ output.puts "#{long_padding}#{failure_color("Failure/Error:")} #{failure_color(read_failed_line(exception, example).strip)}"
301
+ output.puts "#{long_padding}#{failure_color(exception_class_name)}:" unless exception_class_name =~ /RSpec/
302
+ exception.message.to_s.split("\n").each { |line| output.puts "#{long_padding} #{failure_color(line)}" } if exception.message
303
+
304
+ if shared_group = find_shared_group(example)
305
+ dump_shared_failure_info(shared_group)
306
+ end
307
+ end
308
+
309
+ def exception_class_name_for(exception)
310
+ name = exception.class.name.to_s
311
+ name ="(anonymous error class)" if name == ''
312
+ name
313
+ end
314
+
315
+ def dump_shared_failure_info(group)
316
+ output.puts "#{long_padding}Shared Example Group: \"#{group.metadata[:shared_group_name]}\" called from " +
317
+ "#{backtrace_line(group.metadata[:location])}"
318
+ end
319
+
320
+ def find_shared_group(example)
321
+ group_and_parent_groups(example).find {|group| group.metadata[:shared_group_name]}
322
+ end
323
+
324
+ def group_and_parent_groups(example)
325
+ example.example_group.parent_groups + [example.example_group]
326
+ end
327
+ end
328
+ end
329
+ end
330
+ end
@@ -0,0 +1,69 @@
1
+ require 'rspec/legacy_formatters/base_text_formatter'
2
+
3
+ module RSpec
4
+ module Core
5
+ module Formatters
6
+ remove_const :DocumentationFormatter
7
+
8
+ class DocumentationFormatter < BaseTextFormatter
9
+ def initialize(output)
10
+ super(output)
11
+ @group_level = 0
12
+ end
13
+
14
+ def example_group_started(example_group)
15
+ super(example_group)
16
+
17
+ output.puts if @group_level == 0
18
+ output.puts "#{current_indentation}#{example_group.description.strip}"
19
+
20
+ @group_level += 1
21
+ end
22
+
23
+ def example_group_finished(example_group)
24
+ @group_level -= 1
25
+ end
26
+
27
+ def example_passed(example)
28
+ super(example)
29
+ output.puts passed_output(example)
30
+ end
31
+
32
+ def example_pending(example)
33
+ super(example)
34
+ output.puts pending_output(example, example.execution_result.pending_message)
35
+ end
36
+
37
+ def example_failed(example)
38
+ super(example)
39
+ output.puts failure_output(example, example.execution_result.exception)
40
+ end
41
+
42
+ def failure_output(example, exception)
43
+ failure_color("#{current_indentation}#{example.description.strip} (FAILED - #{next_failure_index})")
44
+ end
45
+
46
+ def next_failure_index
47
+ @next_failure_index ||= 0
48
+ @next_failure_index += 1
49
+ end
50
+
51
+ def passed_output(example)
52
+ success_color("#{current_indentation}#{example.description.strip}")
53
+ end
54
+
55
+ def pending_output(example, message)
56
+ pending_color("#{current_indentation}#{example.description.strip} (PENDING: #{message})")
57
+ end
58
+
59
+ def current_indentation
60
+ ' ' * @group_level
61
+ end
62
+
63
+ def example_group_chain
64
+ example_group.parent_groups.reverse
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,108 @@
1
+ module RSpec
2
+ module Core
3
+ module LegacyBacktraceFormatter
4
+ extend self
5
+
6
+ def format_backtrace(backtrace, options = {})
7
+ return "" unless backtrace
8
+ return backtrace if options[:full_backtrace] == true
9
+
10
+ cleansed = backtrace.map { |line| backtrace_line(line) }.compact
11
+ cleansed.empty? ? backtrace : cleansed
12
+ end
13
+
14
+ protected
15
+
16
+ def backtrace_line(line)
17
+ return nil if RSpec.configuration.backtrace_formatter.exclude?(line)
18
+ RSpec::Core::Metadata::relative_path(line)
19
+ rescue SecurityError
20
+ nil
21
+ end
22
+ end
23
+
24
+ module Formatters
25
+ module Helpers
26
+ include LegacyBacktraceFormatter
27
+
28
+ remove_const :SUB_SECOND_PRECISION
29
+ remove_const :DEFAULT_PRECISION
30
+ SUB_SECOND_PRECISION = 5
31
+ DEFAULT_PRECISION = 2
32
+
33
+ # @api private
34
+ #
35
+ # Formats seconds into a human-readable string.
36
+ #
37
+ # @param [Float, Fixnum] duration in seconds
38
+ # @return [String] human-readable time
39
+ #
40
+ # @example
41
+ # format_duration(1) #=> "1 minute 1 second"
42
+ # format_duration(135.14) #=> "2 minutes 15.14 seconds"
43
+ def format_duration(duration)
44
+ precision = case
45
+ when duration < 1; SUB_SECOND_PRECISION
46
+ when duration < 120; DEFAULT_PRECISION
47
+ when duration < 300; 1
48
+ else 0
49
+ end
50
+
51
+ if duration > 60
52
+ minutes = (duration.to_i / 60).to_i
53
+ seconds = duration - minutes * 60
54
+
55
+ "#{pluralize(minutes, 'minute')} #{pluralize(format_seconds(seconds, precision), 'second')}"
56
+ else
57
+ pluralize(format_seconds(duration, precision), 'second')
58
+ end
59
+ end
60
+
61
+ # @api private
62
+ #
63
+ # Formats seconds to have 5 digits of precision with trailing zeros removed if the number
64
+ # is less than 1 or with 2 digits of precision if the number is greater than zero.
65
+ #
66
+ # @param [Float] float
67
+ # @return [String] formatted float
68
+ #
69
+ # @example
70
+ # format_seconds(0.000006) #=> "0.00001"
71
+ # format_seconds(0.020000) #=> "0.02"
72
+ # format_seconds(1.00000000001) #=> "1"
73
+ #
74
+ # The precision used is set in {Helpers::SUB_SECOND_PRECISION} and {Helpers::DEFAULT_PRECISION}.
75
+ #
76
+ # @see #strip_trailing_zeroes
77
+ def format_seconds(float, precision = nil)
78
+ precision ||= (float < 1) ? SUB_SECOND_PRECISION : DEFAULT_PRECISION
79
+ formatted = sprintf("%.#{precision}f", float)
80
+ strip_trailing_zeroes(formatted)
81
+ end
82
+
83
+ # @api private
84
+ #
85
+ # Remove trailing zeros from a string.
86
+ #
87
+ # @param [String] string string with trailing zeros
88
+ # @return [String] string with trailing zeros removed
89
+ def strip_trailing_zeroes(string)
90
+ stripped = string.sub(/[^1-9]+$/, '')
91
+ stripped.empty? ? "0" : stripped
92
+ end
93
+
94
+ # @api private
95
+ #
96
+ # Pluralize a word based on a count.
97
+ #
98
+ # @param [Fixnum] count number of objects
99
+ # @param [String] string word to be pluralized
100
+ # @return [String] pluralized word
101
+ def pluralize(count, string)
102
+ "#{count} #{string}#{'s' unless count.to_f == 1}"
103
+ end
104
+ end
105
+
106
+ end
107
+ end
108
+ end