ci_reporter 2.0.0.alpha2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.txt +10 -0
- data/README.md +13 -2
- data/ci_reporter.gemspec +1 -1
- data/lib/ci/reporter/output_capture.rb +31 -0
- data/lib/ci/reporter/test_suite.rb +43 -62
- data/lib/ci/reporter/version.rb +1 -1
- data/spec/ci/reporter/output_capture_spec.rb +42 -34
- data/spec/ci/reporter/report_manager_spec.rb +66 -64
- data/spec/ci/reporter/test_suite_spec.rb +136 -141
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe5f8b66682882d6a356567fcf2b9683fe5f529a
|
4
|
+
data.tar.gz: 7831002dd54de23d55414b03bfad33061d2c3359
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b41cf605637d2974bb44f18698b80e682d863bae095751b4ac50f1349df7ea363a6346e4ff06e88e6ce1884c641f8277c8dac4a23240baec930157f27c791a98
|
7
|
+
data.tar.gz: 8bc3f23ee5b19300109a141a086fa64da41b0a0c647991c91b68a56adb16edb4114f8a3a8c9b46312ddb677548563e6fe378c044bb6de119553561ea477a6390
|
data/History.txt
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
== 2.0.0 (2014-07-24)
|
2
|
+
|
3
|
+
=== Changed
|
4
|
+
|
5
|
+
- Gem has been refactored into multiple framework-specific gems.
|
6
|
+
|
7
|
+
=== Removed
|
8
|
+
|
9
|
+
- All methods of use except the `ci:setup:*` Rake tasks.
|
10
|
+
|
1
11
|
== 1.9.2 (04/06/14)
|
2
12
|
|
3
13
|
- GH #119: add timestamp attribute (Shawn Zhu)
|
data/README.md
CHANGED
@@ -30,10 +30,21 @@ Each supported testing framework is provided by a separate gem:
|
|
30
30
|
[ci-spin]: https://github.com/ci-reporter/ci_reporter_spinach
|
31
31
|
[ci-tu]: https://github.com/ci-reporter/ci_reporter_test_unit
|
32
32
|
|
33
|
+
### Upgrading from CI::Reporter 1.x
|
34
|
+
|
35
|
+
CI::Reporter 1.x supported all the different test frameworks in a
|
36
|
+
single gem. This was convienient, but caused issues as test frameworks
|
37
|
+
released new, sometimes incompatibile, versions. CI::Reporter 2.x has
|
38
|
+
been split into multiple gems, allowing each gem to specify the test
|
39
|
+
framework versions it supports.
|
40
|
+
|
41
|
+
To upgrade to 2.x, remove `ci_reporter` from your Gemfile and replace
|
42
|
+
it with one or more of the framework-specific gems above.
|
43
|
+
|
33
44
|
## Jenkins setup
|
34
45
|
|
35
|
-
1.
|
36
|
-
configuration
|
46
|
+
1. Add the "Publish JUnit test result report" post-build step
|
47
|
+
in the job configuration.
|
37
48
|
|
38
49
|
2. Enter "test/reports/*.xml,spec/reports/*.xml" in the "Test report
|
39
50
|
XMLs" field (adjust this to suit which tests you are running)
|
data/ci_reporter.gemspec
CHANGED
@@ -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
|
@@ -1,50 +1,32 @@
|
|
1
|
-
require 'delegate'
|
2
|
-
require 'stringio'
|
3
1
|
require 'time'
|
2
|
+
require 'builder'
|
3
|
+
require 'ci/reporter/output_capture'
|
4
4
|
|
5
5
|
module CI
|
6
6
|
module Reporter
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
def initialize(io, &assign)
|
12
|
-
super(io)
|
13
|
-
capture(io, &assign)
|
14
|
-
end
|
7
|
+
module StructureXmlHelpers
|
8
|
+
# Struct#to_h is not available in Ruby 1.9
|
9
|
+
def attr_hash
|
10
|
+
Hash[self.members.zip(self.values)]
|
15
11
|
end
|
16
12
|
|
17
|
-
|
18
|
-
|
13
|
+
# Removes empty attributes and truncates long attributes.
|
14
|
+
def cleaned_attributes
|
15
|
+
attr_array = attr_hash
|
16
|
+
.reject {|k,v| v.to_s.empty? }
|
17
|
+
.map {|k,v| [k, truncate_at_newline(v)] }
|
18
|
+
Hash[attr_array]
|
19
19
|
end
|
20
20
|
|
21
|
-
|
22
|
-
|
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
|
21
|
+
def truncate_at_newline(txt)
|
22
|
+
txt.to_s.sub(/\n.*/m, '...')
|
43
23
|
end
|
44
24
|
end
|
45
25
|
|
46
26
|
# Basic structure representing the running of a test suite. Used to time tests and store results.
|
47
27
|
class TestSuite < Struct.new(:name, :tests, :time, :failures, :errors, :skipped, :assertions, :timestamp)
|
28
|
+
include StructureXmlHelpers
|
29
|
+
|
48
30
|
attr_accessor :testcases
|
49
31
|
attr_accessor :stdout, :stderr
|
50
32
|
def initialize(name)
|
@@ -66,39 +48,30 @@ module CI
|
|
66
48
|
self.tests = testcases.size
|
67
49
|
self.time = Time.now - @start
|
68
50
|
self.timestamp = @start.iso8601
|
69
|
-
self.failures = testcases.
|
70
|
-
self.errors = testcases.
|
71
|
-
self.skipped = testcases.
|
51
|
+
self.failures = testcases.map(&:failure_count).reduce(&:+)
|
52
|
+
self.errors = testcases.map(&:error_count).reduce(&:+)
|
53
|
+
self.skipped = testcases.count(&:skipped?)
|
72
54
|
self.stdout = @capture_out.finish if @capture_out
|
73
55
|
self.stderr = @capture_err.finish if @capture_err
|
74
56
|
end
|
75
57
|
|
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
58
|
# Creates an xml string containing the test suite results.
|
84
59
|
def to_xml
|
85
|
-
builder =
|
86
|
-
# more recent version of Builder doesn't need the escaping
|
87
|
-
def builder.trunc!(txt)
|
88
|
-
txt.sub(/\n.*/m, '...')
|
89
|
-
end
|
60
|
+
builder = Builder::XmlMarkup.new(indent: 2)
|
90
61
|
builder.instruct!
|
91
|
-
|
92
|
-
each_pair {|k,v| attrs[k] = builder.trunc!(v.to_s) unless v.nil? || v.to_s.empty? }
|
93
|
-
builder.testsuite(attrs) do
|
62
|
+
builder.testsuite(cleaned_attributes) do
|
94
63
|
@testcases.each do |tc|
|
95
64
|
tc.to_xml(builder)
|
96
65
|
end
|
97
|
-
|
98
|
-
builder.
|
66
|
+
unless self.stdout.to_s.empty?
|
67
|
+
builder.tag! "system-out" do
|
68
|
+
builder.text!(self.stdout)
|
69
|
+
end
|
99
70
|
end
|
100
|
-
|
101
|
-
builder.
|
71
|
+
unless self.stderr.to_s.empty?
|
72
|
+
builder.tag! "system-err" do
|
73
|
+
builder.text!(self.stderr)
|
74
|
+
end
|
102
75
|
end
|
103
76
|
end
|
104
77
|
end
|
@@ -106,6 +79,8 @@ module CI
|
|
106
79
|
|
107
80
|
# Structure used to represent an individual test case. Used to time the test and store the result.
|
108
81
|
class TestCase < Struct.new(:name, :time, :assertions)
|
82
|
+
include StructureXmlHelpers
|
83
|
+
|
109
84
|
attr_accessor :failures
|
110
85
|
attr_accessor :skipped
|
111
86
|
|
@@ -126,12 +101,20 @@ module CI
|
|
126
101
|
|
127
102
|
# Returns non-nil if the test failed.
|
128
103
|
def failure?
|
129
|
-
|
104
|
+
failures.any?(&:failure?)
|
130
105
|
end
|
131
106
|
|
132
107
|
# Returns non-nil if the test had an error.
|
133
108
|
def error?
|
134
|
-
|
109
|
+
failures.any?(&:error?)
|
110
|
+
end
|
111
|
+
|
112
|
+
def failure_count
|
113
|
+
failures.count(&:failure?)
|
114
|
+
end
|
115
|
+
|
116
|
+
def error_count
|
117
|
+
failures.count(&:error?)
|
135
118
|
end
|
136
119
|
|
137
120
|
def skipped?
|
@@ -140,16 +123,14 @@ module CI
|
|
140
123
|
|
141
124
|
# Writes xml representing the test result to the provided builder.
|
142
125
|
def to_xml(builder)
|
143
|
-
|
144
|
-
each_pair {|k,v| attrs[k] = builder.trunc!(v.to_s) unless v.nil? || v.to_s.empty?}
|
145
|
-
builder.testcase(attrs) do
|
126
|
+
builder.testcase(cleaned_attributes) do
|
146
127
|
if skipped?
|
147
128
|
builder.skipped
|
148
129
|
else
|
149
130
|
failures.each do |failure|
|
150
131
|
tag = failure.error? ? :error : :failure
|
151
132
|
|
152
|
-
builder.tag!(tag, :
|
133
|
+
builder.tag!(tag, type: truncate_at_newline(failure.name), message: truncate_at_newline(failure.message)) do
|
153
134
|
builder.text!(failure.message + " (#{failure.name})\n")
|
154
135
|
builder.text!(failure.location)
|
155
136
|
end
|
data/lib/ci/reporter/version.rb
CHANGED
@@ -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
|
-
|
6
|
-
@suite = CI::Reporter::TestSuite.new "test"
|
7
|
-
end
|
5
|
+
subject(:suite) { CI::Reporter::TestSuite.new "test" }
|
8
6
|
|
9
|
-
it "
|
10
|
-
|
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
|
-
|
14
|
-
|
15
|
-
|
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 "
|
19
|
-
|
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
|
-
|
20
|
+
suite.finish
|
23
21
|
|
24
|
-
root = REXML::Document.new(
|
25
|
-
root.elements.to_a('//system-out').length.
|
26
|
-
root.elements.to_a('//system-err').length.
|
27
|
-
root.elements.to_a('//system-out').first.texts.first.to_s.strip.
|
28
|
-
root.elements.to_a('//system-err').first.texts.first.to_s.strip.
|
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 "
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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 "
|
38
|
+
it "captures only during run of owner test suite" do
|
42
39
|
$stdout.print "A"
|
43
40
|
$stderr.print "A"
|
44
|
-
|
41
|
+
suite.start
|
45
42
|
$stdout.print "B"
|
46
43
|
$stderr.print "B"
|
47
|
-
|
44
|
+
suite.finish
|
48
45
|
$stdout.print "C"
|
49
46
|
$stderr.print "C"
|
50
|
-
|
51
|
-
|
47
|
+
expect(suite.stdout).to eql "B"
|
48
|
+
expect(suite.stderr).to eql "B"
|
52
49
|
end
|
53
50
|
|
54
|
-
|
55
|
-
|
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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
after(:each) do
|
11
|
+
FileUtils.rm_rf @reports_dir
|
12
|
+
ENV["CI_REPORTS"] = nil
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
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
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
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
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
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
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
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 <failure>\.\.\."/
|
139
|
+
end
|
140
|
+
end
|
144
141
|
end
|
145
|
-
end
|
146
142
|
|
147
|
-
describe
|
148
|
-
|
149
|
-
@tc = CI::Reporter::TestCase.new("example test")
|
150
|
-
end
|
143
|
+
describe TestCase do
|
144
|
+
subject(:tc) { TestCase.new("example test") }
|
151
145
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
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
|
4
|
+
version: 2.0.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-
|
12
|
+
date: 2014-07-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: builder
|
@@ -59,14 +59,14 @@ dependencies:
|
|
59
59
|
requirements:
|
60
60
|
- - "~>"
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version: '
|
62
|
+
version: '3.0'
|
63
63
|
type: :development
|
64
64
|
prerelease: false
|
65
65
|
version_requirements: !ruby/object:Gem::Requirement
|
66
66
|
requirements:
|
67
67
|
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
69
|
+
version: '3.0'
|
70
70
|
description: CI::Reporter is an add-on to Ruby testing frameworks that allows you
|
71
71
|
to generate XML reports of your test runs. The resulting files can be read by a
|
72
72
|
continuous integration system that understands Ant's JUnit report format.
|
@@ -91,6 +91,7 @@ files:
|
|
91
91
|
- ci_reporter.gemspec
|
92
92
|
- gemfiles/.gitignore
|
93
93
|
- lib/ci/reporter/core.rb
|
94
|
+
- lib/ci/reporter/output_capture.rb
|
94
95
|
- lib/ci/reporter/rake/utils.rb
|
95
96
|
- lib/ci/reporter/report_manager.rb
|
96
97
|
- lib/ci/reporter/test_suite.rb
|
@@ -114,9 +115,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
114
115
|
version: '0'
|
115
116
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
117
|
requirements:
|
117
|
-
- - "
|
118
|
+
- - ">="
|
118
119
|
- !ruby/object:Gem::Version
|
119
|
-
version:
|
120
|
+
version: '0'
|
120
121
|
requirements: []
|
121
122
|
rubyforge_project:
|
122
123
|
rubygems_version: 2.2.2
|