pax_global_header00006660000000000000000000000064143152325250014514gustar00rootroot0000000000000052 comment=02c1756f2b50853ccf698cca7ab2d607f67b47b3 rspec_junit_formatter-0.6.0/000077500000000000000000000000001431523252500161275ustar00rootroot00000000000000rspec_junit_formatter-0.6.0/.github/000077500000000000000000000000001431523252500174675ustar00rootroot00000000000000rspec_junit_formatter-0.6.0/.github/workflows/000077500000000000000000000000001431523252500215245ustar00rootroot00000000000000rspec_junit_formatter-0.6.0/.github/workflows/ci.yml000066400000000000000000000013771431523252500226520ustar00rootroot00000000000000name: 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 rspec_junit_formatter-0.6.0/.gitignore000066400000000000000000000000521431523252500201140ustar00rootroot00000000000000/.bundle/ /doc/ /example/tmp/ /pkg/ /tmp/ rspec_junit_formatter-0.6.0/Appraisals000066400000000000000000000015721431523252500201560ustar00rootroot00000000000000appraise "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 rspec_junit_formatter-0.6.0/CHANGELOG.md000066400000000000000000000031641431523252500177440ustar00rootroot00000000000000# 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 rspec_junit_formatter-0.6.0/Gemfile000066400000000000000000000000641431523252500174220ustar00rootroot00000000000000source "https://rubygems.org" gemspec gem "rspec" rspec_junit_formatter-0.6.0/Gemfile.lock000066400000000000000000000016671431523252500203630ustar00rootroot00000000000000PATH 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 rspec_junit_formatter-0.6.0/LICENSE000066400000000000000000000020471431523252500171370ustar00rootroot00000000000000Copyright (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 "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. rspec_junit_formatter-0.6.0/README.md000066400000000000000000000101701431523252500174050ustar00rootroot00000000000000# 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], [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 Install the gem: ```sh gem install rspec_junit_formatter ``` Use it: ```sh rspec --format RspecJunitFormatter --out rspec.xml ``` You'll get an XML file `rspec.xml` with your results in it. You can use it in combination with other [formatters][rspec-formatters], too: ```sh rspec --format progress --format RspecJunitFormatter --out rspec.xml ``` [rspec-formatters]: https://relishapp.com/rspec/rspec-core/v/3-6/docs/formatters ### Using in your project with Bundler Add it to your Gemfile if you're using [Bundler][bundler]. Put it in the same groups as rspec. ```ruby group :test do gem "rspec" gem "rspec_junit_formatter" end ``` Put the same arguments as the commands above in [your `.rspec`][rspec-file]: ```sh --format RspecJunitFormatter --out rspec.xml ``` [bundler]: https://bundler.io [rspec-file]: https://relishapp.com/rspec/rspec-core/v/3-6/docs/configuration/read-command-line-configuration-options-from-files ### Parallel tests 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. ```sh --format RspecJunitFormatter --out tmp/rspec<%= ENV["TEST_ENV_NUMBER"] %>.xml ``` The formatter includes `$TEST_ENV_NUMBER` in the test suite name within the XML, too. ### Capturing output 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.: ```ruby # spec_helper.rb RSpec.configure do |config| # register around filter that captures stdout and stderr 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 ``` 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 ## Development Run the specs with `bundle exec rake`, which uses [Appraisal][appraisal] to run the specs against all supported versions of rspec. [appraisal]: https://github.com/thoughtbot/appraisal ## Releasing 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. ## License The MIT License, see [LICENSE](./LICENSE). ## Thanks Inspired by the work of [Diego Souza][dgvncsz0f] on [RSpec Formatters][dgvncsz0f/rspec_formatters] after frustration with [CI Reporter][ci_reporter]. [dgvncsz0f]: https://github.com/dgvncsz0f [dgvncsz0f/rspec_formatters]: https://github.com/dgvncsz0f/rspec_formatters [ci_reporter]: https://github.com/nicksieger/ci_reporter rspec_junit_formatter-0.6.0/Rakefile000066400000000000000000000003331431523252500175730ustar00rootroot00000000000000require "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 rspec_junit_formatter-0.6.0/example/000077500000000000000000000000001431523252500175625ustar00rootroot00000000000000rspec_junit_formatter-0.6.0/example/.rspec000066400000000000000000000000611431523252500206740ustar00rootroot00000000000000--format RspecJunitFormatter --out tmp/rspec.xml rspec_junit_formatter-0.6.0/example/spec/000077500000000000000000000000001431523252500205145ustar00rootroot00000000000000rspec_junit_formatter-0.6.0/example/spec/example_spec.rb000066400000000000000000000020511431523252500235040ustar00rootroot00000000000000require "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 } do expect("

This is important

").to eql("

This is very important

") end it_should_behave_like "shared examples" it "can capture stdout and stderr" do $stdout.puts "Test" $stderr.puts "Bar" end end rspec_junit_formatter-0.6.0/example/spec/shared_examples.rb000066400000000000000000000003161431523252500242050ustar00rootroot00000000000000shared_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 rspec_junit_formatter-0.6.0/example/spec/spec_helper.rb000066400000000000000000000005261431523252500233350ustar00rootroot00000000000000RSpec.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 rspec_junit_formatter-0.6.0/example/tmp/000077500000000000000000000000001431523252500203625ustar00rootroot00000000000000rspec_junit_formatter-0.6.0/example/tmp/.keep000066400000000000000000000000001431523252500212750ustar00rootroot00000000000000rspec_junit_formatter-0.6.0/gemfiles/000077500000000000000000000000001431523252500177225ustar00rootroot00000000000000rspec_junit_formatter-0.6.0/gemfiles/.bundle/000077500000000000000000000000001431523252500212515ustar00rootroot00000000000000rspec_junit_formatter-0.6.0/gemfiles/.bundle/config000066400000000000000000000000711431523252500224370ustar00rootroot00000000000000--- BUNDLE_RETRY: "1" BUNDLE_WITHOUT: "development,test" rspec_junit_formatter-0.6.0/gemfiles/rspec_2_x.gemfile000066400000000000000000000002231431523252500231350ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rspec", "~> 2.14", "< 2.99" gem "rake", "~> 10.0" gemspec path: "../" rspec_junit_formatter-0.6.0/gemfiles/rspec_2_x.gemfile.lock000066400000000000000000000014701431523252500240710ustar00rootroot00000000000000PATH 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 rspec_junit_formatter-0.6.0/gemfiles/rspec_3_0.gemfile000066400000000000000000000002121431523252500230240ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rspec", "~> 3.0.0" gem "rake", "~> 10.0" gemspec path: "../" rspec_junit_formatter-0.6.0/gemfiles/rspec_3_0.gemfile.lock000066400000000000000000000016411431523252500237620ustar00rootroot00000000000000PATH 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 rspec_junit_formatter-0.6.0/gemfiles/rspec_3_1.gemfile000066400000000000000000000002121431523252500230250ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rspec", "~> 3.1.0" gem "rake", "~> 10.0" gemspec path: "../" rspec_junit_formatter-0.6.0/gemfiles/rspec_3_1.gemfile.lock000066400000000000000000000016411431523252500237630ustar00rootroot00000000000000PATH 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 rspec_junit_formatter-0.6.0/gemfiles/rspec_3_10.gemfile000066400000000000000000000001651431523252500231140ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rspec", "~> 3.10.0" gemspec path: "../" rspec_junit_formatter-0.6.0/gemfiles/rspec_3_10.gemfile.lock000066400000000000000000000017041431523252500240430ustar00rootroot00000000000000PATH 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 rspec_junit_formatter-0.6.0/gemfiles/rspec_3_2.gemfile000066400000000000000000000002121431523252500230260ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rspec", "~> 3.2.0" gem "rake", "~> 10.0" gemspec path: "../" rspec_junit_formatter-0.6.0/gemfiles/rspec_3_2.gemfile.lock000066400000000000000000000017021431523252500237620ustar00rootroot00000000000000PATH 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 rspec_junit_formatter-0.6.0/gemfiles/rspec_3_3.gemfile000066400000000000000000000002121431523252500230270ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rspec", "~> 3.3.0" gem "rake", "~> 10.0" gemspec path: "../" rspec_junit_formatter-0.6.0/gemfiles/rspec_3_3.gemfile.lock000066400000000000000000000017021431523252500237630ustar00rootroot00000000000000PATH 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 rspec_junit_formatter-0.6.0/gemfiles/rspec_3_4.gemfile000066400000000000000000000001641431523252500230360ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rspec", "~> 3.4.0" gemspec path: "../" rspec_junit_formatter-0.6.0/gemfiles/rspec_3_4.gemfile.lock000066400000000000000000000016701431523252500237700ustar00rootroot00000000000000PATH 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 rspec_junit_formatter-0.6.0/gemfiles/rspec_3_5.gemfile000066400000000000000000000001641431523252500230370ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rspec", "~> 3.5.0" gemspec path: "../" rspec_junit_formatter-0.6.0/gemfiles/rspec_3_5.gemfile.lock000066400000000000000000000016701431523252500237710ustar00rootroot00000000000000PATH 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 rspec_junit_formatter-0.6.0/gemfiles/rspec_3_6.gemfile000066400000000000000000000001641431523252500230400ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rspec", "~> 3.6.0" gemspec path: "../" rspec_junit_formatter-0.6.0/gemfiles/rspec_3_6.gemfile.lock000066400000000000000000000016701431523252500237720ustar00rootroot00000000000000PATH 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 rspec_junit_formatter-0.6.0/gemfiles/rspec_3_7.gemfile000066400000000000000000000001641431523252500230410ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rspec", "~> 3.7.0" gemspec path: "../" rspec_junit_formatter-0.6.0/gemfiles/rspec_3_7.gemfile.lock000066400000000000000000000016701431523252500237730ustar00rootroot00000000000000PATH 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 rspec_junit_formatter-0.6.0/gemfiles/rspec_3_8.gemfile000066400000000000000000000001641431523252500230420ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rspec", "~> 3.8.0" gemspec path: "../" rspec_junit_formatter-0.6.0/gemfiles/rspec_3_8.gemfile.lock000066400000000000000000000016701431523252500237740ustar00rootroot00000000000000PATH 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 rspec_junit_formatter-0.6.0/gemfiles/rspec_3_9.gemfile000066400000000000000000000001641431523252500230430ustar00rootroot00000000000000# This file was generated by Appraisal source "https://rubygems.org" gem "rspec", "~> 3.9.0" gemspec path: "../" rspec_junit_formatter-0.6.0/gemfiles/rspec_3_9.gemfile.lock000066400000000000000000000016701431523252500237750ustar00rootroot00000000000000PATH 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 rspec_junit_formatter-0.6.0/lib/000077500000000000000000000000001431523252500166755ustar00rootroot00000000000000rspec_junit_formatter-0.6.0/lib/rspec_junit_formatter.rb000066400000000000000000000135421431523252500236370ustar00rootroot00000000000000# frozen_string_literal: true require "socket" require "time" require "rspec/core" require "rspec/core/formatters/base_formatter" # Dumps rspec results as a JUnit XML file. # Based on XML schema: http://windyroad.org/dl/Open%20Source/JUnit.xsd class RSpecJUnitFormatter < RSpec::Core::Formatters::BaseFormatter # rspec 2 and 3 implements are in separate files. private def xml_dump output << %{\n} output << %{\n} output << %{\n} output << %{\n} output << %{\n} xml_dump_examples output << %{\n} end def xml_dump_examples examples.each do |example| case result_of(example) when :pending xml_dump_pending(example) when :failed xml_dump_failed(example) else xml_dump_example(example) end end end def xml_dump_pending(example) xml_dump_example(example) do output << %{} end end def xml_dump_failed(example) xml_dump_example(example) do output << %{} output << escape(failure_for(example)) output << %{} end end def xml_dump_example(example) output << %{} yield if block_given? xml_dump_output(example) output << %{\n} end def xml_dump_output(example) if (stdout = stdout_for(example)) && !stdout.empty? output << %{} output << escape(stdout) output << %{} end if (stderr = stderr_for(example)) && !stderr.empty? output << %{} output << escape(stderr) output << %{} end end # 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 "\u{20}-\u{d7ff}" << "\u{e000}-\u{fffd}" << "\u{10000}-\u{10ffff}" << "]" ) # Replace illegals with a Ruby-like escape ILLEGAL_REPLACEMENT = Hash.new { |_, c| x = c.ord if x <= 0xff "\\x%02X".freeze % x elsif x <= 0xffff "\\u%04X".freeze % x else "\\u{%X}".freeze % x end.freeze }.update( "\0".freeze => "\\0".freeze, "\a".freeze => "\\a".freeze, "\b".freeze => "\\b".freeze, "\f".freeze => "\\f".freeze, "\v".freeze => "\\v".freeze, "\e".freeze => "\\e".freeze, ).freeze # 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}" << # => ' "\u{3c}" << # => < "\u{3e}" << # => > "\u{7f}-\u{84}" << "\u{86}-\u{9f}" << "\u{fdd0}-\u{fdef}" << "\u{1fffe}-\u{1ffff}" << "\u{2fffe}-\u{2ffff}" << "\u{3fffe}-\u{3ffff}" << "\u{4fffe}-\u{4ffff}" << "\u{5fffe}-\u{5ffff}" << "\u{6fffe}-\u{6ffff}" << "\u{7fffe}-\u{7ffff}" << "\u{8fffe}-\u{8ffff}" << "\u{9fffe}-\u{9ffff}" << "\u{afffe}-\u{affff}" << "\u{bfffe}-\u{bffff}" << "\u{cfffe}-\u{cffff}" << "\u{dfffe}-\u{dffff}" << "\u{efffe}-\u{effff}" << "\u{ffffe}-\u{fffff}" << "\u{10fffe}-\u{10ffff}" << "]" ) # Translate well-known entities, or use generic unicode hex entity DISCOURAGED_REPLACEMENTS = Hash.new { |_, c| "&#x#{c.ord.to_s(16)};".freeze }.update( ?".freeze => """.freeze, ?&.freeze => "&".freeze, ?'.freeze => "'".freeze, ?<.freeze => "<".freeze, ?>.freeze => ">".freeze, ).freeze def escape(text) # Make sure it's utf-8, replace illegal characters with ruby-like escapes, and replace special and discouraged characters with entities text.to_s.encode(Encoding::UTF_8).gsub(ILLEGAL_REGEXP, ILLEGAL_REPLACEMENT).gsub(DISCOURAGED_REGEXP, DISCOURAGED_REPLACEMENTS) end STRIP_DIFF_COLORS_BLOCK_REGEXP = /^ ( [ ]* ) Diff: (?: \e\[ 0 m )? (?: \n \1 \e\[ \d+ (?: ; \d+ )* m .* )* /x STRIP_DIFF_COLORS_CODES_REGEXP = /\e\[ \d+ (?: ; \d+ )* m/x def strip_diff_colors(string) # XXX: RSpec diffs are appended to the message lines fairly early and will # contain ANSI escape codes for colorizing terminal output if the global # rspec configuration is turned on, regardless of which notification lines # we ask for. We need to strip the codes from the diff part of the message # for XML output here. # # We also only want to target the diff hunks because the failure message # itself might legitimately contain ansi escape codes. # string.sub(STRIP_DIFF_COLORS_BLOCK_REGEXP) { |match| match.gsub(STRIP_DIFF_COLORS_CODES_REGEXP, "".freeze) } end end RspecJunitFormatter = RSpecJUnitFormatter if Gem::Version.new(RSpec::Core::Version::STRING) >= Gem::Version.new("3") require "rspec_junit_formatter/rspec3" else require "rspec_junit_formatter/rspec2" end rspec_junit_formatter-0.6.0/lib/rspec_junit_formatter/000077500000000000000000000000001431523252500233055ustar00rootroot00000000000000rspec_junit_formatter-0.6.0/lib/rspec_junit_formatter/rspec2.rb000066400000000000000000000036241431523252500250350ustar00rootroot00000000000000# frozen_string_literal: true class RSpecJUnitFormatter < RSpec::Core::Formatters::BaseFormatter attr_reader :started def start(example_count) @started = Time.now super end def dump_summary(duration, example_count, failure_count, pending_count) super xml_dump end private def result_of(example) example.execution_result[:status].to_sym end def example_group_file_path_for(example) meta = example.metadata while meta[:example_group] meta = meta[:example_group] end meta[:file_path] end def classname_for(example) fp = example_group_file_path_for(example) fp.sub(%r{\.[^/.]+\Z}, "").gsub("/", ".").gsub(/\A\.+|\.+\Z/, "") end def duration_for(example) example.execution_result[:run_time] end def description_for(example) example.full_description end def exception_for(example) example.execution_result[:exception] end def failure_type_for(example) exception_for(example).class.name end def failure_message_for(example) strip_diff_colors(exception_for(example).to_s) end def failure_for(example) exception = exception_for(example) message = strip_diff_colors(exception.message) backtrace = format_backtrace(exception.backtrace, example) if shared_group = find_shared_group(example) backtrace << "Shared Example Group: \"#{shared_group.metadata[:shared_group_name]}\" called from #{shared_group.metadata[:example_group][:location]}" end "#{message}\n#{backtrace.join("\n")}" end def error_count 0 end def find_shared_group(example) group_and_parent_groups(example).find { |group| group.metadata[:shared_group_name] } end def group_and_parent_groups(example) example.example_group.parent_groups + [example.example_group] end def stdout_for(example) example.metadata[:stdout] end def stderr_for(example) example.metadata[:stderr] end end rspec_junit_formatter-0.6.0/lib/rspec_junit_formatter/rspec3.rb000066400000000000000000000103161431523252500250320ustar00rootroot00000000000000# frozen_string_literal: true class RSpecJUnitFormatter < RSpec::Core::Formatters::BaseFormatter RSpec::Core::Formatters.register self, :start, :stop, :dump_summary def start(notification) @start_notification = notification @started = Time.now super end def stop(notification) @examples_notification = notification end def dump_summary(notification) @summary_notification = notification without_color { xml_dump } end private attr_reader :started def example_count @summary_notification.example_count end def pending_count @summary_notification.pending_count end def failure_count @summary_notification.failure_count end def duration @summary_notification.duration end def examples @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 def example_group_file_path_for(notification) metadata = notification.example.metadata[:example_group] while parent_metadata = metadata[:parent_example_group] metadata = parent_metadata end metadata[:file_path] end def classname_for(notification) fp = example_group_file_path_for(notification) fp.sub(%r{\.[^/]*\Z}, "").gsub("/", ".").gsub(%r{\A\.+|\.+\Z}, "") end def duration_for(notification) notification.example.execution_result.run_time end def description_for(notification) notification.example.full_description end def failure_type_for(example) exception_for(example).class.name end def failure_message_for(example) strip_diff_colors(exception_for(example).to_s) end def failure_for(notification) strip_diff_colors(notification.message_lines.join("\n")) << "\n" << notification.formatted_backtrace.join("\n") end def exception_for(notification) notification.example.execution_result.exception end # rspec makes it really difficult to swap in configuration temporarily due to # the way it cascades defaults, command line arguments, and user # configuration. This method makes sure configuration gets swapped in # correctly, but also that the original state is definitely restored. def swap_rspec_configuration(key, value) unset = Object.new force = RSpec.configuration.send(:value_for, key) { unset } if unset.equal?(force) previous = RSpec.configuration.send(key) RSpec.configuration.send(:"#{key}=", value) else RSpec.configuration.force({key => value}) end yield ensure if unset.equal?(force) RSpec.configuration.send(:"#{key}=", previous) else RSpec.configuration.force({key => force}) end end # Completely gross hack for absolutely forcing off colorising for the # duration of a block. if RSpec.configuration.respond_to?(:color_mode=) def without_color(&block) swap_rspec_configuration(:color_mode, :off, &block) end elsif RSpec.configuration.respond_to?(:color=) def without_color(&block) swap_rspec_configuration(:color, false, &block) end else warn 'rspec_junit_formatter cannot prevent colorising due to an unexpected RSpec.configuration format' def without_color yield end end def stdout_for(example_notification) example_notification.example.metadata[:stdout] end def stderr_for(example_notification) example_notification.example.metadata[:stderr] end end # rspec-core 3.0.x forgot to mark this as a module function which causes: # # NoMethodError: undefined method `wrap' for RSpec::Core::Notifications::NullColorizer:Class # .../rspec-core-3.0.4/lib/rspec/core/notifications.rb:229:in `add_shared_group_line' # .../rspec-core-3.0.4/lib/rspec/core/notifications.rb:157:in `message_lines' # if defined?(RSpec::Core::Notifications::NullColorizer) && RSpec::Core::Notifications::NullColorizer.is_a?(Class) && !RSpec::Core::Notifications::NullColorizer.respond_to?(:wrap) RSpec::Core::Notifications::NullColorizer.class_eval do def self.wrap(*args) new.wrap(*args) end end end rspec_junit_formatter-0.6.0/reference/000077500000000000000000000000001431523252500200655ustar00rootroot00000000000000rspec_junit_formatter-0.6.0/reference/JUnit.xsd000066400000000000000000000221111431523252500216330ustar00rootroot00000000000000 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). Contains an aggregation of testsuite results Derived from testsuite/@name in the non-aggregated documents Starts at '0' for the first testsuite and is incremented by 1 for each following testsuite Contains the results of exexuting a testsuite Properties (e.g., environment settings) set during test execution 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 The error message. e.g., if a java exception is thrown, the return value of getMessage() The type of error that occured. e.g., if a java execption is thrown the full class name of the exception. 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 The message specified in the assert The type of the assert. Name of the test method Full class name for the class the test method is in. Time taken (in seconds) to execute the test Data that was written to standard out while the test was executed Data that was written to standard error while the test was executed Full class name of the test for non-aggregated testsuite documents. Class name without the package for aggregated testsuites documents when the test was executed. Timezone may not be specified. Host on which the tests were executed. 'localhost' should be used if the hostname cannot be determined. The total number of tests in the suite 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 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. Time taken (in seconds) to execute the tests in the suite rspec_junit_formatter-0.6.0/rspec_junit_formatter.gemspec000066400000000000000000000021041431523252500241010ustar00rootroot00000000000000Gem::Specification.new do |s| 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', } # https://github.com/rspec/rspec-core/commit/f06254c00770387e3a8a2efbdbc973035c217f6a s.add_dependency "rspec-core", ">= 2", "< 4", "!= 2.12.0" 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" s.files = Dir["lib/**/*", "README.md", "LICENSE"] s.require_path = "lib" end rspec_junit_formatter-0.6.0/spec/000077500000000000000000000000001431523252500170615ustar00rootroot00000000000000rspec_junit_formatter-0.6.0/spec/rspec_junit_formatter_spec.rb000066400000000000000000000145651431523252500250430ustar00rootroot00000000000000require "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 }) # 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