ci_reporter 2.0.0.alpha2 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9d4fd920bd59773352edb9dd239cb99ffe419406
4
- data.tar.gz: 227712fdcd966fa2b57d5a32133e5e0587a89e03
2
+ SHA256:
3
+ metadata.gz: a528a2fafebcc8be684a8ca7dc12acef432ac82dec567d5b1176bdfdb5377ffb
4
+ data.tar.gz: 97d80b1b12e409a0d9ad4d5a9592800a30492b41050787c43a16d86128687167
5
5
  SHA512:
6
- metadata.gz: 094edf36eb8b168fb606a2a2ad73ea9bf3e49a078934462ff95d2b07a27f49038291789b162807fe8395f49d237887edd0926f983a1848b100e0d150ff9e2266
7
- data.tar.gz: bdde115c27717e95030df44d1accd7d79b38ba8230895faa0d13409cb4b721444efc79615241dd599e7e0ad25ada12777cad0247783d43428954a1d1298e2dd1
6
+ metadata.gz: af641871ec70d11f86d1afa32590d848a8e3118bb5fd494f07005f8f97421242f365c74197e6cee1b606b4c817622539b5b9d4df4e65449c4c8f745d8c49dafc
7
+ data.tar.gz: e9cbaff5e0ec53a727791a81645282653ac8d29ed68e0970bc454d5c84b05bf170adb4b1ce5f1a8cd2f895b0adfaba9b07ae9a72c34b5115aae12a7189ce8907
@@ -0,0 +1,27 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ branches:
9
+ - main
10
+
11
+ jobs:
12
+ test:
13
+ name: test
14
+ strategy:
15
+ matrix:
16
+ ruby: ['2.6', '2.7', '3.0', '3.1', '3.2', head, jruby, jruby-head]
17
+ runs-on: ubuntu-latest
18
+ steps:
19
+ - uses: actions/checkout@v3
20
+ - uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: ${{ matrix.ruby }}
23
+ bundler-cache: true
24
+ - name: Tests
25
+ run: bundle exec rake
26
+ - name: Gem build
27
+ run: bundle exec rake build
@@ -0,0 +1,41 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v[0-9]+.[0-9]+.[0-9]+"
7
+
8
+ jobs:
9
+ release:
10
+ name: release
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v3
14
+
15
+ - uses: ruby/setup-ruby@v1
16
+ with:
17
+ ruby-version: '3.2'
18
+ bundler-cache: true
19
+
20
+ - name: Log into Rubygems
21
+ run: |
22
+ mkdir -p ~/.local/share/gem
23
+ echo ":rubygems_api_key: ${{ secrets.RUBYGEMS_API_KEY }}" > ~/.local/share/gem/credentials
24
+ chmod 600 ~/.local/share/gem/credentials
25
+
26
+ - name: Release
27
+ run: |
28
+ set -e
29
+ PKG="$(echo *.gemspec | sed 's/.gemspec//')"
30
+ VERSION="${GITHUB_REF#refs/tags/v}"
31
+ bundle exec rake build
32
+ GEM="pkg/$PKG-$VERSION.gem"
33
+ if [ -f "$GEM" ]; then
34
+ gem push $GEM
35
+ echo "Release $VERSION done."
36
+ else
37
+ echo "Build did not create a $VERSION release gem."
38
+ echo "Please check the version in the gemspec and try again."
39
+ cat *.gemspec | grep '\.version'
40
+ exit 1
41
+ fi
data/History.txt CHANGED
@@ -1,3 +1,28 @@
1
+ == 2.1.0 (2023/02/09)
2
+
3
+ === Changed
4
+
5
+ - Testing on Ruby 2.6 - HEAD, JRuby 9.x latest, JRuby HEAD
6
+ - CI changed to GitHub Actions
7
+ - Tracking branch changed to `main`
8
+ - GH #160: Add monotonic time (Michal Cichra)
9
+ - GH #148: fix deprecation issues (Akira Matsuda)
10
+ - GH #149: fix for RSpec 3.1.2 (Akira Matsuda)
11
+
12
+ === Removed
13
+
14
+ - Testing on versions of Ruby < 2.6
15
+
16
+ == 2.0.0 (2014-07-24)
17
+
18
+ === Changed
19
+
20
+ - Gem has been refactored into multiple framework-specific gems.
21
+
22
+ === Removed
23
+
24
+ - All methods of use except the `ci:setup:*` Rake tasks.
25
+
1
26
  == 1.9.2 (04/06/14)
2
27
 
3
28
  - GH #119: add timestamp attribute (Shawn Zhu)
data/README.md CHANGED
@@ -5,8 +5,7 @@ system that understands Ant's JUnit report XML format, thus allowing
5
5
  your CI system to track test/spec successes and failures.
6
6
 
7
7
  [![Gem Version](https://badge.fury.io/rb/ci_reporter.svg)](http://badge.fury.io/rb/ci_reporter)
8
- [![Build Status](https://travis-ci.org/ci-reporter/ci_reporter.svg?branch=master)](https://travis-ci.org/ci-reporter/ci_reporter)
9
- [![Dependency Status](https://gemnasium.com/ci-reporter/ci_reporter.svg)](https://gemnasium.com/ci-reporter/ci_reporter)
8
+ [![Build Status](https://github.com/ci-reporter/ci_reporter/actions/workflows/ci.yaml/badge.svg)](https://github.com/ci-reporter/ci_reporter/actions/workflows/ci.yaml)
10
9
  [![Code Climate](https://codeclimate.com/github/ci-reporter/ci_reporter.png)](https://codeclimate.com/github/ci-reporter/ci_reporter)
11
10
 
12
11
  ## Usage
@@ -30,12 +29,23 @@ Each supported testing framework is provided by a separate gem:
30
29
  [ci-spin]: https://github.com/ci-reporter/ci_reporter_spinach
31
30
  [ci-tu]: https://github.com/ci-reporter/ci_reporter_test_unit
32
31
 
32
+ ### Upgrading from CI::Reporter 1.x
33
+
34
+ CI::Reporter 1.x supported all the different test frameworks in a
35
+ single gem. This was convenient, but caused issues as test frameworks
36
+ released new, sometimes incompatibile, versions. CI::Reporter 2.x has
37
+ been split into multiple gems, allowing each gem to specify the test
38
+ framework versions it supports.
39
+
40
+ To upgrade to 2.x, remove `ci_reporter` from your Gemfile and replace
41
+ it with one or more of the framework-specific gems above.
42
+
33
43
  ## Jenkins setup
34
44
 
35
- 1. Tick the box labelled "Publish JUnit test result report" in the job
36
- configuration
45
+ 1. Add the "Publish JUnit test result report" post-build step
46
+ in the job configuration.
37
47
 
38
- 2. Enter "test/reports/*.xml,spec/reports/*.xml" in the "Test report
48
+ 2. Enter "test/reports/\*.xml,spec/reports/\*.xml" in the "Test report
39
49
  XMLs" field (adjust this to suit which tests you are running)
40
50
 
41
51
  Report files are written, by default, to the
@@ -58,7 +68,7 @@ will be invoked:
58
68
  ```ruby
59
69
  if ENV['GENERATE_REPORTS'] == 'true'
60
70
  require 'ci/reporter/rake/rspec'
61
- task :rspec => 'ci:setup:rspec'
71
+ task :spec => 'ci:setup:rspec'
62
72
  end
63
73
  ```
64
74
 
@@ -66,7 +76,7 @@ You can either inject this variable in your CI or simply call `rake`
66
76
  with the environment variable set:
67
77
 
68
78
  ```
69
- GENERATE_REPORTS=true rake rspec
79
+ GENERATE_REPORTS=true rake spec
70
80
  ```
71
81
 
72
82
  ### With CI-specific Rake tasks
@@ -75,7 +85,7 @@ Instead of modifying your existing Rake tasks, create new ones:
75
85
 
76
86
  ```ruby
77
87
  namespace :ci do
78
- task :all => ['ci:setup:rspec', 'rspec']
88
+ task :all => ['ci:setup:rspec', 'spec']
79
89
  end
80
90
  ```
81
91
 
data/Rakefile CHANGED
@@ -2,7 +2,6 @@ require "bundler/gem_tasks"
2
2
  require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:rspec) do |t|
5
- t.pattern = FileList['spec']
6
5
  t.rspec_opts = "--color"
7
6
  end
8
7
 
data/ci_reporter.gemspec CHANGED
@@ -21,8 +21,9 @@ Gem::Specification.new do |spec|
21
21
  spec.extra_rdoc_files = ["History.txt", "LICENSE.txt", "README.md"]
22
22
 
23
23
  spec.add_dependency "builder", ">= 2.1.2"
24
+ spec.add_dependency "rexml"
24
25
 
25
26
  spec.add_development_dependency "rake"
26
27
  spec.add_development_dependency "rdoc", "~> 4.0"
27
- spec.add_development_dependency "rspec", "~> 2.0"
28
+ spec.add_development_dependency "rspec", "~> 3.0"
28
29
  end
@@ -0,0 +1,22 @@
1
+ module CI
2
+ module Reporter
3
+ module MonotonicTime
4
+ module_function
5
+
6
+ if defined?(Process::CLOCK_MONOTONIC)
7
+ def time_in_nanoseconds
8
+ Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)
9
+ end
10
+ else
11
+ def time_in_nanoseconds
12
+ t = Time.now
13
+ t.to_i * 10 ** 9 + t.nsec
14
+ end
15
+ end
16
+
17
+ def time_in_seconds
18
+ time_in_nanoseconds / 10 ** 9.0
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,31 @@
1
+ require 'delegate'
2
+ require 'stringio'
3
+
4
+ module CI
5
+ module Reporter
6
+ # Captures $stdout or $stderr in order report it in the XML file.
7
+ class OutputCapture
8
+ # Creates an OutputCapture and immediately starts capturing.
9
+ def self.wrap(io, &assign)
10
+ new(io, &assign).tap {|oc| oc.start}
11
+ end
12
+
13
+ def initialize(io, &assign)
14
+ @original_io = io
15
+ @captured_io = StringIO.new
16
+ @assign_block = assign
17
+ end
18
+
19
+ # Start capturing IO.
20
+ def start
21
+ @assign_block.call(@captured_io)
22
+ end
23
+
24
+ # Finalize the capture and reset to the original IO object.
25
+ def finish
26
+ @assign_block.call(@original_io)
27
+ @captured_io.string
28
+ end
29
+ end
30
+ end
31
+ end
@@ -31,7 +31,7 @@ module CI #:nodoc:
31
31
  # with N < 100000, to prevent endless sidestep loops
32
32
  MAX_SIDESTEPS = 100000
33
33
  MAX_FILENAME_SIZE = 240
34
- #
34
+
35
35
  def filename_for(suite)
36
36
  basename = "#{@basename}-#{suite.name.gsub(/[^a-zA-Z0-9]+/, '-')}"
37
37
  suffix = "xml"
@@ -48,7 +48,7 @@ module CI #:nodoc:
48
48
  # if the initial filename is already in use
49
49
  # do sidesteps, beginning with SPEC-MailsController.0.xml
50
50
  i = 0
51
- while File.exists?(filename) && i < MAX_SIDESTEPS
51
+ while File.exist?(filename) && i < MAX_SIDESTEPS
52
52
  filename = [basename, i, suffix].join(".")
53
53
  i += 1
54
54
  end
@@ -1,60 +1,46 @@
1
- require 'delegate'
2
- require 'stringio'
3
1
  require 'time'
2
+ require 'builder'
3
+ require 'ci/reporter/output_capture'
4
+ require 'ci/reporter/monotonic_time'
4
5
 
5
6
  module CI
6
7
  module Reporter
7
- # Emulates/delegates IO to $stdout or $stderr in order to capture output to report in the XML file.
8
- module OutputCapture
9
- class Delegate < DelegateClass(IO)
10
- include OutputCapture
11
- def initialize(io, &assign)
12
- super(io)
13
- capture(io, &assign)
14
- end
8
+ module StructureXmlHelpers
9
+ # Struct#to_h is not available in Ruby 1.9
10
+ def attr_hash
11
+ Hash[self.members.zip(self.values)]
15
12
  end
16
13
 
17
- def self.wrap(io, &assign)
18
- Delegate.new(io, &assign)
14
+ # Removes empty attributes and truncates long attributes.
15
+ def cleaned_attributes
16
+ attr_array = attr_hash
17
+ .reject {|k,v| v.to_s.empty? }
18
+ .map {|k,v| [k, truncate_at_newline(v)] }
19
+ Hash[attr_array]
19
20
  end
20
21
 
21
- # Start capturing IO, using the given block to assign self to the proper IO global.
22
- def capture(io, &assign)
23
- @delegate_io = io
24
- @captured_io = StringIO.new
25
- @assign_block = assign
26
- @assign_block.call @captured_io
27
- end
28
-
29
- # Finalize the capture and reset to the original IO object.
30
- def finish
31
- @assign_block.call @delegate_io
32
- @captured_io.string
33
- end
34
-
35
- # setup tee methods
36
- %w(<< print printf putc puts write).each do |m|
37
- module_eval(<<-EOS, __FILE__, __LINE__)
38
- def #{m}(*args, &block)
39
- @delegate_io.send(:#{m}, *args, &block)
40
- @captured_io.send(:#{m}, *args, &block)
41
- end
42
- EOS
22
+ def truncate_at_newline(txt)
23
+ txt.to_s.sub(/\n.*/m, '...')
43
24
  end
44
25
  end
45
26
 
46
27
  # Basic structure representing the running of a test suite. Used to time tests and store results.
47
28
  class TestSuite < Struct.new(:name, :tests, :time, :failures, :errors, :skipped, :assertions, :timestamp)
29
+ include StructureXmlHelpers
30
+
48
31
  attr_accessor :testcases
49
32
  attr_accessor :stdout, :stderr
50
33
  def initialize(name)
51
34
  super(name.to_s) # RSpec passes a "description" object instead of a string
52
35
  @testcases = []
36
+ @capture_out = nil
37
+ @capture_err = nil
53
38
  end
54
39
 
55
40
  # Starts timing the test suite.
56
41
  def start
57
- @start = Time.now
42
+ @start_time = Time.now
43
+ @start = MonotonicTime.time_in_seconds
58
44
  unless ENV['CI_CAPTURE'] == "off"
59
45
  @capture_out = OutputCapture.wrap($stdout) {|io| $stdout = io }
60
46
  @capture_err = OutputCapture.wrap($stderr) {|io| $stderr = io }
@@ -64,41 +50,32 @@ module CI
64
50
  # Finishes timing the test suite.
65
51
  def finish
66
52
  self.tests = testcases.size
67
- self.time = Time.now - @start
68
- self.timestamp = @start.iso8601
69
- self.failures = testcases.inject(0) {|sum,tc| sum += tc.failures.select{|f| f.failure? }.size }
70
- self.errors = testcases.inject(0) {|sum,tc| sum += tc.failures.select{|f| f.error? }.size }
71
- self.skipped = testcases.inject(0) {|sum,tc| sum += (tc.skipped? ? 1 : 0) }
53
+ self.time = MonotonicTime.time_in_seconds - @start
54
+ self.timestamp = @start_time.iso8601
55
+ self.failures = testcases.map(&:failure_count).reduce(&:+)
56
+ self.errors = testcases.map(&:error_count).reduce(&:+)
57
+ self.skipped = testcases.count(&:skipped?)
72
58
  self.stdout = @capture_out.finish if @capture_out
73
59
  self.stderr = @capture_err.finish if @capture_err
74
60
  end
75
61
 
76
- # Creates the xml builder instance used to create the report xml document.
77
- def create_builder
78
- require 'builder'
79
- # :escape_attrs is obsolete in a newer version, but should do no harm
80
- Builder::XmlMarkup.new(:indent => 2, :escape_attrs => true)
81
- end
82
-
83
62
  # Creates an xml string containing the test suite results.
84
63
  def to_xml
85
- builder = create_builder
86
- # more recent version of Builder doesn't need the escaping
87
- def builder.trunc!(txt)
88
- txt.sub(/\n.*/m, '...')
89
- end
64
+ builder = Builder::XmlMarkup.new(indent: 2)
90
65
  builder.instruct!
91
- attrs = {}
92
- each_pair {|k,v| attrs[k] = builder.trunc!(v.to_s) unless v.nil? || v.to_s.empty? }
93
- builder.testsuite(attrs) do
66
+ builder.testsuite(cleaned_attributes) do
94
67
  @testcases.each do |tc|
95
68
  tc.to_xml(builder)
96
69
  end
97
- builder.tag! "system-out" do
98
- builder.text!(self.stdout || '' )
70
+ unless self.stdout.to_s.empty?
71
+ builder.tag! "system-out" do
72
+ builder.text!(self.stdout)
73
+ end
99
74
  end
100
- builder.tag! "system-err" do
101
- builder.text!(self.stderr || '' )
75
+ unless self.stderr.to_s.empty?
76
+ builder.tag! "system-err" do
77
+ builder.text!(self.stderr)
78
+ end
102
79
  end
103
80
  end
104
81
  end
@@ -106,6 +83,8 @@ module CI
106
83
 
107
84
  # Structure used to represent an individual test case. Used to time the test and store the result.
108
85
  class TestCase < Struct.new(:name, :time, :assertions)
86
+ include StructureXmlHelpers
87
+
109
88
  attr_accessor :failures
110
89
  attr_accessor :skipped
111
90
 
@@ -116,22 +95,30 @@ module CI
116
95
 
117
96
  # Starts timing the test.
118
97
  def start
119
- @start = Time.now
98
+ @start = MonotonicTime.time_in_seconds
120
99
  end
121
100
 
122
101
  # Finishes timing the test.
123
102
  def finish
124
- self.time = Time.now - @start
103
+ self.time = MonotonicTime.time_in_seconds - @start
125
104
  end
126
105
 
127
106
  # Returns non-nil if the test failed.
128
107
  def failure?
129
- !failures.empty? && failures.detect {|f| f.failure? }
108
+ failures.any?(&:failure?)
130
109
  end
131
110
 
132
111
  # Returns non-nil if the test had an error.
133
112
  def error?
134
- !failures.empty? && failures.detect {|f| f.error? }
113
+ failures.any?(&:error?)
114
+ end
115
+
116
+ def failure_count
117
+ failures.count(&:failure?)
118
+ end
119
+
120
+ def error_count
121
+ failures.count(&:error?)
135
122
  end
136
123
 
137
124
  def skipped?
@@ -140,16 +127,14 @@ module CI
140
127
 
141
128
  # Writes xml representing the test result to the provided builder.
142
129
  def to_xml(builder)
143
- attrs = {}
144
- each_pair {|k,v| attrs[k] = builder.trunc!(v.to_s) unless v.nil? || v.to_s.empty?}
145
- builder.testcase(attrs) do
130
+ builder.testcase(cleaned_attributes) do
146
131
  if skipped?
147
132
  builder.skipped
148
133
  else
149
134
  failures.each do |failure|
150
135
  tag = failure.error? ? :error : :failure
151
136
 
152
- builder.tag!(tag, :type => builder.trunc!(failure.name), :message => builder.trunc!(failure.message)) do
137
+ builder.tag!(tag, type: truncate_at_newline(failure.name), message: truncate_at_newline(failure.message)) do
153
138
  builder.text!(failure.message + " (#{failure.name})\n")
154
139
  builder.text!(failure.location)
155
140
  end
@@ -1,5 +1,5 @@
1
1
  module CI
2
2
  module Reporter
3
- VERSION = "2.0.0.alpha2"
3
+ VERSION = "2.1.0"
4
4
  end
5
5
  end
@@ -2,59 +2,67 @@ require File.dirname(__FILE__) + "/../../spec_helper.rb"
2
2
  require 'rexml/document'
3
3
 
4
4
  describe "Output capture" do
5
- before(:each) do
6
- @suite = CI::Reporter::TestSuite.new "test"
7
- end
5
+ subject(:suite) { CI::Reporter::TestSuite.new "test" }
8
6
 
9
- it "should save stdout and stderr messages written during the test run" do
10
- @suite.start
7
+ it "saves stdout and stderr messages written during the test run" do
8
+ suite.start
11
9
  puts "Hello"
12
10
  $stderr.print "Hi"
13
- @suite.finish
14
- @suite.stdout.should == "Hello\n"
15
- @suite.stderr.should == "Hi"
11
+ suite.finish
12
+ expect(suite.stdout).to eql "Hello\n"
13
+ expect(suite.stderr).to eql "Hi"
16
14
  end
17
15
 
18
- it "should include system-out and system-err elements in the xml output" do
19
- @suite.start
16
+ it "includes system-out and system-err elements in the xml output" do
17
+ suite.start
20
18
  puts "Hello"
21
19
  $stderr.print "Hi"
22
- @suite.finish
20
+ suite.finish
23
21
 
24
- root = REXML::Document.new(@suite.to_xml).root
25
- root.elements.to_a('//system-out').length.should == 1
26
- root.elements.to_a('//system-err').length.should == 1
27
- root.elements.to_a('//system-out').first.texts.first.to_s.strip.should == "Hello"
28
- root.elements.to_a('//system-err').first.texts.first.to_s.strip.should == "Hi"
22
+ root = REXML::Document.new(suite.to_xml).root
23
+ expect(root.elements.to_a('//system-out').length).to eql 1
24
+ expect(root.elements.to_a('//system-err').length).to eql 1
25
+ expect(root.elements.to_a('//system-out').first.texts.first.to_s.strip).to eql "Hello"
26
+ expect(root.elements.to_a('//system-err').first.texts.first.to_s.strip).to eql "Hi"
29
27
  end
30
28
 
31
- it "should return $stdout and $stderr to original value after finish" do
32
- out, err = $stdout, $stderr
33
- @suite.start
34
- $stdout.object_id.should_not == out.object_id
35
- $stderr.object_id.should_not == err.object_id
36
- @suite.finish
37
- $stdout.object_id.should == out.object_id
38
- $stderr.object_id.should == err.object_id
29
+ it "does not include system-out or system-err elements if nothing was output" do
30
+ suite.start
31
+ suite.finish
32
+
33
+ root = REXML::Document.new(suite.to_xml).root
34
+ expect(root.elements.to_a('//system-out').length).to eql 0
35
+ expect(root.elements.to_a('//system-err').length).to eql 0
39
36
  end
40
37
 
41
- it "should capture only during run of owner test suite" do
38
+ it "captures only during run of owner test suite" do
42
39
  $stdout.print "A"
43
40
  $stderr.print "A"
44
- @suite.start
41
+ suite.start
45
42
  $stdout.print "B"
46
43
  $stderr.print "B"
47
- @suite.finish
44
+ suite.finish
48
45
  $stdout.print "C"
49
46
  $stderr.print "C"
50
- @suite.stdout.should == "B"
51
- @suite.stderr.should == "B"
47
+ expect(suite.stdout).to eql "B"
48
+ expect(suite.stderr).to eql "B"
52
49
  end
53
50
 
54
- it "should not barf when commands are executed with back-ticks" do
55
- @suite.start
56
- `echo "B"`
57
- @suite.finish
58
- end
51
+ describe CI::Reporter::OutputCapture do
52
+ subject(:capture) { CI::Reporter::OutputCapture.new($stdout) {|x| $stdout = x } }
59
53
 
54
+ it "returns the IO to the original value after finish" do
55
+ original = $stdout
56
+ capture.start
57
+ expect($stdout.object_id).to_not eql original.object_id
58
+ capture.finish
59
+ expect($stdout.object_id).to eql original.object_id
60
+ end
61
+
62
+ it "does not barf when commands are executed with back-ticks" do
63
+ capture.start
64
+ `echo "B"`
65
+ capture.finish
66
+ end
67
+ end
60
68
  end
@@ -1,75 +1,77 @@
1
1
  require File.dirname(__FILE__) + "/../../spec_helper.rb"
2
2
 
3
- describe "The ReportManager" do
4
- before(:each) do
5
- @reports_dir = REPORTS_DIR
6
- ENV.delete 'MAX_FILENAME_SIZE'
7
- end
3
+ module CI::Reporter
4
+ describe ReportManager do
5
+ before(:each) do
6
+ @reports_dir = REPORTS_DIR
7
+ ENV.delete 'MAX_FILENAME_SIZE'
8
+ end
8
9
 
9
- after(:each) do
10
- FileUtils.rm_rf @reports_dir
11
- ENV["CI_REPORTS"] = nil
12
- end
10
+ after(:each) do
11
+ FileUtils.rm_rf @reports_dir
12
+ ENV["CI_REPORTS"] = nil
13
+ end
13
14
 
14
- it "should create the report directory according to the given prefix" do
15
- CI::Reporter::ReportManager.new("spec")
16
- File.directory?(@reports_dir).should be true
17
- end
15
+ it "creates the report directory according to the given prefix" do
16
+ CI::Reporter::ReportManager.new("spec")
17
+ expect(File.directory?(@reports_dir)).to be true
18
+ end
18
19
 
19
- it "should create the report directory based on CI_REPORTS environment variable if set" do
20
- @reports_dir = "#{Dir.getwd}/dummy"
21
- ENV["CI_REPORTS"] = @reports_dir
22
- CI::Reporter::ReportManager.new("spec")
23
- File.directory?(@reports_dir).should be true
24
- end
20
+ it "creates the report directory based on CI_REPORTS environment variable if set" do
21
+ @reports_dir = "#{Dir.getwd}/dummy"
22
+ ENV["CI_REPORTS"] = @reports_dir
23
+ CI::Reporter::ReportManager.new("spec")
24
+ expect(File.directory?(@reports_dir)).to be true
25
+ end
25
26
 
26
- it "should write reports based on name and xml content of a test suite" do
27
- reporter = CI::Reporter::ReportManager.new("spec")
28
- suite = double("test suite")
29
- suite.should_receive(:name).and_return("some test suite name")
30
- suite.should_receive(:to_xml).and_return("<xml></xml>")
31
- reporter.write_report(suite)
32
- filename = "#{REPORTS_DIR}/SPEC-some-test-suite-name.xml"
33
- File.exist?(filename).should be true
34
- File.open(filename) {|f| f.read.should == "<xml></xml>"}
35
- end
27
+ it "writes reports based on name and xml content of a test suite" do
28
+ reporter = CI::Reporter::ReportManager.new("spec")
29
+ suite = double("test suite")
30
+ expect(suite).to receive(:name).and_return("some test suite name")
31
+ expect(suite).to receive(:to_xml).and_return("<xml></xml>")
32
+ reporter.write_report(suite)
33
+ filename = "#{REPORTS_DIR}/SPEC-some-test-suite-name.xml"
34
+ expect(File.exist?(filename)).to be true
35
+ expect(File.read(filename)).to eql "<xml></xml>"
36
+ end
36
37
 
37
- it "should shorten extremely long report filenames" do
38
- reporter = CI::Reporter::ReportManager.new("spec")
39
- suite = double("test suite")
40
- very_long_name = "some test suite name that goes on and on and on and on and on and on and does not look like it will end any time soon and just when you think it is almost over it just continues to go on and on and on and on and on until it is almost over but wait there is more and then el fin"
41
- suite.should_receive(:name).and_return(very_long_name)
42
- suite.should_receive(:to_xml).and_return("<xml></xml>")
43
- reporter.write_report(suite)
44
- filename = "#{REPORTS_DIR}/SPEC-#{very_long_name}"[0..CI::Reporter::ReportManager::MAX_FILENAME_SIZE].gsub(/\s/, '-') + ".xml"
45
- filename.length.should be <= 255
46
- File.exist?(filename).should be true
47
- File.open(filename) {|f| f.read.should == "<xml></xml>"}
48
- end
38
+ it "shortens extremely long report filenames" do
39
+ reporter = CI::Reporter::ReportManager.new("spec")
40
+ suite = double("test suite")
41
+ very_long_name = "some test suite name that goes on and on and on and on and on and on and does not look like it will end any time soon and just when you think it is almost over it just continues to go on and on and on and on and on until it is almost over but wait there is more and then el fin"
42
+ expect(suite).to receive(:name).and_return(very_long_name)
43
+ expect(suite).to receive(:to_xml).and_return("<xml></xml>")
44
+ reporter.write_report(suite)
45
+ filename = "#{REPORTS_DIR}/SPEC-#{very_long_name}"[0..CI::Reporter::ReportManager::MAX_FILENAME_SIZE].gsub(/\s/, '-') + ".xml"
46
+ expect(filename.length).to be <= 255
47
+ expect(File.exist?(filename)).to be true
48
+ expect(File.read(filename)).to eql "<xml></xml>"
49
+ end
49
50
 
50
- it "should shorten extremely long report filenames to custom length" do
51
- reporter = CI::Reporter::ReportManager.new("spec")
52
- suite = double("test suite")
53
- very_long_name = "some test suite name that goes on and on and on and on and on and on and does not look like it will end any time soon and just when you think it is almost over it just continues to go on and on and on and on and on until it is almost over but wait there is more and then el fin"
54
- suite.should_receive(:name).and_return(very_long_name)
55
- suite.should_receive(:to_xml).and_return("<xml></xml>")
56
- ENV['MAX_FILENAME_SIZE'] = '170'
57
- reporter.write_report(suite)
58
- filename = "#{REPORTS_DIR}/SPEC-#{very_long_name}"[0..170].gsub(/\s/, '-') + ".xml"
59
- filename.length.should be <= 188
60
- File.exist?(filename).should be true
61
- File.open(filename) {|f| f.read.should == "<xml></xml>"}
62
- end
51
+ it "shortens extremely long report filenames to custom length" do
52
+ reporter = CI::Reporter::ReportManager.new("spec")
53
+ suite = double("test suite")
54
+ very_long_name = "some test suite name that goes on and on and on and on and on and on and does not look like it will end any time soon and just when you think it is almost over it just continues to go on and on and on and on and on until it is almost over but wait there is more and then el fin"
55
+ expect(suite).to receive(:name).and_return(very_long_name)
56
+ expect(suite).to receive(:to_xml).and_return("<xml></xml>")
57
+ ENV['MAX_FILENAME_SIZE'] = '170'
58
+ reporter.write_report(suite)
59
+ filename = "#{REPORTS_DIR}/SPEC-#{very_long_name}"[0..170].gsub(/\s/, '-') + ".xml"
60
+ expect(filename.length).to be <= 188
61
+ expect(File.exist?(filename)).to be true
62
+ expect(File.read(filename)).to eql "<xml></xml>"
63
+ end
63
64
 
64
- it "sidesteps existing files by adding an incrementing number" do
65
- filename = "#{REPORTS_DIR}/SPEC-colliding-test-suite-name.xml"
66
- FileUtils.mkdir_p(File.dirname(filename))
67
- FileUtils.touch filename
68
- reporter = CI::Reporter::ReportManager.new("spec")
69
- suite = double("test suite")
70
- suite.should_receive(:name).and_return("colliding test suite name")
71
- suite.should_receive(:to_xml).and_return("<xml></xml>")
72
- reporter.write_report(suite)
73
- File.exist?(filename.sub('.xml', '.0.xml')).should be true
65
+ it "sidesteps existing files by adding an incrementing number" do
66
+ filename = "#{REPORTS_DIR}/SPEC-colliding-test-suite-name.xml"
67
+ FileUtils.mkdir_p(File.dirname(filename))
68
+ FileUtils.touch filename
69
+ reporter = CI::Reporter::ReportManager.new("spec")
70
+ suite = double("test suite")
71
+ expect(suite).to receive(:name).and_return("colliding test suite name")
72
+ expect(suite).to receive(:to_xml).and_return("<xml></xml>")
73
+ reporter.write_report(suite)
74
+ expect(File.exist?(filename.sub('.xml', '.0.xml'))).to be true
75
+ end
74
76
  end
75
77
  end
@@ -1,157 +1,152 @@
1
1
  require File.dirname(__FILE__) + "/../../spec_helper.rb"
2
2
  require 'rexml/document'
3
3
 
4
- describe "A TestSuite" do
5
- before(:each) do
6
- @suite = CI::Reporter::TestSuite.new("example suite")
7
- end
8
-
9
- it "should collect timings when start and finish are invoked in sequence" do
10
- @suite.start
11
- @suite.finish
12
- @suite.time.should >= 0
13
- end
14
-
15
- it "should aggregate tests" do
16
- @suite.start
17
- @suite.testcases << CI::Reporter::TestCase.new("example test")
18
- @suite.finish
19
- @suite.tests.should == 1
20
- end
4
+ module CI::Reporter
5
+ describe TestSuite do
6
+ subject(:suite) { CI::Reporter::TestSuite.new("example suite") }
7
+
8
+ let(:exception) do
9
+ begin
10
+ raise StandardError, "an exception occurred"
11
+ rescue => e
12
+ e
13
+ end
14
+ end
21
15
 
22
- it "should stringify the name for cases when the object passed in is not a string" do
23
- name = Object.new
24
- def name.to_s; "object name"; end
25
- CI::Reporter::TestSuite.new(name).name.should == "object name"
26
- end
16
+ let(:failure) do
17
+ double("failure",
18
+ :failure? => true,
19
+ :error? => false,
20
+ :name => "failure",
21
+ :message => "There was a failure",
22
+ :location => exception.backtrace.join("\n"))
23
+ end
27
24
 
28
- it "should indicate number of failures and errors" do
29
- failure = double("failure")
30
- failure.stub(:failure?).and_return true
31
- failure.stub(:error?).and_return false
32
-
33
- error = double("error")
34
- error.stub(:failure?).and_return false
35
- error.stub(:error?).and_return true
36
-
37
- @suite.start
38
- @suite.testcases << CI::Reporter::TestCase.new("example test")
39
- @suite.testcases << CI::Reporter::TestCase.new("failure test")
40
- @suite.testcases.last.failures << failure
41
- @suite.testcases << CI::Reporter::TestCase.new("error test")
42
- @suite.testcases.last.failures << error
43
- @suite.finish
44
- @suite.tests.should == 3
45
- @suite.failures.should == 1
46
- @suite.errors.should == 1
47
- end
48
- end
25
+ let(:error) do
26
+ double("error",
27
+ :failure? => false,
28
+ :error? => true,
29
+ :name => "error",
30
+ :message => "There was a error",
31
+ :location => exception.backtrace.join("\n"))
32
+ end
49
33
 
50
- describe "TestSuite xml" do
51
- before(:each) do
52
- ENV['CI_CAPTURE'] = nil
53
- @suite = CI::Reporter::TestSuite.new("example suite")
54
- @suite.assertions = 11
55
- begin
56
- raise StandardError, "an exception occurred"
57
- rescue => e
58
- @exception = e
34
+ it "collects timings when start and finish are invoked in sequence" do
35
+ suite.start
36
+ suite.finish
37
+ expect(suite.time).to be >= 0
59
38
  end
60
- end
61
39
 
62
- it "should render successfully with CI_CAPTURE off" do
63
- ENV['CI_CAPTURE'] = 'off'
64
- @suite.start
65
- @suite.testcases << CI::Reporter::TestCase.new("example test")
66
- @suite.finish
67
- xml = @suite.to_xml
68
- end
40
+ it "aggregates tests" do
41
+ suite.start
42
+ suite.testcases << CI::Reporter::TestCase.new("example test")
43
+ suite.finish
44
+ expect(suite.tests).to eql 1
45
+ end
69
46
 
70
- it "should contain Ant/JUnit-formatted description of entire suite" do
71
- failure = double("failure")
72
- failure.stub(:failure?).and_return true
73
- failure.stub(:error?).and_return false
74
- failure.stub(:name).and_return "failure"
75
- failure.stub(:message).and_return "There was a failure"
76
- failure.stub(:location).and_return @exception.backtrace.join("\n")
77
-
78
- error = double("error")
79
- error.stub(:failure?).and_return false
80
- error.stub(:error?).and_return true
81
- error.stub(:name).and_return "error"
82
- error.stub(:message).and_return "There was a error"
83
- error.stub(:location).and_return @exception.backtrace.join("\n")
84
-
85
- @suite.start
86
- @suite.testcases << CI::Reporter::TestCase.new("example test")
87
- @suite.testcases << CI::Reporter::TestCase.new("skipped test").tap {|tc| tc.skipped = true }
88
- @suite.testcases << CI::Reporter::TestCase.new("failure test")
89
- @suite.testcases.last.failures << failure
90
- @suite.testcases << CI::Reporter::TestCase.new("error test")
91
- @suite.testcases.last.failures << error
92
- @suite.finish
93
-
94
- xml = @suite.to_xml
95
- doc = REXML::Document.new(xml)
96
- testsuite = doc.root.elements.to_a("/testsuite")
97
- testsuite.length.should == 1
98
- testsuite = testsuite.first
99
- testsuite.attributes["name"].should == "example suite"
100
- testsuite.attributes["assertions"].should == "11"
101
- testsuite.attributes["timestamp"].should match(/(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})[+-](\d{2})\:(\d{2})/)
102
-
103
- testcases = testsuite.elements.to_a("testcase")
104
- testcases.length.should == 4
105
- end
47
+ it "stringifies the name for cases when the object passed in is not a string" do
48
+ name = Object.new
49
+ def name.to_s; "object name"; end
50
+ expect(CI::Reporter::TestSuite.new(name).name).to eql "object name"
51
+ end
106
52
 
107
- it "should contain full exception type and message in location element" do
108
- failure = double("failure")
109
- failure.stub(:failure?).and_return true
110
- failure.stub(:error?).and_return false
111
- failure.stub(:name).and_return "failure"
112
- failure.stub(:message).and_return "There was a failure"
113
- failure.stub(:location).and_return @exception.backtrace.join("\n")
114
-
115
- @suite.start
116
- @suite.testcases << CI::Reporter::TestCase.new("example test")
117
- @suite.testcases << CI::Reporter::TestCase.new("failure test")
118
- @suite.testcases.last.failures << failure
119
- @suite.finish
120
-
121
- xml = @suite.to_xml
122
- doc = REXML::Document.new(xml)
123
- elem = doc.root.elements.to_a("/testsuite/testcase[@name='failure test']/failure").first
124
- location = elem.texts.join
125
- location.should =~ Regexp.new(failure.message)
126
- location.should =~ Regexp.new(failure.name)
127
- end
53
+ it "indicates number of failures and errors" do
54
+ suite.start
55
+ suite.testcases << CI::Reporter::TestCase.new("example test")
56
+ suite.testcases << CI::Reporter::TestCase.new("failure test")
57
+ suite.testcases.last.failures << failure
58
+ suite.testcases << CI::Reporter::TestCase.new("error test")
59
+ suite.testcases.last.failures << error
60
+ suite.finish
61
+ expect(suite.tests).to eql 3
62
+ expect(suite.failures).to eql 1
63
+ expect(suite.errors).to eql 1
64
+ end
128
65
 
129
- it "should filter attributes properly for invalid characters" do
130
- failure = double("failure")
131
- failure.stub(:failure?).and_return true
132
- failure.stub(:error?).and_return false
133
- failure.stub(:name).and_return "failure"
134
- failure.stub(:message).and_return "There was a <failure>\nReason: blah"
135
- failure.stub(:location).and_return @exception.backtrace.join("\n")
136
-
137
- @suite.start
138
- @suite.testcases << CI::Reporter::TestCase.new("failure test")
139
- @suite.testcases.last.failures << failure
140
- @suite.finish
141
-
142
- xml = @suite.to_xml
143
- xml.should =~ %r/message="There was a &lt;failure&gt;\.\.\."/
66
+ context "xml" do
67
+ let(:suite) { CI::Reporter::TestSuite.new("example suite") }
68
+
69
+ before(:each) do
70
+ ENV['CI_CAPTURE'] = nil
71
+ suite.assertions = 11
72
+ end
73
+
74
+ after(:each) do
75
+ ENV['CI_CAPTURE'] = nil
76
+ end
77
+
78
+ it "renders successfully with CI_CAPTURE off" do
79
+ ENV['CI_CAPTURE'] = 'off'
80
+ suite.start
81
+ suite.testcases << CI::Reporter::TestCase.new("example test")
82
+ suite.finish
83
+ xml = suite.to_xml
84
+ end
85
+
86
+ it "contains Ant/JUnit-formatted description of entire suite" do
87
+ suite.start
88
+ suite.testcases << CI::Reporter::TestCase.new("example test")
89
+ suite.testcases << CI::Reporter::TestCase.new("skipped test").tap {|tc| tc.skipped = true }
90
+ suite.testcases << CI::Reporter::TestCase.new("failure test")
91
+ suite.testcases.last.failures << failure
92
+ suite.testcases << CI::Reporter::TestCase.new("error test")
93
+ suite.testcases.last.failures << error
94
+ suite.finish
95
+
96
+ xml = suite.to_xml
97
+ doc = REXML::Document.new(xml)
98
+ testsuite = doc.root.elements.to_a("/testsuite")
99
+ expect(testsuite.length).to eql 1
100
+ testsuite = testsuite.first
101
+ expect(testsuite.attributes["name"]).to eql "example suite"
102
+ expect(testsuite.attributes["assertions"]).to eql "11"
103
+ expect(testsuite.attributes["timestamp"]).to match(/(\d{4})-(\d{2})-(\d{2})T(\d{2})\:(\d{2})\:(\d{2})[+-](\d{2})\:(\d{2})/)
104
+
105
+ testcases = testsuite.elements.to_a("testcase")
106
+ expect(testcases.length).to eql 4
107
+ end
108
+
109
+ it "contains full exception type and message in location element" do
110
+ suite.start
111
+ suite.testcases << CI::Reporter::TestCase.new("example test")
112
+ suite.testcases << CI::Reporter::TestCase.new("failure test")
113
+ suite.testcases.last.failures << failure
114
+ suite.finish
115
+
116
+ xml = suite.to_xml
117
+ doc = REXML::Document.new(xml)
118
+ elem = doc.root.elements.to_a("/testsuite/testcase[@name='failure test']/failure").first
119
+ location = elem.texts.join
120
+ expect(location).to match Regexp.new(failure.message)
121
+ expect(location).to match Regexp.new(failure.name)
122
+ end
123
+
124
+ it "filters attributes properly for invalid characters" do
125
+ failure = double("failure",
126
+ :failure? => true,
127
+ :error? => false,
128
+ :name => "failure",
129
+ :message => "There was a <failure>\nReason: blah",
130
+ :location => exception.backtrace.join("\n"))
131
+
132
+ suite.start
133
+ suite.testcases << CI::Reporter::TestCase.new("failure test")
134
+ suite.testcases.last.failures << failure
135
+ suite.finish
136
+
137
+ xml = suite.to_xml
138
+ expect(xml).to match %r/message="There was a &lt;failure&gt;\.\.\."/
139
+ end
140
+ end
144
141
  end
145
- end
146
142
 
147
- describe "A TestCase" do
148
- before(:each) do
149
- @tc = CI::Reporter::TestCase.new("example test")
150
- end
143
+ describe TestCase do
144
+ subject(:tc) { TestCase.new("example test") }
151
145
 
152
- it "should collect timings when start and finish are invoked in sequence" do
153
- @tc.start
154
- @tc.finish
155
- @tc.time.should >= 0
146
+ it "collects timings when start and finish are invoked in sequence" do
147
+ tc.start
148
+ tc.finish
149
+ expect(tc.time).to be >= 0
150
+ end
156
151
  end
157
152
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ci_reporter
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.alpha2
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sieger
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-06-30 00:00:00.000000000 Z
12
+ date: 2023-02-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: builder
@@ -25,6 +25,20 @@ dependencies:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: 2.1.2
28
+ - !ruby/object:Gem::Dependency
29
+ name: rexml
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
28
42
  - !ruby/object:Gem::Dependency
29
43
  name: rake
30
44
  requirement: !ruby/object:Gem::Requirement
@@ -59,14 +73,14 @@ dependencies:
59
73
  requirements:
60
74
  - - "~>"
61
75
  - !ruby/object:Gem::Version
62
- version: '2.0'
76
+ version: '3.0'
63
77
  type: :development
64
78
  prerelease: false
65
79
  version_requirements: !ruby/object:Gem::Requirement
66
80
  requirements:
67
81
  - - "~>"
68
82
  - !ruby/object:Gem::Version
69
- version: '2.0'
83
+ version: '3.0'
70
84
  description: CI::Reporter is an add-on to Ruby testing frameworks that allows you
71
85
  to generate XML reports of your test runs. The resulting files can be read by a
72
86
  continuous integration system that understands Ant's JUnit report format.
@@ -80,17 +94,19 @@ extra_rdoc_files:
80
94
  - LICENSE.txt
81
95
  - README.md
82
96
  files:
97
+ - ".github/workflows/ci.yaml"
98
+ - ".github/workflows/release.yaml"
83
99
  - ".gitignore"
84
100
  - ".rspec"
85
- - ".travis.yml"
86
101
  - Gemfile
87
102
  - History.txt
88
103
  - LICENSE.txt
89
104
  - README.md
90
105
  - Rakefile
91
106
  - ci_reporter.gemspec
92
- - gemfiles/.gitignore
93
107
  - lib/ci/reporter/core.rb
108
+ - lib/ci/reporter/monotonic_time.rb
109
+ - lib/ci/reporter/output_capture.rb
94
110
  - lib/ci/reporter/rake/utils.rb
95
111
  - lib/ci/reporter/report_manager.rb
96
112
  - lib/ci/reporter/test_suite.rb
@@ -114,12 +130,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
114
130
  version: '0'
115
131
  required_rubygems_version: !ruby/object:Gem::Requirement
116
132
  requirements:
117
- - - ">"
133
+ - - ">="
118
134
  - !ruby/object:Gem::Version
119
- version: 1.3.1
135
+ version: '0'
120
136
  requirements: []
121
- rubyforge_project:
122
- rubygems_version: 2.2.2
137
+ rubygems_version: 3.4.1
123
138
  signing_key:
124
139
  specification_version: 4
125
140
  summary: Connects Ruby test frameworks to CI systems via JUnit reports.
data/.travis.yml DELETED
@@ -1,5 +0,0 @@
1
- rvm:
2
- - 1.9.3
3
- - 2.0
4
- - 2.1
5
- - jruby
data/gemfiles/.gitignore DELETED
@@ -1 +0,0 @@
1
- Gemfile.*.lock