rspec-legacy_formatters 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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