Class: RSpec::TAP::Formatters::Printer

Inherits:
Object
  • Object
show all
Defined in:
lib/rspec/tap/formatters/printer.rb

Overview

TAP report printer

Constant Summary collapse

EXAMPLE_PROGRESS =

Example status progress report characters

{
  success: '.',
  failure: 'F',
  pending: '*'
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(output) ⇒ Printer

Constructor

Parameters:

  • output (StringIO, File) —

    output stream



22
23
24
25
26
27
28
29
30
31
32
# File 'lib/rspec/tap/formatters/printer.rb', line 22

def initialize(output)
  @output = output
  @write_to_file = output.is_a?(File)
  @display_colors = !@write_to_file
  @force_colors = false

  @bailed_out = false

  @failed_examples = ''
  @pending_examples = ''
end

Instance Method Details

#bailed_out_message_output(notification) (private)

Prints failure reason outside of example. It is the only bail out scenario.

Parameters:

  • notification (ExampleNotification) —

    example notification



322
323
324
325
326
327
328
329
330
331
332
333
334
# File 'lib/rspec/tap/formatters/printer.rb', line 322

def bailed_out_message_output(notification)
  bailed_out_report_output

  uncolorize_lines(notification.message.split("\n")).each do |line|
    next if line.blank?

    if line.start_with?('#')
      @output.puts("# #{line.chars.drop(1).join.strip}")
    else
      @output.puts("# #{line}")
    end
  end
end

#bailed_out_report_output (private)

Prints required TAP lines for bailed out scenario.



337
338
339
340
341
# File 'lib/rspec/tap/formatters/printer.rb', line 337

def bailed_out_report_output
  @output.puts('TAP version 13')
  @output.puts('1..0')
  @output.puts('Bail out!')
end

#colored_line(line, status) ⇒ String (private)

Converts string to colored string.

Parameters:

  • line (String) —

    line to print

  • status (Symbol) —

    status for color (:detail, :success, :failure, and :pending)

Returns:



401
402
403
404
405
406
407
# File 'lib/rspec/tap/formatters/printer.rb', line 401

def colored_line(line, status)
  if @force_colors || @display_colors
    RSpec::Core::Formatters::ConsoleCodes.wrap(line, status)
  else
    line
  end
end

#dump_failed_examples_summary (private)

Prints failed examples list. It is not included in the TAP report.



377
378
379
380
381
382
383
# File 'lib/rspec/tap/formatters/printer.rb', line 377

def dump_failed_examples_summary
  if @write_to_file
    $stdout.puts(@failed_examples)
  else
    @output.puts(@failed_examples)
  end
end

#dump_pending_examples_summary (private)

Prints pending examples list. It is not included in the TAP report.



387
388
389
390
391
392
393
# File 'lib/rspec/tap/formatters/printer.rb', line 387

def dump_pending_examples_summary
  if @write_to_file
    $stdout.puts(@pending_examples)
  else
    @output.puts(@pending_examples)
  end
end

#example_progress_dump

Handler for formatter start_dump notification.



85
86
87
# File 'lib/rspec/tap/formatters/printer.rb', line 85

def example_progress_dump
  $stdout.puts if @write_to_file
end

#example_progress_output(status)

Prints example progress when writing to a file. . for passing, F for failing, and * for pending example.

Parameters:

  • status (Symbol) —

    example status



74
75
76
77
78
79
80
81
82
# File 'lib/rspec/tap/formatters/printer.rb', line 74

def example_progress_output(status)
  return unless @write_to_file

  @force_colors = RSpec.configuration.color_enabled?

  $stdout.print(colored_line(EXAMPLE_PROGRESS[status], status))

  @force_colors = false
end

#execution_stats_output(notification) (private)

Prints example stats and duration for the entire execution.

Parameters:

  • notification (ExampleNotification) —

    example notification



346
347
348
349
350
351
352
353
354
355
356
357
358
# File 'lib/rspec/tap/formatters/printer.rb', line 346

def execution_stats_output(notification)
  test_stats = [
    notification.examples.size,
    0,
    notification.failed_examples.size,
    notification.pending_examples.size
  ]
  test_stats[1] = test_stats[0] - test_stats.drop(1).reduce(:+)

  stats_output(test_stats, 0)

  @output.puts("# duration: #{notification.duration} seconds")
end

#failure_backtrace(notification) ⇒ String (private)

Provides failure backtrace.

Parameters:

  • notification (ExampleNotification) —

    example notification

Returns:

  • (String) —

    failure backtrace



255
256
257
258
259
260
261
262
263
264
# File 'lib/rspec/tap/formatters/printer.rb', line 255

def failure_backtrace(notification)
  formatted_backtrace = notification.formatted_backtrace

  return if formatted_backtrace.empty?

  uncolorize_lines(formatted_backtrace)
    .reject(&:blank?)
    .first(10)
    .join("\n")
end

#failure_diagnostics_output(reason, padding) (private)

Prints failure error YAML block.

Parameters:

  • reason (Hash<String, String>) —

    failure reason hash for location, error, and backtrace

  • padding (Integer) —

    indentation width



295
296
297
298
299
300
301
# File 'lib/rspec/tap/formatters/printer.rb', line 295

def failure_diagnostics_output(reason, padding)
  Psych.dump(reason).lines.each do |line|
    @output.print("#{indentation(padding)}#{line}")
  end

  @output.puts("#{indentation(padding)}...")
end

#failure_error(notification) ⇒ String (private)

Provides failure error.

Parameters:

  • notification (ExampleNotification) —

    example notification

Returns:



241
242
243
244
245
246
247
248
249
# File 'lib/rspec/tap/formatters/printer.rb', line 241

def failure_error(notification)
  message_lines = notification.message_lines

  return if message_lines.empty?

  uncolorize_lines(message_lines)
    .reject(&:blank?)
    .join("\n")
end

#failure_error_and_backtrace(notification) ⇒ Hash<Symbol, String> (private)

Provides failure error and backtrace.

Parameters:

  • notification (ExampleNotification) —

    example notification

Returns:

  • (Hash<Symbol, String>) —

    error and backtrace for the YAML block



230
231
232
233
234
235
# File 'lib/rspec/tap/formatters/printer.rb', line 230

def failure_error_and_backtrace(notification)
  {
    error: failure_error(notification),
    backtrace: failure_backtrace(notification)
  }.compact
end

#failure_output(description, example_number, padding)

Handler for formatter example_failed notification.

Parameters:

  • description (String) —

    example description

  • example_number (Integer) —

    example number

  • padding (Integer) —

    indentation width



106
107
108
109
110
111
# File 'lib/rspec/tap/formatters/printer.rb', line 106

def failure_output(description, example_number, padding)
  line = "not ok #{example_number} - #{description}"
  line = colored_line("#{indentation(padding)}#{line}", :failure)

  @output.puts(line)
end

#failure_reason_for_and_post_3_3_0(notification) ⇒ Hash<Symbol, String> (private)

Provides failure reason for RSpec version after 3.3.0.

Parameters:

  • notification (ExampleNotification) —

    example notification

Returns:

  • (Hash<Symbol, String>) —

    error and backtrace for the YAML block



216
217
218
219
220
221
222
223
# File 'lib/rspec/tap/formatters/printer.rb', line 216

def failure_reason_for_and_post_3_3_0(notification)
  case notification.example.execution_result.exception
  when RSpec::Expectations::MultipleExpectationsNotMetError
    multiple_failures_error_and_backtrace(notification)
  else
    failure_error_and_backtrace(notification)
  end
end

#failure_reason_output(notification, padding)

Prints failure reason YAML block The aggregate failures are not reported for RSpec version before 3.3.0.

Parameters:

  • notification (ExampleNotification) —

    example notification

  • padding (Integer) —

    indentation width



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/rspec/tap/formatters/printer.rb', line 119

def failure_reason_output(notification, padding)
  rspec_version = Gem::Version.new(RSpec::Core::Version::STRING)
  reason =
    if rspec_version >= Gem::Version.new('3.3.0')
      failure_reason_for_and_post_3_3_0(notification)
    else
      failure_reason_pre_3_3_0(notification)
    end

  return if reason.empty?

  failure_diagnostics_output(
    {
      location: notification.example.[:location]
    }.merge(reason).stringify_keys,
    padding
  )
end

#failure_reason_pre_3_3_0(notification) ⇒ Hash<Symbol, String> (private)

Provides failure reason for RSpec version before 3.3.0.

Parameters:

  • notification (ExampleNotification) —

    example notification

Returns:

  • (Hash<Symbol, String>) —

    error and backtrace for the YAML block



207
208
209
# File 'lib/rspec/tap/formatters/printer.rb', line 207

def failure_reason_pre_3_3_0(notification)
  failure_error_and_backtrace(notification)
end

#group_finished_output(test_stats, padding)

Handler for formatter example_group_finished notification.

Parameters:

  • test_stats (Array<Integer>) —

    stats for the example group

  • padding (Integer) —

    indentation width

See Also:



64
65
66
67
68
# File 'lib/rspec/tap/formatters/printer.rb', line 64

def group_finished_output(test_stats, padding)
  @output.puts("#{indentation(padding)}1..#{test_stats[0]}")
  stats_output(test_stats, padding)
  @output.puts(colored_line("#{indentation(padding - 1)}}", :detail))
end

#group_start_output(notification, padding)

Handler for formatter example_group_started notification.

Parameters:

  • notification (ExampleNotification) —

    example notification

  • padding (Integer) —

    indentation width



45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/rspec/tap/formatters/printer.rb', line 45

def group_start_output(notification, padding)
  description = notification.group.description.strip

  line =
    if padding.zero?
      "#{indentation(padding)}# test: #{description} {"
    else
      "#{indentation(padding)}# group: #{description} {"
    end

  @output.puts(colored_line(line, :detail))
end

#indentation(padding) ⇒ String (private)

Computes the indentation width by padding. The default indentation width is 2.

Parameters:

  • padding (Integer) —

    indentation width

Returns:

  • (String) —

    string of whitespaces



437
438
439
440
441
# File 'lib/rspec/tap/formatters/printer.rb', line 437

def indentation(padding)
  return unless padding.positive?

  '  ' * padding
end

#message_output(notification)

Handler for formatter message notification.

Parameters:

  • notification (ExampleNotification) —

    example notification



154
155
156
157
158
159
160
161
# File 'lib/rspec/tap/formatters/printer.rb', line 154

def message_output(notification)
  return if @bailed_out
  return unless RSpec.world.non_example_failure

  bailed_out_message_output(notification)

  @bailed_out = true
end

#multiple_failures_error(notification) ⇒ String (private)

Provides aggregate failure error.

Parameters:

  • notification (ExampleNotification) —

    example notification

Returns:

  • (String) —

    aggregate failure error



280
281
282
283
284
285
286
287
288
# File 'lib/rspec/tap/formatters/printer.rb', line 280

def multiple_failures_error(notification)
  message = notification.example.execution_result.exception.message

  return if message.blank?

  uncolorize_lines(message.split("\n"))
    .reject(&:blank?)
    .join("\n")
end

#multiple_failures_error_and_backtrace(notification) ⇒ Hash<Symbol, String> (private)

Provides aggregate failure error.

Parameters:

  • notification (ExampleNotification) —

    example notification

Returns:

  • (Hash<Symbol, String>) —

    error for the YAML block



270
271
272
273
274
# File 'lib/rspec/tap/formatters/printer.rb', line 270

def multiple_failures_error_and_backtrace(notification)
  {
    error: multiple_failures_error(notification)
  }.compact
end

#pending_example_directive(notification) ⇒ String (private)

Finds the directive for pending example.

Parameters:

  • notification (ExampleNotification) —

    example notification

Returns:

  • (String) —

    directive SKIP or TODO



307
308
309
310
311
312
313
314
315
316
# File 'lib/rspec/tap/formatters/printer.rb', line 307

def pending_example_directive(notification)
  execution_result = notification.example.execution_result
  could_be_skipped = execution_result.respond_to?(:example_skipped?)

  if could_be_skipped && execution_result.example_skipped?
    "SKIP: #{execution_result.pending_message}"
  else
    "TODO: #{execution_result.pending_message}"
  end
end

#pending_output(notification, description, example_number, padding)

Handler for formatter example_pending notification.

Parameters:

  • description (String) —

    example description

  • example_number (Integer) —

    example number

  • padding (Integer) —

    indentation width



143
144
145
146
147
148
149
# File 'lib/rspec/tap/formatters/printer.rb', line 143

def pending_output(notification, description, example_number, padding)
  directive = pending_example_directive(notification)
  line = "ok #{example_number} - #{description} # #{directive}"
  line = colored_line("#{indentation(padding)}#{line}", :pending)

  @output.puts(line)
end

#start_output

Handler for formatter start notification.



35
36
37
38
39
# File 'lib/rspec/tap/formatters/printer.rb', line 35

def start_output
  return if @bailed_out

  @output.puts('TAP version 13')
end

#stats_output(test_stats, padding) (private)

Prints example stats.

Parameters:

  • test_stats (Array<Integer>) —

    stats for the example group

  • padding (Integer) —

    indentation width



364
365
366
367
368
369
370
371
372
373
# File 'lib/rspec/tap/formatters/printer.rb', line 364

def stats_output(test_stats, padding)
  stats = %i[tests passed failed pending]
    .zip(test_stats)
    .to_h
    .reject { |_, value| value.zero? }
    .map { |key, value| "#{key}: #{value}" }
    .join(', ')

  @output.puts("#{indentation(padding)}# #{stats}")
end

#store_failed_examples_summary(notification)

Handler for formatter dump_failures notification.

Parameters:

  • notification (ExampleNotification) —

    example notification



166
167
168
169
170
# File 'lib/rspec/tap/formatters/printer.rb', line 166

def store_failed_examples_summary(notification)
  return if notification.failure_notifications.empty?

  @failed_examples = notification.fully_formatted_failed_examples
end

#store_pending_examples_summary(notification)

Handler for formatter dump_pending notification.

Parameters:

  • notification (ExampleNotification) —

    example notification



175
176
177
178
179
# File 'lib/rspec/tap/formatters/printer.rb', line 175

def store_pending_examples_summary(notification)
  return if notification.pending_examples.empty?

  @pending_examples = notification.fully_formatted_pending_examples
end

#success_output(description, example_number, padding)

Handler for formatter example_passed notification.

Parameters:

  • description (String) —

    example description

  • example_number (Integer) —

    example number

  • padding (Integer) —

    indentation width



94
95
96
97
98
99
# File 'lib/rspec/tap/formatters/printer.rb', line 94

def success_output(description, example_number, padding)
  line = "ok #{example_number} - #{description}"
  line = colored_line("#{indentation(padding)}#{line}", :success)

  @output.puts(line)
end

#summary_output(notification, seed)

Handler for formatter dump_summary notification.

Parameters:

  • notification (ExampleNotification) —

    example notification

  • seed (Integer) —

    used seed



185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/rspec/tap/formatters/printer.rb', line 185

def summary_output(notification, seed)
  return if @bailed_out

  @output.puts("1..#{notification.examples.size}")

  return if notification.examples.size.zero?

  execution_stats_output(notification)

  @output.puts("# seed: #{seed}") if seed

  dump_failed_examples_summary if @failed_examples.present?
  dump_pending_examples_summary if @pending_examples.present?
end

#uncolorize_line(line) ⇒ String (private)

Converts string to uncolored line. It strips ANSI escape sequences \033[XXXm.

Examples:

uncolorize_line('\033[0;31mcolored line\033[0m')
#=> 'colored line'

Parameters:

  • line (String) —

    line to print

Returns:



426
427
428
429
430
# File 'lib/rspec/tap/formatters/printer.rb', line 426

def uncolorize_line(line)
  return line if line.blank?

  line.gsub(/\e\[(\d+)(;\d+)*m/, '')
end

#uncolorize_lines(lines) ⇒ Array<String> (private)

Converts array of colored strings to uncolored string

Parameters:

  • lines (Array<String>) —

    lines to uncolor

Returns:

  • (Array<String>) —

    uncolored lines



413
414
415
# File 'lib/rspec/tap/formatters/printer.rb', line 413

def uncolorize_lines(lines)
  lines.map { |line| uncolorize_line(line) }
end