rspec-core 3.0.4 → 3.12.2

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