class RSpecJUnitFormatter
Dumps rspec results as a JUnit XML file. Based on XML schema: windyroad.org/dl/Open%20Source/JUnit.xsd
Constants
- DISCOURAGED_REGEXP
Discouraged characters from www.w3.org/TR/xml/#charsets Plus special characters with well-known entity replacements
- DISCOURAGED_REPLACEMENTS
Translate well-known entities, or use generic unicode hex entity
- ILLEGAL_REGEXP
Inversion of character range from www.w3.org/TR/xml/#charsets
- ILLEGAL_REPLACEMENT
Replace illegals with a Ruby-like escape
- STRIP_DIFF_COLORS_BLOCK_REGEXP
- STRIP_DIFF_COLORS_CODES_REGEXP
Attributes
started[R]
Public Instance Methods
dump_summary(duration, example_count, failure_count, pending_count)
click to toggle source
Calls superclass method
# File lib/rspec_junit_formatter/rspec2.rb, line 9 def dump_summary(duration, example_count, failure_count, pending_count) super xml_dump end
start(example_count)
click to toggle source
Calls superclass method
# File lib/rspec_junit_formatter/rspec2.rb, line 4 def start(example_count) @started = Time.now super end
stop(notification)
click to toggle source
# File lib/rspec_junit_formatter/rspec3.rb, line 13 def stop(notification) @examples_notification = notification end
Private Instance Methods
classname_for(example)
click to toggle source
# File lib/rspec_junit_formatter/rspec2.rb, line 28 def classname_for(example) fp = example_group_file_path_for(example) fp.sub(%r{\.[^/.]+\Z}, "").gsub("/", ".").gsub(/\A\.+|\.+\Z/, "") end
description_for(example)
click to toggle source
# File lib/rspec_junit_formatter/rspec2.rb, line 37 def description_for(example) example.full_description end
duration()
click to toggle source
# File lib/rspec_junit_formatter/rspec3.rb, line 38 def duration @summary_notification.duration end
duration_for(example)
click to toggle source
# File lib/rspec_junit_formatter/rspec2.rb, line 33 def duration_for(example) example.execution_result[:run_time] end
escape(text)
click to toggle source
# File lib/rspec_junit_formatter.rb, line 163 def escape(text) # Make sure it's utf-8, replace illegal characters with ruby-like escapes, and replace special and discouraged characters with entities text.to_s.encode(Encoding::UTF_8).gsub(ILLEGAL_REGEXP, ILLEGAL_REPLACEMENT).gsub(DISCOURAGED_REGEXP, DISCOURAGED_REPLACEMENTS) end
example_count()
click to toggle source
# File lib/rspec_junit_formatter/rspec3.rb, line 26 def example_count @summary_notification.example_count end
example_group_file_path_for(example)
click to toggle source
# File lib/rspec_junit_formatter/rspec2.rb, line 20 def example_group_file_path_for(example) meta = example.metadata while meta[:example_group] meta = meta[:example_group] end meta[:file_path] end
examples()
click to toggle source
# File lib/rspec_junit_formatter/rspec3.rb, line 42 def examples @examples_notification.notifications end
exception_for(example)
click to toggle source
# File lib/rspec_junit_formatter/rspec2.rb, line 41 def exception_for(example) example.execution_result[:exception] end
failure_count()
click to toggle source
# File lib/rspec_junit_formatter/rspec3.rb, line 34 def failure_count @summary_notification.failure_count end
failure_for(example)
click to toggle source
# File lib/rspec_junit_formatter/rspec2.rb, line 53 def failure_for(example) exception = exception_for(example) message = strip_diff_colors(exception.message) backtrace = format_backtrace(exception.backtrace, example) if shared_group = find_shared_group(example) backtrace << "Shared Example Group: \"#{shared_group.metadata[:shared_group_name]}\" called from #{shared_group.metadata[:example_group][:location]}" end "#{message}\n#{backtrace.join("\n")}" end
failure_message_for(example)
click to toggle source
# File lib/rspec_junit_formatter/rspec2.rb, line 49 def failure_message_for(example) strip_diff_colors(exception_for(example).to_s) end
failure_type_for(example)
click to toggle source
# File lib/rspec_junit_formatter/rspec2.rb, line 45 def failure_type_for(example) exception_for(example).class.name end
group_and_parent_groups(example)
click to toggle source
# File lib/rspec_junit_formatter/rspec2.rb, line 69 def group_and_parent_groups(example) example.example_group.parent_groups + [example.example_group] end
pending_count()
click to toggle source
# File lib/rspec_junit_formatter/rspec3.rb, line 30 def pending_count @summary_notification.pending_count end
result_of(example)
click to toggle source
# File lib/rspec_junit_formatter/rspec2.rb, line 16 def result_of(example) example.execution_result[:status].to_sym end
stderr_for(example)
click to toggle source
# File lib/rspec_junit_formatter/rspec2.rb, line 77 def stderr_for(example) example.metadata[:stderr] end
stdout_for(example)
click to toggle source
# File lib/rspec_junit_formatter/rspec2.rb, line 73 def stdout_for(example) example.metadata[:stdout] end
strip_diff_colors(string)
click to toggle source
# File lib/rspec_junit_formatter.rb, line 171 def strip_diff_colors(string) # XXX: RSpec diffs are appended to the message lines fairly early and will # contain ANSI escape codes for colorizing terminal output if the global # rspec configuration is turned on, regardless of which notification lines # we ask for. We need to strip the codes from the diff part of the message # for XML output here. # # We also only want to target the diff hunks because the failure message # itself might legitimately contain ansi escape codes. # string.sub(STRIP_DIFF_COLORS_BLOCK_REGEXP) { |match| match.gsub(STRIP_DIFF_COLORS_CODES_REGEXP, "".freeze) } end
swap_rspec_configuration(key, value) { || ... }
click to toggle source
rspec makes it really difficult to swap in configuration temporarily due to the way it cascades defaults, command line arguments, and user configuration. This method makes sure configuration gets swapped in correctly, but also that the original state is definitely restored.
# File lib/rspec_junit_formatter/rspec3.rb, line 91 def swap_rspec_configuration(key, value) unset = Object.new force = RSpec.configuration.send(:value_for, key) { unset } if unset.equal?(force) previous = RSpec.configuration.send(key) RSpec.configuration.send(:"#{key}=", value) else RSpec.configuration.force({key => value}) end yield ensure if unset.equal?(force) RSpec.configuration.send(:"#{key}=", previous) else RSpec.configuration.force({key => force}) end end
without_color(&block)
click to toggle source
# File lib/rspec_junit_formatter/rspec3.rb, line 112 def without_color(&block) swap_rspec_configuration(:color_mode, :off, &block) end
xml_dump()
click to toggle source
rspec 2 and 3 implements are in separate files.
# File lib/rspec_junit_formatter.rb, line 14 def xml_dump output << %{<?xml version="1.0" encoding="UTF-8"?>\n} output << %{<testsuite} output << %{ name="rspec#{escape(ENV["TEST_ENV_NUMBER"].to_s)}"} output << %{ tests="#{example_count}"} output << %{ skipped="#{pending_count}"} output << %{ failures="#{failure_count}"} output << %{ errors="0"} output << %{ time="#{escape("%.6f" % duration)}"} output << %{ timestamp="#{escape(started.iso8601)}"} output << %{ hostname="#{escape(Socket.gethostname)}"} output << %{>\n} output << %{<properties>\n} output << %{<property} output << %{ name="seed"} output << %{ value="#{escape(RSpec.configuration.seed.to_s)}"} output << %{/>\n} output << %{</properties>\n} xml_dump_examples output << %{</testsuite>\n} end
xml_dump_example(example) { || ... }
click to toggle source
# File lib/rspec_junit_formatter.rb, line 66 def xml_dump_example(example) output << %{<testcase} output << %{ classname="#{escape(classname_for(example))}"} output << %{ name="#{escape(description_for(example))}"} output << %{ file="#{escape(example_group_file_path_for(example))}"} output << %{ time="#{escape("%.6f" % duration_for(example))}"} output << %{>} yield if block_given? xml_dump_output(example) output << %{</testcase>\n} end
xml_dump_examples()
click to toggle source
# File lib/rspec_junit_formatter.rb, line 36 def xml_dump_examples examples.each do |example| case result_of(example) when :pending xml_dump_pending(example) when :failed xml_dump_failed(example) else xml_dump_example(example) end end end
xml_dump_failed(example)
click to toggle source
# File lib/rspec_junit_formatter.rb, line 55 def xml_dump_failed(example) xml_dump_example(example) do output << %{<failure} output << %{ message="#{escape(failure_message_for(example))}"} output << %{ type="#{escape(failure_type_for(example))}"} output << %{>} output << escape(failure_for(example)) output << %{</failure>} end end
xml_dump_output(example)
click to toggle source
# File lib/rspec_junit_formatter.rb, line 78 def xml_dump_output(example) if (stdout = stdout_for(example)) && !stdout.empty? output << %{<system-out>} output << escape(stdout) output << %{</system-out>} end if (stderr = stderr_for(example)) && !stderr.empty? output << %{<system-err>} output << escape(stderr) output << %{</system-err>} end end
xml_dump_pending(example)
click to toggle source
# File lib/rspec_junit_formatter.rb, line 49 def xml_dump_pending(example) xml_dump_example(example) do output << %{<skipped/>} end end