rspec-core 3.0.4 → 3.12.2

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 (85) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.document +1 -1
  4. data/.yardopts +2 -1
  5. data/Changelog.md +888 -2
  6. data/{License.txt → LICENSE.md} +6 -5
  7. data/README.md +165 -24
  8. data/lib/rspec/autorun.rb +1 -0
  9. data/lib/rspec/core/backtrace_formatter.rb +19 -20
  10. data/lib/rspec/core/bisect/coordinator.rb +62 -0
  11. data/lib/rspec/core/bisect/example_minimizer.rb +173 -0
  12. data/lib/rspec/core/bisect/fork_runner.rb +138 -0
  13. data/lib/rspec/core/bisect/server.rb +61 -0
  14. data/lib/rspec/core/bisect/shell_command.rb +126 -0
  15. data/lib/rspec/core/bisect/shell_runner.rb +73 -0
  16. data/lib/rspec/core/bisect/utilities.rb +69 -0
  17. data/lib/rspec/core/configuration.rb +1287 -246
  18. data/lib/rspec/core/configuration_options.rb +95 -35
  19. data/lib/rspec/core/did_you_mean.rb +46 -0
  20. data/lib/rspec/core/drb.rb +21 -12
  21. data/lib/rspec/core/dsl.rb +10 -6
  22. data/lib/rspec/core/example.rb +305 -113
  23. data/lib/rspec/core/example_group.rb +431 -223
  24. data/lib/rspec/core/example_status_persister.rb +235 -0
  25. data/lib/rspec/core/filter_manager.rb +86 -115
  26. data/lib/rspec/core/flat_map.rb +6 -4
  27. data/lib/rspec/core/formatters/base_bisect_formatter.rb +45 -0
  28. data/lib/rspec/core/formatters/base_formatter.rb +14 -116
  29. data/lib/rspec/core/formatters/base_text_formatter.rb +18 -21
  30. data/lib/rspec/core/formatters/bisect_drb_formatter.rb +29 -0
  31. data/lib/rspec/core/formatters/bisect_progress_formatter.rb +157 -0
  32. data/lib/rspec/core/formatters/console_codes.rb +29 -18
  33. data/lib/rspec/core/formatters/deprecation_formatter.rb +16 -16
  34. data/lib/rspec/core/formatters/documentation_formatter.rb +49 -16
  35. data/lib/rspec/core/formatters/exception_presenter.rb +525 -0
  36. data/lib/rspec/core/formatters/failure_list_formatter.rb +23 -0
  37. data/lib/rspec/core/formatters/fallback_message_formatter.rb +28 -0
  38. data/lib/rspec/core/formatters/helpers.rb +45 -15
  39. data/lib/rspec/core/formatters/html_formatter.rb +33 -28
  40. data/lib/rspec/core/formatters/html_printer.rb +30 -20
  41. data/lib/rspec/core/formatters/html_snippet_extractor.rb +120 -0
  42. data/lib/rspec/core/formatters/json_formatter.rb +18 -9
  43. data/lib/rspec/core/formatters/profile_formatter.rb +10 -9
  44. data/lib/rspec/core/formatters/progress_formatter.rb +5 -4
  45. data/lib/rspec/core/formatters/protocol.rb +182 -0
  46. data/lib/rspec/core/formatters/snippet_extractor.rb +113 -82
  47. data/lib/rspec/core/formatters/syntax_highlighter.rb +91 -0
  48. data/lib/rspec/core/formatters.rb +81 -41
  49. data/lib/rspec/core/hooks.rb +314 -244
  50. data/lib/rspec/core/invocations.rb +87 -0
  51. data/lib/rspec/core/memoized_helpers.rb +161 -51
  52. data/lib/rspec/core/metadata.rb +132 -61
  53. data/lib/rspec/core/metadata_filter.rb +224 -64
  54. data/lib/rspec/core/minitest_assertions_adapter.rb +6 -3
  55. data/lib/rspec/core/mocking_adapters/flexmock.rb +4 -2
  56. data/lib/rspec/core/mocking_adapters/mocha.rb +11 -9
  57. data/lib/rspec/core/mocking_adapters/null.rb +2 -0
  58. data/lib/rspec/core/mocking_adapters/rr.rb +3 -1
  59. data/lib/rspec/core/mocking_adapters/rspec.rb +3 -1
  60. data/lib/rspec/core/notifications.rb +192 -206
  61. data/lib/rspec/core/option_parser.rb +174 -69
  62. data/lib/rspec/core/ordering.rb +48 -35
  63. data/lib/rspec/core/output_wrapper.rb +29 -0
  64. data/lib/rspec/core/pending.rb +25 -33
  65. data/lib/rspec/core/profiler.rb +34 -0
  66. data/lib/rspec/core/project_initializer/.rspec +0 -2
  67. data/lib/rspec/core/project_initializer/spec/spec_helper.rb +59 -39
  68. data/lib/rspec/core/project_initializer.rb +5 -3
  69. data/lib/rspec/core/rake_task.rb +99 -55
  70. data/lib/rspec/core/reporter.rb +128 -15
  71. data/lib/rspec/core/ruby_project.rb +14 -6
  72. data/lib/rspec/core/runner.rb +96 -45
  73. data/lib/rspec/core/sandbox.rb +37 -0
  74. data/lib/rspec/core/set.rb +54 -0
  75. data/lib/rspec/core/shared_example_group.rb +133 -43
  76. data/lib/rspec/core/shell_escape.rb +49 -0
  77. data/lib/rspec/core/test_unit_assertions_adapter.rb +4 -4
  78. data/lib/rspec/core/version.rb +1 -1
  79. data/lib/rspec/core/warnings.rb +6 -6
  80. data/lib/rspec/core/world.rb +172 -68
  81. data/lib/rspec/core.rb +66 -21
  82. data.tar.gz.sig +0 -0
  83. metadata +93 -69
  84. metadata.gz.sig +0 -0
  85. data/lib/rspec/core/backport_random.rb +0 -336
@@ -1,9 +1,10 @@
1
+ RSpec::Support.require_rspec_core "shell_escape"
2
+
1
3
  module RSpec
2
4
  module Core
3
5
  module Formatters
4
- # Formatters helpers
6
+ # Formatters helpers.
5
7
  module Helpers
6
-
7
8
  # @private
8
9
  SUB_SECOND_PRECISION = 5
9
10
 
@@ -22,15 +23,15 @@ module RSpec
22
23
  # format_duration(135.14) #=> "2 minutes 15.14 seconds"
23
24
  def self.format_duration(duration)
24
25
  precision = case
25
- when duration < 1; SUB_SECOND_PRECISION
26
- when duration < 120; DEFAULT_PRECISION
27
- when duration < 300; 1
26
+ when duration < 1 then SUB_SECOND_PRECISION
27
+ when duration < 120 then DEFAULT_PRECISION
28
+ when duration < 300 then 1
28
29
  else 0
29
30
  end
30
31
 
31
32
  if duration > 60
32
- minutes = (duration.to_i / 60).to_i
33
- seconds = duration - minutes * 60
33
+ minutes = (duration.round / 60).to_i
34
+ seconds = (duration - minutes * 60)
34
35
 
35
36
  "#{pluralize(minutes, 'minute')} #{pluralize(format_seconds(seconds, precision), 'second')}"
36
37
  else
@@ -40,8 +41,9 @@ module RSpec
40
41
 
41
42
  # @api private
42
43
  #
43
- # Formats seconds to have 5 digits of precision with trailing zeros removed if the number
44
- # is less than 1 or with 2 digits of precision if the number is greater than zero.
44
+ # Formats seconds to have 5 digits of precision with trailing zeros
45
+ # removed if the number is less than 1 or with 2 digits of precision if
46
+ # the number is greater than zero.
45
47
  #
46
48
  # @param float [Float]
47
49
  # @return [String] formatted float
@@ -51,12 +53,14 @@ module RSpec
51
53
  # format_seconds(0.020000) #=> "0.02"
52
54
  # format_seconds(1.00000000001) #=> "1"
53
55
  #
54
- # The precision used is set in {Helpers::SUB_SECOND_PRECISION} and {Helpers::DEFAULT_PRECISION}.
56
+ # The precision used is set in {Helpers::SUB_SECOND_PRECISION} and
57
+ # {Helpers::DEFAULT_PRECISION}.
55
58
  #
56
59
  # @see #strip_trailing_zeroes
57
- def self.format_seconds(float, precision = nil)
60
+ def self.format_seconds(float, precision=nil)
61
+ return '0' if float < 0
58
62
  precision ||= (float < 1) ? SUB_SECOND_PRECISION : DEFAULT_PRECISION
59
- formatted = sprintf("%.#{precision}f", float)
63
+ formatted = "%.#{precision}f" % float
60
64
  strip_trailing_zeroes(formatted)
61
65
  end
62
66
 
@@ -64,11 +68,13 @@ module RSpec
64
68
  #
65
69
  # Remove trailing zeros from a string.
66
70
  #
71
+ # Only remove trailing zeros after a decimal place.
72
+ # see: http://rubular.com/r/ojtTydOgpn
73
+ #
67
74
  # @param string [String] string with trailing zeros
68
75
  # @return [String] string with trailing zeros removed
69
76
  def self.strip_trailing_zeroes(string)
70
- stripped = string.sub(/[^1-9]+$/, '')
71
- stripped.empty? ? "0" : stripped
77
+ string.sub(/(?:(\..*[^0])0+|\.0+)$/, '\1')
72
78
  end
73
79
  private_class_method :strip_trailing_zeroes
74
80
 
@@ -80,7 +86,31 @@ module RSpec
80
86
  # @param string [String] word to be pluralized
81
87
  # @return [String] pluralized word
82
88
  def self.pluralize(count, string)
83
- "#{count} #{string}#{'s' unless count.to_f == 1}"
89
+ pluralized_string = if count.to_f == 1
90
+ string
91
+ elsif string.end_with?('s') # e.g. "process"
92
+ "#{string}es" # e.g. "processes"
93
+ else
94
+ "#{string}s"
95
+ end
96
+
97
+ "#{count} #{pluralized_string}"
98
+ end
99
+
100
+ # @api private
101
+ # Given a list of example ids, organizes them into a compact, ordered list.
102
+ def self.organize_ids(ids)
103
+ grouped = ids.inject(Hash.new { |h, k| h[k] = [] }) do |hash, id|
104
+ file, id = Example.parse_id(id)
105
+ hash[file] << id
106
+ hash
107
+ end
108
+
109
+ grouped.sort_by(&:first).map do |file, grouped_ids|
110
+ grouped_ids = grouped_ids.sort_by { |id| id.split(':').map(&:to_i) }
111
+ id = Metadata.id_from(:rerun_file_path => file, :scoped_id => grouped_ids.join(','))
112
+ ShellEscape.conditionally_quote(id)
113
+ end
84
114
  end
85
115
  end
86
116
  end
@@ -7,8 +7,8 @@ module RSpec
7
7
  # @private
8
8
  class HtmlFormatter < BaseFormatter
9
9
  Formatters.register self, :start, :example_group_started, :start_dump,
10
- :example_started, :example_passed, :example_failed,
11
- :example_pending, :dump_summary
10
+ :example_started, :example_passed, :example_failed,
11
+ :example_pending, :dump_summary
12
12
 
13
13
  def initialize(output)
14
14
  super(output)
@@ -30,25 +30,25 @@ module RSpec
30
30
  @example_group_red = false
31
31
  @example_group_number += 1
32
32
 
33
- unless example_group_number == 1
34
- @printer.print_example_group_end
35
- end
36
- @printer.print_example_group_start( example_group_number, notification.group.description, notification.group.parent_groups.size )
33
+ @printer.print_example_group_end unless example_group_number == 1
34
+ @printer.print_example_group_start(example_group_number,
35
+ notification.group.description,
36
+ notification.group.parent_groups.size)
37
37
  @printer.flush
38
38
  end
39
39
 
40
- def start_dump(notification)
40
+ def start_dump(_notification)
41
41
  @printer.print_example_group_end
42
42
  @printer.flush
43
43
  end
44
44
 
45
- def example_started(notification)
45
+ def example_started(_notification)
46
46
  @example_number += 1
47
47
  end
48
48
 
49
49
  def example_passed(passed)
50
50
  @printer.move_progress(percent_done)
51
- @printer.print_example_passed( passed.example.description, passed.example.execution_result.run_time )
51
+ @printer.print_example_passed(passed.example.description, passed.example.execution_result.run_time)
52
52
  @printer.flush
53
53
  end
54
54
 
@@ -69,14 +69,14 @@ module RSpec
69
69
  example = failure.example
70
70
 
71
71
  exception = failure.exception
72
+ message_lines = failure.fully_formatted_lines(nil, RSpec::Core::Notifications::NullColorizer)
72
73
  exception_details = if exception
73
- {
74
- :message => exception.message,
75
- :backtrace => failure.formatted_backtrace.join("\n")
76
- }
77
- else
78
- false
79
- end
74
+ {
75
+ # drop 2 removes the description (regardless of newlines) and leading blank line
76
+ :message => message_lines.drop(2).join("\n"),
77
+ :backtrace => failure.formatted_backtrace.join("\n"),
78
+ }
79
+ end
80
80
  extra = extra_failure_content(failure)
81
81
 
82
82
  @printer.print_example_failed(
@@ -85,8 +85,7 @@ module RSpec
85
85
  example.execution_result.run_time,
86
86
  @failed_examples.size,
87
87
  exception_details,
88
- (extra == "") ? false : extra,
89
- true
88
+ (extra == "") ? false : extra
90
89
  )
91
90
  @printer.flush
92
91
  end
@@ -97,7 +96,7 @@ module RSpec
97
96
  @printer.make_header_yellow unless @header_red
98
97
  @printer.make_example_group_header_yellow(example_group_number) unless @example_group_red
99
98
  @printer.move_progress(percent_done)
100
- @printer.print_example_pending( example.description, example.execution_result.pending_message )
99
+ @printer.print_example_pending(example.description, example.execution_result.pending_message)
101
100
  @printer.flush
102
101
  end
103
102
 
@@ -113,15 +112,20 @@ module RSpec
113
112
 
114
113
  private
115
114
 
116
- # The number of the currently running example_group
115
+ # If these methods are declared with attr_reader Ruby will issue a
116
+ # warning because they are private.
117
+ # rubocop:disable Style/TrivialAccessors
118
+
119
+ # The number of the currently running example_group.
117
120
  def example_group_number
118
121
  @example_group_number
119
122
  end
120
123
 
121
- # The number of the currently running example (a global counter)
124
+ # The number of the currently running example (a global counter).
122
125
  def example_number
123
126
  @example_number
124
127
  end
128
+ # rubocop:enable Style/TrivialAccessors
125
129
 
126
130
  def percent_done
127
131
  result = 100.0
@@ -131,17 +135,18 @@ module RSpec
131
135
  result
132
136
  end
133
137
 
134
- # Override this method if you wish to output extra HTML for a failed spec. For example, you
135
- # could output links to images or other files produced during the specs.
136
- #
138
+ # Override this method if you wish to output extra HTML for a failed
139
+ # spec. For example, you could output links to images or other files
140
+ # produced during the specs.
137
141
  def extra_failure_content(failure)
138
- RSpec::Support.require_rspec_core "formatters/snippet_extractor"
139
- backtrace = failure.exception.backtrace.map {|line| RSpec.configuration.backtrace_formatter.backtrace_line(line)}
142
+ RSpec::Support.require_rspec_core "formatters/html_snippet_extractor"
143
+ backtrace = (failure.exception.backtrace || []).map do |line|
144
+ RSpec.configuration.backtrace_formatter.backtrace_line(line)
145
+ end
140
146
  backtrace.compact!
141
- @snippet_extractor ||= SnippetExtractor.new
147
+ @snippet_extractor ||= HtmlSnippetExtractor.new
142
148
  " <pre class=\"ruby\"><code>#{@snippet_extractor.snippet(backtrace)}</code></pre>"
143
149
  end
144
-
145
150
  end
146
151
  end
147
152
  end
@@ -5,7 +5,7 @@ module RSpec
5
5
  module Formatters
6
6
  # @private
7
7
  class HtmlPrinter
8
- include ERB::Util # for the #h method
8
+ include ERB::Util # For the #h method.
9
9
  def initialize(output)
10
10
  @output = output
11
11
  end
@@ -27,12 +27,15 @@ module RSpec
27
27
  end
28
28
 
29
29
  def print_example_passed(description, run_time)
30
- formatted_run_time = sprintf("%.5f", run_time)
31
- @output.puts " <dd class=\"example passed\"><span class=\"passed_spec_name\">#{h(description)}</span><span class='duration'>#{formatted_run_time}s</span></dd>"
30
+ formatted_run_time = "%.5f" % run_time
31
+ @output.puts " <dd class=\"example passed\">" \
32
+ "<span class=\"passed_spec_name\">#{h(description)}</span>" \
33
+ "<span class='duration'>#{formatted_run_time}s</span></dd>"
32
34
  end
33
35
 
34
- def print_example_failed(pending_fixed, description, run_time, failure_id, exception, extra_content, escape_backtrace = false)
35
- formatted_run_time = sprintf("%.5f", run_time)
36
+ def print_example_failed(pending_fixed, description, run_time, failure_id,
37
+ exception, extra_content)
38
+ formatted_run_time = "%.5f" % run_time
36
39
 
37
40
  @output.puts " <dd class=\"example #{pending_fixed ? 'pending_fixed' : 'failed'}\">"
38
41
  @output.puts " <span class=\"failed_spec_name\">#{h(description)}</span>"
@@ -40,11 +43,7 @@ module RSpec
40
43
  @output.puts " <div class=\"failure\" id=\"failure_#{failure_id}\">"
41
44
  if exception
42
45
  @output.puts " <div class=\"message\"><pre>#{h(exception[:message])}</pre></div>"
43
- if escape_backtrace
44
- @output.puts " <div class=\"backtrace\"><pre>#{h exception[:backtrace]}</pre></div>"
45
- else
46
- @output.puts " <div class=\"backtrace\"><pre>#{exception[:backtrace]}</pre></div>"
47
- end
46
+ @output.puts " <div class=\"backtrace\"><pre>#{h exception[:backtrace]}</pre></div>"
48
47
  end
49
48
  @output.puts extra_content if extra_content
50
49
  @output.puts " </div>"
@@ -52,18 +51,25 @@ module RSpec
52
51
  end
53
52
 
54
53
  def print_example_pending(description, pending_message)
55
- @output.puts " <dd class=\"example not_implemented\"><span class=\"not_implemented_spec_name\">#{h(description)} (PENDING: #{h(pending_message)})</span></dd>"
54
+ @output.puts " <dd class=\"example not_implemented\">" \
55
+ "<span class=\"not_implemented_spec_name\">#{h(description)} " \
56
+ "(PENDING: #{h(pending_message)})</span></dd>"
56
57
  end
57
58
 
58
59
  def print_summary(duration, example_count, failure_count, pending_count)
59
- totals = "#{example_count} example#{'s' unless example_count == 1}, "
60
+ totals = String.new(
61
+ "#{example_count} example#{'s' unless example_count == 1}, "
62
+ )
60
63
  totals << "#{failure_count} failure#{'s' unless failure_count == 1}"
61
64
  totals << ", #{pending_count} pending" if pending_count > 0
62
65
 
63
- formatted_duration = sprintf("%.5f", duration)
66
+ formatted_duration = "%.5f" % duration
64
67
 
65
- @output.puts "<script type=\"text/javascript\">document.getElementById('duration').innerHTML = \"Finished in <strong>#{formatted_duration} seconds</strong>\";</script>"
66
- @output.puts "<script type=\"text/javascript\">document.getElementById('totals').innerHTML = \"#{totals}\";</script>"
68
+ @output.puts "<script type=\"text/javascript\">" \
69
+ "document.getElementById('duration').innerHTML = \"Finished in " \
70
+ "<strong>#{formatted_duration} seconds</strong>\";</script>"
71
+ @output.puts "<script type=\"text/javascript\">" \
72
+ "document.getElementById('totals').innerHTML = \"#{totals}\";</script>"
67
73
  @output.puts "</div>"
68
74
  @output.puts "</div>"
69
75
  @output.puts "</body>"
@@ -88,13 +94,17 @@ module RSpec
88
94
  end
89
95
 
90
96
  def make_example_group_header_red(group_id)
91
- @output.puts " <script type=\"text/javascript\">makeRed('div_group_#{group_id}');</script>"
92
- @output.puts " <script type=\"text/javascript\">makeRed('example_group_#{group_id}');</script>"
97
+ @output.puts " <script type=\"text/javascript\">" \
98
+ "makeRed('div_group_#{group_id}');</script>"
99
+ @output.puts " <script type=\"text/javascript\">" \
100
+ "makeRed('example_group_#{group_id}');</script>"
93
101
  end
94
102
 
95
103
  def make_example_group_header_yellow(group_id)
96
- @output.puts " <script type=\"text/javascript\">makeYellow('div_group_#{group_id}');</script>"
97
- @output.puts " <script type=\"text/javascript\">makeYellow('example_group_#{group_id}');</script>"
104
+ @output.puts " <script type=\"text/javascript\">" \
105
+ "makeYellow('div_group_#{group_id}');</script>"
106
+ @output.puts " <script type=\"text/javascript\">" \
107
+ "makeYellow('example_group_#{group_id}');</script>"
98
108
  end
99
109
 
100
110
  private
@@ -203,6 +213,7 @@ function assign_display_style_for_group(classname, display_flag, subgroup_flag)
203
213
  }
204
214
  }
205
215
  EOF
216
+ # rubocop:enable Layout/LineLength
206
217
 
207
218
  GLOBAL_STYLES = <<-EOF
208
219
  #rspec-header {
@@ -395,7 +406,6 @@ EOF
395
406
  </head>
396
407
  <body>
397
408
  EOF
398
-
399
409
  end
400
410
  end
401
411
  end
@@ -0,0 +1,120 @@
1
+ module RSpec
2
+ module Core
3
+ module Formatters
4
+ # @api private
5
+ #
6
+ # Extracts code snippets by looking at the backtrace of the passed error
7
+ # and applies synax highlighting and line numbers using html.
8
+ class HtmlSnippetExtractor
9
+ # @private
10
+ module NullConverter
11
+ def self.convert(code)
12
+ %Q(#{code}\n<span class="comment"># Install the coderay gem to get syntax highlighting</span>)
13
+ end
14
+ end
15
+
16
+ # @private
17
+ module CoderayConverter
18
+ def self.convert(code)
19
+ CodeRay.scan(code, :ruby).html(:line_numbers => false)
20
+ end
21
+ end
22
+
23
+ # rubocop:disable Style/ClassVars
24
+ # @private
25
+ @@converter = NullConverter
26
+
27
+ begin
28
+ require 'coderay'
29
+ RSpec::Support.require_rspec_core 'formatters/syntax_highlighter'
30
+ RSpec::Core::Formatters::SyntaxHighlighter.attempt_to_add_rspec_terms_to_coderay_keywords
31
+ @@converter = CoderayConverter
32
+ # rubocop:disable Lint/HandleExceptions
33
+ rescue LoadError
34
+ # it'll fall back to the NullConverter assigned above
35
+ # rubocop:enable Lint/HandleExceptions
36
+ end
37
+
38
+ # rubocop:enable Style/ClassVars
39
+
40
+ # @api private
41
+ #
42
+ # Extract lines of code corresponding to a backtrace.
43
+ #
44
+ # @param backtrace [String] the backtrace from a test failure
45
+ # @return [String] highlighted code snippet indicating where the test
46
+ # failure occurred
47
+ #
48
+ # @see #post_process
49
+ def snippet(backtrace)
50
+ raw_code, line = snippet_for(backtrace[0])
51
+ highlighted = @@converter.convert(raw_code)
52
+ post_process(highlighted, line)
53
+ end
54
+ # rubocop:enable Style/ClassVars
55
+
56
+ # @api private
57
+ #
58
+ # Create a snippet from a line of code.
59
+ #
60
+ # @param error_line [String] file name with line number (i.e.
61
+ # 'foo_spec.rb:12')
62
+ # @return [String] lines around the target line within the file
63
+ #
64
+ # @see #lines_around
65
+ def snippet_for(error_line)
66
+ if error_line =~ /(.*):(\d+)/
67
+ file = Regexp.last_match[1]
68
+ line = Regexp.last_match[2].to_i
69
+ [lines_around(file, line), line]
70
+ else
71
+ ["# Couldn't get snippet for #{error_line}", 1]
72
+ end
73
+ end
74
+
75
+ # @api private
76
+ #
77
+ # Extract lines of code centered around a particular line within a
78
+ # source file.
79
+ #
80
+ # @param file [String] filename
81
+ # @param line [Fixnum] line number
82
+ # @return [String] lines around the target line within the file (2 above
83
+ # and 1 below).
84
+ def lines_around(file, line)
85
+ if File.file?(file)
86
+ lines = File.read(file).split("\n")
87
+ min = [0, line - 3].max
88
+ max = [line + 1, lines.length - 1].min
89
+ selected_lines = []
90
+ selected_lines.join("\n")
91
+ lines[min..max].join("\n")
92
+ else
93
+ "# Couldn't get snippet for #{file}"
94
+ end
95
+ rescue SecurityError
96
+ "# Couldn't get snippet for #{file}"
97
+ end
98
+
99
+ # @api private
100
+ #
101
+ # Adds line numbers to all lines and highlights the line where the
102
+ # failure occurred using html `span` tags.
103
+ #
104
+ # @param highlighted [String] syntax-highlighted snippet surrounding the
105
+ # offending line of code
106
+ # @param offending_line [Fixnum] line where failure occurred
107
+ # @return [String] completed snippet
108
+ def post_process(highlighted, offending_line)
109
+ new_lines = []
110
+ highlighted.split("\n").each_with_index do |line, i|
111
+ new_line = "<span class=\"linenum\">#{offending_line + i - 2}</span>#{line}"
112
+ new_line = "<span class=\"offending\">#{new_line}</span>" if i == 2
113
+ new_lines << new_line
114
+ end
115
+ new_lines.join("\n")
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -6,13 +6,15 @@ module RSpec
6
6
  module Formatters
7
7
  # @private
8
8
  class JsonFormatter < BaseFormatter
9
- Formatters.register self, :message, :dump_summary, :dump_profile, :stop, :close
9
+ Formatters.register self, :message, :dump_summary, :dump_profile, :stop, :seed, :close
10
10
 
11
11
  attr_reader :output_hash
12
12
 
13
13
  def initialize(output)
14
14
  super
15
- @output_hash = {}
15
+ @output_hash = {
16
+ :version => RSpec::Core::Version::STRING
17
+ }
16
18
  end
17
19
 
18
20
  def message(notification)
@@ -24,7 +26,8 @@ module RSpec
24
26
  :duration => summary.duration,
25
27
  :example_count => summary.example_count,
26
28
  :failure_count => summary.failure_count,
27
- :pending_count => summary.pending_count
29
+ :pending_count => summary.pending_count,
30
+ :errors_outside_of_examples_count => summary.errors_outside_of_examples_count
28
31
  }
29
32
  @output_hash[:summary_line] = summary.totals_line
30
33
  end
@@ -32,7 +35,8 @@ module RSpec
32
35
  def stop(notification)
33
36
  @output_hash[:examples] = notification.examples.map do |example|
34
37
  format_example(example).tap do |hash|
35
- if e=example.exception
38
+ e = example.exception
39
+ if e
36
40
  hash[:exception] = {
37
41
  :class => e.class.name,
38
42
  :message => e.message,
@@ -43,9 +47,13 @@ module RSpec
43
47
  end
44
48
  end
45
49
 
46
- def close(notification)
50
+ def seed(notification)
51
+ return unless notification.seed_used?
52
+ @output_hash[:seed] = notification.seed
53
+ end
54
+
55
+ def close(_notification)
47
56
  output.write @output_hash.to_json
48
- output.close if IO === output && output != $stdout
49
57
  end
50
58
 
51
59
  def dump_profile(profile)
@@ -57,8 +65,7 @@ module RSpec
57
65
  # @api private
58
66
  def dump_profile_slowest_examples(profile)
59
67
  @output_hash[:profile] = {}
60
- sorted_examples = profile.slowest_examples
61
- @output_hash[:profile][:examples] = sorted_examples.map do |example|
68
+ @output_hash[:profile][:examples] = profile.slowest_examples.map do |example|
62
69
  format_example(example).tap do |hash|
63
70
  hash[:run_time] = example.execution_result.run_time
64
71
  end
@@ -79,12 +86,14 @@ module RSpec
79
86
 
80
87
  def format_example(example)
81
88
  {
89
+ :id => example.id,
82
90
  :description => example.description,
83
91
  :full_description => example.full_description,
84
92
  :status => example.execution_result.status.to_s,
85
93
  :file_path => example.metadata[:file_path],
86
94
  :line_number => example.metadata[:line_number],
87
- :run_time => example.execution_result.run_time
95
+ :run_time => example.execution_result.run_time,
96
+ :pending_message => example.execution_result.pending_message,
88
97
  }
89
98
  end
90
99
  end
@@ -3,9 +3,8 @@ RSpec::Support.require_rspec_core "formatters/console_codes"
3
3
  module RSpec
4
4
  module Core
5
5
  module Formatters
6
-
7
6
  # @api private
8
- # Formatter for providing profile output
7
+ # Formatter for providing profile output.
9
8
  class ProfileFormatter
10
9
  Formatters.register self, :dump_profile
11
10
 
@@ -16,14 +15,13 @@ module RSpec
16
15
  # @private
17
16
  attr_reader :output
18
17
 
19
- # @method dump_profile
20
18
  # @api public
21
19
  #
22
20
  # This method is invoked after the dumping the summary if profiling is
23
21
  # enabled.
24
22
  #
25
- # @param profile [ProfileNotification] containing duration, slowest_examples
26
- # and slowest_example_groups
23
+ # @param profile [ProfileNotification] containing duration,
24
+ # slowest_examples and slowest_example_groups
27
25
  def dump_profile(profile)
28
26
  dump_profile_slowest_examples(profile)
29
27
  dump_profile_slowest_example_groups(profile)
@@ -32,11 +30,14 @@ module RSpec
32
30
  private
33
31
 
34
32
  def dump_profile_slowest_examples(profile)
35
- @output.puts "\nTop #{profile.slowest_examples.size} slowest examples (#{Helpers.format_seconds(profile.slow_duration)} seconds, #{profile.percentage}% of total time):\n"
33
+ @output.puts "\nTop #{profile.slowest_examples.size} slowest " \
34
+ "examples (#{Helpers.format_seconds(profile.slow_duration)} " \
35
+ "seconds, #{profile.percentage}% of total time):\n"
36
36
 
37
37
  profile.slowest_examples.each do |example|
38
38
  @output.puts " #{example.full_description}"
39
- @output.puts " #{bold(Helpers.format_seconds(example.execution_result.run_time))} #{bold("seconds")} #{format_caller(example.location)}"
39
+ @output.puts " #{bold(Helpers.format_seconds(example.execution_result.run_time))} " \
40
+ "#{bold("seconds")} #{format_caller(example.location)}"
40
41
  end
41
42
  end
42
43
 
@@ -54,13 +55,13 @@ module RSpec
54
55
  end
55
56
 
56
57
  def format_caller(caller_info)
57
- RSpec.configuration.backtrace_formatter.backtrace_line(caller_info.to_s.split(':in `block').first)
58
+ RSpec.configuration.backtrace_formatter.backtrace_line(
59
+ caller_info.to_s.split(':in `block').first)
58
60
  end
59
61
 
60
62
  def bold(text)
61
63
  ConsoleCodes.wrap(text, :bold)
62
64
  end
63
-
64
65
  end
65
66
  end
66
67
  end
@@ -1,4 +1,5 @@
1
1
  RSpec::Support.require_rspec_core "formatters/base_text_formatter"
2
+ RSpec::Support.require_rspec_core "formatters/console_codes"
2
3
 
3
4
  module RSpec
4
5
  module Core
@@ -7,19 +8,19 @@ module RSpec
7
8
  class ProgressFormatter < BaseTextFormatter
8
9
  Formatters.register self, :example_passed, :example_pending, :example_failed, :start_dump
9
10
 
10
- def example_passed(notification)
11
+ def example_passed(_notification)
11
12
  output.print ConsoleCodes.wrap('.', :success)
12
13
  end
13
14
 
14
- def example_pending(notification)
15
+ def example_pending(_notification)
15
16
  output.print ConsoleCodes.wrap('*', :pending)
16
17
  end
17
18
 
18
- def example_failed(notification)
19
+ def example_failed(_notification)
19
20
  output.print ConsoleCodes.wrap('F', :failure)
20
21
  end
21
22
 
22
- def start_dump(notification)
23
+ def start_dump(_notification)
23
24
  output.puts
24
25
  end
25
26
  end