rspec_junit_formatter 0.2.0 → 0.6.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 4ff821525517ff9e64733fd500e22399577252b5
4
- data.tar.gz: d988af0bd85a6a198d314597df587239a22e3c94
2
+ SHA256:
3
+ metadata.gz: 903f156687c6fff260143332222e9950fca53b5306bcde7cf197c44f3af4acf7
4
+ data.tar.gz: 1d2ffca113b3cd78b3230d66ed41268609ce38f06e50da6cd196af9073670500
5
5
  SHA512:
6
- metadata.gz: 09bda5d34cd82f1ddd6c31c61a3c4249d23ef842352ad799968ac826ad498a099c561beccdd3794f3c2ebbab52582d81781beb865f7276d0d853ebf0a062727f
7
- data.tar.gz: 484ad5700266c03add749dc3a87b5805e486f51f21e965d4d11764cb312a32e66fad92ee28a6ee55eda1cb01a52f9e68588e369df5f1fe2b3ac4a259d492fee8
6
+ metadata.gz: f8d32b7a3b5dec828fe29c714755b3698ad8a48b1cfc92185b6f53e5eb4a6ab47adae5cb74743cbc6b5814d0a5d61d15d49b632aadd5afdede74820628796687
7
+ data.tar.gz: 76537f5a365796f1e062cbfde157f8f48c163b7973ae6a1faae533cbf4684bd3c29cd26d6cb344eac8c46c0ae950f854b48f21bbf2bd28bfbf2ebab6e12b639e
checksums.yaml.gz.sig CHANGED
Binary file
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011 Samuel Cochran
1
+ Copyright (c) 2011-2022 Samuel Cochran
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,48 +1,121 @@
1
1
  # RSpec JUnit Formatter
2
2
 
3
- [![Build results](http://img.shields.io/travis/sj26/rspec_junit_formatter.svg)](https://travis-ci.org/sj26/rspec_junit_formatter)
3
+ [![Build results](https://github.com/sj26/rspec_junit_formatter/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/sj26/rspec_junit_formatter/actions/workflows/ci.yml?branch=main)
4
+ [![Gem version](http://img.shields.io/gem/v/rspec_junit_formatter.svg)](https://rubygems.org/gems/rspec_junit_formatter)
4
5
 
5
- [RSpec][rspec] 2 & 3 results that [Jenkins][jenkins] can read. Probably a few other CI servers, too.
6
+ [RSpec][rspec] 2 & 3 results that your CI can read. [Jenkins][jenkins-junit], [Buildkite][buildkite-junit], [CircleCI][circleci-junit], [Gitlab][gitlab-junit], and probably more, too.
6
7
 
7
- Inspired by the work of [Diego Souza][dgvncsz0f] on [RSpec Formatters][dgvncsz0f/rspec_formatters] after frustration with [CI Reporter][ci_reporter].
8
+ [rspec]: http://rspec.info/
9
+ [jenkins-junit]: https://jenkins.io/doc/pipeline/steps/junit/
10
+ [buildkite-junit]: https://github.com/buildkite/rspec-junit-example
11
+ [circleci-junit]: https://circleci.com/docs/2.0/collect-test-data/
12
+ [gitlab-junit]: https://docs.gitlab.com/ee/ci/unit_test_reports.html#ruby-example
8
13
 
9
14
  ## Usage
10
15
 
11
16
  Install the gem:
12
17
 
13
- gem install rspec_junit_formatter
18
+ ```sh
19
+ gem install rspec_junit_formatter
20
+ ```
14
21
 
15
22
  Use it:
16
23
 
17
- rspec --format RspecJunitFormatter --out rspec.xml
24
+ ```sh
25
+ rspec --format RspecJunitFormatter --out rspec.xml
26
+ ```
27
+
28
+ You'll get an XML file `rspec.xml` with your results in it.
29
+
30
+ You can use it in combination with other [formatters][rspec-formatters], too:
18
31
 
19
- You'll get an XML file with your results in it.
32
+ ```sh
33
+ rspec --format progress --format RspecJunitFormatter --out rspec.xml
34
+ ```
20
35
 
21
- ## More Permanent Usage
36
+ [rspec-formatters]: https://relishapp.com/rspec/rspec-core/v/3-6/docs/formatters
37
+
38
+ ### Using in your project with Bundler
22
39
 
23
40
  Add it to your Gemfile if you're using [Bundler][bundler]. Put it in the same groups as rspec.
24
41
 
25
- In your .rspec, usually alongside another formatter, add:
42
+ ```ruby
43
+ group :test do
44
+ gem "rspec"
45
+ gem "rspec_junit_formatter"
46
+ end
47
+ ```
48
+
49
+ Put the same arguments as the commands above in [your `.rspec`][rspec-file]:
50
+
51
+ ```sh
52
+ --format RspecJunitFormatter
53
+ --out rspec.xml
54
+ ```
55
+ [bundler]: https://bundler.io
56
+ [rspec-file]: https://relishapp.com/rspec/rspec-core/v/3-6/docs/configuration/read-command-line-configuration-options-from-files
57
+
58
+ ### Parallel tests
59
+
60
+ For use with `parallel_tests`, add `$TEST_ENV_NUMBER` in the output file option (in `.rspec` or `.rspec_parallel`) to avoid concurrent process write conflicts.
61
+
62
+ ```sh
63
+ --format RspecJunitFormatter
64
+ --out tmp/rspec<%= ENV["TEST_ENV_NUMBER"] %>.xml
65
+ ```
66
+
67
+ The formatter includes `$TEST_ENV_NUMBER` in the test suite name within the XML, too.
68
+
69
+ ### Capturing output
70
+
71
+ If you like, you can capture the standard output and error streams of each test into the `:stdout` and `:stderr` example metadata which will be added to the junit report, e.g.:
72
+
73
+ ```ruby
74
+ # spec_helper.rb
26
75
 
27
- --format RspecJunitFormatter
28
- --out rspec.xml
76
+ RSpec.configure do |config|
77
+ # register around filter that captures stdout and stderr
78
+ config.around(:each) do |example|
79
+ $stdout = StringIO.new
80
+ $stderr = StringIO.new
29
81
 
30
- I use it with the excellent [Fuubar formatter][fuubar].
82
+ example.run
31
83
 
32
- ## Roadmap
84
+ example.metadata[:stdout] = $stdout.string
85
+ example.metadata[:stderr] = $stderr.string
33
86
 
34
- * It would be nice to split things up into individual test suites, although would this correspond to example groups? The subject? The spec file? Not sure yet.
35
- * This would sit nicely in rspec-core, and has been designed to do so.
87
+ $stdout = STDOUT
88
+ $stderr = STDERR
89
+ end
90
+ end
91
+ ```
92
+
93
+ Note that this example captures all output from every example all the time, potentially interfering with local debugging. You might like to restrict this to only on CI, or by using [rspec filters](https://relishapp.com/rspec/rspec-core/docs/hooks/filters).
94
+
95
+ ## Caveats
96
+
97
+ * XML can only represent a [limited subset of characters][xml-charsets] which excludes null bytes and most control characters. This gem will use character entities where possible and fall back to replacing invalid characters with Ruby-like escape codes otherwise. For example, the null byte becomes `\0`.
98
+
99
+ [xml-charsets]: https://www.w3.org/TR/xml/#charsets
100
+
101
+ ## Development
102
+
103
+ Run the specs with `bundle exec rake`, which uses [Appraisal][appraisal] to run the specs against all supported versions of rspec.
104
+
105
+ [appraisal]: https://github.com/thoughtbot/appraisal
106
+
107
+ ## Releasing
108
+
109
+ Bump the gem version in the gemspec, and commit. Then `bundle exec rake build` to build a gem package, `bundle exec rake install` to install and test it locally, then `bundle exec rake release` to tag and push the commits and gem.
36
110
 
37
111
  ## License
38
112
 
39
- The MIT License, see [LICENSE][license].
113
+ The MIT License, see [LICENSE](./LICENSE).
114
+
115
+ ## Thanks
116
+
117
+ Inspired by the work of [Diego Souza][dgvncsz0f] on [RSpec Formatters][dgvncsz0f/rspec_formatters] after frustration with [CI Reporter][ci_reporter].
40
118
 
41
- [rspec]: http://rspec.info/
42
- [jenkins]: http://jenkins-ci.org/
43
119
  [dgvncsz0f]: https://github.com/dgvncsz0f
44
120
  [dgvncsz0f/rspec_formatters]: https://github.com/dgvncsz0f/rspec_formatters
45
- [ci_reporter]: http://caldersphere.rubyforge.org/ci_reporter/
46
- [bundler]: http://gembundler.com/
47
- [fuubar]: http://jeffkreeftmeijer.com/2010/fuubar-the-instafailing-rspec-progress-bar-formatter/
48
- [license]: https://github.com/sj26/rspec-junit-formatter/blob/master/LICENSE
121
+ [ci_reporter]: https://github.com/nicksieger/ci_reporter
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class RSpecJUnitFormatter < RSpec::Core::Formatters::BaseFormatter
2
4
  attr_reader :started
3
5
 
@@ -13,18 +15,21 @@ class RSpecJUnitFormatter < RSpec::Core::Formatters::BaseFormatter
13
15
 
14
16
  private
15
17
 
16
- def xml_dump_examples
17
- examples.each do |example|
18
- send :"xml_dump_#{example.execution_result[:status]}", example
19
- end
18
+ def result_of(example)
19
+ example.execution_result[:status].to_sym
20
20
  end
21
21
 
22
- def result_of(example)
23
- example.execution_result[:status]
22
+ def example_group_file_path_for(example)
23
+ meta = example.metadata
24
+ while meta[:example_group]
25
+ meta = meta[:example_group]
26
+ end
27
+ meta[:file_path]
24
28
  end
25
29
 
26
30
  def classname_for(example)
27
- example.file_path.sub(%r{\.[^/.]+\Z}, "").gsub("/", ".").gsub(/\A\.+|\.+\Z/, "")
31
+ fp = example_group_file_path_for(example)
32
+ fp.sub(%r{\.[^/.]+\Z}, "").gsub("/", ".").gsub(/\A\.+|\.+\Z/, "")
28
33
  end
29
34
 
30
35
  def duration_for(example)
@@ -39,7 +44,43 @@ private
39
44
  example.execution_result[:exception]
40
45
  end
41
46
 
42
- def formatted_backtrace_for(example)
43
- format_backtrace exception_for(example).backtrace, example
47
+ def failure_type_for(example)
48
+ exception_for(example).class.name
49
+ end
50
+
51
+ def failure_message_for(example)
52
+ strip_diff_colors(exception_for(example).to_s)
53
+ end
54
+
55
+ def failure_for(example)
56
+ exception = exception_for(example)
57
+ message = strip_diff_colors(exception.message)
58
+ backtrace = format_backtrace(exception.backtrace, example)
59
+
60
+ if shared_group = find_shared_group(example)
61
+ backtrace << "Shared Example Group: \"#{shared_group.metadata[:shared_group_name]}\" called from #{shared_group.metadata[:example_group][:location]}"
62
+ end
63
+
64
+ "#{message}\n#{backtrace.join("\n")}"
65
+ end
66
+
67
+ def error_count
68
+ 0
69
+ end
70
+
71
+ def find_shared_group(example)
72
+ group_and_parent_groups(example).find { |group| group.metadata[:shared_group_name] }
73
+ end
74
+
75
+ def group_and_parent_groups(example)
76
+ example.example_group.parent_groups + [example.example_group]
77
+ end
78
+
79
+ def stdout_for(example)
80
+ example.metadata[:stdout]
81
+ end
82
+
83
+ def stderr_for(example)
84
+ example.metadata[:stderr]
44
85
  end
45
86
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class RSpecJUnitFormatter < RSpec::Core::Formatters::BaseFormatter
2
4
  RSpec::Core::Formatters.register self,
3
5
  :start,
@@ -16,7 +18,7 @@ class RSpecJUnitFormatter < RSpec::Core::Formatters::BaseFormatter
16
18
 
17
19
  def dump_summary(notification)
18
20
  @summary_notification = notification
19
- xml_dump
21
+ without_color { xml_dump }
20
22
  end
21
23
 
22
24
  private
@@ -24,11 +26,15 @@ private
24
26
  attr_reader :started
25
27
 
26
28
  def example_count
27
- @summary_notification.examples.count
29
+ @summary_notification.example_count
30
+ end
31
+
32
+ def pending_count
33
+ @summary_notification.pending_count
28
34
  end
29
35
 
30
36
  def failure_count
31
- @summary_notification.failed_examples.count
37
+ @summary_notification.failure_count
32
38
  end
33
39
 
34
40
  def duration
@@ -39,27 +45,114 @@ private
39
45
  @examples_notification.notifications
40
46
  end
41
47
 
48
+ def error_count
49
+ # Introduced in rspec 3.6
50
+ if @summary_notification.respond_to?(:errors_outside_of_examples_count)
51
+ @summary_notification.errors_outside_of_examples_count
52
+ else
53
+ 0
54
+ end
55
+ end
56
+
42
57
  def result_of(notification)
43
- notification.example.execution_result[:status]
58
+ notification.example.execution_result.status
59
+ end
60
+
61
+ def example_group_file_path_for(notification)
62
+ metadata = notification.example.metadata[:example_group]
63
+ while parent_metadata = metadata[:parent_example_group]
64
+ metadata = parent_metadata
65
+ end
66
+ metadata[:file_path]
44
67
  end
45
68
 
46
69
  def classname_for(notification)
47
- notification.example.file_path.sub(%r{\.[^/]*\Z}, "").gsub("/", ".").gsub(%r{\A\.+|\.+\Z}, "")
70
+ fp = example_group_file_path_for(notification)
71
+ fp.sub(%r{\.[^/]*\Z}, "").gsub("/", ".").gsub(%r{\A\.+|\.+\Z}, "")
48
72
  end
49
73
 
50
74
  def duration_for(notification)
51
- notification.example.execution_result[:run_time]
75
+ notification.example.execution_result.run_time
52
76
  end
53
77
 
54
78
  def description_for(notification)
55
79
  notification.example.full_description
56
80
  end
57
81
 
82
+ def failure_type_for(example)
83
+ exception_for(example).class.name
84
+ end
85
+
86
+ def failure_message_for(example)
87
+ strip_diff_colors(exception_for(example).to_s)
88
+ end
89
+
90
+ def failure_for(notification)
91
+ strip_diff_colors(notification.message_lines.join("\n")) << "\n" << notification.formatted_backtrace.join("\n")
92
+ end
93
+
58
94
  def exception_for(notification)
59
- notification.example.execution_result[:exception]
95
+ notification.example.execution_result.exception
96
+ end
97
+
98
+ # rspec makes it really difficult to swap in configuration temporarily due to
99
+ # the way it cascades defaults, command line arguments, and user
100
+ # configuration. This method makes sure configuration gets swapped in
101
+ # correctly, but also that the original state is definitely restored.
102
+ def swap_rspec_configuration(key, value)
103
+ unset = Object.new
104
+ force = RSpec.configuration.send(:value_for, key) { unset }
105
+ if unset.equal?(force)
106
+ previous = RSpec.configuration.send(key)
107
+ RSpec.configuration.send(:"#{key}=", value)
108
+ else
109
+ RSpec.configuration.force({key => value})
110
+ end
111
+ yield
112
+ ensure
113
+ if unset.equal?(force)
114
+ RSpec.configuration.send(:"#{key}=", previous)
115
+ else
116
+ RSpec.configuration.force({key => force})
117
+ end
118
+ end
119
+
120
+ # Completely gross hack for absolutely forcing off colorising for the
121
+ # duration of a block.
122
+ if RSpec.configuration.respond_to?(:color_mode=)
123
+ def without_color(&block)
124
+ swap_rspec_configuration(:color_mode, :off, &block)
125
+ end
126
+ elsif RSpec.configuration.respond_to?(:color=)
127
+ def without_color(&block)
128
+ swap_rspec_configuration(:color, false, &block)
129
+ end
130
+ else
131
+ warn 'rspec_junit_formatter cannot prevent colorising due to an unexpected RSpec.configuration format'
132
+ def without_color
133
+ yield
134
+ end
60
135
  end
61
136
 
62
- def formatted_backtrace_for(notification)
63
- backtrace = notification.formatted_backtrace
137
+ def stdout_for(example_notification)
138
+ example_notification.example.metadata[:stdout]
139
+ end
140
+
141
+ def stderr_for(example_notification)
142
+ example_notification.example.metadata[:stderr]
143
+ end
144
+ end
145
+
146
+ # rspec-core 3.0.x forgot to mark this as a module function which causes:
147
+ #
148
+ # NoMethodError: undefined method `wrap' for RSpec::Core::Notifications::NullColorizer:Class
149
+ # .../rspec-core-3.0.4/lib/rspec/core/notifications.rb:229:in `add_shared_group_line'
150
+ # .../rspec-core-3.0.4/lib/rspec/core/notifications.rb:157:in `message_lines'
151
+ #
152
+ if defined?(RSpec::Core::Notifications::NullColorizer) && RSpec::Core::Notifications::NullColorizer.is_a?(Class) && !RSpec::Core::Notifications::NullColorizer.respond_to?(:wrap)
153
+ RSpec::Core::Notifications::NullColorizer.class_eval do
154
+ def self.wrap(*args)
155
+ new.wrap(*args)
156
+ end
64
157
  end
65
158
  end
@@ -1,8 +1,9 @@
1
- require "time"
1
+ # frozen_string_literal: true
2
2
 
3
- require "builder"
4
- require "rspec"
3
+ require "socket"
4
+ require "time"
5
5
 
6
+ require "rspec/core"
6
7
  require "rspec/core/formatters/base_formatter"
7
8
 
8
9
  # Dumps rspec results as a JUnit XML file.
@@ -12,54 +13,183 @@ class RSpecJUnitFormatter < RSpec::Core::Formatters::BaseFormatter
12
13
 
13
14
  private
14
15
 
15
- def xml
16
- @xml ||= Builder::XmlMarkup.new target: output, indent: 2
17
- end
18
-
19
16
  def xml_dump
20
- xml.instruct!
21
- xml.testsuite name: "rspec", tests: example_count, failures: failure_count, errors: 0, time: "%.6f" % duration, timestamp: started.iso8601 do
22
- xml.properties
23
- xml_dump_examples
24
- end
17
+ output << %{<?xml version="1.0" encoding="UTF-8"?>\n}
18
+ output << %{<testsuite}
19
+ output << %{ name="rspec#{escape(ENV["TEST_ENV_NUMBER"].to_s)}"}
20
+ output << %{ tests="#{example_count}"}
21
+ output << %{ skipped="#{pending_count}"}
22
+ output << %{ failures="#{failure_count}"}
23
+ output << %{ errors="#{error_count}"}
24
+ output << %{ time="#{escape("%.6f" % duration)}"}
25
+ output << %{ timestamp="#{escape(started.iso8601)}"}
26
+ output << %{ hostname="#{escape(Socket.gethostname)}"}
27
+ output << %{>\n}
28
+ output << %{<properties>\n}
29
+ output << %{<property}
30
+ output << %{ name="seed"}
31
+ output << %{ value="#{escape(RSpec.configuration.seed.to_s)}"}
32
+ output << %{/>\n}
33
+ output << %{</properties>\n}
34
+ xml_dump_examples
35
+ output << %{</testsuite>\n}
25
36
  end
26
37
 
27
38
  def xml_dump_examples
28
39
  examples.each do |example|
29
- send :"xml_dump_#{result_of(example)}", example
40
+ case result_of(example)
41
+ when :pending
42
+ xml_dump_pending(example)
43
+ when :failed
44
+ xml_dump_failed(example)
45
+ else
46
+ xml_dump_example(example)
47
+ end
30
48
  end
31
49
  end
32
50
 
33
- def xml_dump_passed(example)
34
- xml_dump_example(example)
35
- end
36
-
37
51
  def xml_dump_pending(example)
38
52
  xml_dump_example(example) do
39
- xml.skipped
53
+ output << %{<skipped/>}
40
54
  end
41
55
  end
42
56
 
43
57
  def xml_dump_failed(example)
44
- exception = exception_for(example)
45
- backtrace = formatted_backtrace_for(example)
46
-
47
58
  xml_dump_example(example) do
48
- xml.failure message: exception.to_s, type: exception.class.name do
49
- xml.cdata! "#{exception.message}\n#{backtrace.join "\n"}"
50
- end
59
+ output << %{<failure}
60
+ output << %{ message="#{escape(failure_message_for(example))}"}
61
+ output << %{ type="#{escape(failure_type_for(example))}"}
62
+ output << %{>}
63
+ output << escape(failure_for(example))
64
+ output << %{</failure>}
65
+ end
66
+ end
67
+
68
+ def xml_dump_example(example)
69
+ output << %{<testcase}
70
+ output << %{ classname="#{escape(classname_for(example))}"}
71
+ output << %{ name="#{escape(description_for(example))}"}
72
+ output << %{ file="#{escape(example_group_file_path_for(example))}"}
73
+ if duration = duration_for(example)
74
+ output << %{ time="#{escape("%.6f" % duration)}"}
51
75
  end
76
+ output << %{>}
77
+ yield if block_given?
78
+ xml_dump_output(example)
79
+ output << %{</testcase>\n}
52
80
  end
53
81
 
54
- def xml_dump_example(example, &block)
55
- xml.testcase classname: classname_for(example), name: description_for(example), time: "%.6f" % duration_for(example), &block
82
+ def xml_dump_output(example)
83
+ if (stdout = stdout_for(example)) && !stdout.empty?
84
+ output << %{<system-out>}
85
+ output << escape(stdout)
86
+ output << %{</system-out>}
87
+ end
88
+
89
+ if (stderr = stderr_for(example)) && !stderr.empty?
90
+ output << %{<system-err>}
91
+ output << escape(stderr)
92
+ output << %{</system-err>}
93
+ end
94
+ end
95
+
96
+ # Inversion of character range from https://www.w3.org/TR/xml/#charsets
97
+ ILLEGAL_REGEXP = Regexp.new(
98
+ "[^".dup <<
99
+ "\u{9}" << # => \t
100
+ "\u{a}" << # => \n
101
+ "\u{d}" << # => \r
102
+ "\u{20}-\u{d7ff}" <<
103
+ "\u{e000}-\u{fffd}" <<
104
+ "\u{10000}-\u{10ffff}" <<
105
+ "]"
106
+ )
107
+
108
+ # Replace illegals with a Ruby-like escape
109
+ ILLEGAL_REPLACEMENT = Hash.new { |_, c|
110
+ x = c.ord
111
+ if x <= 0xff
112
+ "\\x%02X".freeze % x
113
+ elsif x <= 0xffff
114
+ "\\u%04X".freeze % x
115
+ else
116
+ "\\u{%X}".freeze % x
117
+ end.freeze
118
+ }.update(
119
+ "\0".freeze => "\\0".freeze,
120
+ "\a".freeze => "\\a".freeze,
121
+ "\b".freeze => "\\b".freeze,
122
+ "\f".freeze => "\\f".freeze,
123
+ "\v".freeze => "\\v".freeze,
124
+ "\e".freeze => "\\e".freeze,
125
+ ).freeze
126
+
127
+ # Discouraged characters from https://www.w3.org/TR/xml/#charsets
128
+ # Plus special characters with well-known entity replacements
129
+ DISCOURAGED_REGEXP = Regexp.new(
130
+ "[".dup <<
131
+ "\u{22}" << # => "
132
+ "\u{26}" << # => &
133
+ "\u{27}" << # => '
134
+ "\u{3c}" << # => <
135
+ "\u{3e}" << # => >
136
+ "\u{7f}-\u{84}" <<
137
+ "\u{86}-\u{9f}" <<
138
+ "\u{fdd0}-\u{fdef}" <<
139
+ "\u{1fffe}-\u{1ffff}" <<
140
+ "\u{2fffe}-\u{2ffff}" <<
141
+ "\u{3fffe}-\u{3ffff}" <<
142
+ "\u{4fffe}-\u{4ffff}" <<
143
+ "\u{5fffe}-\u{5ffff}" <<
144
+ "\u{6fffe}-\u{6ffff}" <<
145
+ "\u{7fffe}-\u{7ffff}" <<
146
+ "\u{8fffe}-\u{8ffff}" <<
147
+ "\u{9fffe}-\u{9ffff}" <<
148
+ "\u{afffe}-\u{affff}" <<
149
+ "\u{bfffe}-\u{bffff}" <<
150
+ "\u{cfffe}-\u{cffff}" <<
151
+ "\u{dfffe}-\u{dffff}" <<
152
+ "\u{efffe}-\u{effff}" <<
153
+ "\u{ffffe}-\u{fffff}" <<
154
+ "\u{10fffe}-\u{10ffff}" <<
155
+ "]"
156
+ )
157
+
158
+ # Translate well-known entities, or use generic unicode hex entity
159
+ DISCOURAGED_REPLACEMENTS = Hash.new { |_, c| "&#x#{c.ord.to_s(16)};".freeze }.update(
160
+ ?".freeze => "&quot;".freeze,
161
+ ?&.freeze => "&amp;".freeze,
162
+ ?'.freeze => "&apos;".freeze,
163
+ ?<.freeze => "&lt;".freeze,
164
+ ?>.freeze => "&gt;".freeze,
165
+ ).freeze
166
+
167
+ def escape(text)
168
+ # Make sure it's utf-8, replace illegal characters with ruby-like escapes, and replace special and discouraged characters with entities
169
+ text.to_s.encode(Encoding::UTF_8).gsub(ILLEGAL_REGEXP, ILLEGAL_REPLACEMENT).gsub(DISCOURAGED_REGEXP, DISCOURAGED_REPLACEMENTS)
170
+ end
171
+
172
+ STRIP_DIFF_COLORS_BLOCK_REGEXP = /^ ( [ ]* ) Diff: (?: \e\[ 0 m )? (?: \n \1 \e\[ \d+ (?: ; \d+ )* m .* )* /x
173
+ STRIP_DIFF_COLORS_CODES_REGEXP = /\e\[ \d+ (?: ; \d+ )* m/x
174
+
175
+ def strip_diff_colors(string)
176
+ # XXX: RSpec diffs are appended to the message lines fairly early and will
177
+ # contain ANSI escape codes for colorizing terminal output if the global
178
+ # rspec configuration is turned on, regardless of which notification lines
179
+ # we ask for. We need to strip the codes from the diff part of the message
180
+ # for XML output here.
181
+ #
182
+ # We also only want to target the diff hunks because the failure message
183
+ # itself might legitimately contain ansi escape codes.
184
+ #
185
+ string.sub(STRIP_DIFF_COLORS_BLOCK_REGEXP) { |match| match.gsub(STRIP_DIFF_COLORS_CODES_REGEXP, "".freeze) }
56
186
  end
57
187
  end
58
188
 
59
189
  RspecJunitFormatter = RSpecJUnitFormatter
60
190
 
61
- if RSpec::Version::STRING.start_with? "3."
191
+ if Gem::Version.new(RSpec::Core::Version::STRING) >= Gem::Version.new("3")
62
192
  require "rspec_junit_formatter/rspec3"
63
- else RSpec::Version::STRING.start_with? "2."
193
+ else
64
194
  require "rspec_junit_formatter/rspec2"
65
195
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,37 +1,38 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec_junit_formatter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Cochran
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
- MIIDKDCCAhCgAwIBAgIBAjANBgkqhkiG9w0BAQUFADA6MQ0wCwYDVQQDDARzajI2
14
- MRQwEgYKCZImiZPyLGQBGRYEc2oyNjETMBEGCgmSJomT8ixkARkWA2NvbTAeFw0x
15
- NDAzMTUwNDM2MTZaFw0xNTAzMTUwNDM2MTZaMDoxDTALBgNVBAMMBHNqMjYxFDAS
13
+ MIIDXDCCAkSgAwIBAgIBATANBgkqhkiG9w0BAQsFADA6MQ0wCwYDVQQDDARzajI2
14
+ MRQwEgYKCZImiZPyLGQBGRYEc2oyNjETMBEGCgmSJomT8ixkARkWA2NvbTAeFw0y
15
+ MjA3MDQwMDQwNDZaFw0yMzA3MDQwMDQwNDZaMDoxDTALBgNVBAMMBHNqMjYxFDAS
16
16
  BgoJkiaJk/IsZAEZFgRzajI2MRMwEQYKCZImiZPyLGQBGRYDY29tMIIBIjANBgkq
17
17
  hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr60Eo/ttCk8GMTMFiPr3GoYMIMFvLak
18
18
  xSmTk9YGCB6UiEePB4THSSA5w6IPyeaCF/nWkDp3/BAam0eZMWG1IzYQB23TqIM0
19
19
  1xzcNRvFsn0aQoQ00k+sj+G83j3T5OOV5OZIlu8xAChMkQmiPd1NXc6uFv+Iacz7
20
20
  kj+CMsI9YUFdNoU09QY0b+u+Rb6wDYdpyvN60YC30h0h1MeYbvYZJx/iZK4XY5zu
21
21
  4O/FL2ChjL2CPCpLZW55ShYyrzphWJwLOJe+FJ/ZBl6YXwrzQM9HKnt4titSNvyU
22
- KzE3L63A3PZvExzLrN9u09kuWLLJfXB2sGOlw3n9t72rJiuBr3/OQQIDAQABozkw
23
- NzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQU99dfRjEKFyczTeIz
24
- m3ZsDWrNC80wDQYJKoZIhvcNAQEFBQADggEBAFVYjABGprFHcomF60jQZojPyBVj
25
- IBUmAKQ2UEserCwV8GbzxKn9/C+cqO109m1KckeGvFDSvUToBUIEzj5xKNMLJCYJ
26
- xjH30ex7X0LDgqI4z4Z9eXiIR61d9haKEDpqVRKrERMcf4HAyvQoNmYtVTesVNJr
27
- rWOeOPhl1Is+NdYcm1c99Y1ltcstn762ROxVCFk9c6Xe9mrDgB5oBW+LKOY2YCjD
28
- HLacq0o6ejD7AFG3HPAVFeYEnrwCYd6siMnzpVrt3pHfZJxsuhbNnteASNcnk9Uk
29
- YIxHmqJUGGnmqwuBfXe8LZHC5ETJLuZlzO2odzNueQlhukD4wdNa/r4pD1o=
22
+ KzE3L63A3PZvExzLrN9u09kuWLLJfXB2sGOlw3n9t72rJiuBr3/OQQIDAQABo20w
23
+ azAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQU99dfRjEKFyczTeIz
24
+ m3ZsDWrNC80wGAYDVR0RBBEwD4ENc2oyNkBzajI2LmNvbTAYBgNVHRIEETAPgQ1z
25
+ ajI2QHNqMjYuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQCsa7k3TABBcyXotr3yCq6f
26
+ xsgbMG9FR71c4wRgVNQi9O3jN64fQBbxo//BQlHfPCjs1CeU4es9xdQFfhqXAPXG
27
+ P7mK3+qd5jObjh6l3/rDKrTXNS+P+YO/1frlZ6xPjCA8XgGc4y0rhAjZnVBDV6t1
28
+ kmdtEmue1s1OxaMakr78XRZDxEuAeLM5fg8MYnlOFygEcAH6lZkTjXavY7s9MXRB
29
+ AAMioxgB6J5QhXQ42OSWIzwHZIbSv3DV9Lf5sde50HIW5f9u5jn29TUGDhSWYKkh
30
+ LDvy9dfwMMOdIZi75Q8SBBib84AuwhMHIlUv9FcHhh3dXsDDYkrVrpUAwCsG6yCm
30
31
  -----END CERTIFICATE-----
31
- date: 2014-06-04 00:00:00.000000000 Z
32
+ date: 2022-09-29 00:00:00.000000000 Z
32
33
  dependencies:
33
34
  - !ruby/object:Gem::Dependency
34
- name: rspec
35
+ name: rspec-core
35
36
  requirement: !ruby/object:Gem::Requirement
36
37
  requirements:
37
38
  - - ">="
@@ -40,6 +41,9 @@ dependencies:
40
41
  - - "<"
41
42
  - !ruby/object:Gem::Version
42
43
  version: '4'
44
+ - - "!="
45
+ - !ruby/object:Gem::Version
46
+ version: 2.12.0
43
47
  type: :runtime
44
48
  prerelease: false
45
49
  version_requirements: !ruby/object:Gem::Requirement
@@ -50,49 +54,86 @@ dependencies:
50
54
  - - "<"
51
55
  - !ruby/object:Gem::Version
52
56
  version: '4'
57
+ - - "!="
58
+ - !ruby/object:Gem::Version
59
+ version: 2.12.0
53
60
  - !ruby/object:Gem::Dependency
54
- name: rspec-core
61
+ name: bundler
55
62
  requirement: !ruby/object:Gem::Requirement
56
63
  requirements:
57
- - - "!="
64
+ - - ">="
58
65
  - !ruby/object:Gem::Version
59
- version: 2.12.0
60
- type: :runtime
66
+ version: '0'
67
+ type: :development
61
68
  prerelease: false
62
69
  version_requirements: !ruby/object:Gem::Requirement
63
70
  requirements:
64
- - - "!="
71
+ - - ">="
65
72
  - !ruby/object:Gem::Version
66
- version: 2.12.0
73
+ version: '0'
67
74
  - !ruby/object:Gem::Dependency
68
- name: builder
75
+ name: appraisal
69
76
  requirement: !ruby/object:Gem::Requirement
70
77
  requirements:
71
- - - "<"
78
+ - - ">="
72
79
  - !ruby/object:Gem::Version
73
- version: '4'
74
- type: :runtime
80
+ version: '0'
81
+ type: :development
75
82
  prerelease: false
76
83
  version_requirements: !ruby/object:Gem::Requirement
77
84
  requirements:
78
- - - "<"
85
+ - - ">="
79
86
  - !ruby/object:Gem::Version
80
- version: '4'
87
+ version: '0'
81
88
  - !ruby/object:Gem::Dependency
82
89
  name: nokogiri
83
90
  requirement: !ruby/object:Gem::Requirement
84
91
  requirements:
85
92
  - - "~>"
86
93
  - !ruby/object:Gem::Version
87
- version: '1.6'
94
+ version: '1.8'
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: 1.8.2
88
98
  type: :development
89
99
  prerelease: false
90
100
  version_requirements: !ruby/object:Gem::Requirement
91
101
  requirements:
92
102
  - - "~>"
93
103
  - !ruby/object:Gem::Version
94
- version: '1.6'
95
- description: RSpec results that Hudson can read.
104
+ version: '1.8'
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: 1.8.2
108
+ - !ruby/object:Gem::Dependency
109
+ name: rake
110
+ requirement: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ type: :development
116
+ prerelease: false
117
+ version_requirements: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ - !ruby/object:Gem::Dependency
123
+ name: coderay
124
+ requirement: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ type: :development
130
+ prerelease: false
131
+ version_requirements: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ description: RSpec results that your continuous integration service can read.
96
137
  email: sj26@sj26.com
97
138
  executables: []
98
139
  extensions: []
@@ -103,11 +144,12 @@ files:
103
144
  - lib/rspec_junit_formatter.rb
104
145
  - lib/rspec_junit_formatter/rspec2.rb
105
146
  - lib/rspec_junit_formatter/rspec3.rb
106
- homepage: http://github.com/sj26/rspec_junit_formatter
147
+ homepage: https://github.com/sj26/rspec_junit_formatter
107
148
  licenses:
108
149
  - MIT
109
- metadata: {}
110
- post_install_message:
150
+ metadata:
151
+ changelog_uri: https://github.com/sj26/rspec_junit_formatter/blob/HEAD/CHANGELOG.md
152
+ post_install_message:
111
153
  rdoc_options: []
112
154
  require_paths:
113
155
  - lib
@@ -115,16 +157,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
115
157
  requirements:
116
158
  - - ">="
117
159
  - !ruby/object:Gem::Version
118
- version: '0'
160
+ version: 2.3.0
119
161
  required_rubygems_version: !ruby/object:Gem::Requirement
120
162
  requirements:
121
163
  - - ">="
122
164
  - !ruby/object:Gem::Version
123
- version: 1.3.6
165
+ version: 2.0.0
124
166
  requirements: []
125
- rubyforge_project:
126
- rubygems_version: 2.2.2
127
- signing_key:
167
+ rubygems_version: 3.3.7
168
+ signing_key:
128
169
  specification_version: 4
129
170
  summary: RSpec JUnit XML formatter
130
171
  test_files: []
metadata.gz.sig CHANGED
Binary file