simplecov-cobertura 2.1.0 → 4.0.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 +4 -4
- data/.github/workflows/build.yml +4 -4
- data/.gitignore +1 -0
- data/README.md +12 -10
- data/lib/simplecov-cobertura/version.rb +1 -1
- data/lib/simplecov-cobertura.rb +130 -107
- data/simplecov-cobertura.gemspec +13 -13
- data/test/fixtures/sample/lib/sample.rb +28 -0
- data/test/fixtures/sample/test/simplecov_setup.rb +17 -0
- data/test/fixtures/sample/test/test_merged_a.rb +11 -0
- data/test/fixtures/sample/test/test_merged_b.rb +7 -0
- data/test/fixtures/sample/test/test_sample.rb +12 -0
- data/test/integration_test.rb +175 -0
- data/test/simplecov-cobertura_test.rb +88 -48
- metadata +20 -13
- data/test/coverage/coverage.xml +0 -21
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: af6021ce1207169b5c8d5bbb7aba68a6a02df4c88a248b7fca763f817cfe0600
|
|
4
|
+
data.tar.gz: e9ded405dcfbb983a77153fd13a376addcdbb77d8e34a44b68c2ecb61f6af9c5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e6678dab612071560ecde49409ed10285778dc6c73445766e80283828548c5a142631dc44ee7be5a1da637f8d3fa7ee8d077e226528574b1978b9742f21c1571
|
|
7
|
+
data.tar.gz: af788e30f13b615b2016359a49b6d1ab34931ac74732ca25beefb4c0cac0ddff8f5bb378a3b92ed4ed699a0c404d5590982f50f32084186b861c2bde528f7e26
|
data/.github/workflows/build.yml
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
name: Build
|
|
9
9
|
|
|
10
|
-
on: [push, pull_request]
|
|
10
|
+
on: [ push, pull_request ]
|
|
11
11
|
|
|
12
12
|
jobs:
|
|
13
13
|
test:
|
|
@@ -15,14 +15,14 @@ jobs:
|
|
|
15
15
|
runs-on: ubuntu-latest
|
|
16
16
|
strategy:
|
|
17
17
|
matrix:
|
|
18
|
-
ruby-version: [2
|
|
18
|
+
ruby-version: [ 3.2, 3.3, 3.4, 4.0 ]
|
|
19
19
|
|
|
20
20
|
steps:
|
|
21
|
-
- uses: actions/checkout@
|
|
21
|
+
- uses: actions/checkout@v6
|
|
22
22
|
- name: Set up Ruby
|
|
23
23
|
uses: ruby/setup-ruby@v1
|
|
24
24
|
with:
|
|
25
25
|
ruby-version: ${{ matrix.ruby-version }}
|
|
26
26
|
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
|
27
27
|
- name: Run tests
|
|
28
|
-
run: bundle exec rake
|
|
28
|
+
run: bundle exec rake
|
data/.gitignore
CHANGED
data/README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
# simplecov-cobertura
|
|
2
|
-
[](https://github.com/dashingrocket/simplecov-cobertura/actions/workflows/build.yml) [](http://badge.fury.io/rb/simplecov-cobertura) [](https://rubygems.org/gems/simplecov-cobertura)
|
|
1
|
+
# simplecov-cobertura
|
|
3
2
|
|
|
3
|
+
[](https://github.com/jessebs/simplecov-cobertura/actions/workflows/build.yml) [](http://badge.fury.io/rb/simplecov-cobertura)
|
|
4
4
|
|
|
5
|
-
Produces [Cobertura](http://cobertura.sourceforge.net/) formatted XML
|
|
5
|
+
Produces [Cobertura](http://cobertura.sourceforge.net/) formatted XML
|
|
6
|
+
from [SimpleCov](https://github.com/colszowka/simplecov).
|
|
6
7
|
|
|
7
|
-
Output can be consumed by the [Jenkins Cobertura Plugin](https://wiki.jenkins-ci.org/display/JENKINS/Cobertura+Plugin)
|
|
8
|
+
Output can be consumed by the [Jenkins Cobertura Plugin](https://wiki.jenkins-ci.org/display/JENKINS/Cobertura+Plugin)
|
|
9
|
+
for easy
|
|
8
10
|
coverage visualization.
|
|
9
11
|
|
|
10
12
|
## Installation
|
|
@@ -32,22 +34,22 @@ SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter
|
|
|
32
34
|
```
|
|
33
35
|
|
|
34
36
|
## Continuous Integration
|
|
37
|
+
|
|
35
38
|
Tested in a CI environment against the following Ruby versions:
|
|
36
|
-
|
|
37
|
-
* 2.
|
|
38
|
-
* 2.6
|
|
39
|
-
* 2.5
|
|
39
|
+
|
|
40
|
+
* 3.2 - 4.0
|
|
40
41
|
|
|
41
42
|
## Contributing
|
|
42
43
|
|
|
43
|
-
1. Fork it ( https://github.com/
|
|
44
|
+
1. Fork it ( https://github.com/jessebs/simplecov-cobertura/fork )
|
|
44
45
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
45
46
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
46
47
|
4. Push to the branch (`git push origin my-new-feature`)
|
|
47
48
|
5. Create a new Pull Request
|
|
48
49
|
|
|
49
50
|
## License
|
|
50
|
-
|
|
51
|
+
|
|
52
|
+
Copyright 2014-2026 Jesse Bowes
|
|
51
53
|
|
|
52
54
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
53
55
|
you may not use this file except in compliance with the License.
|
data/lib/simplecov-cobertura.rb
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
require '
|
|
2
|
-
|
|
1
|
+
require 'stringio'
|
|
3
2
|
require 'rexml/document'
|
|
4
3
|
require 'rexml/element'
|
|
5
4
|
require 'pathname'
|
|
5
|
+
require 'simplecov'
|
|
6
6
|
|
|
7
7
|
require_relative 'simplecov-cobertura/version'
|
|
8
8
|
|
|
@@ -27,149 +27,172 @@ module SimpleCov
|
|
|
27
27
|
|
|
28
28
|
xml_str = string_io.string
|
|
29
29
|
File.write(result_path, xml_str)
|
|
30
|
-
puts
|
|
30
|
+
puts output_message(result, result_path)
|
|
31
|
+
|
|
31
32
|
xml_str
|
|
32
33
|
end
|
|
33
34
|
|
|
34
35
|
private
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
def result_to_xml(result)
|
|
38
|
+
doc = REXML::Document.new
|
|
39
|
+
doc.context[:attribute_quote] = :quote
|
|
40
|
+
doc << REXML::XMLDecl.new('1.0')
|
|
41
|
+
doc << REXML::DocType.new('coverage', "SYSTEM \"#{DTD_URL}\"")
|
|
42
|
+
doc << REXML::Comment.new("Generated by simplecov-cobertura version #{VERSION} (https://github.com/jessebs/simplecov-cobertura)")
|
|
43
|
+
doc.add_element REXML::Element.new('coverage')
|
|
44
|
+
coverage = doc.root
|
|
41
45
|
|
|
42
|
-
|
|
46
|
+
set_coverage_attributes(coverage, result)
|
|
43
47
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
coverage.add_element(sources = REXML::Element.new('sources'))
|
|
49
|
+
sources.add_element(source = REXML::Element.new('source'))
|
|
50
|
+
source.text = SimpleCov.root
|
|
47
51
|
|
|
48
|
-
|
|
52
|
+
coverage.add_element(packages = REXML::Element.new('packages'))
|
|
49
53
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
if result.groups.empty?
|
|
55
|
+
groups = { File.basename(SimpleCov.root) => result.files }
|
|
56
|
+
else
|
|
57
|
+
groups = result.groups
|
|
58
|
+
end
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
groups.each do |name, files|
|
|
61
|
+
next if files.empty?
|
|
62
|
+
packages.add_element(package = REXML::Element.new('package'))
|
|
63
|
+
set_package_attributes(package, name, files)
|
|
60
64
|
|
|
61
|
-
|
|
65
|
+
package.add_element(classes = REXML::Element.new('classes'))
|
|
62
66
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
files.each do |file|
|
|
68
|
+
classes.add_element(class_ = REXML::Element.new('class'))
|
|
69
|
+
set_class_attributes(class_, file)
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
class_.add_element(REXML::Element.new('methods'))
|
|
72
|
+
class_.add_element(lines = REXML::Element.new('lines'))
|
|
69
73
|
|
|
70
|
-
|
|
71
|
-
|
|
74
|
+
branches_by_line = {}
|
|
75
|
+
if SimpleCov.branch_coverage?
|
|
76
|
+
build_branches_by_line(file, branches_by_line)
|
|
77
|
+
end
|
|
72
78
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
end
|
|
79
|
+
file.lines.each do |file_line|
|
|
80
|
+
if file_line.covered? || file_line.missed?
|
|
81
|
+
lines.add_element(line = REXML::Element.new('line'))
|
|
82
|
+
set_line_attributes(line, file_line)
|
|
83
|
+
set_branch_attributes(line, file_line, branches_by_line) if SimpleCov.branch_coverage?
|
|
79
84
|
end
|
|
80
85
|
end
|
|
81
86
|
end
|
|
82
|
-
|
|
83
|
-
doc
|
|
84
87
|
end
|
|
85
88
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
coverage.attributes['
|
|
99
|
-
coverage.attributes['
|
|
100
|
-
coverage.attributes['timestamp'] = Time.now.to_i.to_s
|
|
89
|
+
doc
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def set_coverage_attributes(coverage, result)
|
|
93
|
+
ls = result.coverage_statistics[:line]
|
|
94
|
+
bs = result.coverage_statistics[:branch]
|
|
95
|
+
|
|
96
|
+
coverage.attributes['line-rate'] = extract_rate(ls.percent)
|
|
97
|
+
coverage.attributes['lines-covered'] = ls.covered.to_s.to_s
|
|
98
|
+
coverage.attributes['lines-valid'] = ls.total.to_s.to_s
|
|
99
|
+
if SimpleCov.branch_coverage?
|
|
100
|
+
coverage.attributes['branches-covered'] = bs.covered.to_s
|
|
101
|
+
coverage.attributes['branches-valid'] = bs.total.to_s
|
|
102
|
+
coverage.attributes['branch-rate'] = extract_rate(bs.percent)
|
|
101
103
|
end
|
|
104
|
+
coverage.attributes['complexity'] = '0'
|
|
105
|
+
coverage.attributes['version'] = '0'
|
|
106
|
+
coverage.attributes['timestamp'] = Time.now.to_i.to_s
|
|
107
|
+
end
|
|
102
108
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
109
|
+
def set_package_attributes(package, name, result)
|
|
110
|
+
ls = result.coverage_statistics[:line]
|
|
111
|
+
bs = result.coverage_statistics[:branch]
|
|
106
112
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
end
|
|
112
|
-
package.attributes['complexity'] = '0'
|
|
113
|
+
package.attributes['name'] = name
|
|
114
|
+
package.attributes['line-rate'] = extract_rate(ls.percent)
|
|
115
|
+
if SimpleCov.branch_coverage?
|
|
116
|
+
package.attributes['branch-rate'] = extract_rate(bs.percent)
|
|
113
117
|
end
|
|
118
|
+
package.attributes['complexity'] = '0'
|
|
119
|
+
end
|
|
114
120
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
121
|
+
def set_class_attributes(class_, file)
|
|
122
|
+
ls = file.coverage_statistics[:line]
|
|
123
|
+
bs = file.coverage_statistics[:branch]
|
|
118
124
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
end
|
|
126
|
-
class_.attributes['complexity'] = '0'
|
|
125
|
+
filename = file.filename
|
|
126
|
+
class_.attributes['name'] = resolve_filename(filename)
|
|
127
|
+
class_.attributes['filename'] = resolve_filename(filename)
|
|
128
|
+
class_.attributes['line-rate'] = extract_rate(ls.percent)
|
|
129
|
+
if SimpleCov.branch_coverage?
|
|
130
|
+
class_.attributes['branch-rate'] = extract_rate(bs.percent)
|
|
127
131
|
end
|
|
132
|
+
class_.attributes['complexity'] = '0'
|
|
133
|
+
end
|
|
128
134
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
135
|
+
def set_line_attributes(line, file_line)
|
|
136
|
+
line.attributes['number'] = file_line.line_number.to_s
|
|
137
|
+
line.attributes['hits'] = file_line.coverage.to_s
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def set_branch_attributes(line, file_line, branches_by_line)
|
|
141
|
+
branch_info = branches_by_line[file_line.line_number]
|
|
142
|
+
if branch_info
|
|
143
|
+
total = branch_info[:total]
|
|
144
|
+
covered = branch_info[:covered]
|
|
145
|
+
pct_coverage = total > 0 ? (covered * 100 / total) : 0
|
|
146
|
+
line.attributes['branch'] = 'true'
|
|
147
|
+
line.attributes['condition-coverage'] = "#{pct_coverage}% (#{covered}/#{total})"
|
|
148
|
+
else
|
|
149
|
+
line.attributes['branch'] = 'false'
|
|
132
150
|
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def build_branches_by_line(file, branches_by_line)
|
|
154
|
+
file.coverage_data.fetch("branches", {}).each do |condition, branches|
|
|
155
|
+
line = condition_start_line(condition)
|
|
156
|
+
next unless line
|
|
133
157
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
line.attributes['condition-coverage'] = "#{pct_coverage}% (#{branches_covered})"
|
|
139
|
-
else
|
|
140
|
-
line.attributes['branch'] = 'false'
|
|
158
|
+
info = branches_by_line[line] ||= { total: 0, covered: 0 }
|
|
159
|
+
branches.each_value do |hit_count|
|
|
160
|
+
info[:total] += 1
|
|
161
|
+
info[:covered] += 1 if hit_count.to_i > 0
|
|
141
162
|
end
|
|
142
163
|
end
|
|
164
|
+
rescue StandardError => e
|
|
165
|
+
warn "simplecov-cobertura: couldn't extract per-line branch detail " \
|
|
166
|
+
"(#{e.class}: #{e.message}); lines will report branch=\"false\""
|
|
167
|
+
branches_by_line.clear
|
|
168
|
+
end
|
|
143
169
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
lines << "<!-- Generated by simplecov-cobertura version #{VERSION} (https://github.com/dashingrocket/simplecov-cobertura) -->"
|
|
148
|
-
lines.join("\n")
|
|
149
|
-
end
|
|
170
|
+
def condition_start_line(condition)
|
|
171
|
+
return condition[2] if condition.is_a?(Array)
|
|
172
|
+
return nil unless condition.is_a?(String)
|
|
150
173
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
bs = result.coverage_statistics[:branch]
|
|
174
|
+
condition.scan(/-?\d+/)[1]&.to_i # [id, start_line, ...]
|
|
175
|
+
end
|
|
154
176
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
177
|
+
# Roughly mirrors private method SimpleCov::Formatter::HTMLFormatter#output_coverage
|
|
178
|
+
def output_message(result, output_path)
|
|
179
|
+
output = "Coverage report generated for #{result.command_name} to #{output_path}."
|
|
180
|
+
output += "\nLine Coverage: #{result.covered_percent.round(2)}% (#{result.covered_lines} / #{result.total_lines})"
|
|
181
|
+
output += "\nBranch Coverage: #{result.coverage_statistics[:branch].percent.round(2)}% (#{result.covered_branches} / #{result.total_branches})" if SimpleCov.branch_coverage?
|
|
182
|
+
output
|
|
183
|
+
end
|
|
161
184
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
185
|
+
def resolve_filename(filename)
|
|
186
|
+
Pathname.new(filename).relative_path_from(project_root).to_s
|
|
187
|
+
end
|
|
165
188
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
189
|
+
def extract_rate(percent)
|
|
190
|
+
(percent / 100).round(4).to_s
|
|
191
|
+
end
|
|
169
192
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
193
|
+
def project_root
|
|
194
|
+
@project_root ||= Pathname.new(SimpleCov.root)
|
|
195
|
+
end
|
|
173
196
|
end
|
|
174
197
|
end
|
|
175
198
|
end
|
data/simplecov-cobertura.gemspec
CHANGED
|
@@ -5,25 +5,25 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
|
5
5
|
require 'simplecov-cobertura/version'
|
|
6
6
|
|
|
7
7
|
Gem::Specification.new do |spec|
|
|
8
|
-
spec.name
|
|
9
|
-
spec.version
|
|
10
|
-
spec.authors
|
|
11
|
-
spec.email
|
|
12
|
-
spec.summary
|
|
13
|
-
spec.description
|
|
14
|
-
spec.homepage
|
|
15
|
-
spec.license
|
|
16
|
-
spec.required_ruby_version = '>= 2
|
|
8
|
+
spec.name = 'simplecov-cobertura'
|
|
9
|
+
spec.version = SimpleCov::Formatter::CoberturaFormatter::VERSION
|
|
10
|
+
spec.authors = ['Jesse Bowes']
|
|
11
|
+
spec.email = ['jessebowes@acm.org']
|
|
12
|
+
spec.summary = 'SimpleCov Cobertura Formatter'
|
|
13
|
+
spec.description = 'Produces Cobertura XML formatted output from SimpleCov'
|
|
14
|
+
spec.homepage = 'https://github.com/jessebs/simplecov-cobertura'
|
|
15
|
+
spec.license = 'Apache-2.0'
|
|
16
|
+
spec.required_ruby_version = '>= 3.2'
|
|
17
17
|
|
|
18
|
-
spec.files
|
|
19
|
-
spec.executables
|
|
20
|
-
spec.test_files
|
|
18
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
21
21
|
spec.require_paths = ['lib']
|
|
22
22
|
|
|
23
23
|
spec.add_development_dependency 'test-unit', '~> 3.2'
|
|
24
24
|
spec.add_development_dependency 'nokogiri', '~> 1.0'
|
|
25
25
|
spec.add_development_dependency 'rake', '~> 13.0'
|
|
26
26
|
|
|
27
|
-
spec.add_dependency 'simplecov', '~> 0
|
|
27
|
+
spec.add_dependency 'simplecov', '~> 1.0'
|
|
28
28
|
spec.add_dependency 'rexml'
|
|
29
29
|
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
class Sample
|
|
2
|
+
def greet(name)
|
|
3
|
+
if name.nil?
|
|
4
|
+
"Hello, stranger!"
|
|
5
|
+
else
|
|
6
|
+
"Hello, #{name}!"
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def absolute(n)
|
|
11
|
+
if n < 0
|
|
12
|
+
-n
|
|
13
|
+
else
|
|
14
|
+
n
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def unused_method
|
|
19
|
+
x = 1
|
|
20
|
+
y = 2
|
|
21
|
+
z = x + y
|
|
22
|
+
if z > 0
|
|
23
|
+
"positive"
|
|
24
|
+
else
|
|
25
|
+
"non-positive"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
$LOAD_PATH.unshift(File.join(ENV.fetch('GEM_ROOT'), 'lib'))
|
|
2
|
+
|
|
3
|
+
require 'simplecov'
|
|
4
|
+
require 'simplecov-cobertura'
|
|
5
|
+
|
|
6
|
+
SimpleCov.command_name ENV.fetch('COMMAND_NAME', 'Unit Tests')
|
|
7
|
+
SimpleCov.start do
|
|
8
|
+
enable_coverage :branch
|
|
9
|
+
use_merging true
|
|
10
|
+
merge_timeout 3600 # generous so slow CI can't expire run A's result
|
|
11
|
+
root ENV.fetch('PROJECT_ROOT')
|
|
12
|
+
coverage_dir 'coverage'
|
|
13
|
+
formatter SimpleCov::Formatter::CoberturaFormatter
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
require File.join(ENV.fetch('PROJECT_ROOT'), 'lib', 'sample')
|
|
17
|
+
require 'test/unit'
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
require_relative 'simplecov_setup'
|
|
2
|
+
|
|
3
|
+
class MergedATest < Test::Unit::TestCase
|
|
4
|
+
def test_greet_with_name
|
|
5
|
+
assert_equal 'Hello, World!', Sample.new.greet('World') # greet: else branch
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def test_absolute_positive
|
|
9
|
+
assert_equal 5, Sample.new.absolute(5) # absolute: else branch
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
require_relative 'simplecov_setup'
|
|
2
|
+
|
|
3
|
+
class SampleTest < Test::Unit::TestCase
|
|
4
|
+
def test_greet_with_name
|
|
5
|
+
assert_equal "Hello, World!", Sample.new.greet("World")
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def test_absolute_positive
|
|
9
|
+
# Only exercises the else branch (n >= 0), never the then branch (n < 0)
|
|
10
|
+
assert_equal 5, Sample.new.absolute(5)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'tmpdir'
|
|
3
|
+
require 'open3'
|
|
4
|
+
require 'nokogiri'
|
|
5
|
+
require 'fileutils'
|
|
6
|
+
|
|
7
|
+
class IntegrationTest < Test::Unit::TestCase
|
|
8
|
+
FIXTURES_DIR = File.join(__dir__, 'fixtures')
|
|
9
|
+
GEM_ROOT = File.expand_path('..', __dir__)
|
|
10
|
+
|
|
11
|
+
def setup
|
|
12
|
+
@tmpdir = Dir.mktmpdir('simplecov-cobertura-integration')
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def teardown
|
|
16
|
+
FileUtils.remove_entry(@tmpdir) if @tmpdir && Dir.exist?(@tmpdir)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_clean_load_require_and_assign_formatter
|
|
20
|
+
# In a fresh subprocess, require simplecov-cobertura and assign the formatter.
|
|
21
|
+
# This catches missing requires (e.g. simplecov, stringio).
|
|
22
|
+
code = <<~RUBY
|
|
23
|
+
require 'simplecov-cobertura'
|
|
24
|
+
SimpleCov.formatter = SimpleCov::Formatter::CoberturaFormatter
|
|
25
|
+
RUBY
|
|
26
|
+
stdout, stderr, status = Open3.capture3('ruby', '-e', code)
|
|
27
|
+
assert status.success?, "Clean-load subprocess failed.\nstdout: #{stdout}\nstderr: #{stderr}"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_real_coverage_run_produces_valid_cobertura_xml
|
|
31
|
+
install_fixture('sample')
|
|
32
|
+
|
|
33
|
+
# Run the sample test in a subprocess.
|
|
34
|
+
stdout, stderr, status = run_fixture_test('test/test_sample.rb')
|
|
35
|
+
assert status.success?, "Sample test subprocess failed.\nstdout: #{stdout}\nstderr: #{stderr}"
|
|
36
|
+
|
|
37
|
+
# --- Assert on the generated coverage.xml ---
|
|
38
|
+
coverage_xml_path = File.join(@tmpdir, 'coverage', 'coverage.xml')
|
|
39
|
+
assert File.exist?(coverage_xml_path), "coverage.xml was not generated"
|
|
40
|
+
xml_content = File.read(coverage_xml_path)
|
|
41
|
+
assert !xml_content.empty?, "coverage.xml is empty"
|
|
42
|
+
|
|
43
|
+
doc = Nokogiri::XML(xml_content) { |config| config.strict }
|
|
44
|
+
assert doc.errors.empty?, "XML parse errors: #{doc.errors.join(', ')}"
|
|
45
|
+
|
|
46
|
+
# Root element
|
|
47
|
+
coverage = doc.at_xpath('/coverage')
|
|
48
|
+
assert_not_nil coverage, "Missing /coverage root element"
|
|
49
|
+
|
|
50
|
+
# Line coverage attributes — partial, not 100% and not 0%
|
|
51
|
+
line_rate = coverage['line-rate'].to_f
|
|
52
|
+
assert line_rate > 0.0, "line-rate should be > 0, got #{line_rate}"
|
|
53
|
+
assert line_rate < 1.0, "line-rate should be < 1.0 (partial coverage), got #{line_rate}"
|
|
54
|
+
|
|
55
|
+
lines_covered = coverage['lines-covered'].to_i
|
|
56
|
+
lines_valid = coverage['lines-valid'].to_i
|
|
57
|
+
assert lines_covered > 0, "lines-covered should be > 0"
|
|
58
|
+
assert lines_valid > lines_covered, "lines-valid (#{lines_valid}) should be > lines-covered (#{lines_covered})"
|
|
59
|
+
|
|
60
|
+
# Branch coverage attributes — partial
|
|
61
|
+
branch_rate = coverage['branch-rate'].to_f
|
|
62
|
+
assert branch_rate > 0.0, "branch-rate should be > 0, got #{branch_rate}"
|
|
63
|
+
assert branch_rate < 1.0, "branch-rate should be < 1.0 (partial coverage), got #{branch_rate}"
|
|
64
|
+
|
|
65
|
+
branches_covered = coverage['branches-covered'].to_i
|
|
66
|
+
branches_valid = coverage['branches-valid'].to_i
|
|
67
|
+
assert branches_covered > 0, "branches-covered should be > 0"
|
|
68
|
+
assert branches_valid > branches_covered, "branches-valid (#{branches_valid}) should be > branches-covered (#{branches_covered})"
|
|
69
|
+
|
|
70
|
+
# The sample library file appears as a class with the expected relative filename
|
|
71
|
+
classes = doc.xpath('//class')
|
|
72
|
+
filenames = classes.map { |c| c['filename'] }
|
|
73
|
+
assert filenames.any? { |f| f.include?('lib/sample.rb') },
|
|
74
|
+
"Expected a class with filename containing 'lib/sample.rb', got: #{filenames}"
|
|
75
|
+
|
|
76
|
+
# Line-level <line> elements exist with hits and branch attributes
|
|
77
|
+
lines = doc.xpath('//line')
|
|
78
|
+
assert lines.length > 0, "Expected <line> elements in the output"
|
|
79
|
+
lines.each do |line|
|
|
80
|
+
assert_not_nil line['number'], "Line element missing 'number' attribute"
|
|
81
|
+
assert_not_nil line['hits'], "Line element missing 'hits' attribute"
|
|
82
|
+
assert_not_nil line['branch'], "Line element missing 'branch' attribute"
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# At least one line should have branch='true' (from the if/else)
|
|
86
|
+
branch_lines = lines.select { |l| l['branch'] == 'true' }
|
|
87
|
+
assert branch_lines.length > 0, "Expected at least one line with branch='true'"
|
|
88
|
+
|
|
89
|
+
# Validate condition-coverage on branch lines
|
|
90
|
+
branch_lines.each do |bl|
|
|
91
|
+
cc = bl['condition-coverage']
|
|
92
|
+
assert_not_nil cc, "Branch line missing 'condition-coverage' attribute"
|
|
93
|
+
assert_match(/\d+% \(\d+\/\d+\)/, cc, "condition-coverage format unexpected: #{cc}")
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def test_condition_coverage_values_are_accurate
|
|
98
|
+
install_fixture('sample')
|
|
99
|
+
|
|
100
|
+
stdout, stderr, status = run_fixture_test('test/test_sample.rb')
|
|
101
|
+
assert status.success?, "Sample test subprocess failed.\nstdout: #{stdout}\nstderr: #{stderr}"
|
|
102
|
+
|
|
103
|
+
coverage_xml_path = File.join(@tmpdir, 'coverage', 'coverage.xml')
|
|
104
|
+
assert File.exist?(coverage_xml_path), "coverage.xml was not generated"
|
|
105
|
+
doc = Nokogiri::XML(File.read(coverage_xml_path)) { |config| config.strict }
|
|
106
|
+
|
|
107
|
+
# Find the branch line for the if statement in sample.rb's absolute method
|
|
108
|
+
sample_class = doc.xpath('//class').find { |c| c['filename'].include?('sample.rb') }
|
|
109
|
+
assert_not_nil sample_class, "Expected sample.rb class in output"
|
|
110
|
+
|
|
111
|
+
branch_lines = sample_class.xpath('.//line[@branch="true"]')
|
|
112
|
+
assert branch_lines.length > 0, "Expected branch lines in sample.rb"
|
|
113
|
+
|
|
114
|
+
# Each if/else has 2 total branches. greet and absolute each have 1/2 covered,
|
|
115
|
+
# unused_method has 0/2 covered. Verify exact values by line number.
|
|
116
|
+
condition_coverages = branch_lines.map { |bl| [bl['number'].to_i, bl['condition-coverage']] }.to_h
|
|
117
|
+
|
|
118
|
+
# greet: line 3 — only else branch taken => 50% (1/2)
|
|
119
|
+
assert_equal '50% (1/2)', condition_coverages[3], "greet condition-coverage mismatch"
|
|
120
|
+
# absolute: line 11 — only else branch taken => 50% (1/2)
|
|
121
|
+
assert_equal '50% (1/2)', condition_coverages[11], "absolute condition-coverage mismatch"
|
|
122
|
+
# unused_method: line 22 — neither branch taken => 0% (0/2)
|
|
123
|
+
assert_equal '0% (0/2)', condition_coverages[22], "unused_method condition-coverage mismatch"
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def test_merged_results_exercise_string_condition_keys
|
|
127
|
+
install_fixture('sample')
|
|
128
|
+
|
|
129
|
+
stdout, stderr, status = run_fixture_test('test/test_merged_a.rb',
|
|
130
|
+
'COMMAND_NAME' => 'Run A')
|
|
131
|
+
assert status.success?, "Run A failed.\nstdout: #{stdout}\nstderr: #{stderr}"
|
|
132
|
+
|
|
133
|
+
# Tripwire: confirm the stored resultset actually contains stringified
|
|
134
|
+
# condition keys. If a future simplecov changes its serialization, this
|
|
135
|
+
# assertion fails and tells you this test no longer covers the string path.
|
|
136
|
+
resultset = File.read(File.join(@tmpdir, 'coverage', '.resultset.json'))
|
|
137
|
+
assert_match(/\[:if, \d+, \d+/, resultset,
|
|
138
|
+
'Expected stringified branch condition keys in .resultset.json')
|
|
139
|
+
|
|
140
|
+
stdout, stderr, status = run_fixture_test('test/test_merged_b.rb',
|
|
141
|
+
'COMMAND_NAME' => 'Run B')
|
|
142
|
+
assert status.success?, "Run B failed.\nstdout: #{stdout}\nstderr: #{stderr}"
|
|
143
|
+
|
|
144
|
+
doc = Nokogiri::XML(File.read(File.join(@tmpdir, 'coverage', 'coverage.xml'))) { |c| c.strict }
|
|
145
|
+
sample_class = doc.xpath('//class').find { |c| c['filename'].include?('sample.rb') }
|
|
146
|
+
assert_not_nil sample_class
|
|
147
|
+
|
|
148
|
+
cc = sample_class.xpath('.//line[@branch="true"]')
|
|
149
|
+
.map { |l| [l['number'].to_i, l['condition-coverage']] }
|
|
150
|
+
.to_h
|
|
151
|
+
|
|
152
|
+
# greet (line 3): else in Run A + then in Run B => merged 2/2.
|
|
153
|
+
# Proves string keys were parsed AND hit counts summed across runs.
|
|
154
|
+
assert_equal '100% (2/2)', cc[3], 'greet should be fully covered after merge'
|
|
155
|
+
# absolute (line 11): only Run A touched it => still 1/2.
|
|
156
|
+
assert_equal '50% (1/2)', cc[11]
|
|
157
|
+
# unused_method (line 22): never called in either run => 0/2.
|
|
158
|
+
assert_equal '0% (0/2)', cc[22]
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
private
|
|
162
|
+
|
|
163
|
+
def install_fixture(name)
|
|
164
|
+
FileUtils.cp_r(File.join(FIXTURES_DIR, name, '.'), @tmpdir)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def run_fixture_test(test_path, extra_env = {})
|
|
168
|
+
Open3.capture3(
|
|
169
|
+
{ 'GEM_ROOT' => GEM_ROOT, 'PROJECT_ROOT' => @tmpdir }.merge(extra_env),
|
|
170
|
+
'ruby', File.join(@tmpdir, test_path),
|
|
171
|
+
chdir: @tmpdir
|
|
172
|
+
)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
end
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
require 'test/unit'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
require 'tmpdir'
|
|
2
4
|
require 'nokogiri'
|
|
3
5
|
require 'open-uri'
|
|
4
6
|
require 'simplecov'
|
|
@@ -6,26 +8,35 @@ require 'simplecov-cobertura'
|
|
|
6
8
|
|
|
7
9
|
class CoberturaFormatterTest < Test::Unit::TestCase
|
|
8
10
|
def setup
|
|
11
|
+
@tmpdir = Dir.mktmpdir('simplecov-cobertura-test')
|
|
9
12
|
SimpleCov.enable_coverage :branch
|
|
10
|
-
SimpleCov.coverage_dir
|
|
13
|
+
SimpleCov.coverage_dir @tmpdir
|
|
14
|
+
@no_filter = SimpleCov::Result::FilterConfig.new(filters: [], cover_filters: [], groups: {})
|
|
11
15
|
@result = SimpleCov::Result.new({
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
"#{__FILE__}" => {
|
|
17
|
+
"lines" => [1, 1, 1, nil, 1, nil, 1, 0, nil, 1, nil, nil, nil],
|
|
18
|
+
"branches" => {
|
|
19
|
+
[:if, 0, 3, 4, 3, 21] =>
|
|
20
|
+
{ [:then, 1, 3, 4, 3, 10] => 0, [:else, 2, 3, 4, 3, 21] => 1 },
|
|
21
|
+
[:if, 3, 5, 4, 5, 26] =>
|
|
22
|
+
{ [:then, 4, 5, 16, 5, 20] => 1, [:else, 5, 5, 23, 5, 26] => 0 },
|
|
23
|
+
[:if, 6, 7, 4, 11, 7] =>
|
|
24
|
+
{ [:then, 7, 8, 6, 8, 10] => 0, [:else, 8, 10, 6, 10, 9] => 1 },
|
|
25
|
+
[:if, 9, 12, 4, 12, 15] =>
|
|
26
|
+
{ [:then, 10, 12, 6, 12, 10] => 1, [:else, 11, 12, 13, 12, 15] => 0 },
|
|
27
|
+
[:if, 12, 13, 4, 13, 20] =>
|
|
28
|
+
{ [:then, 13, 13, 6, 13, 15] => 1, [:else, 14, 13, 18, 13, 20] => 0 },
|
|
29
|
+
[:if, 15, 15, 4, 15, 25] =>
|
|
30
|
+
{ [:then, 16, 15, 6, 15, 20] => 0, [:else, 17, 15, 23, 15, 25] => 0 }
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}, filter_config: @no_filter)
|
|
24
34
|
@formatter = SimpleCov::Formatter::CoberturaFormatter.new
|
|
25
35
|
end
|
|
26
36
|
|
|
27
37
|
def teardown
|
|
28
38
|
SimpleCov.groups.clear
|
|
39
|
+
FileUtils.remove_entry(@tmpdir) if @tmpdir && Dir.exist?(@tmpdir)
|
|
29
40
|
end
|
|
30
41
|
|
|
31
42
|
def test_format_save_file
|
|
@@ -45,28 +56,32 @@ class CoberturaFormatterTest < Test::Unit::TestCase
|
|
|
45
56
|
def test_terminal_output
|
|
46
57
|
output, _ = capture_output { @formatter.format(@result) }
|
|
47
58
|
result_path = File.join(SimpleCov.coverage_path, SimpleCov::Formatter::CoberturaFormatter::RESULT_FILE_NAME)
|
|
48
|
-
output_regex = /Coverage report generated for #{@result.command_name} to #{result_path}
|
|
59
|
+
output_regex = /Coverage report generated for #{@result.command_name} to #{result_path}.\nLine Coverage: (.*)\nBranch Coverage: (.*)/
|
|
49
60
|
assert_match(output_regex, output)
|
|
50
61
|
end
|
|
51
62
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
63
|
+
# Rather than support HTTPS the HTTP client was removed from libxml2 / xmllint:
|
|
64
|
+
# https://gitlab.gnome.org/GNOME/libxml2/-/issues/160
|
|
65
|
+
# I am not sure what this means for Nokogiri or this issue, but it certainly means something will change soon.
|
|
66
|
+
# Disable this test until it becomes clear what the new behavior should be.
|
|
67
|
+
# def test_format_dtd_validates
|
|
68
|
+
# xml = @formatter.format(@result)
|
|
69
|
+
# options = Nokogiri::XML::ParseOptions::DTDLOAD
|
|
70
|
+
# doc = Nokogiri::XML::Document.parse(xml, nil, nil, options)
|
|
71
|
+
# assert_empty doc.external_subset.validate(doc)
|
|
72
|
+
# end
|
|
58
73
|
|
|
59
74
|
def test_no_groups
|
|
60
75
|
xml = @formatter.format(@result)
|
|
61
76
|
doc = Nokogiri::XML::Document.parse(xml)
|
|
62
77
|
|
|
63
78
|
coverage = doc.xpath '/coverage'
|
|
64
|
-
assert_equal '0.
|
|
65
|
-
assert_equal '0.
|
|
79
|
+
assert_equal '0.8571', coverage.attribute('line-rate').value
|
|
80
|
+
assert_equal '0.4167', coverage.attribute('branch-rate').value
|
|
66
81
|
assert_equal '6', coverage.attribute('lines-covered').value
|
|
67
82
|
assert_equal '7', coverage.attribute('lines-valid').value
|
|
68
|
-
assert_equal '
|
|
69
|
-
assert_equal '
|
|
83
|
+
assert_equal '5', coverage.attribute('branches-covered').value
|
|
84
|
+
assert_equal '12', coverage.attribute('branches-valid').value
|
|
70
85
|
assert_equal '0', coverage.attribute('complexity').value
|
|
71
86
|
assert_equal '0', coverage.attribute('version').value
|
|
72
87
|
assert_not_empty coverage.attribute('timestamp').value
|
|
@@ -79,17 +94,17 @@ class CoberturaFormatterTest < Test::Unit::TestCase
|
|
|
79
94
|
assert_equal 1, packages.length
|
|
80
95
|
package = packages.first
|
|
81
96
|
assert_equal 'simplecov-cobertura', package.attribute('name').value
|
|
82
|
-
assert_equal '0.
|
|
83
|
-
assert_equal '0.
|
|
97
|
+
assert_equal '0.8571', package.attribute('line-rate').value
|
|
98
|
+
assert_equal '0.4167', package.attribute('branch-rate').value
|
|
84
99
|
assert_equal '0', package.attribute('complexity').value
|
|
85
100
|
|
|
86
101
|
classes = doc.xpath '/coverage/packages/package/classes/class'
|
|
87
102
|
assert_equal 1, classes.length
|
|
88
103
|
clazz = classes.first
|
|
89
|
-
assert_equal 'simplecov-cobertura_test', clazz.attribute('name').value
|
|
104
|
+
assert_equal 'test/simplecov-cobertura_test.rb', clazz.attribute('name').value
|
|
90
105
|
assert_equal 'test/simplecov-cobertura_test.rb', clazz.attribute('filename').value
|
|
91
|
-
assert_equal '0.
|
|
92
|
-
assert_equal '0.
|
|
106
|
+
assert_equal '0.8571', clazz.attribute('line-rate').value
|
|
107
|
+
assert_equal '0.4167', clazz.attribute('branch-rate').value
|
|
93
108
|
assert_equal '0', clazz.attribute('complexity').value
|
|
94
109
|
|
|
95
110
|
lines = doc.xpath '/coverage/packages/package/classes/class/lines/line'
|
|
@@ -100,23 +115,38 @@ class CoberturaFormatterTest < Test::Unit::TestCase
|
|
|
100
115
|
assert_equal '1', first_line.attribute('hits').value
|
|
101
116
|
last_line = lines.last
|
|
102
117
|
assert_equal '10', last_line.attribute('number').value
|
|
103
|
-
assert_equal '
|
|
118
|
+
assert_equal 'false', last_line.attribute('branch').value
|
|
104
119
|
assert_equal '1', last_line.attribute('hits').value
|
|
120
|
+
|
|
121
|
+
# Verify condition-coverage accurately reflects branch counts per condition line
|
|
122
|
+
branched_lines = lines.select { |l| l.attribute('branch').value == 'true' }
|
|
123
|
+
condition_coverages = branched_lines.map { |l| [l.attribute('number').value, l.attribute('condition-coverage').value] }
|
|
124
|
+
# Line 3: condition [:if, 0, 3, ...] with 2 branches (then=>0, else=>1) => 50% (1/2)
|
|
125
|
+
assert_include condition_coverages, ['3', '50% (1/2)']
|
|
126
|
+
# Line 5: condition [:if, 3, 5, ...] with 2 branches (then=>1, else=>0) => 50% (1/2)
|
|
127
|
+
assert_include condition_coverages, ['5', '50% (1/2)']
|
|
128
|
+
# Line 7: condition [:if, 6, 7, ...] with 2 branches (then=>0, else=>1) => 50% (1/2)
|
|
129
|
+
assert_include condition_coverages, ['7', '50% (1/2)']
|
|
130
|
+
# Lines 12, 13, 15 have nil line coverage so they don't get <line> elements,
|
|
131
|
+
# but their conditions are still correctly grouped by condition start line.
|
|
132
|
+
assert_equal 3, branched_lines.length
|
|
105
133
|
end
|
|
106
134
|
|
|
107
135
|
def test_groups
|
|
108
|
-
SimpleCov.
|
|
136
|
+
SimpleCov.group('test_group', 'test/')
|
|
137
|
+
group_filter = SimpleCov::Result::FilterConfig.new(filters: [], cover_filters: [], groups: SimpleCov.groups)
|
|
138
|
+
result = SimpleCov::Result.new(@result.original_result, filter_config: group_filter)
|
|
109
139
|
|
|
110
|
-
xml = @formatter.format(
|
|
140
|
+
xml = @formatter.format(result)
|
|
111
141
|
doc = Nokogiri::XML::Document.parse(xml)
|
|
112
142
|
|
|
113
143
|
coverage = doc.xpath '/coverage'
|
|
114
|
-
assert_equal '0.
|
|
115
|
-
assert_equal '0.
|
|
144
|
+
assert_equal '0.8571', coverage.attribute('line-rate').value
|
|
145
|
+
assert_equal '0.4167', coverage.attribute('branch-rate').value
|
|
116
146
|
assert_equal '6', coverage.attribute('lines-covered').value
|
|
117
147
|
assert_equal '7', coverage.attribute('lines-valid').value
|
|
118
|
-
assert_equal '
|
|
119
|
-
assert_equal '
|
|
148
|
+
assert_equal '5', coverage.attribute('branches-covered').value
|
|
149
|
+
assert_equal '12', coverage.attribute('branches-valid').value
|
|
120
150
|
assert_equal '0', coverage.attribute('complexity').value
|
|
121
151
|
assert_equal '0', coverage.attribute('version').value
|
|
122
152
|
assert_not_empty coverage.attribute('timestamp').value
|
|
@@ -129,17 +159,17 @@ class CoberturaFormatterTest < Test::Unit::TestCase
|
|
|
129
159
|
assert_equal 1, packages.length
|
|
130
160
|
package = packages.first
|
|
131
161
|
assert_equal 'test_group', package.attribute('name').value
|
|
132
|
-
assert_equal '0.
|
|
133
|
-
assert_equal '0.
|
|
162
|
+
assert_equal '0.8571', package.attribute('line-rate').value
|
|
163
|
+
assert_equal '0.4167', package.attribute('branch-rate').value
|
|
134
164
|
assert_equal '0', package.attribute('complexity').value
|
|
135
165
|
|
|
136
166
|
classes = doc.xpath '/coverage/packages/package/classes/class'
|
|
137
167
|
assert_equal 1, classes.length
|
|
138
168
|
clazz = classes.first
|
|
139
|
-
assert_equal 'simplecov-cobertura_test', clazz.attribute('name').value
|
|
169
|
+
assert_equal 'test/simplecov-cobertura_test.rb', clazz.attribute('name').value
|
|
140
170
|
assert_equal 'test/simplecov-cobertura_test.rb', clazz.attribute('filename').value
|
|
141
|
-
assert_equal '0.
|
|
142
|
-
assert_equal '0.
|
|
171
|
+
assert_equal '0.8571', clazz.attribute('line-rate').value
|
|
172
|
+
assert_equal '0.4167', clazz.attribute('branch-rate').value
|
|
143
173
|
assert_equal '0', clazz.attribute('complexity').value
|
|
144
174
|
|
|
145
175
|
lines = doc.xpath '/coverage/packages/package/classes/class/lines/line'
|
|
@@ -150,24 +180,34 @@ class CoberturaFormatterTest < Test::Unit::TestCase
|
|
|
150
180
|
assert_equal '1', first_line.attribute('hits').value
|
|
151
181
|
last_line = lines.last
|
|
152
182
|
assert_equal '10', last_line.attribute('number').value
|
|
153
|
-
assert_equal '
|
|
183
|
+
assert_equal 'false', last_line.attribute('branch').value
|
|
154
184
|
assert_equal '1', last_line.attribute('hits').value
|
|
155
185
|
end
|
|
156
186
|
|
|
157
187
|
def test_supports_root_project_path
|
|
158
188
|
old_root = SimpleCov.root
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
189
|
+
@alt_root = Dir.mktmpdir('simplecov-cobertura-root')
|
|
190
|
+
SimpleCov.root(@alt_root)
|
|
191
|
+
expected_prefix = Pathname.new(old_root).relative_path_from(Pathname.new(@alt_root)).to_s
|
|
192
|
+
result = SimpleCov::Result.new(@result.original_result, filter_config: @no_filter)
|
|
193
|
+
xml = @formatter.format(result)
|
|
163
194
|
doc = Nokogiri::XML::Document.parse(xml)
|
|
164
195
|
|
|
165
196
|
classes = doc.xpath '/coverage/packages/package/classes/class'
|
|
166
197
|
assert_equal 1, classes.length
|
|
167
198
|
clazz = classes.first
|
|
168
|
-
assert_equal
|
|
169
|
-
assert_equal "
|
|
199
|
+
assert_equal "#{expected_prefix}/test/simplecov-cobertura_test.rb", clazz.attribute('name').value
|
|
200
|
+
assert_equal "#{expected_prefix}/test/simplecov-cobertura_test.rb", clazz.attribute('filename').value
|
|
170
201
|
ensure
|
|
171
202
|
SimpleCov.root(old_root)
|
|
203
|
+
FileUtils.remove_entry(@alt_root) if @alt_root && Dir.exist?(@alt_root)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def test_condition_start_line_handles_both_key_forms
|
|
207
|
+
formatter = SimpleCov::Formatter::CoberturaFormatter.new
|
|
208
|
+
assert_equal 3, formatter.send(:condition_start_line, [:if, 0, 3, 4, 5, 10])
|
|
209
|
+
assert_equal 3, formatter.send(:condition_start_line, '[:if, 0, 3, 4, 5, 10]')
|
|
210
|
+
assert_equal 7, formatter.send(:condition_start_line, '[:case, 12, 7, 0, 9, 3]')
|
|
211
|
+
assert_nil formatter.send(:condition_start_line, 42)
|
|
172
212
|
end
|
|
173
213
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: simplecov-cobertura
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 4.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jesse Bowes
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: test-unit
|
|
@@ -58,14 +57,14 @@ dependencies:
|
|
|
58
57
|
requirements:
|
|
59
58
|
- - "~>"
|
|
60
59
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '0
|
|
60
|
+
version: '1.0'
|
|
62
61
|
type: :runtime
|
|
63
62
|
prerelease: false
|
|
64
63
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
64
|
requirements:
|
|
66
65
|
- - "~>"
|
|
67
66
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '0
|
|
67
|
+
version: '1.0'
|
|
69
68
|
- !ruby/object:Gem::Dependency
|
|
70
69
|
name: rexml
|
|
71
70
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -82,7 +81,7 @@ dependencies:
|
|
|
82
81
|
version: '0'
|
|
83
82
|
description: Produces Cobertura XML formatted output from SimpleCov
|
|
84
83
|
email:
|
|
85
|
-
-
|
|
84
|
+
- jessebowes@acm.org
|
|
86
85
|
executables: []
|
|
87
86
|
extensions: []
|
|
88
87
|
extra_rdoc_files: []
|
|
@@ -96,13 +95,17 @@ files:
|
|
|
96
95
|
- lib/simplecov-cobertura.rb
|
|
97
96
|
- lib/simplecov-cobertura/version.rb
|
|
98
97
|
- simplecov-cobertura.gemspec
|
|
99
|
-
- test/
|
|
98
|
+
- test/fixtures/sample/lib/sample.rb
|
|
99
|
+
- test/fixtures/sample/test/simplecov_setup.rb
|
|
100
|
+
- test/fixtures/sample/test/test_merged_a.rb
|
|
101
|
+
- test/fixtures/sample/test/test_merged_b.rb
|
|
102
|
+
- test/fixtures/sample/test/test_sample.rb
|
|
103
|
+
- test/integration_test.rb
|
|
100
104
|
- test/simplecov-cobertura_test.rb
|
|
101
|
-
homepage: https://github.com/
|
|
105
|
+
homepage: https://github.com/jessebs/simplecov-cobertura
|
|
102
106
|
licenses:
|
|
103
107
|
- Apache-2.0
|
|
104
108
|
metadata: {}
|
|
105
|
-
post_install_message:
|
|
106
109
|
rdoc_options: []
|
|
107
110
|
require_paths:
|
|
108
111
|
- lib
|
|
@@ -110,17 +113,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
110
113
|
requirements:
|
|
111
114
|
- - ">="
|
|
112
115
|
- !ruby/object:Gem::Version
|
|
113
|
-
version: 2
|
|
116
|
+
version: '3.2'
|
|
114
117
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
115
118
|
requirements:
|
|
116
119
|
- - ">="
|
|
117
120
|
- !ruby/object:Gem::Version
|
|
118
121
|
version: '0'
|
|
119
122
|
requirements: []
|
|
120
|
-
rubygems_version: 3.
|
|
121
|
-
signing_key:
|
|
123
|
+
rubygems_version: 3.6.9
|
|
122
124
|
specification_version: 4
|
|
123
125
|
summary: SimpleCov Cobertura Formatter
|
|
124
126
|
test_files:
|
|
125
|
-
- test/
|
|
127
|
+
- test/fixtures/sample/lib/sample.rb
|
|
128
|
+
- test/fixtures/sample/test/simplecov_setup.rb
|
|
129
|
+
- test/fixtures/sample/test/test_merged_a.rb
|
|
130
|
+
- test/fixtures/sample/test/test_merged_b.rb
|
|
131
|
+
- test/fixtures/sample/test/test_sample.rb
|
|
132
|
+
- test/integration_test.rb
|
|
126
133
|
- test/simplecov-cobertura_test.rb
|
data/test/coverage/coverage.xml
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
<?xml version='1.0'?>
|
|
2
|
-
<!DOCTYPE coverage SYSTEM "http://cobertura.sourceforge.net/xml/coverage-04.dtd">
|
|
3
|
-
<!-- Generated by simplecov-cobertura version 1.4.3-dev (https://github.com/dashingrocket/simplecov-cobertura) -->
|
|
4
|
-
<coverage line-rate="1.0" branch-rate="0" lines-covered="2" lines-valid="2" branches-covered="0" branches-valid="0" complexity="0" version="0" timestamp="1636204971">
|
|
5
|
-
<sources>
|
|
6
|
-
<source>/Users/st0012/projects/simplecov-cobertura/test</source>
|
|
7
|
-
</sources>
|
|
8
|
-
<packages>
|
|
9
|
-
<package name="test" line-rate="1.0" branch-rate="0" complexity="0">
|
|
10
|
-
<classes>
|
|
11
|
-
<class name="simplecov-cobertura_test" filename="simplecov-cobertura_test.rb" line-rate="1.0" branch-rate="0" complexity="0">
|
|
12
|
-
<methods/>
|
|
13
|
-
<lines>
|
|
14
|
-
<line number="1" branch="false" hits="1"/>
|
|
15
|
-
<line number="2" branch="false" hits="2"/>
|
|
16
|
-
</lines>
|
|
17
|
-
</class>
|
|
18
|
-
</classes>
|
|
19
|
-
</package>
|
|
20
|
-
</packages>
|
|
21
|
-
</coverage>
|