rspec_junit_formatter 0.2.3 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: aba33189eb6723f651a6d245f76fbd9c875339d8
4
- data.tar.gz: 9de71e43b41fd5772143206cf51657380790042d
2
+ SHA256:
3
+ metadata.gz: 903f156687c6fff260143332222e9950fca53b5306bcde7cf197c44f3af4acf7
4
+ data.tar.gz: 1d2ffca113b3cd78b3230d66ed41268609ce38f06e50da6cd196af9073670500
5
5
  SHA512:
6
- metadata.gz: 53f6734e3e839de30f60d22ed80371a458927796e46ea6b2ec2b2d8a8a9e00ef7ffd3d5dd663151de5be1aed33dd2de0e716bc79c1a84cb757292a7f943469d5
7
- data.tar.gz: 50d33e7d36886ea36679b02871771c482e2d3aacd7fd94c4accb08e49c4858db2857ab90f1e5e215e2b78769a50c861e228d23a1177b863ae9d2879b03a39796
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,49 +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)
4
- [![Gem version](http://img.shields.io/gem/v/rspec_junit_formatter.svg)](https://rubygems.org/gem/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)
5
5
 
6
- [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.
7
7
 
8
- 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
9
13
 
10
14
  ## Usage
11
15
 
12
16
  Install the gem:
13
17
 
14
- gem install rspec_junit_formatter
18
+ ```sh
19
+ gem install rspec_junit_formatter
20
+ ```
15
21
 
16
22
  Use it:
17
23
 
18
- 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:
19
31
 
20
- You'll get an XML file with your results in it.
32
+ ```sh
33
+ rspec --format progress --format RspecJunitFormatter --out rspec.xml
34
+ ```
21
35
 
22
- ## 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
23
39
 
24
40
  Add it to your Gemfile if you're using [Bundler][bundler]. Put it in the same groups as rspec.
25
41
 
26
- 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
27
75
 
28
- --format RspecJunitFormatter
29
- --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
30
81
 
31
- I use it with the excellent [Fuubar formatter][fuubar].
82
+ example.run
32
83
 
33
- ## Roadmap
84
+ example.metadata[:stdout] = $stdout.string
85
+ example.metadata[:stderr] = $stderr.string
34
86
 
35
- * 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.
36
- * 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.
37
110
 
38
111
  ## License
39
112
 
40
- 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].
41
118
 
42
- [rspec]: http://rspec.info/
43
- [jenkins]: http://jenkins-ci.org/
44
119
  [dgvncsz0f]: https://github.com/dgvncsz0f
45
120
  [dgvncsz0f/rspec_formatters]: https://github.com/dgvncsz0f/rspec_formatters
46
121
  [ci_reporter]: https://github.com/nicksieger/ci_reporter
47
- [bundler]: http://gembundler.com/
48
- [fuubar]: http://jeffkreeftmeijer.com/2010/fuubar-the-instafailing-rspec-progress-bar-formatter/
49
- [license]: https://github.com/sj26/rspec-junit-formatter/blob/master/LICENSE
@@ -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,14 +15,8 @@ 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
20
- end
21
-
22
18
  def result_of(example)
23
- example.execution_result[:status]
19
+ example.execution_result[:status].to_sym
24
20
  end
25
21
 
26
22
  def example_group_file_path_for(example)
@@ -48,7 +44,43 @@ private
48
44
  example.execution_result[:exception]
49
45
  end
50
46
 
51
- def formatted_backtrace_for(example)
52
- 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]
53
85
  end
54
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,12 +45,25 @@ 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
58
  notification.example.execution_result.status
44
59
  end
45
60
 
46
61
  def example_group_file_path_for(notification)
47
- notification.example.example_group.file_path
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]
48
67
  end
49
68
 
50
69
  def classname_for(notification)
@@ -60,11 +79,80 @@ private
60
79
  notification.example.full_description
61
80
  end
62
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
+
63
94
  def exception_for(notification)
64
95
  notification.example.execution_result.exception
65
96
  end
66
97
 
67
- def formatted_backtrace_for(notification)
68
- notification.formatted_backtrace
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
135
+ end
136
+
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
69
157
  end
70
158
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "socket"
1
4
  require "time"
2
- require "builder"
3
5
 
4
6
  require "rspec/core"
5
7
  require "rspec/core/formatters/base_formatter"
@@ -11,55 +13,183 @@ class RSpecJUnitFormatter < RSpec::Core::Formatters::BaseFormatter
11
13
 
12
14
  private
13
15
 
14
- def xml
15
- @xml ||= Builder::XmlMarkup.new target: output, indent: 2
16
- end
17
-
18
16
  def xml_dump
19
- xml.instruct!
20
- xml.testsuite name: "rspec#{ENV['TEST_ENV_NUMBER']}", tests: example_count, failures: failure_count, errors: 0, time: "%.6f" % duration, timestamp: started.iso8601 do
21
- xml.comment! "Randomized with seed #{RSpec.configuration.seed}"
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), file: example_group_file_path_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::Core::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::Core::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,34 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec_junit_formatter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
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
- MIIDKDCCAhCgAwIBAgIBAzANBgkqhkiG9w0BAQUFADA6MQ0wCwYDVQQDDARzajI2
14
- MRQwEgYKCZImiZPyLGQBGRYEc2oyNjETMBEGCgmSJomT8ixkARkWA2NvbTAeFw0x
15
- NTAzMTcyMjUwMjZaFw0xNjAzMTYyMjUwMjZaMDoxDTALBgNVBAMMBHNqMjYxFDAS
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
- m3ZsDWrNC80wDQYJKoZIhvcNAQEFBQADggEBAFxKLjiLkMLkUmdpsAzJad/t7Jo/
25
- CGby/3n0WSXPBeZJfsnSdJ2qtG7iy/xqYDc1RjpKgX0RlMgeQRSE3ZDL/HZzBKDF
26
- azaTgG9Zk1Quu59/79Z0Sltq07Z/IeccFl5j9M+1YS8VY2mOPi9g03OoOSRmhsMS
27
- wpEF+zvJ0ESS5OPjtp6Sk4q1QYc0aVIthEznuVNMW6CPpTNhMAOFMaTC5AXCzJ3Q
28
- 52G9HuhbVSTgE/I10H9qZBOE3qdP8ka/Fk0PUrux/DuUanNZgSKJokrQvRA4H9Au
29
- WpPA7HJYV6msWQiukoBEhfQ2l6Fl2HUwntvX3MCcFNHeJJ5ETERp9alo88E=
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: 2015-06-03 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
35
  name: rspec-core
@@ -57,34 +58,82 @@ dependencies:
57
58
  - !ruby/object:Gem::Version
58
59
  version: 2.12.0
59
60
  - !ruby/object:Gem::Dependency
60
- name: builder
61
+ name: bundler
61
62
  requirement: !ruby/object:Gem::Requirement
62
63
  requirements:
63
- - - "<"
64
+ - - ">="
64
65
  - !ruby/object:Gem::Version
65
- version: '4'
66
- type: :runtime
66
+ version: '0'
67
+ type: :development
67
68
  prerelease: false
68
69
  version_requirements: !ruby/object:Gem::Requirement
69
70
  requirements:
70
- - - "<"
71
+ - - ">="
71
72
  - !ruby/object:Gem::Version
72
- version: '4'
73
+ version: '0'
74
+ - !ruby/object:Gem::Dependency
75
+ name: appraisal
76
+ requirement: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ type: :development
82
+ prerelease: false
83
+ version_requirements: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
73
88
  - !ruby/object:Gem::Dependency
74
89
  name: nokogiri
75
90
  requirement: !ruby/object:Gem::Requirement
76
91
  requirements:
77
92
  - - "~>"
78
93
  - !ruby/object:Gem::Version
79
- version: '1.6'
94
+ version: '1.8'
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: 1.8.2
80
98
  type: :development
81
99
  prerelease: false
82
100
  version_requirements: !ruby/object:Gem::Requirement
83
101
  requirements:
84
102
  - - "~>"
85
103
  - !ruby/object:Gem::Version
86
- version: '1.6'
87
- 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.
88
137
  email: sj26@sj26.com
89
138
  executables: []
90
139
  extensions: []
@@ -95,11 +144,12 @@ files:
95
144
  - lib/rspec_junit_formatter.rb
96
145
  - lib/rspec_junit_formatter/rspec2.rb
97
146
  - lib/rspec_junit_formatter/rspec3.rb
98
- homepage: http://github.com/sj26/rspec_junit_formatter
147
+ homepage: https://github.com/sj26/rspec_junit_formatter
99
148
  licenses:
100
149
  - MIT
101
- metadata: {}
102
- post_install_message:
150
+ metadata:
151
+ changelog_uri: https://github.com/sj26/rspec_junit_formatter/blob/HEAD/CHANGELOG.md
152
+ post_install_message:
103
153
  rdoc_options: []
104
154
  require_paths:
105
155
  - lib
@@ -107,16 +157,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
107
157
  requirements:
108
158
  - - ">="
109
159
  - !ruby/object:Gem::Version
110
- version: '0'
160
+ version: 2.3.0
111
161
  required_rubygems_version: !ruby/object:Gem::Requirement
112
162
  requirements:
113
163
  - - ">="
114
164
  - !ruby/object:Gem::Version
115
- version: 1.3.6
165
+ version: 2.0.0
116
166
  requirements: []
117
- rubyforge_project:
118
- rubygems_version: 2.4.5
119
- signing_key:
167
+ rubygems_version: 3.3.7
168
+ signing_key:
120
169
  specification_version: 4
121
170
  summary: RSpec JUnit XML formatter
122
171
  test_files: []
metadata.gz.sig CHANGED
Binary file