New Upstream Release - ruby-rspec-junit-formatter

Ready changes

Summary

Merged new upstream version: 0.6.0 (was: 0.4.1).

Resulting package

Built on 2022-12-29T15:22 (took 5m33s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases ruby-rspec-junit-formatter

Lintian Result

Diff

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..dc2c6ae
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,37 @@
+name: CI
+
+on:
+  push:
+    branches: [ main ]
+  pull_request: 
+    branches: [ main ]
+
+jobs:
+  test:
+    strategy:
+      matrix:
+        ruby-version: ["2.6", "2.7", "3.0", "3.1"]
+        rspec-version: ["2_x", "3_0", "3_1", "3_2", "3_3", "3_4", "3_5", "3_6", "3_7", "3_8", "3_9", "3_10"]
+
+    runs-on: ubuntu-latest
+
+    env:
+      BUNDLE_GEMFILE: gemfiles/rspec_${{ matrix.rspec-version }}.gemfile
+
+    steps:
+    - uses: actions/checkout@v2
+
+    - uses: ruby/setup-ruby@v1
+      with:
+        ruby-version: ${{ matrix.ruby-version }}
+        bundler-cache: true
+
+    - name: Run tests
+      run: bundle exec rake
+
+    - name: Upload test artifacts
+      uses: actions/upload-artifact@v2
+      if: always()
+      with:
+        name: test-artifacts
+        path: tmp
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..451a832
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+/.bundle/
+/doc/
+/example/tmp/
+/pkg/
+/tmp/
diff --git a/Appraisals b/Appraisals
new file mode 100644
index 0000000..55d8ebb
--- /dev/null
+++ b/Appraisals
@@ -0,0 +1,52 @@
+appraise "rspec-2-x" do
+  gem "rspec", "~> 2.14", "< 2.99"
+  gem "rake", "~> 10.0" # Rake.last_comment
+end
+
+appraise "rspec-3-0" do
+  gem "rspec", "~> 3.0.0"
+  gem "rake", "~> 10.0" # Rake.last_comment
+end
+
+appraise "rspec-3-1" do
+  gem "rspec", "~> 3.1.0"
+  gem "rake", "~> 10.0" # Rake.last_comment
+end
+
+appraise "rspec-3-2" do
+  gem "rspec", "~> 3.2.0"
+  gem "rake", "~> 10.0" # Rake.last_comment
+end
+
+appraise "rspec-3-3" do
+  gem "rspec", "~> 3.3.0"
+  gem "rake", "~> 10.0" # Rake.last_comment
+end
+
+appraise "rspec-3-4" do
+  gem "rspec", "~> 3.4.0"
+end
+
+appraise "rspec-3-5" do
+  gem "rspec", "~> 3.5.0"
+end
+
+appraise "rspec-3-6" do
+  gem "rspec", "~> 3.6.0"
+end
+
+appraise "rspec-3-7" do
+  gem "rspec", "~> 3.7.0"
+end
+
+appraise "rspec-3-8" do
+  gem "rspec", "~> 3.8.0"
+end
+
+appraise "rspec-3-9" do
+  gem "rspec", "~> 3.9.0"
+end
+
+appraise "rspec-3-10" do
+  gem "rspec", "~> 3.10.0"
+end
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..692388b
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,50 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog] and this project adheres to [Semantic Versioning].
+
+  [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/
+  [Semantic Versioning]: http://semver.org/spec/v2.0.0.html
+
+## [Unreleased]
+
+  [Unreleased]: https://github.com/sj26/rspec_junit_formatter/compare/v0.6.0...main
+
+## [v0.6.0]
+### Changed
+- Restrict to Ruby 2.3+
+### Fixed
+- Fix handling of nil durations
+
+  [v0.6.0]: https://github.com/sj26/rspec_junit_formatter/compare/v0.5.1...v0.6.0
+
+## [v0.5.1] - 2022-01-06
+### Fixed
+- Fixed compatibility with older rubies
+
+  [v0.5.1]: https://github.com/sj26/rspec_junit_formatter/compare/v0.5.0...v0.5.1
+
+## [v0.5.0] - 2022-01-04
+### Added
+- Added support to read outside error count returned from XML formatter (#86)
+### Changed
+- Moved to GitHub Actions for CI
+- Test on current Ruby and RSpec versions
+
+  [v0.5.0]: https://github.com/sj26/rspec_junit_formatter/compare/v0.4.1...v0.5.0
+
+## [v0.4.1] - 2018-05-26
+### Fixed
+- Diff ANSI stripping now works for codes with multiple tags, too
+
+  [v0.4.1]: https://github.com/sj26/rspec_junit_formatter/compare/v0.4.0...v0.4.1
+
+## [v0.4.0] - 2018-05-26
+### Added
+- Add support for including STDOUT and STDERR from tests in the JUnit output (see ["Capturing output"] in the readme for details)
+### Fixed
+- When RSpec includes a diff in its output, strip out ANSI escape codes used to color it for shell display
+
+  [v0.4.0]: https://github.com/sj26/rspec_junit_formatter/compare/v0.3.0...v0.4.0
+  ["Capturing output"]: https://github.com/sj26/rspec_junit_formatter#capturing-output
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..83f1f9d
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,5 @@
+source "https://rubygems.org"
+
+gemspec
+
+gem "rspec"
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000..793e5be
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,50 @@
+PATH
+  remote: .
+  specs:
+    rspec_junit_formatter (0.6.0)
+      rspec-core (>= 2, < 4, != 2.12.0)
+
+GEM
+  remote: https://rubygems.org/
+  specs:
+    appraisal (2.4.1)
+      bundler
+      rake
+      thor (>= 0.14.0)
+    coderay (1.1.3)
+    diff-lcs (1.5.0)
+    mini_portile2 (2.8.0)
+    nokogiri (1.13.4)
+      mini_portile2 (~> 2.8.0)
+      racc (~> 1.4)
+    racc (1.6.0)
+    rake (13.0.6)
+    rspec (3.10.0)
+      rspec-core (~> 3.10.0)
+      rspec-expectations (~> 3.10.0)
+      rspec-mocks (~> 3.10.0)
+    rspec-core (3.10.1)
+      rspec-support (~> 3.10.0)
+    rspec-expectations (3.10.1)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.10.0)
+    rspec-mocks (3.10.2)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.10.0)
+    rspec-support (3.10.3)
+    thor (1.1.0)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  appraisal
+  bundler
+  coderay
+  nokogiri (~> 1.8, >= 1.8.2)
+  rake
+  rspec
+  rspec_junit_formatter!
+
+BUNDLED WITH
+   2.2.26
diff --git a/LICENSE b/LICENSE
index e8ad393..2df682c 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2011-2018 Samuel Cochran
+Copyright (c) 2011-2022 Samuel Cochran
 
 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
diff --git a/README.md b/README.md
index 331c49a..1872724 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,15 @@
 # RSpec JUnit Formatter
 
-[![Build results](http://img.shields.io/travis/sj26/rspec_junit_formatter/master.svg)](https://travis-ci.org/sj26/rspec_junit_formatter) 
+[![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) 
 [![Gem version](http://img.shields.io/gem/v/rspec_junit_formatter.svg)](https://rubygems.org/gems/rspec_junit_formatter)
 
-[RSpec][rspec] 2 & 3 results that your CI can read. [Jenkins][jenkins-junit], [Buildkite][buildkite-junit], [CircleCI][circleci-junit], and probably more, too.
+[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.
 
   [rspec]: http://rspec.info/
   [jenkins-junit]: https://jenkins.io/doc/pipeline/steps/junit/
   [buildkite-junit]: https://github.com/buildkite/rspec-junit-example
   [circleci-junit]: https://circleci.com/docs/2.0/collect-test-data/
+  [gitlab-junit]: https://docs.gitlab.com/ee/ci/unit_test_reports.html#ruby-example
 
 ## Usage
 
@@ -89,16 +90,14 @@ RSpec.configure do |config|
 end
 ```
 
+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).
+
 ## Caveats
 
  * 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`.
 
   [xml-charsets]: https://www.w3.org/TR/xml/#charsets
 
-## Roadmap
-
- * 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.
-
 ## Development
 
 Run the specs with `bundle exec rake`, which uses [Appraisal][appraisal] to run the specs against all supported versions of rspec.
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..000d52a
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,11 @@
+require "bundler/gem_tasks"
+require "appraisal"
+require "rspec/core/rake_task"
+
+RSpec::Core::RakeTask.new(:spec)
+
+task :default => :spec
+
+if !ENV["APPRAISAL_INITIALIZED"] && !ENV["CI"]
+  task :default => :appraisal
+end
diff --git a/checksums.yaml.gz.sig b/checksums.yaml.gz.sig
deleted file mode 100644
index 7433024..0000000
--- a/checksums.yaml.gz.sig
+++ /dev/null
@@ -1 +0,0 @@
-(����3�E��2�M�;8��K`�8"}Z��� /�3�ft��K��Pa ��:n�&�Sc��9�Z��;:o�zЛ��|W�4�+"ޟ]��E��I�i\U�3�S4�1%nR�n�>t��{z�9�4�=�QDXN���M�+C$�IJ/���?=����y.�`E�t*�I�<�	�9kG�_J�q���=�z����#�v)=R�6�ۺ�Z�\�OKe���h����.��y�
ņ[`��*S4g��\����:
\ No newline at end of file
diff --git a/data.tar.gz.sig b/data.tar.gz.sig
deleted file mode 100644
index 185965c..0000000
--- a/data.tar.gz.sig
+++ /dev/null
@@ -1,2 +0,0 @@
-R�����%3��i]��^���./J3�h�����z�J#���p�F�5
-�61D(�f4��o )j�=P�0�(J�;e'����k̰cԒR��޾�n3�� iP2�+Œ�n�k]��z��w�M*{BBq����u94e]�ăf�6��ۣJ�2�_��^�|-�A��I,[��j�Aq��oŬk	�0K��C'@�Xb*�jC��R��Vo3��4�0r"c"K�ӅT���F6�������Y��>�k01|B
\ No newline at end of file
diff --git a/debian/changelog b/debian/changelog
index 69cc653..72575f7 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+ruby-rspec-junit-formatter (0.6.0-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Thu, 29 Dec 2022 15:17:11 -0000
+
 ruby-rspec-junit-formatter (0.4.1-2) unstable; urgency=medium
 
   * Team upload
diff --git a/example/.rspec b/example/.rspec
new file mode 100644
index 0000000..7be94c6
--- /dev/null
+++ b/example/.rspec
@@ -0,0 +1,2 @@
+--format RspecJunitFormatter
+--out tmp/rspec.xml
diff --git a/example/spec/example_spec.rb b/example/spec/example_spec.rb
new file mode 100644
index 0000000..da25204
--- /dev/null
+++ b/example/spec/example_spec.rb
@@ -0,0 +1,51 @@
+require "spec_helper"
+require_relative "shared_examples"
+
+describe "some example specs" do
+  it "should succeed" do
+    expect(true).to be(true)
+  end
+
+  it "should fail" do
+    expect(false).to be(true)
+  end
+
+  it "should raise" do
+    raise ArgumentError
+  end
+
+  it "should be pending" do
+    if defined? skip
+      skip
+    else
+      pending
+    end
+  end
+
+  it "shows diffs cleanly" do
+    expect({a: "b", c: "d"}).to eql({a: 2, c: 4})
+  end
+
+  it "replaces naughty \0 and \e characters, \x01 and \uFFFF too" do
+    expect("\0\0\0").to eql("emergency services")
+  end
+
+  it "escapes controlling \u{7f} characters" do
+    expect("\u{7f}").to eql("pacman om nom nom")
+  end
+
+  it "can include unicodes 😁" do
+    expect("🚀").to eql("🔥")
+  end
+
+  it %{escapes <html tags='correctly' and="such &amp; such">} do
+    expect("<p>This is important</p>").to eql("<p>This is <strong>very</strong> important</p>")
+  end
+
+  it_should_behave_like "shared examples"
+
+  it "can capture stdout and stderr" do
+    $stdout.puts "Test"
+    $stderr.puts "Bar"
+  end
+end
diff --git a/example/spec/shared_examples.rb b/example/spec/shared_examples.rb
new file mode 100644
index 0000000..f13751d
--- /dev/null
+++ b/example/spec/shared_examples.rb
@@ -0,0 +1,11 @@
+shared_examples "shared examples" do
+  context "in a shared example" do
+    it "succeeds" do
+      expect(true).to be(true)
+    end
+
+    it "also fails" do
+      expect(false).to be(true)
+    end
+  end
+end
diff --git a/example/spec/spec_helper.rb b/example/spec/spec_helper.rb
new file mode 100644
index 0000000..254be61
--- /dev/null
+++ b/example/spec/spec_helper.rb
@@ -0,0 +1,15 @@
+RSpec.configure do |config|
+  # register around filter that captures stderr and stdout
+  config.around(:each) do |example|
+    $stdout = StringIO.new
+    $stderr = StringIO.new
+
+    example.run
+
+    example.metadata[:stdout] = $stdout.string
+    example.metadata[:stderr] = $stderr.string
+
+    $stdout = STDOUT
+    $stderr = STDERR
+  end
+end
diff --git a/example/tmp/.keep b/example/tmp/.keep
new file mode 100644
index 0000000..e69de29
diff --git a/gemfiles/.bundle/config b/gemfiles/.bundle/config
new file mode 100644
index 0000000..3ffd4b2
--- /dev/null
+++ b/gemfiles/.bundle/config
@@ -0,0 +1,3 @@
+---
+BUNDLE_RETRY: "1"
+BUNDLE_WITHOUT: "development,test"
diff --git a/gemfiles/rspec_2_x.gemfile b/gemfiles/rspec_2_x.gemfile
new file mode 100644
index 0000000..34d4941
--- /dev/null
+++ b/gemfiles/rspec_2_x.gemfile
@@ -0,0 +1,8 @@
+# This file was generated by Appraisal
+
+source "https://rubygems.org"
+
+gem "rspec", "~> 2.14", "< 2.99"
+gem "rake", "~> 10.0"
+
+gemspec path: "../"
diff --git a/gemfiles/rspec_2_x.gemfile.lock b/gemfiles/rspec_2_x.gemfile.lock
new file mode 100644
index 0000000..b5ff8e6
--- /dev/null
+++ b/gemfiles/rspec_2_x.gemfile.lock
@@ -0,0 +1,45 @@
+PATH
+  remote: ..
+  specs:
+    rspec_junit_formatter (0.6.0)
+      rspec-core (>= 2, < 4, != 2.12.0)
+
+GEM
+  remote: https://rubygems.org/
+  specs:
+    appraisal (2.4.1)
+      bundler
+      rake
+      thor (>= 0.14.0)
+    coderay (1.1.3)
+    diff-lcs (1.5.0)
+    mini_portile2 (2.6.1)
+    nokogiri (1.12.5)
+      mini_portile2 (~> 2.6.1)
+      racc (~> 1.4)
+    racc (1.6.0)
+    rake (10.5.0)
+    rspec (2.14.1)
+      rspec-core (~> 2.14.0)
+      rspec-expectations (~> 2.14.0)
+      rspec-mocks (~> 2.14.0)
+    rspec-core (2.14.8)
+    rspec-expectations (2.14.5)
+      diff-lcs (>= 1.1.3, < 2.0)
+    rspec-mocks (2.14.6)
+    thor (1.1.0)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  appraisal
+  bundler
+  coderay
+  nokogiri (~> 1.8, >= 1.8.2)
+  rake (~> 10.0)
+  rspec (~> 2.14, < 2.99)
+  rspec_junit_formatter!
+
+BUNDLED WITH
+   2.2.26
diff --git a/gemfiles/rspec_3_0.gemfile b/gemfiles/rspec_3_0.gemfile
new file mode 100644
index 0000000..a71fa16
--- /dev/null
+++ b/gemfiles/rspec_3_0.gemfile
@@ -0,0 +1,8 @@
+# This file was generated by Appraisal
+
+source "https://rubygems.org"
+
+gem "rspec", "~> 3.0.0"
+gem "rake", "~> 10.0"
+
+gemspec path: "../"
diff --git a/gemfiles/rspec_3_0.gemfile.lock b/gemfiles/rspec_3_0.gemfile.lock
new file mode 100644
index 0000000..b5dd297
--- /dev/null
+++ b/gemfiles/rspec_3_0.gemfile.lock
@@ -0,0 +1,49 @@
+PATH
+  remote: ..
+  specs:
+    rspec_junit_formatter (0.6.0)
+      rspec-core (>= 2, < 4, != 2.12.0)
+
+GEM
+  remote: https://rubygems.org/
+  specs:
+    appraisal (2.4.1)
+      bundler
+      rake
+      thor (>= 0.14.0)
+    coderay (1.1.3)
+    diff-lcs (1.5.0)
+    mini_portile2 (2.6.1)
+    nokogiri (1.12.5)
+      mini_portile2 (~> 2.6.1)
+      racc (~> 1.4)
+    racc (1.6.0)
+    rake (10.5.0)
+    rspec (3.0.0)
+      rspec-core (~> 3.0.0)
+      rspec-expectations (~> 3.0.0)
+      rspec-mocks (~> 3.0.0)
+    rspec-core (3.0.4)
+      rspec-support (~> 3.0.0)
+    rspec-expectations (3.0.4)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.0.0)
+    rspec-mocks (3.0.4)
+      rspec-support (~> 3.0.0)
+    rspec-support (3.0.4)
+    thor (1.1.0)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  appraisal
+  bundler
+  coderay
+  nokogiri (~> 1.8, >= 1.8.2)
+  rake (~> 10.0)
+  rspec (~> 3.0.0)
+  rspec_junit_formatter!
+
+BUNDLED WITH
+   2.2.26
diff --git a/gemfiles/rspec_3_1.gemfile b/gemfiles/rspec_3_1.gemfile
new file mode 100644
index 0000000..2b67948
--- /dev/null
+++ b/gemfiles/rspec_3_1.gemfile
@@ -0,0 +1,8 @@
+# This file was generated by Appraisal
+
+source "https://rubygems.org"
+
+gem "rspec", "~> 3.1.0"
+gem "rake", "~> 10.0"
+
+gemspec path: "../"
diff --git a/gemfiles/rspec_3_1.gemfile.lock b/gemfiles/rspec_3_1.gemfile.lock
new file mode 100644
index 0000000..9fb2764
--- /dev/null
+++ b/gemfiles/rspec_3_1.gemfile.lock
@@ -0,0 +1,49 @@
+PATH
+  remote: ..
+  specs:
+    rspec_junit_formatter (0.6.0)
+      rspec-core (>= 2, < 4, != 2.12.0)
+
+GEM
+  remote: https://rubygems.org/
+  specs:
+    appraisal (2.4.1)
+      bundler
+      rake
+      thor (>= 0.14.0)
+    coderay (1.1.3)
+    diff-lcs (1.5.0)
+    mini_portile2 (2.6.1)
+    nokogiri (1.12.5)
+      mini_portile2 (~> 2.6.1)
+      racc (~> 1.4)
+    racc (1.6.0)
+    rake (10.5.0)
+    rspec (3.1.0)
+      rspec-core (~> 3.1.0)
+      rspec-expectations (~> 3.1.0)
+      rspec-mocks (~> 3.1.0)
+    rspec-core (3.1.7)
+      rspec-support (~> 3.1.0)
+    rspec-expectations (3.1.2)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.1.0)
+    rspec-mocks (3.1.3)
+      rspec-support (~> 3.1.0)
+    rspec-support (3.1.2)
+    thor (1.1.0)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  appraisal
+  bundler
+  coderay
+  nokogiri (~> 1.8, >= 1.8.2)
+  rake (~> 10.0)
+  rspec (~> 3.1.0)
+  rspec_junit_formatter!
+
+BUNDLED WITH
+   2.2.26
diff --git a/gemfiles/rspec_3_10.gemfile b/gemfiles/rspec_3_10.gemfile
new file mode 100644
index 0000000..1c4ab36
--- /dev/null
+++ b/gemfiles/rspec_3_10.gemfile
@@ -0,0 +1,7 @@
+# This file was generated by Appraisal
+
+source "https://rubygems.org"
+
+gem "rspec", "~> 3.10.0"
+
+gemspec path: "../"
diff --git a/gemfiles/rspec_3_10.gemfile.lock b/gemfiles/rspec_3_10.gemfile.lock
new file mode 100644
index 0000000..66ac4e0
--- /dev/null
+++ b/gemfiles/rspec_3_10.gemfile.lock
@@ -0,0 +1,50 @@
+PATH
+  remote: ..
+  specs:
+    rspec_junit_formatter (0.6.0)
+      rspec-core (>= 2, < 4, != 2.12.0)
+
+GEM
+  remote: https://rubygems.org/
+  specs:
+    appraisal (2.4.1)
+      bundler
+      rake
+      thor (>= 0.14.0)
+    coderay (1.1.3)
+    diff-lcs (1.5.0)
+    mini_portile2 (2.6.1)
+    nokogiri (1.12.5)
+      mini_portile2 (~> 2.6.1)
+      racc (~> 1.4)
+    racc (1.6.0)
+    rake (13.0.6)
+    rspec (3.10.0)
+      rspec-core (~> 3.10.0)
+      rspec-expectations (~> 3.10.0)
+      rspec-mocks (~> 3.10.0)
+    rspec-core (3.10.1)
+      rspec-support (~> 3.10.0)
+    rspec-expectations (3.10.1)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.10.0)
+    rspec-mocks (3.10.2)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.10.0)
+    rspec-support (3.10.3)
+    thor (1.1.0)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  appraisal
+  bundler
+  coderay
+  nokogiri (~> 1.8, >= 1.8.2)
+  rake
+  rspec (~> 3.10.0)
+  rspec_junit_formatter!
+
+BUNDLED WITH
+   2.2.26
diff --git a/gemfiles/rspec_3_2.gemfile b/gemfiles/rspec_3_2.gemfile
new file mode 100644
index 0000000..ab54ba6
--- /dev/null
+++ b/gemfiles/rspec_3_2.gemfile
@@ -0,0 +1,8 @@
+# This file was generated by Appraisal
+
+source "https://rubygems.org"
+
+gem "rspec", "~> 3.2.0"
+gem "rake", "~> 10.0"
+
+gemspec path: "../"
diff --git a/gemfiles/rspec_3_2.gemfile.lock b/gemfiles/rspec_3_2.gemfile.lock
new file mode 100644
index 0000000..8e71c6d
--- /dev/null
+++ b/gemfiles/rspec_3_2.gemfile.lock
@@ -0,0 +1,50 @@
+PATH
+  remote: ..
+  specs:
+    rspec_junit_formatter (0.6.0)
+      rspec-core (>= 2, < 4, != 2.12.0)
+
+GEM
+  remote: https://rubygems.org/
+  specs:
+    appraisal (2.4.1)
+      bundler
+      rake
+      thor (>= 0.14.0)
+    coderay (1.1.3)
+    diff-lcs (1.5.0)
+    mini_portile2 (2.6.1)
+    nokogiri (1.12.5)
+      mini_portile2 (~> 2.6.1)
+      racc (~> 1.4)
+    racc (1.6.0)
+    rake (10.5.0)
+    rspec (3.2.0)
+      rspec-core (~> 3.2.0)
+      rspec-expectations (~> 3.2.0)
+      rspec-mocks (~> 3.2.0)
+    rspec-core (3.2.3)
+      rspec-support (~> 3.2.0)
+    rspec-expectations (3.2.1)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.2.0)
+    rspec-mocks (3.2.1)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.2.0)
+    rspec-support (3.2.2)
+    thor (1.1.0)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  appraisal
+  bundler
+  coderay
+  nokogiri (~> 1.8, >= 1.8.2)
+  rake (~> 10.0)
+  rspec (~> 3.2.0)
+  rspec_junit_formatter!
+
+BUNDLED WITH
+   2.2.26
diff --git a/gemfiles/rspec_3_3.gemfile b/gemfiles/rspec_3_3.gemfile
new file mode 100644
index 0000000..e740e25
--- /dev/null
+++ b/gemfiles/rspec_3_3.gemfile
@@ -0,0 +1,8 @@
+# This file was generated by Appraisal
+
+source "https://rubygems.org"
+
+gem "rspec", "~> 3.3.0"
+gem "rake", "~> 10.0"
+
+gemspec path: "../"
diff --git a/gemfiles/rspec_3_3.gemfile.lock b/gemfiles/rspec_3_3.gemfile.lock
new file mode 100644
index 0000000..0727e3e
--- /dev/null
+++ b/gemfiles/rspec_3_3.gemfile.lock
@@ -0,0 +1,50 @@
+PATH
+  remote: ..
+  specs:
+    rspec_junit_formatter (0.6.0)
+      rspec-core (>= 2, < 4, != 2.12.0)
+
+GEM
+  remote: https://rubygems.org/
+  specs:
+    appraisal (2.4.1)
+      bundler
+      rake
+      thor (>= 0.14.0)
+    coderay (1.1.3)
+    diff-lcs (1.5.0)
+    mini_portile2 (2.6.1)
+    nokogiri (1.12.5)
+      mini_portile2 (~> 2.6.1)
+      racc (~> 1.4)
+    racc (1.6.0)
+    rake (10.5.0)
+    rspec (3.3.0)
+      rspec-core (~> 3.3.0)
+      rspec-expectations (~> 3.3.0)
+      rspec-mocks (~> 3.3.0)
+    rspec-core (3.3.2)
+      rspec-support (~> 3.3.0)
+    rspec-expectations (3.3.1)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.3.0)
+    rspec-mocks (3.3.2)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.3.0)
+    rspec-support (3.3.0)
+    thor (1.1.0)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  appraisal
+  bundler
+  coderay
+  nokogiri (~> 1.8, >= 1.8.2)
+  rake (~> 10.0)
+  rspec (~> 3.3.0)
+  rspec_junit_formatter!
+
+BUNDLED WITH
+   2.2.26
diff --git a/gemfiles/rspec_3_4.gemfile b/gemfiles/rspec_3_4.gemfile
new file mode 100644
index 0000000..65438b6
--- /dev/null
+++ b/gemfiles/rspec_3_4.gemfile
@@ -0,0 +1,7 @@
+# This file was generated by Appraisal
+
+source "https://rubygems.org"
+
+gem "rspec", "~> 3.4.0"
+
+gemspec path: "../"
diff --git a/gemfiles/rspec_3_4.gemfile.lock b/gemfiles/rspec_3_4.gemfile.lock
new file mode 100644
index 0000000..f466aff
--- /dev/null
+++ b/gemfiles/rspec_3_4.gemfile.lock
@@ -0,0 +1,50 @@
+PATH
+  remote: ..
+  specs:
+    rspec_junit_formatter (0.6.0)
+      rspec-core (>= 2, < 4, != 2.12.0)
+
+GEM
+  remote: https://rubygems.org/
+  specs:
+    appraisal (2.4.1)
+      bundler
+      rake
+      thor (>= 0.14.0)
+    coderay (1.1.3)
+    diff-lcs (1.5.0)
+    mini_portile2 (2.6.1)
+    nokogiri (1.12.5)
+      mini_portile2 (~> 2.6.1)
+      racc (~> 1.4)
+    racc (1.6.0)
+    rake (13.0.6)
+    rspec (3.4.0)
+      rspec-core (~> 3.4.0)
+      rspec-expectations (~> 3.4.0)
+      rspec-mocks (~> 3.4.0)
+    rspec-core (3.4.4)
+      rspec-support (~> 3.4.0)
+    rspec-expectations (3.4.0)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.4.0)
+    rspec-mocks (3.4.1)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.4.0)
+    rspec-support (3.4.1)
+    thor (1.1.0)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  appraisal
+  bundler
+  coderay
+  nokogiri (~> 1.8, >= 1.8.2)
+  rake
+  rspec (~> 3.4.0)
+  rspec_junit_formatter!
+
+BUNDLED WITH
+   2.2.26
diff --git a/gemfiles/rspec_3_5.gemfile b/gemfiles/rspec_3_5.gemfile
new file mode 100644
index 0000000..4bae171
--- /dev/null
+++ b/gemfiles/rspec_3_5.gemfile
@@ -0,0 +1,7 @@
+# This file was generated by Appraisal
+
+source "https://rubygems.org"
+
+gem "rspec", "~> 3.5.0"
+
+gemspec path: "../"
diff --git a/gemfiles/rspec_3_5.gemfile.lock b/gemfiles/rspec_3_5.gemfile.lock
new file mode 100644
index 0000000..449e725
--- /dev/null
+++ b/gemfiles/rspec_3_5.gemfile.lock
@@ -0,0 +1,50 @@
+PATH
+  remote: ..
+  specs:
+    rspec_junit_formatter (0.6.0)
+      rspec-core (>= 2, < 4, != 2.12.0)
+
+GEM
+  remote: https://rubygems.org/
+  specs:
+    appraisal (2.4.1)
+      bundler
+      rake
+      thor (>= 0.14.0)
+    coderay (1.1.3)
+    diff-lcs (1.5.0)
+    mini_portile2 (2.6.1)
+    nokogiri (1.12.5)
+      mini_portile2 (~> 2.6.1)
+      racc (~> 1.4)
+    racc (1.6.0)
+    rake (13.0.6)
+    rspec (3.5.0)
+      rspec-core (~> 3.5.0)
+      rspec-expectations (~> 3.5.0)
+      rspec-mocks (~> 3.5.0)
+    rspec-core (3.5.4)
+      rspec-support (~> 3.5.0)
+    rspec-expectations (3.5.0)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.5.0)
+    rspec-mocks (3.5.0)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.5.0)
+    rspec-support (3.5.0)
+    thor (1.1.0)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  appraisal
+  bundler
+  coderay
+  nokogiri (~> 1.8, >= 1.8.2)
+  rake
+  rspec (~> 3.5.0)
+  rspec_junit_formatter!
+
+BUNDLED WITH
+   2.2.26
diff --git a/gemfiles/rspec_3_6.gemfile b/gemfiles/rspec_3_6.gemfile
new file mode 100644
index 0000000..0bb6b26
--- /dev/null
+++ b/gemfiles/rspec_3_6.gemfile
@@ -0,0 +1,7 @@
+# This file was generated by Appraisal
+
+source "https://rubygems.org"
+
+gem "rspec", "~> 3.6.0"
+
+gemspec path: "../"
diff --git a/gemfiles/rspec_3_6.gemfile.lock b/gemfiles/rspec_3_6.gemfile.lock
new file mode 100644
index 0000000..72604b1
--- /dev/null
+++ b/gemfiles/rspec_3_6.gemfile.lock
@@ -0,0 +1,50 @@
+PATH
+  remote: ..
+  specs:
+    rspec_junit_formatter (0.6.0)
+      rspec-core (>= 2, < 4, != 2.12.0)
+
+GEM
+  remote: https://rubygems.org/
+  specs:
+    appraisal (2.4.1)
+      bundler
+      rake
+      thor (>= 0.14.0)
+    coderay (1.1.3)
+    diff-lcs (1.5.0)
+    mini_portile2 (2.6.1)
+    nokogiri (1.12.5)
+      mini_portile2 (~> 2.6.1)
+      racc (~> 1.4)
+    racc (1.6.0)
+    rake (13.0.6)
+    rspec (3.6.0)
+      rspec-core (~> 3.6.0)
+      rspec-expectations (~> 3.6.0)
+      rspec-mocks (~> 3.6.0)
+    rspec-core (3.6.0)
+      rspec-support (~> 3.6.0)
+    rspec-expectations (3.6.0)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.6.0)
+    rspec-mocks (3.6.0)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.6.0)
+    rspec-support (3.6.0)
+    thor (1.1.0)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  appraisal
+  bundler
+  coderay
+  nokogiri (~> 1.8, >= 1.8.2)
+  rake
+  rspec (~> 3.6.0)
+  rspec_junit_formatter!
+
+BUNDLED WITH
+   2.2.26
diff --git a/gemfiles/rspec_3_7.gemfile b/gemfiles/rspec_3_7.gemfile
new file mode 100644
index 0000000..876511d
--- /dev/null
+++ b/gemfiles/rspec_3_7.gemfile
@@ -0,0 +1,7 @@
+# This file was generated by Appraisal
+
+source "https://rubygems.org"
+
+gem "rspec", "~> 3.7.0"
+
+gemspec path: "../"
diff --git a/gemfiles/rspec_3_7.gemfile.lock b/gemfiles/rspec_3_7.gemfile.lock
new file mode 100644
index 0000000..fd15699
--- /dev/null
+++ b/gemfiles/rspec_3_7.gemfile.lock
@@ -0,0 +1,50 @@
+PATH
+  remote: ..
+  specs:
+    rspec_junit_formatter (0.6.0)
+      rspec-core (>= 2, < 4, != 2.12.0)
+
+GEM
+  remote: https://rubygems.org/
+  specs:
+    appraisal (2.4.1)
+      bundler
+      rake
+      thor (>= 0.14.0)
+    coderay (1.1.3)
+    diff-lcs (1.5.0)
+    mini_portile2 (2.6.1)
+    nokogiri (1.12.5)
+      mini_portile2 (~> 2.6.1)
+      racc (~> 1.4)
+    racc (1.6.0)
+    rake (13.0.6)
+    rspec (3.7.0)
+      rspec-core (~> 3.7.0)
+      rspec-expectations (~> 3.7.0)
+      rspec-mocks (~> 3.7.0)
+    rspec-core (3.7.1)
+      rspec-support (~> 3.7.0)
+    rspec-expectations (3.7.0)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.7.0)
+    rspec-mocks (3.7.0)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.7.0)
+    rspec-support (3.7.1)
+    thor (1.1.0)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  appraisal
+  bundler
+  coderay
+  nokogiri (~> 1.8, >= 1.8.2)
+  rake
+  rspec (~> 3.7.0)
+  rspec_junit_formatter!
+
+BUNDLED WITH
+   2.2.26
diff --git a/gemfiles/rspec_3_8.gemfile b/gemfiles/rspec_3_8.gemfile
new file mode 100644
index 0000000..3c5bb23
--- /dev/null
+++ b/gemfiles/rspec_3_8.gemfile
@@ -0,0 +1,7 @@
+# This file was generated by Appraisal
+
+source "https://rubygems.org"
+
+gem "rspec", "~> 3.8.0"
+
+gemspec path: "../"
diff --git a/gemfiles/rspec_3_8.gemfile.lock b/gemfiles/rspec_3_8.gemfile.lock
new file mode 100644
index 0000000..d3adb61
--- /dev/null
+++ b/gemfiles/rspec_3_8.gemfile.lock
@@ -0,0 +1,50 @@
+PATH
+  remote: ..
+  specs:
+    rspec_junit_formatter (0.6.0)
+      rspec-core (>= 2, < 4, != 2.12.0)
+
+GEM
+  remote: https://rubygems.org/
+  specs:
+    appraisal (2.4.1)
+      bundler
+      rake
+      thor (>= 0.14.0)
+    coderay (1.1.3)
+    diff-lcs (1.5.0)
+    mini_portile2 (2.6.1)
+    nokogiri (1.12.5)
+      mini_portile2 (~> 2.6.1)
+      racc (~> 1.4)
+    racc (1.6.0)
+    rake (13.0.6)
+    rspec (3.8.0)
+      rspec-core (~> 3.8.0)
+      rspec-expectations (~> 3.8.0)
+      rspec-mocks (~> 3.8.0)
+    rspec-core (3.8.2)
+      rspec-support (~> 3.8.0)
+    rspec-expectations (3.8.6)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.8.0)
+    rspec-mocks (3.8.2)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.8.0)
+    rspec-support (3.8.3)
+    thor (1.1.0)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  appraisal
+  bundler
+  coderay
+  nokogiri (~> 1.8, >= 1.8.2)
+  rake
+  rspec (~> 3.8.0)
+  rspec_junit_formatter!
+
+BUNDLED WITH
+   2.2.26
diff --git a/gemfiles/rspec_3_9.gemfile b/gemfiles/rspec_3_9.gemfile
new file mode 100644
index 0000000..4212c75
--- /dev/null
+++ b/gemfiles/rspec_3_9.gemfile
@@ -0,0 +1,7 @@
+# This file was generated by Appraisal
+
+source "https://rubygems.org"
+
+gem "rspec", "~> 3.9.0"
+
+gemspec path: "../"
diff --git a/gemfiles/rspec_3_9.gemfile.lock b/gemfiles/rspec_3_9.gemfile.lock
new file mode 100644
index 0000000..dbaf669
--- /dev/null
+++ b/gemfiles/rspec_3_9.gemfile.lock
@@ -0,0 +1,50 @@
+PATH
+  remote: ..
+  specs:
+    rspec_junit_formatter (0.6.0)
+      rspec-core (>= 2, < 4, != 2.12.0)
+
+GEM
+  remote: https://rubygems.org/
+  specs:
+    appraisal (2.4.1)
+      bundler
+      rake
+      thor (>= 0.14.0)
+    coderay (1.1.3)
+    diff-lcs (1.5.0)
+    mini_portile2 (2.6.1)
+    nokogiri (1.12.5)
+      mini_portile2 (~> 2.6.1)
+      racc (~> 1.4)
+    racc (1.6.0)
+    rake (13.0.6)
+    rspec (3.9.0)
+      rspec-core (~> 3.9.0)
+      rspec-expectations (~> 3.9.0)
+      rspec-mocks (~> 3.9.0)
+    rspec-core (3.9.3)
+      rspec-support (~> 3.9.3)
+    rspec-expectations (3.9.4)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.9.0)
+    rspec-mocks (3.9.1)
+      diff-lcs (>= 1.2.0, < 2.0)
+      rspec-support (~> 3.9.0)
+    rspec-support (3.9.4)
+    thor (1.1.0)
+
+PLATFORMS
+  ruby
+
+DEPENDENCIES
+  appraisal
+  bundler
+  coderay
+  nokogiri (~> 1.8, >= 1.8.2)
+  rake
+  rspec (~> 3.9.0)
+  rspec_junit_formatter!
+
+BUNDLED WITH
+   2.2.26
diff --git a/lib/rspec_junit_formatter.rb b/lib/rspec_junit_formatter.rb
index 4670b7a..7c9b7c3 100644
--- a/lib/rspec_junit_formatter.rb
+++ b/lib/rspec_junit_formatter.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 require "socket"
 require "time"
 
@@ -18,7 +20,7 @@ private
     output << %{ tests="#{example_count}"}
     output << %{ skipped="#{pending_count}"}
     output << %{ failures="#{failure_count}"}
-    output << %{ errors="0"}
+    output << %{ errors="#{error_count}"}
     output << %{ time="#{escape("%.6f" % duration)}"}
     output << %{ timestamp="#{escape(started.iso8601)}"}
     output << %{ hostname="#{escape(Socket.gethostname)}"}
@@ -68,7 +70,9 @@ private
     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))}"}
+    if duration = duration_for(example)
+      output << %{ time="#{escape("%.6f" % duration)}"}
+    end
     output << %{>}
     yield if block_given?
     xml_dump_output(example)
@@ -91,7 +95,7 @@ private
 
   # Inversion of character range from https://www.w3.org/TR/xml/#charsets
   ILLEGAL_REGEXP = Regexp.new(
-    "[^" <<
+    "[^".dup <<
     "\u{9}" << # => \t
     "\u{a}" << # => \n
     "\u{d}" << # => \r
@@ -123,7 +127,7 @@ private
   # Discouraged characters from https://www.w3.org/TR/xml/#charsets
   # Plus special characters with well-known entity replacements
   DISCOURAGED_REGEXP = Regexp.new(
-    "[" <<
+    "[".dup <<
     "\u{22}" << # => "
     "\u{26}" << # => &
     "\u{27}" << # => '
diff --git a/lib/rspec_junit_formatter/rspec2.rb b/lib/rspec_junit_formatter/rspec2.rb
index 86de36a..8171cc7 100644
--- a/lib/rspec_junit_formatter/rspec2.rb
+++ b/lib/rspec_junit_formatter/rspec2.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class RSpecJUnitFormatter < RSpec::Core::Formatters::BaseFormatter
   attr_reader :started
 
@@ -62,6 +64,10 @@ private
     "#{message}\n#{backtrace.join("\n")}"
   end
 
+  def error_count
+    0
+  end
+
   def find_shared_group(example)
     group_and_parent_groups(example).find { |group| group.metadata[:shared_group_name] }
   end
diff --git a/lib/rspec_junit_formatter/rspec3.rb b/lib/rspec_junit_formatter/rspec3.rb
index 2a471ae..af59096 100644
--- a/lib/rspec_junit_formatter/rspec3.rb
+++ b/lib/rspec_junit_formatter/rspec3.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
 class RSpecJUnitFormatter < RSpec::Core::Formatters::BaseFormatter
   RSpec::Core::Formatters.register self,
     :start,
@@ -43,6 +45,15 @@ private
     @examples_notification.notifications
   end
 
+  def error_count
+    # Introduced in rspec 3.6
+    if @summary_notification.respond_to?(:errors_outside_of_examples_count)
+      @summary_notification.errors_outside_of_examples_count
+    else
+      0
+    end
+  end
+
   def result_of(notification)
     notification.example.execution_result.status
   end
diff --git a/metadata.gz.sig b/metadata.gz.sig
deleted file mode 100644
index cc00ae9..0000000
Binary files a/metadata.gz.sig and /dev/null differ
diff --git a/reference/JUnit.xsd b/reference/JUnit.xsd
new file mode 100644
index 0000000..44b841f
--- /dev/null
+++ b/reference/JUnit.xsd
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
+	 elementFormDefault="qualified"
+	 attributeFormDefault="unqualified">
+	<xs:annotation>
+		<xs:documentation xml:lang="en">JUnit test result schema for the Apache Ant JUnit and JUnitReport tasks
+Copyright © 2011, Windy Road Technology Pty. Limited
+The Apache Ant JUnit XML Schema is distributed under the terms of the GNU Lesser General Public License (LGPL) http://www.gnu.org/licenses/lgpl.html
+Permission to waive conditions of this license may be requested from Windy Road Support (http://windyroad.org/support).</xs:documentation>
+	</xs:annotation>
+	<xs:element name="testsuite" type="testsuite"/>
+	<xs:simpleType name="ISO8601_DATETIME_PATTERN">
+		<xs:restriction base="xs:dateTime">
+			<xs:pattern value="[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}"/>
+		</xs:restriction>
+	</xs:simpleType>
+	<xs:element name="testsuites">
+		<xs:annotation>
+			<xs:documentation xml:lang="en">Contains an aggregation of testsuite results</xs:documentation>
+		</xs:annotation>
+		<xs:complexType>
+			<xs:sequence>
+				<xs:element name="testsuite" minOccurs="0" maxOccurs="unbounded">
+					<xs:complexType>
+						<xs:complexContent>
+							<xs:extension base="testsuite">
+								<xs:attribute name="package" type="xs:token" use="required">
+									<xs:annotation>
+										<xs:documentation xml:lang="en">Derived from testsuite/@name in the non-aggregated documents</xs:documentation>
+									</xs:annotation>
+								</xs:attribute>
+								<xs:attribute name="id" type="xs:int" use="required">
+									<xs:annotation>
+										<xs:documentation xml:lang="en">Starts at '0' for the first testsuite and is incremented by 1 for each following testsuite</xs:documentation>
+									</xs:annotation>
+								</xs:attribute>
+							</xs:extension>
+						</xs:complexContent>
+					</xs:complexType>
+				</xs:element>
+			</xs:sequence>
+		</xs:complexType>
+	</xs:element>
+	<xs:complexType name="testsuite">
+		<xs:annotation>
+			<xs:documentation xml:lang="en">Contains the results of exexuting a testsuite</xs:documentation>
+		</xs:annotation>
+		<xs:sequence>
+			<xs:element name="properties">
+				<xs:annotation>
+					<xs:documentation xml:lang="en">Properties (e.g., environment settings) set during test execution</xs:documentation>
+				</xs:annotation>
+				<xs:complexType>
+					<xs:sequence>
+						<xs:element name="property" minOccurs="0" maxOccurs="unbounded">
+							<xs:complexType>
+								<xs:attribute name="name" use="required">
+									<xs:simpleType>
+										<xs:restriction base="xs:token">
+											<xs:minLength value="1"/>
+										</xs:restriction>
+									</xs:simpleType>
+								</xs:attribute>
+								<xs:attribute name="value" type="xs:string" use="required"/>
+							</xs:complexType>
+						</xs:element>
+					</xs:sequence>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="testcase" minOccurs="0" maxOccurs="unbounded">
+				<xs:complexType>
+					<xs:choice minOccurs="0">
+						<xs:element name="error">
+			<xs:annotation>
+				<xs:documentation xml:lang="en">Indicates that the test errored.  An errored test is one that had an unanticipated problem. e.g., an unchecked throwable; or a problem with the implementation of the test. Contains as a text node relevant data for the error, e.g., a stack trace</xs:documentation>
+			</xs:annotation>
+							<xs:complexType>
+								<xs:simpleContent>
+									<xs:extension base="pre-string">
+										<xs:attribute name="message" type="xs:string">
+											<xs:annotation>
+												<xs:documentation xml:lang="en">The error message. e.g., if a java exception is thrown, the return value of getMessage()</xs:documentation>
+											</xs:annotation>
+										</xs:attribute>
+										<xs:attribute name="type" type="xs:string" use="required">
+											<xs:annotation>
+												<xs:documentation xml:lang="en">The type of error that occured. e.g., if a java execption is thrown the full class name of the exception.</xs:documentation>
+											</xs:annotation>
+										</xs:attribute>
+									</xs:extension>
+								</xs:simpleContent>
+							</xs:complexType>
+						</xs:element>
+						<xs:element name="failure">
+			<xs:annotation>
+				<xs:documentation xml:lang="en">Indicates that the test failed. A failure is a test which the code has explicitly failed by using the mechanisms for that purpose. e.g., via an assertEquals. Contains as a text node relevant data for the failure, e.g., a stack trace</xs:documentation>
+			</xs:annotation>
+							<xs:complexType>
+								<xs:simpleContent>
+									<xs:extension base="pre-string">
+										<xs:attribute name="message" type="xs:string">
+											<xs:annotation>
+												<xs:documentation xml:lang="en">The message specified in the assert</xs:documentation>
+											</xs:annotation>
+										</xs:attribute>
+										<xs:attribute name="type" type="xs:string" use="required">
+											<xs:annotation>
+												<xs:documentation xml:lang="en">The type of the assert.</xs:documentation>
+											</xs:annotation>
+										</xs:attribute>
+									</xs:extension>
+								</xs:simpleContent>
+							</xs:complexType>
+						</xs:element>
+					</xs:choice>
+					<xs:attribute name="name" type="xs:token" use="required">
+						<xs:annotation>
+							<xs:documentation xml:lang="en">Name of the test method</xs:documentation>
+						</xs:annotation>
+					</xs:attribute>
+					<xs:attribute name="classname" type="xs:token" use="required">
+						<xs:annotation>
+							<xs:documentation xml:lang="en">Full class name for the class the test method is in.</xs:documentation>
+						</xs:annotation>
+					</xs:attribute>
+					<xs:attribute name="time" type="xs:decimal" use="required">
+						<xs:annotation>
+							<xs:documentation xml:lang="en">Time taken (in seconds) to execute the test</xs:documentation>
+						</xs:annotation>
+					</xs:attribute>
+				</xs:complexType>
+			</xs:element>
+			<xs:element name="system-out">
+				<xs:annotation>
+					<xs:documentation xml:lang="en">Data that was written to standard out while the test was executed</xs:documentation>
+				</xs:annotation>
+				<xs:simpleType>
+					<xs:restriction base="pre-string">
+						<xs:whiteSpace value="preserve"/>
+					</xs:restriction>
+				</xs:simpleType>
+			</xs:element>
+			<xs:element name="system-err">
+				<xs:annotation>
+					<xs:documentation xml:lang="en">Data that was written to standard error while the test was executed</xs:documentation>
+				</xs:annotation>
+				<xs:simpleType>
+					<xs:restriction base="pre-string">
+						<xs:whiteSpace value="preserve"/>
+					</xs:restriction>
+				</xs:simpleType>
+			</xs:element>
+		</xs:sequence>
+		<xs:attribute name="name" use="required">
+			<xs:annotation>
+				<xs:documentation xml:lang="en">Full class name of the test for non-aggregated testsuite documents. Class name without the package for aggregated testsuites documents</xs:documentation>
+			</xs:annotation>
+			<xs:simpleType>
+				<xs:restriction base="xs:token">
+					<xs:minLength value="1"/>
+				</xs:restriction>
+			</xs:simpleType>
+		</xs:attribute>
+		<xs:attribute name="timestamp" type="ISO8601_DATETIME_PATTERN" use="required">
+			<xs:annotation>
+				<xs:documentation xml:lang="en">when the test was executed. Timezone may not be specified.</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="hostname" use="required">
+			<xs:annotation>
+				<xs:documentation xml:lang="en">Host on which the tests were executed. 'localhost' should be used if the hostname cannot be determined.</xs:documentation>
+			</xs:annotation>
+			<xs:simpleType>
+				<xs:restriction base="xs:token">
+					<xs:minLength value="1"/>
+				</xs:restriction>
+			</xs:simpleType>
+		</xs:attribute>
+		<xs:attribute name="tests" type="xs:int" use="required">
+			<xs:annotation>
+				<xs:documentation xml:lang="en">The total number of tests in the suite</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="failures" type="xs:int" use="required">
+			<xs:annotation>
+				<xs:documentation xml:lang="en">The total number of tests in the suite that failed. A failure is a test which the code has explicitly failed by using the mechanisms for that purpose. e.g., via an assertEquals</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="errors" type="xs:int" use="required">
+			<xs:annotation>
+				<xs:documentation xml:lang="en">The total number of tests in the suite that errorrd. An errored test is one that had an unanticipated problem. e.g., an unchecked throwable; or a problem with the implementation of the test.</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+		<xs:attribute name="time" type="xs:decimal" use="required">
+			<xs:annotation>
+				<xs:documentation xml:lang="en">Time taken (in seconds) to execute the tests in the suite</xs:documentation>
+			</xs:annotation>
+		</xs:attribute>
+	</xs:complexType>
+	<xs:simpleType name="pre-string">
+		<xs:restriction base="xs:string">
+			<xs:whiteSpace value="preserve"/>
+		</xs:restriction>
+	</xs:simpleType>
+</xs:schema>
\ No newline at end of file
diff --git a/rspec_junit_formatter.gemspec b/rspec_junit_formatter.gemspec
index e60b3d5..05ac241 100644
--- a/rspec_junit_formatter.gemspec
+++ b/rspec_junit_formatter.gemspec
@@ -1,45 +1,30 @@
-#########################################################
-# This file has been automatically generated by gem2tgz #
-#########################################################
-# -*- encoding: utf-8 -*-
-# stub: rspec_junit_formatter 0.4.1 ruby lib
-
 Gem::Specification.new do |s|
-  s.name = "rspec_junit_formatter".freeze
-  s.version = "0.4.1"
+  s.name        = "rspec_junit_formatter"
+  s.version     = "0.6.0"
+  s.platform    = Gem::Platform::RUBY
+  s.author      = "Samuel Cochran"
+  s.email       = "sj26@sj26.com"
+  s.homepage    = "https://github.com/sj26/rspec_junit_formatter"
+  s.summary     = "RSpec JUnit XML formatter"
+  s.description = "RSpec results that your continuous integration service can read."
+  s.license     = "MIT"
+
+  s.required_ruby_version = ">= 2.3.0"
+  s.required_rubygems_version = ">= 2.0.0"
+
+  s.metadata = {
+    'changelog_uri' => 'https://github.com/sj26/rspec_junit_formatter/blob/HEAD/CHANGELOG.md',
+  }
 
-  s.required_rubygems_version = Gem::Requirement.new(">= 2.0.0".freeze) if s.respond_to? :required_rubygems_version=
-  s.metadata = { "changelog_uri" => "https://github.com/sj26/rspec_junit_formatter/blob/master/CHANGELOG.md" } if s.respond_to? :metadata=
-  s.require_paths = ["lib".freeze]
-  s.authors = ["Samuel Cochran".freeze]
-  s.cert_chain = ["-----BEGIN CERTIFICATE-----\nMIIDKDCCAhCgAwIBAgIBBTANBgkqhkiG9w0BAQUFADA6MQ0wCwYDVQQDDARzajI2\nMRQwEgYKCZImiZPyLGQBGRYEc2oyNjETMBEGCgmSJomT8ixkARkWA2NvbTAeFw0x\nNzA3MzEwNTQ3MDVaFw0xODA3MzEwNTQ3MDVaMDoxDTALBgNVBAMMBHNqMjYxFDAS\nBgoJkiaJk/IsZAEZFgRzajI2MRMwEQYKCZImiZPyLGQBGRYDY29tMIIBIjANBgkq\nhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr60Eo/ttCk8GMTMFiPr3GoYMIMFvLak\nxSmTk9YGCB6UiEePB4THSSA5w6IPyeaCF/nWkDp3/BAam0eZMWG1IzYQB23TqIM0\n1xzcNRvFsn0aQoQ00k+sj+G83j3T5OOV5OZIlu8xAChMkQmiPd1NXc6uFv+Iacz7\nkj+CMsI9YUFdNoU09QY0b+u+Rb6wDYdpyvN60YC30h0h1MeYbvYZJx/iZK4XY5zu\n4O/FL2ChjL2CPCpLZW55ShYyrzphWJwLOJe+FJ/ZBl6YXwrzQM9HKnt4titSNvyU\nKzE3L63A3PZvExzLrN9u09kuWLLJfXB2sGOlw3n9t72rJiuBr3/OQQIDAQABozkw\nNzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQU99dfRjEKFyczTeIz\nm3ZsDWrNC80wDQYJKoZIhvcNAQEFBQADggEBADGiXpvK754s0zTFx3y31ZRDdvAI\nlA209JIjUlDyr9ptCRadihyfF2l9/hb+hLemiPEYppzG6vEK1TIyzbAR36yOJ8CX\n4vPkCXLuwHhs6UIRbwN+IEy41nsIlBxmjLYei8h3t/G2Vm2oOaLdbjDXS+Srl9U8\nshsE8ft81PxSQfzEL7Mr9cC9XvWbHW+SyTpfGm8rAtaqZkNeke4U8a0di4oz2EfA\nP4lSfmXxsd1C71ckIp0cyXkPhyTtpyS/5hq9HhuUNzEHkSDe36/Rd1xYKV5JxMC2\nYAttWFUs06lor2q1wwncPaMtUtbWwW35+1IV6xhs2rFY6DD/I6ZkK3GnHdY=\n-----END CERTIFICATE-----\n".freeze]
-  s.date = "2018-05-30"
-  s.description = "RSpec results that your continuous integration service can read.".freeze
-  s.email = "sj26@sj26.com".freeze
-  s.files = ["LICENSE".freeze, "README.md".freeze, "lib/rspec_junit_formatter.rb".freeze, "lib/rspec_junit_formatter/rspec2.rb".freeze, "lib/rspec_junit_formatter/rspec3.rb".freeze]
-  s.homepage = "http://github.com/sj26/rspec_junit_formatter".freeze
-  s.licenses = ["MIT".freeze]
-  s.required_ruby_version = Gem::Requirement.new(">= 2.0.0".freeze)
-  s.rubygems_version = "3.1.2".freeze
-  s.summary = "RSpec JUnit XML formatter".freeze
+  # https://github.com/rspec/rspec-core/commit/f06254c00770387e3a8a2efbdbc973035c217f6a
+  s.add_dependency "rspec-core", ">= 2", "< 4", "!= 2.12.0"
 
-  if s.respond_to? :specification_version then
-    s.specification_version = 4
-  end
+  s.add_development_dependency "bundler"
+  s.add_development_dependency "appraisal"
+  s.add_development_dependency "nokogiri", "~> 1.8", ">= 1.8.2"
+  s.add_development_dependency "rake"
+  s.add_development_dependency "coderay"
 
-  if s.respond_to? :add_runtime_dependency then
-    s.add_development_dependency(%q<appraisal>.freeze, [">= 0"])
-    s.add_development_dependency(%q<bundler>.freeze, [">= 0"])
-    s.add_development_dependency(%q<coderay>.freeze, [">= 0"])
-    s.add_development_dependency(%q<nokogiri>.freeze, ["~> 1.8", ">= 1.8.2"])
-    s.add_development_dependency(%q<rake>.freeze, [">= 0"])
-    s.add_runtime_dependency(%q<rspec-core>.freeze, [">= 2", "< 4", "!= 2.12.0"])
-  else
-    s.add_dependency(%q<appraisal>.freeze, [">= 0"])
-    s.add_dependency(%q<bundler>.freeze, [">= 0"])
-    s.add_dependency(%q<coderay>.freeze, [">= 0"])
-    s.add_dependency(%q<nokogiri>.freeze, ["~> 1.8", ">= 1.8.2"])
-    s.add_dependency(%q<rake>.freeze, [">= 0"])
-    s.add_dependency(%q<rspec-core>.freeze, [">= 2", "< 4", "!= 2.12.0"])
-  end
+  s.files        = Dir["lib/**/*", "README.md", "LICENSE"]
+  s.require_path = "lib"
 end
diff --git a/spec/rspec_junit_formatter_spec.rb b/spec/rspec_junit_formatter_spec.rb
new file mode 100644
index 0000000..7a9d1dc
--- /dev/null
+++ b/spec/rspec_junit_formatter_spec.rb
@@ -0,0 +1,189 @@
+require "pty"
+require "stringio"
+require "nokogiri"
+require "rspec_junit_formatter"
+
+describe RspecJunitFormatter do
+  TMP_DIR = File.expand_path("../../tmp", __FILE__)
+  EXAMPLE_DIR = File.expand_path("../../example", __FILE__)
+
+  before(:all) { ENV.delete("TEST_ENV_NUMBER") } # Make sure this doesn't exist by default
+
+  let(:formatter_output_path) { File.join(TMP_DIR, "junit.xml") }
+  let(:formatter_output) { output; File.read(formatter_output_path) }
+
+  let(:formatter_arguments) { ["--format", "RspecJunitFormatter", "--out", formatter_output_path] }
+  let(:extra_arguments) { [] }
+
+  let(:color_opt) do
+    RSpec.configuration.respond_to?(:color_mode=) ? "--force-color" : "--color"
+  end
+
+  def safe_pty(command, **pty_options)
+    output = StringIO.new
+
+    PTY.spawn(*command, **pty_options) do |r, w, pid|
+      begin
+        r.each_line { |line| output.puts(line) }
+      rescue Errno::EIO
+        # Command closed output, or exited
+      ensure
+        Process.wait pid
+      end
+    end
+
+    output.string
+  end
+
+  def execute_example_spec
+    command = ["bundle", "exec", "rspec", *formatter_arguments, color_opt, *extra_arguments]
+
+    safe_pty(command, chdir: EXAMPLE_DIR)
+  end
+
+  let(:output) { execute_example_spec }
+
+  let(:doc) { Nokogiri::XML::Document.parse(formatter_output) }
+
+  let(:testsuite) { doc.xpath("/testsuite").first }
+  let(:testcases) { doc.xpath("/testsuite/testcase") }
+  let(:successful_testcases) { doc.xpath("/testsuite/testcase[not(failure) and not(skipped)]") }
+  let(:pending_testcases) { doc.xpath("/testsuite/testcase[skipped]") }
+  let(:failed_testcases) { doc.xpath("/testsuite/testcase[failure]") }
+  let(:shared_testcases) { doc.xpath("/testsuite/testcase[contains(@name, 'shared example')]") }
+  let(:failed_shared_testcases) { doc.xpath("/testsuite/testcase[contains(@name, 'shared example')][failure]") }
+
+  # Combined into a single example so we don't have to re-run the example rspec
+  # process over and over. (We need to change the parameters in later specs so
+  # we can't use before(:all).)
+  #
+  it "correctly describes the test results", aggregate_failures: true do
+    # it has a testsuite
+
+    expect(testsuite).not_to be(nil)
+
+    expect(testsuite["name"]).to eql("rspec")
+    expect(testsuite["tests"]).to eql("12")
+    expect(testsuite["skipped"]).to eql("1")
+    expect(testsuite["failures"]).to eql("8")
+    expect(testsuite["errors"]).to eql("0")
+    expect(Time.parse(testsuite["timestamp"])).to be_within(60).of(Time.now)
+    expect(testsuite["time"].to_f).to be > 0
+    expect(testsuite["hostname"]).not_to be_empty
+
+    # it has some test cases
+
+    expect(testcases.size).to eql(12)
+
+    testcases.each do |testcase|
+      expect(testcase["classname"]).to eql("spec.example_spec")
+      expect(testcase["name"]).not_to be_empty
+      expect(testcase["time"].to_f).to be > 0
+    end
+
+    # it has successful test cases
+
+    expect(successful_testcases.size).to eql(3)
+
+    successful_testcases.each do |testcase|
+      expect(testcase).not_to be(nil)
+      # test results that capture stdout / stderr are not 'empty'
+      unless (testcase["name"]) =~ /capture stdout and stderr/
+        expect(testcase.children).to be_empty
+      end
+    end
+
+    # it has pending test cases
+
+    expect(pending_testcases.size).to eql(1)
+
+    pending_testcases.each do |testcase|
+      expect(testcase.element_children.size).to eql(1)
+      child = testcase.element_children.first
+      expect(child.name).to eql("skipped")
+      expect(child.attributes).to be_empty
+      expect(child.text).to be_empty
+    end
+
+    # it has failed test cases
+
+    expect(failed_testcases.size).to eql(8)
+
+    failed_testcases.each do |testcase|
+      expect(testcase).not_to be(nil)
+      expect(testcase.element_children.size).to eql(1)
+
+      child = testcase.element_children.first
+      expect(child.name).to eql("failure")
+      expect(child["message"]).not_to be_empty
+      expect(child.text.strip).not_to be_empty
+      expect(child.text.strip).not_to match(/\\e\[(?:\d+;?)+m/)
+    end
+
+    # it has shared test cases which list both the inclusion and included files
+
+    expect(shared_testcases.size).to eql(2)
+    shared_testcases.each do |testcase|
+      # shared examples should be groups with their including files
+      expect(testcase["classname"]).to eql("spec.example_spec")
+    end
+
+    expect(failed_shared_testcases.size).to eql(1)
+    failed_shared_testcases.each do |testcase|
+      expect(testcase.text).to include("example_spec.rb")
+      expect(testcase.text).to include("shared_examples.rb")
+    end
+
+    # it cleans up diffs
+
+    diff_testcase_failure = doc.xpath("//testcase[contains(@name, 'diffs')]/failure").first
+    expect(diff_testcase_failure[:message]).not_to match(/\e | \\e/x)
+    expect(diff_testcase_failure.text).not_to match(/\e | \\e/x)
+
+    # it correctly replaces illegal characters
+
+    expect(doc.xpath("//testcase[contains(@name, 'naughty')]").first[:name]).to eql("some example specs replaces naughty \\0 and \\e characters, \\x01 and \\uFFFF too")
+
+    # it correctly escapes discouraged characters
+
+    expect(doc.xpath("//testcase[contains(@name, 'controlling')]").first[:name]).to eql("some example specs escapes controlling \u{7f} characters")
+
+    # it correctly escapes emoji characters
+
+    expect(doc.xpath("//testcase[contains(@name, 'unicodes')]").first[:name]).to eql("some example specs can include unicodes \u{1f601}")
+
+    # it correctly escapes reserved xml characters
+
+    expect(doc.xpath("//testcase[contains(@name, 'html')]").first[:name]).to eql(%{some example specs escapes <html tags='correctly' and="such &amp; such">})
+
+    # it correctly captures stdout / stderr output
+    expect(doc.xpath("//testcase/system-out").text).to eql("Test\n")
+    expect(doc.xpath("//testcase/system-err").text).to eql("Bar\n")
+  end
+
+  context "when $TEST_ENV_NUMBER is set" do
+    around do |example|
+      begin
+        ENV["TEST_ENV_NUMBER"] = "42"
+        example.call
+      ensure
+        ENV.delete("TEST_ENV_NUMBER")
+      end
+    end
+
+    it "includes $TEST_ENV_NUMBER in the testsuite name" do
+      expect(testsuite["name"]).to eql("rspec42")
+    end
+  end
+
+  context "with a known rspec seed" do
+    let(:extra_arguments) { ["--seed", "12345"] }
+
+    let(:seed_property) { doc.xpath("/testsuite/properties/property[@name='seed']").first }
+
+    it "has a property with seed info" do
+      expect(seed_property["name"]).to eql("seed")
+      expect(seed_property["value"]).to eql("12345")
+    end
+  end
+end

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/share/doc/ruby-rspec-junit-formatter/README.md.gz
-rw-r--r--  root/root   /usr/share/doc/ruby-rspec-junit-formatter/changelog.gz
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/rspec_junit_formatter-0.6.0/lib/rspec_junit_formatter.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/rspec_junit_formatter-0.6.0/lib/rspec_junit_formatter/rspec2.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/rspec_junit_formatter-0.6.0/lib/rspec_junit_formatter/rspec3.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/specifications/rspec_junit_formatter-0.6.0.gemspec

Files in first set of .debs but not in second

-rw-r--r--  root/root   /usr/share/doc/ruby-rspec-junit-formatter/README.md
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/rspec_junit_formatter-0.4.1/lib/rspec_junit_formatter.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/rspec_junit_formatter-0.4.1/lib/rspec_junit_formatter/rspec2.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/gems/rspec_junit_formatter-0.4.1/lib/rspec_junit_formatter/rspec3.rb
-rw-r--r--  root/root   /usr/share/rubygems-integration/all/specifications/rspec_junit_formatter-0.4.1.gemspec

Control files: lines which differ (wdiff format)

  • Ruby-Versions: all

More details

Full run details