minitest-junit_formatter 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6187bdbdbb70fedb0f8ae74880f5dc52be2b5fcd1dbbf8c2c33d1d45ec50951c
4
- data.tar.gz: d6f6d37a483382f086aae7257bfd11b5c4df6bdcfb8e95223ffdb3388e89bdd1
3
+ metadata.gz: 48efdf67a0c1a27752128640d319129d3575a5212d5a74def0ae6dfecb27b58f
4
+ data.tar.gz: 66bca0a2dd39f15b4d2b9e24bca3baca67e51ef019857b1675e94b1b84961d07
5
5
  SHA512:
6
- metadata.gz: ef3ec5092642cd0a897e94710e959090f6745ec02a659bba65fa4ffda7159f9ed3a25c0c787eb17f0e27b0f37f2327322cb391d9718005f3841e03498f600c00
7
- data.tar.gz: 85257d6d9755ba2829b0d83e6ce3132768b8ab3c287b177059e37f123996cec7ba93d80ce525f94c5a6d315b13d2518eb4995dbba541bc7d612a5a6c4942b9fe
6
+ metadata.gz: 58548caa1d3bc7b99cad7d3a5bb834aea49cb1f47770dde967146fc524589bf9c4ae1e172f234f6b8629880b3fbd14992413f5721ed0e55b649d5389c9405e8f
7
+ data.tar.gz: ac6d1f4c2c04bab8574acedc4020b4f2c6b20f5ef198b87be0ecbbb4a326fac3fea0fb1e5402db5bfa915f70a95ef9381a893df98f633cfcff670c9ef7999937
@@ -1,18 +1,21 @@
1
1
  name: Main
2
2
  on:
3
3
  push:
4
- branches: [release]
4
+ branches: [main, release]
5
5
  pull_request:
6
- types: [opened, synchronize]
6
+ workflow_dispatch:
7
7
 
8
8
  jobs:
9
9
  tests:
10
- name: Tests
10
+ name: Ruby ${{ matrix.ruby }} / Minitest ${{ matrix.minitest }}
11
11
  runs-on: ubuntu-latest
12
12
  strategy:
13
13
  fail-fast: false
14
14
  matrix:
15
- ruby: ["2.7", "3.0", "3.1", "3.2"]
15
+ ruby: ["3.2", "3.3", "3.4", "jruby-10.0", "jruby-10.1"]
16
+ minitest: ["5", "6"]
17
+ env:
18
+ MINITEST_VERSION: ${{ matrix.minitest }}
16
19
 
17
20
  steps:
18
21
  - name: Checkout code
@@ -23,12 +26,8 @@ jobs:
23
26
  with:
24
27
  ruby-version: ${{ matrix.ruby }}
25
28
  bundler-cache: true
26
-
27
- - name: Generate lockfile
28
- run: bundle lock
29
-
30
- - name: Bundle
31
- run: bundle check || bundle install
29
+ # Separate gem caches per Minitest major version.
30
+ cache-version: minitest-${{ matrix.minitest }}
32
31
 
33
32
  - name: Run tests
34
33
  run: bundle exec rake test
data/.gitignore CHANGED
@@ -20,3 +20,5 @@ tmp
20
20
  *.o
21
21
  *.a
22
22
  mkmf.log
23
+ pik.sh
24
+ report.xml
data/Gemfile CHANGED
@@ -2,3 +2,11 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in minitest-junit.gemspec
4
4
  gemspec
5
+
6
+ # Test against a specific Minitest major version, e.g. MINITEST_VERSION=5
7
+ # Minitest 6 requires Ruby 3.2+.
8
+ minitest_version = ENV.fetch('MINITEST_VERSION') { RUBY_VERSION >= '3.2' ? '6' : '5' }
9
+ gem 'minitest', "~> #{minitest_version}.0"
10
+
11
+ # Minitest 6 extracted minitest/mock into its own gem.
12
+ gem 'minitest-mock' if minitest_version.to_i >= 6
data/README.md CHANGED
@@ -14,7 +14,7 @@ And then execute:
14
14
 
15
15
  Or install it yourself as:
16
16
 
17
- $ gem install minitest-junit
17
+ $ gem install minitest-junit_formatter
18
18
 
19
19
  ## Usage
20
20
 
@@ -27,10 +27,9 @@ Or install it yourself as:
27
27
  --junit-jenkins Sanitize test names for Jenkins display
28
28
  ...
29
29
 
30
- ## Contributing
30
+ ## Acknowledgment
31
+
32
+ This project is based on
33
+
34
+ https://github.com/aespinosa/minitest-junit
31
35
 
32
- 1. Fork it ( https://github.com/aespinosa/minitest-junit/fork )
33
- 2. Create your feature branch (`git checkout -b my-new-feature`)
34
- 3. Commit your changes (`git commit -am 'Add some feature'`)
35
- 4. Push to the branch (`git push origin my-new-feature`)
36
- 5. Create a new Pull Request
@@ -1,6 +1,6 @@
1
1
  module Minitest
2
2
  # :nodoc:
3
3
  module JunitFormatter
4
- VERSION = "0.1.0"
4
+ VERSION = "0.3.0"
5
5
  end
6
6
  end
@@ -0,0 +1,34 @@
1
+ module Minitest
2
+ module JunitFormatter
3
+ class NokogiriDocument
4
+ def initialize
5
+ @doc = Nokogiri::XML::Document.new
6
+ @doc.encoding = 'UTF-8'
7
+ end
8
+
9
+ def document
10
+ @doc
11
+ end
12
+
13
+ def element(name)
14
+ Nokogiri::XML::Node.new(name, @doc)
15
+ end
16
+
17
+ def set_attr(el, name, value)
18
+ el[name.to_s] = value.to_s
19
+ end
20
+
21
+ def add_child(parent, child)
22
+ parent << child
23
+ end
24
+
25
+ def add_text(el, text)
26
+ el.content = text.to_s
27
+ end
28
+
29
+ def dump(doc)
30
+ doc.to_xml(indent: 2)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,38 @@
1
+ module Minitest
2
+ module JunitFormatter
3
+ class RexmlDocument
4
+ # Emit double-quoted attributes, matching the Nokogiri backend.
5
+ CONTEXT = { attribute_quote: :quote }.freeze
6
+
7
+ def document
8
+ doc = REXML::Document.new
9
+ doc << REXML::XMLDecl.new('1.0', 'UTF-8')
10
+ doc
11
+ end
12
+
13
+ def element(name)
14
+ REXML::Element.new(name, nil, CONTEXT)
15
+ end
16
+
17
+ def set_attr(el, name, value)
18
+ el.add_attribute(name, value.to_s)
19
+ end
20
+
21
+ def add_child(parent, child)
22
+ parent << child
23
+ end
24
+
25
+ def add_text(el, text)
26
+ el.add_text(text.to_s)
27
+ end
28
+
29
+ def dump(doc)
30
+ output = String.new
31
+ formatter = REXML::Formatters::Pretty.new(2)
32
+ formatter.compact = true
33
+ formatter.write(doc, output)
34
+ output + "\n"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -1,9 +1,17 @@
1
1
  require "minitest/junit_formatter/version"
2
2
  require 'minitest'
3
- require 'ox'
4
3
  require 'socket'
5
4
  require 'time'
6
5
 
6
+ # XML backend: Nokogiri (fast) > REXML (stdlib fallback).
7
+ begin
8
+ require 'nokogiri'
9
+ require "minitest/junit_formatter/xml_nokogiri"
10
+ rescue LoadError
11
+ require 'rexml/document'
12
+ require "minitest/junit_formatter/xml_rexml"
13
+ end
14
+
7
15
  # :nodoc:
8
16
  module Minitest
9
17
  module JunitFormatter
@@ -15,6 +23,15 @@ module Minitest
15
23
  @options = options
16
24
  @options[:timestamp] = options.fetch(:timestamp, Time.now.iso8601)
17
25
  @options[:hostname] = options.fetch(:hostname, Socket.gethostname)
26
+
27
+ @doc = document_factory.new
28
+ end
29
+
30
+ def prerecord(klass, name)
31
+ return unless @options[:verbose]
32
+
33
+ io.print "%s#%s = " % [klass.name, name]
34
+ io.flush
18
35
  end
19
36
 
20
37
  def passed?
@@ -28,52 +45,47 @@ module Minitest
28
45
  end
29
46
 
30
47
  def report
31
- doc = Ox::Document.new(version: '1.0', encoding: 'UTF-8')
32
- instruct = Ox::Instruct.new(:xml)
33
- instruct[:version] = '1.0'
34
- instruct[:encoding] = 'UTF-8'
35
- doc << instruct
36
-
37
- testsuite = Ox::Element.new('testsuite')
38
- testsuite['name'] = @options[:name] || 'minitest'
39
- testsuite['timestamp'] = @options[:timestamp]
40
- testsuite['hostname'] = @options[:hostname]
41
- testsuite['tests'] = @results.size
42
- testsuite['skipped'] = @results.count(&:skipped?)
43
- testsuite['failures'] = @results.count { |result| !result.error? && result.failure }
44
- testsuite['errors'] = @results.count(&:error?)
45
- testsuite['time'] = format_time(@results.map(&:time).inject(0, :+))
48
+ doc = @doc.document
49
+
50
+ testsuites = @doc.element('testsuites')
51
+ testsuite = @doc.element('testsuite')
52
+ @doc.set_attr(testsuite, 'name', @options[:name] || 'minitest')
53
+ @doc.set_attr(testsuite, 'timestamp', @options[:timestamp])
54
+ @doc.set_attr(testsuite, 'hostname', @options[:hostname])
55
+ @doc.set_attr(testsuite, 'tests', @results.size)
56
+ @doc.set_attr(testsuite, 'skipped', @results.count(&:skipped?))
57
+ @doc.set_attr(testsuite, 'failures', @results.count { |result| !result.error? && result.failure })
58
+ @doc.set_attr(testsuite, 'errors', @results.count(&:error?))
59
+ @doc.set_attr(testsuite, 'time', format_time(@results.map(&:time).inject(0, :+)))
46
60
  @results.each do |result|
47
- testsuite << format(result)
61
+ @doc.add_child(testsuite, format(result))
48
62
  end
49
63
 
50
- testsuites = Ox::Element.new('testsuites')
51
- testsuites << testsuite
52
-
53
- doc << testsuites
54
- @io << Ox.dump(doc)
64
+ @doc.add_child(testsuites, testsuite)
65
+ @doc.add_child(doc, testsuites)
66
+ @io << @doc.dump(doc)
55
67
  end
56
68
 
57
69
  def format(result, parent = nil)
58
- testcase = Ox::Element.new('testcase')
59
- testcase['classname'] = format_class(result)
60
- testcase['name'] = format_name(result)
61
- testcase['time'] = format_time(result.time)
62
- testcase['file'] = relative_to_cwd(result.source_location.first)
63
- testcase['line'] = result.source_location.last
64
- testcase['assertions'] = result.assertions
70
+ testcase = @doc.element('testcase')
71
+ @doc.set_attr(testcase, 'classname', format_class(result))
72
+ @doc.set_attr(testcase, 'name', format_name(result))
73
+ @doc.set_attr(testcase, 'time', format_time(result.time))
74
+ @doc.set_attr(testcase, 'file', relative_to_cwd(result.source_location.first))
75
+ @doc.set_attr(testcase, 'line', result.source_location.last)
76
+ @doc.set_attr(testcase, 'assertions', result.assertions)
65
77
 
66
78
  if result.skipped?
67
- skipped = Ox::Element.new('skipped')
68
- skipped['message'] = result
69
- skipped << ""
70
- testcase << skipped
79
+ skipped = @doc.element('skipped')
80
+ @doc.set_attr(skipped, 'message', result)
81
+ @doc.add_text(skipped, '')
82
+ @doc.add_child(testcase, skipped)
71
83
  else
72
84
  result.failures.each do |failure|
73
- failure_tag = Ox::Element.new(classify(failure))
74
- failure_tag['message'] = result
75
- failure_tag << format_backtrace(failure)
76
- testcase << failure_tag
85
+ failure_tag = @doc.element(classify(failure))
86
+ @doc.set_attr(failure_tag, 'message', result)
87
+ @doc.add_text(failure_tag, format_backtrace(failure))
88
+ @doc.add_child(testcase, failure_tag)
77
89
  end
78
90
  end
79
91
 
@@ -82,9 +94,9 @@ module Minitest
82
94
  # Output according to Gitlab format
83
95
  # https://docs.gitlab.com/ee/ci/testing/unit_test_reports.html#view-junit-screenshots-on-gitlab
84
96
  if result.respond_to?("metadata") && result.metadata[:failure_screenshot_path]
85
- screenshot = Ox::Element.new("system-out")
86
- screenshot << "[[ATTACHMENT|#{result.metadata[:failure_screenshot_path]}]]"
87
- testcase << screenshot
97
+ screenshot = @doc.element("system-out")
98
+ @doc.add_text(screenshot, "[[ATTACHMENT|#{result.metadata[:failure_screenshot_path]}]]")
99
+ @doc.add_child(testcase, screenshot)
88
100
  end
89
101
 
90
102
  testcase
@@ -92,6 +104,14 @@ module Minitest
92
104
 
93
105
  private
94
106
 
107
+ def document_factory
108
+ if defined?(Nokogiri)
109
+ NokogiriDocument
110
+ else
111
+ RexmlDocument
112
+ end
113
+ end
114
+
95
115
  def classify(failure)
96
116
  if failure.instance_of? UnexpectedError
97
117
  'error'
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Minitest::JunitFormatter::VERSION
9
9
  spec.authors = ["Jesse Chavez", "Allan Espinosa"]
10
10
  spec.email = ["jesse.chavez.jp@gmail.com"]
11
- spec.summary = "Junit report formatter for Minitest ~> 5.0"
12
- spec.description = "Junit report formatter for Minitest ~> 5.0"
11
+ spec.summary = "Junit report formatter for Minitest 5 and 6"
12
+ spec.description = "Junit report formatter for Minitest 5 and 6"
13
13
  spec.homepage = "https://github.com/JesseChavez/minitest-junit_formatter"
14
14
  spec.license = "MIT"
15
15
 
@@ -18,11 +18,11 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(/^(test)\//)
19
19
  spec.require_paths = ['lib']
20
20
 
21
- spec.add_dependency 'minitest', '~> 5.11'
22
- spec.add_dependency 'ox', '~> 2', '>= 2.14.2'
21
+ spec.add_dependency 'minitest', '>= 5.11', '< 7'
23
22
 
24
23
  spec.add_development_dependency 'bundler'
25
24
  spec.add_development_dependency 'nokogiri'
26
25
  spec.add_development_dependency 'rake', '~> 13'
26
+ spec.add_development_dependency 'rexml'
27
27
  spec.add_development_dependency 'rubocop', '~> 1'
28
28
  end
@@ -1,5 +1,4 @@
1
- require 'minitest/autorun'
2
- require 'minitest/mock'
1
+ require_relative 'test_helper'
3
2
  require "minitest/junit_formatter_plugin"
4
3
 
5
4
  class PluginTest < Minitest::Test
@@ -1,4 +1,4 @@
1
- require 'minitest/autorun'
1
+ require_relative 'test_helper'
2
2
  require 'stringio'
3
3
  require 'time'
4
4
  require 'nokogiri'
@@ -13,10 +13,22 @@ class ReporterTest < Minitest::Test
13
13
 
14
14
  reporter.report
15
15
 
16
- assert_match(
17
- %r{<?xml version="1.0" encoding="UTF-8"\?>\n<testsuites>\n <testsuite name="minitest" timestamp="[^"]+" hostname="[^"]+" tests="0" skipped="0" failures="0" errors="0" time="0.000000"\/>\n<\/testsuites>\n},
18
- reporter.output
16
+ assert_match(/\A<\?xml version="1.0" encoding="UTF-8"\?>\n/, reporter.output)
17
+
18
+ # Parse rather than match text: JRuby's Nokogiri orders attributes and whitespace differently
19
+ parsed_report = Nokogiri::XML(reporter.output)
20
+ assert_equal 'testsuites', parsed_report.root.name
21
+ testsuites = parsed_report.root.element_children
22
+ assert_equal ['testsuite'], testsuites.map(&:name)
23
+
24
+ testsuite = testsuites.first
25
+ assert_empty testsuite.children
26
+ assert_equal(
27
+ { 'name' => 'minitest', 'tests' => '0', 'skipped' => '0', 'failures' => '0', 'errors' => '0', 'time' => '0.000000' },
28
+ testsuite.to_h.reject { |key, _| %w[timestamp hostname].include?(key) }
19
29
  )
30
+ refute_empty testsuite['timestamp']
31
+ refute_empty testsuite['hostname']
20
32
  end
21
33
 
22
34
  # NOTE: This test will generate a temp file: "test/tmp/report.xml"
@@ -35,9 +47,11 @@ class ReporterTest < Minitest::Test
35
47
  reporter = create_reporter
36
48
 
37
49
  results = do_formatting_test(reporter, count: rand(100), cause_failures: 0)
50
+ parsed_report = Nokogiri::XML(reporter.output)
38
51
 
39
52
  results.each do |result|
40
- assert_match("<testcase classname=\"FakeTestName\" name=\"#{result.name}\"", reporter.output)
53
+ assert parsed_report.at_xpath("//testcase[@classname='FakeTestName' and @name='#{result.name}']"),
54
+ "expected a testcase for #{result.name}"
41
55
  end
42
56
  end
43
57
 
@@ -0,0 +1,5 @@
1
+ require 'minitest/autorun'
2
+ require 'minitest/mock'
3
+
4
+ # Minitest 6 made plugin loading opt-in.
5
+ Minitest.load :junit_formatter if Minitest::VERSION.to_i >= 6
@@ -1,4 +1,4 @@
1
- require 'minitest/autorun'
1
+ require_relative 'test_helper'
2
2
  require 'stringio'
3
3
  require 'time'
4
4
 
@@ -31,7 +31,7 @@ class TestCaseFormatter < Minitest::Test
31
31
 
32
32
  reporter.report
33
33
 
34
- assert_match(/<skipped message="[^<>]+"\><\/skipped>\n\s+<\/testcase>\n\s*<\/testsuite>\n/, reporter.output)
34
+ assert_match(/<skipped message="[^<>]+"(\/>|><\/skipped>)\n\s+<\/testcase>\n\s*<\/testsuite>\n/, reporter.output)
35
35
  end
36
36
 
37
37
  def test_failing_tests_creates_failure_tag
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minitest-junit_formatter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jesse Chavez
@@ -14,36 +14,22 @@ dependencies:
14
14
  name: minitest
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '5.11'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
17
+ - - ">="
25
18
  - !ruby/object:Gem::Version
26
19
  version: '5.11'
27
- - !ruby/object:Gem::Dependency
28
- name: ox
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '2'
34
- - - ">="
20
+ - - "<"
35
21
  - !ruby/object:Gem::Version
36
- version: 2.14.2
22
+ version: '7'
37
23
  type: :runtime
38
24
  prerelease: false
39
25
  version_requirements: !ruby/object:Gem::Requirement
40
26
  requirements:
41
- - - "~>"
42
- - !ruby/object:Gem::Version
43
- version: '2'
44
27
  - - ">="
45
28
  - !ruby/object:Gem::Version
46
- version: 2.14.2
29
+ version: '5.11'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '7'
47
33
  - !ruby/object:Gem::Dependency
48
34
  name: bundler
49
35
  requirement: !ruby/object:Gem::Requirement
@@ -86,6 +72,20 @@ dependencies:
86
72
  - - "~>"
87
73
  - !ruby/object:Gem::Version
88
74
  version: '13'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rexml
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
89
  - !ruby/object:Gem::Dependency
90
90
  name: rubocop
91
91
  requirement: !ruby/object:Gem::Requirement
@@ -100,7 +100,7 @@ dependencies:
100
100
  - - "~>"
101
101
  - !ruby/object:Gem::Version
102
102
  version: '1'
103
- description: Junit report formatter for Minitest ~> 5.0
103
+ description: Junit report formatter for Minitest 5 and 6
104
104
  email:
105
105
  - jesse.chavez.jp@gmail.com
106
106
  executables: []
@@ -115,11 +115,14 @@ files:
115
115
  - Rakefile
116
116
  - lib/minitest/junit_formatter.rb
117
117
  - lib/minitest/junit_formatter/version.rb
118
+ - lib/minitest/junit_formatter/xml_nokogiri.rb
119
+ - lib/minitest/junit_formatter/xml_rexml.rb
118
120
  - lib/minitest/junit_formatter_plugin.rb
119
121
  - minitest-junit_formatter.gemspec
120
122
  - test/.rubocop.yml
121
123
  - test/junit_plugin_test.rb
122
124
  - test/reporter_test.rb
125
+ - test/test_helper.rb
123
126
  - test/testcase_formatter_test.rb
124
127
  - test/tmp/.keep
125
128
  homepage: https://github.com/JesseChavez/minitest-junit_formatter
@@ -140,12 +143,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
143
  - !ruby/object:Gem::Version
141
144
  version: '0'
142
145
  requirements: []
143
- rubygems_version: 3.6.9
146
+ rubygems_version: 3.7.2
144
147
  specification_version: 4
145
- summary: Junit report formatter for Minitest ~> 5.0
148
+ summary: Junit report formatter for Minitest 5 and 6
146
149
  test_files:
147
150
  - test/.rubocop.yml
148
151
  - test/junit_plugin_test.rb
149
152
  - test/reporter_test.rb
153
+ - test/test_helper.rb
150
154
  - test/testcase_formatter_test.rb
151
155
  - test/tmp/.keep