slather 2.4.4 → 2.4.9
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 +5 -5
- data/.gitignore +5 -1
- data/.travis.yml +2 -12
- data/CHANGELOG.md +63 -1
- data/README.md +20 -0
- data/README_Images/test_scheme.png +0 -0
- data/assets/list.min.js +1 -1
- data/lib/slather.rb +1 -0
- data/lib/slather/command/coverage_command.rb +9 -0
- data/lib/slather/coverage_service/simple_output.rb +1 -0
- data/lib/slather/coverage_service/sonarqube_xml_output.rb +61 -0
- data/lib/slather/profdata_coverage_file.rb +24 -10
- data/lib/slather/project.rb +133 -44
- data/lib/slather/version.rb +1 -1
- data/slather.gemspec +14 -15
- data/spec/fixtures/sonarqube-generic-coverage.xml +93 -0
- data/spec/slather/cocoapods_plugin_spec.rb +1 -1
- data/spec/slather/coverage_service/coveralls_spec.rb +9 -0
- data/spec/slather/coverage_service/hardcover_spec.rb +9 -1
- data/spec/slather/coverage_service/simple_output_spec.rb +2 -0
- data/spec/slather/coverage_service/sonarqube_xml_spec.rb +46 -0
- data/spec/slather/profdata_coverage_spec.rb +21 -0
- data/spec/slather/project_spec.rb +126 -7
- data/spec/spec_helper.rb +1 -0
- metadata +50 -46
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 1e8bb7fa0d1346a2a81a47272a1f55d2625a8457d8c4b88a82f2b737792aa39a
|
|
4
|
+
data.tar.gz: a375044a21453e30695adf31c20f5a9ea885091d1eb3ac6fafc3f3ef9d44d752
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9a9dddfd5dcf8160cd31327f170030f3520c2a885b7c56f6f2d7d470e5442b8c49c3f30ba289664767cc43d597415c2309654699a5ac2fd59db90ac5bc796697
|
|
7
|
+
data.tar.gz: 5f67d766eb09e18df9a2bf1016f49a3a7a7f912be2bf5e05ed31c925540fb51ccaef34e53f1dffaed6aadfef827a3e69aa1c7144fa30a024f9f72a1ce2d47605
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
|
@@ -1,20 +1,10 @@
|
|
|
1
1
|
language: objective-c
|
|
2
2
|
script: bundle exec rake
|
|
3
|
-
osx_image:
|
|
4
|
-
|
|
5
|
-
# Sets Travis to run the Ruby specs on OS X machines which are required to
|
|
6
|
-
# build the native extensions of Xcodeproj.
|
|
7
|
-
|
|
8
|
-
env:
|
|
9
|
-
- RVM_RUBY_VERSION=system
|
|
3
|
+
osx_image: xcode9.2
|
|
10
4
|
|
|
11
5
|
before_install:
|
|
12
6
|
- curl http://curl.haxx.se/ca/cacert.pem -o /usr/local/share/cacert.pem
|
|
13
|
-
-
|
|
14
|
-
- if [[ $RVM_RUBY_VERSION != 'system' ]]; then rvm install $RVM_RUBY_VERSION; fi
|
|
15
|
-
- rvm use $RVM_RUBY_VERSION
|
|
16
|
-
- if [[ $RVM_RUBY_VERSION == 'system' ]]; then export ARCHFLAGS=-Wno-error=unused-command-line-argument-hard-error-in-future; fi
|
|
17
|
-
- if [[ $RVM_RUBY_VERSION == 'system' ]]; then sudo gem install bundler --no-ri --no-rdoc; else gem install bundler --no-ri --no-rdoc; fi
|
|
7
|
+
- gem install bundler -v "~> 1.0" --no-ri --no-rdoc
|
|
18
8
|
|
|
19
9
|
install:
|
|
20
10
|
- bundle install --without=documentation
|
data/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,71 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## v2.4.9
|
|
4
|
+
|
|
5
|
+
* Added support for Sonarqube output
|
|
6
|
+
[adellibovi](https://github.com/adellibovi)
|
|
7
|
+
[#456](https://github.com/SlatherOrg/slather/pull/456)
|
|
8
|
+
|
|
9
|
+
## v2.4.8
|
|
10
|
+
|
|
11
|
+
* Optimize performance for many binaries
|
|
12
|
+
[cltnschlosser](https://github.com/cltnschlosser)
|
|
13
|
+
[#455](https://github.com/SlatherOrg/slather/pull/455)
|
|
14
|
+
|
|
15
|
+
* Don't generate line 0 in profdata_coverage_file.rb from line with error
|
|
16
|
+
[tthbalazs](https://github.com/tthbalazs)
|
|
17
|
+
[#449](https://github.com/SlatherOrg/slather/pull/449)
|
|
18
|
+
|
|
19
|
+
* coveralls dependency update
|
|
20
|
+
[GRiMe2D](https://github.com/GRiMe2D)
|
|
21
|
+
[#448](https://github.com/SlatherOrg/slather/pull/448)
|
|
22
|
+
|
|
23
|
+
## v2.4.7
|
|
24
|
+
|
|
25
|
+
* Update dependencies
|
|
26
|
+
[dnedrow](https://github.com/dnedrow)
|
|
27
|
+
|
|
28
|
+
* Fixed errors when llvm-cov argument length exceeds ARG_MAX
|
|
29
|
+
[weibel](https://github.com/weibel)
|
|
30
|
+
[#414](https://github.com/SlatherOrg/slather/pull/414)
|
|
31
|
+
|
|
32
|
+
* Show "No coverage directory found." instead of "implicit conversion nil into String"
|
|
33
|
+
[phimage](https://github.com/phimage)
|
|
34
|
+
[#381](https://github.com/SlatherOrg/slather/pull/381) [#341](https://github.com/SlatherOrg/slather/issues/341)
|
|
35
|
+
|
|
36
|
+
## v2.4.6
|
|
37
|
+
|
|
38
|
+
* Fix .dSYM and .swiftmodule files filtering in find_binary_files()
|
|
39
|
+
[krin-san](https://github.com/krin-san)
|
|
40
|
+
[#368](https://github.com/SlatherOrg/slather/pull/368)
|
|
41
|
+
|
|
42
|
+
* Fixed loading coverage for a single source file
|
|
43
|
+
[blackm00n](https://github.com/blackm00n)
|
|
44
|
+
[#377](https://github.com/SlatherOrg/slather/pull/377) [#398](https://github.com/SlatherOrg/slather/pull/398)
|
|
45
|
+
|
|
46
|
+
* Fixed truncated file list in HTML export
|
|
47
|
+
[miroslavkovac](https://github.com/miroslavkovac)
|
|
48
|
+
[#402](https://github.com/SlatherOrg/slather/pull/402) [#261](https://github.com/SlatherOrg/slather/issues/261)
|
|
49
|
+
|
|
50
|
+
## v2.4.5
|
|
51
|
+
|
|
52
|
+
* Support for specifying a specific binary architecture
|
|
53
|
+
[ksuther](https://github.com/ksuther), [nickolas-pohilets](https://github.com/nickolas-pohilets)
|
|
54
|
+
[#367](https://github.com/SlatherOrg/slather/pull/367)
|
|
55
|
+
|
|
56
|
+
* Added absolute statement count to simple output (instead of showing just a percentage)
|
|
57
|
+
[barrault01](https://github.com/barrault01), [ivanbrunel](https://github.com/ivanbruel)
|
|
58
|
+
[#365](https://github.com/SlatherOrg/slather/pull/365)
|
|
59
|
+
|
|
60
|
+
* Updated nokogiri dependency version
|
|
61
|
+
[#363](https://github.com/SlatherOrg/slather/issues/363), [#366](https://github.com/SlatherOrg/slather/pull/366)
|
|
62
|
+
|
|
63
|
+
* slather now requires ruby 2.1 or later (10.13 ships with 2.3.3)
|
|
64
|
+
|
|
3
65
|
## v2.4.4
|
|
4
66
|
|
|
5
67
|
* Added llvm-cov output format
|
|
6
|
-
[
|
|
68
|
+
[sgtsquiggs](https://github.com/sgtsquiggs) [#354](https://github.com/SlatherOrg/slather/pull/354)
|
|
7
69
|
|
|
8
70
|
* Exclude swiftmodule from product search
|
|
9
71
|
[lampietti](https://github.com/lampietti) [#352](https://github.com/SlatherOrg/slather/pull/352)
|
data/README.md
CHANGED
|
@@ -61,6 +61,26 @@ If you use a different configuration for your tests:
|
|
|
61
61
|
$ slather coverage -s --scheme YourXcodeSchemeName --configuration YourBuildConfigurationName path/to/project.xcodeproj
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
+
If your configuration produces a universal binary you need to specify a specific architecture to use:
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
$ slather coverage -s --arch x86_64 --scheme YourXcodeSchemeName --configuration YourBuildConfigurationName path/to/project.xcodeproj
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### For multiple modules
|
|
71
|
+
|
|
72
|
+
If you want to run some modules, but not all (like modules created by CocoaPods) you can do it like this:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
$ slather coverage --binary-basename module1 --binary-basename module2 path/to/project.xcodeproj
|
|
76
|
+
```
|
|
77
|
+
You can also add it to the `.slather.yml` file as an array:
|
|
78
|
+
```yml
|
|
79
|
+
binary_basename:
|
|
80
|
+
- module1
|
|
81
|
+
- module2
|
|
82
|
+
```
|
|
83
|
+
|
|
64
84
|
### Setup for Xcode 5 and 6
|
|
65
85
|
|
|
66
86
|
Run this command to enable the `Generate Test Coverage` and `Instrument Program Flow` flags for your project:
|
|
Binary file
|
data/assets/list.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(){function a(b,c,d){var e=a.resolve(b);if(null==e){d=d||b,c=c||"root";var f=new Error('Failed to require "'+d+'" from "'+c+'"');throw f.path=d,f.parent=c,f.require=!0,f}var g=a.modules[e];if(!g._resolving&&!g.exports){var h={};h.exports={},h.client=h.component=!0,g._resolving=!0,g.call(this,h.exports,a.relative(e),h),delete g._resolving,g.exports=h.exports}return g.exports}a.modules={},a.aliases={},a.resolve=function(b){"/"===b.charAt(0)&&(b=b.slice(1));for(var c=[b,b+".js",b+".json",b+"/index.js",b+"/index.json"],d=0;d
|
|
1
|
+
var List=function(t){function e(n){if(r[n])return r[n].exports;var i=r[n]={i:n,l:!1,exports:{}};return t[n].call(i.exports,i,i.exports,e),i.l=!0,i.exports}var r={};return e.m=t,e.c=r,e.i=function(t){return t},e.d=function(t,r,n){e.o(t,r)||Object.defineProperty(t,r,{configurable:!1,enumerable:!0,get:n})},e.n=function(t){var r=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(r,"a",r),r},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="",e(e.s=11)}([function(t,e,r){function n(t){if(!t||!t.nodeType)throw new Error("A DOM element reference is required");this.el=t,this.list=t.classList}var i=r(4),s=/\s+/;Object.prototype.toString;t.exports=function(t){return new n(t)},n.prototype.add=function(t){if(this.list)return this.list.add(t),this;var e=this.array(),r=i(e,t);return~r||e.push(t),this.el.className=e.join(" "),this},n.prototype.remove=function(t){if(this.list)return this.list.remove(t),this;var e=this.array(),r=i(e,t);return~r&&e.splice(r,1),this.el.className=e.join(" "),this},n.prototype.toggle=function(t,e){return this.list?("undefined"!=typeof e?e!==this.list.toggle(t,e)&&this.list.toggle(t):this.list.toggle(t),this):("undefined"!=typeof e?e?this.add(t):this.remove(t):this.has(t)?this.remove(t):this.add(t),this)},n.prototype.array=function(){var t=this.el.getAttribute("class")||"",e=t.replace(/^\s+|\s+$/g,""),r=e.split(s);return""===r[0]&&r.shift(),r},n.prototype.has=n.prototype.contains=function(t){return this.list?this.list.contains(t):!!~i(this.array(),t)}},function(t,e,r){var n=window.addEventListener?"addEventListener":"attachEvent",i=window.removeEventListener?"removeEventListener":"detachEvent",s="addEventListener"!==n?"on":"",a=r(5);e.bind=function(t,e,r,i){t=a(t);for(var o=0;o
|
data/lib/slather.rb
CHANGED
|
@@ -12,6 +12,7 @@ require 'slather/coverage_service/simple_output'
|
|
|
12
12
|
require 'slather/coverage_service/html_output'
|
|
13
13
|
require 'slather/coverage_service/json_output'
|
|
14
14
|
require 'slather/coverage_service/llvm_cov_output'
|
|
15
|
+
require 'slather/coverage_service/sonarqube_xml_output'
|
|
15
16
|
require 'cfpropertylist'
|
|
16
17
|
|
|
17
18
|
module Slather
|
|
@@ -13,6 +13,7 @@ class CoverageCommand < Clamp::Command
|
|
|
13
13
|
option ["--simple-output", "-s"], :flag, "Output coverage results to the terminal"
|
|
14
14
|
option ["--gutter-json", "-g"], :flag, "Output coverage results as Gutter JSON format"
|
|
15
15
|
option ["--cobertura-xml", "-x"], :flag, "Output coverage results as Cobertura XML format"
|
|
16
|
+
option ["--sonarqube-xml", "-sq"], :flag, "Output coverage results as Cobertura XML format"
|
|
16
17
|
option ["--llvm-cov", "-r"], :flag, "Output coverage as llvm-cov format"
|
|
17
18
|
option ["--json"], :flag, "Output coverage results as simple JSON"
|
|
18
19
|
option ["--html"], :flag, "Output coverage results as static html pages"
|
|
@@ -30,6 +31,7 @@ class CoverageCommand < Clamp::Command
|
|
|
30
31
|
option ["--workspace"], "WORKSPACE", "The workspace that the project was built in"
|
|
31
32
|
option ["--binary-file"], "BINARY_FILE", "The binary file against the which the coverage will be run", :multivalued => true
|
|
32
33
|
option ["--binary-basename"], "BINARY_BASENAME", "Basename of the file against which the coverage will be run", :multivalued => true
|
|
34
|
+
option ["--arch"], "ARCH", "Architecture to use from universal binaries"
|
|
33
35
|
option ["--source-files"], "SOURCE_FILES", "A Dir.glob compatible pattern used to limit the lookup to specific source files. Ignored in gcov mode.", :multivalued => true
|
|
34
36
|
option ["--decimals"], "DECIMALS", "The amount of decimals to use for % coverage reporting"
|
|
35
37
|
|
|
@@ -49,6 +51,7 @@ class CoverageCommand < Clamp::Command
|
|
|
49
51
|
setup_workspace
|
|
50
52
|
setup_binary_file
|
|
51
53
|
setup_binary_basename
|
|
54
|
+
setup_arch
|
|
52
55
|
setup_source_files
|
|
53
56
|
setup_decimals
|
|
54
57
|
|
|
@@ -122,6 +125,8 @@ class CoverageCommand < Clamp::Command
|
|
|
122
125
|
project.show_html = show?
|
|
123
126
|
elsif json?
|
|
124
127
|
project.coverage_service = :json
|
|
128
|
+
elsif sonarqube_xml?
|
|
129
|
+
project.coverage_service = :sonarqube_xml
|
|
125
130
|
end
|
|
126
131
|
end
|
|
127
132
|
|
|
@@ -153,6 +158,10 @@ class CoverageCommand < Clamp::Command
|
|
|
153
158
|
project.binary_basename = binary_basename_list if !binary_basename_list.empty?
|
|
154
159
|
end
|
|
155
160
|
|
|
161
|
+
def setup_arch
|
|
162
|
+
project.arch = arch
|
|
163
|
+
end
|
|
164
|
+
|
|
156
165
|
def setup_source_files
|
|
157
166
|
project.source_files = source_files_list if !source_files_list.empty?
|
|
158
167
|
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require 'nokogiri'
|
|
2
|
+
require 'date'
|
|
3
|
+
|
|
4
|
+
module Slather
|
|
5
|
+
module CoverageService
|
|
6
|
+
module SonarqubeXmlOutput
|
|
7
|
+
|
|
8
|
+
def coverage_file_class
|
|
9
|
+
if input_format == "profdata"
|
|
10
|
+
Slather::ProfdataCoverageFile
|
|
11
|
+
else
|
|
12
|
+
Slather::CoverageFile
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
private :coverage_file_class
|
|
16
|
+
|
|
17
|
+
def post
|
|
18
|
+
cobertura_xml_report = create_xml_report(coverage_files)
|
|
19
|
+
store_report(cobertura_xml_report)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def store_report(report)
|
|
23
|
+
output_file = 'sonarqube-generic-coverage.xml'
|
|
24
|
+
if output_directory
|
|
25
|
+
FileUtils.mkdir_p(output_directory)
|
|
26
|
+
output_file = File.join(output_directory, output_file)
|
|
27
|
+
end
|
|
28
|
+
File.write(output_file, report.to_s)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def create_xml_report(coverage_files)
|
|
32
|
+
create_empty_xml_report
|
|
33
|
+
coverage_node = @doc.root
|
|
34
|
+
coverage_node['version'] = "1"
|
|
35
|
+
|
|
36
|
+
coverage_files.each do |coverage_file|
|
|
37
|
+
file_node = Nokogiri::XML::Node.new "file", @doc
|
|
38
|
+
file_node.parent = coverage_node
|
|
39
|
+
file_node['path'] = coverage_file.source_file_pathname_relative_to_repo_root.to_s
|
|
40
|
+
coverage_file.all_lines.each do |line|
|
|
41
|
+
if coverage_file.coverage_for_line(line)
|
|
42
|
+
line_node = Nokogiri::XML::Node.new "lineToCover", @doc
|
|
43
|
+
line_node['lineNumber'] = coverage_file.line_number_in_line(line)
|
|
44
|
+
line_node['covered'] = coverage_file.coverage_for_line(line) == 0 ? "false" : "true"
|
|
45
|
+
line_node.parent = file_node
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
@doc.to_xml
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def create_empty_xml_report
|
|
53
|
+
builder = Nokogiri::XML::Builder.new do |xml|
|
|
54
|
+
xml.coverage
|
|
55
|
+
end
|
|
56
|
+
@doc = builder.doc
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -18,7 +18,6 @@ module Slather
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def create_line_data
|
|
21
|
-
all_lines = source_code_lines
|
|
22
21
|
line_data = Hash.new
|
|
23
22
|
all_lines.each { |line| line_data[line_number_in_line(line, self.line_numbers_first)] = line }
|
|
24
23
|
self.line_data = line_data
|
|
@@ -26,14 +25,20 @@ module Slather
|
|
|
26
25
|
private :create_line_data
|
|
27
26
|
|
|
28
27
|
def path_on_first_line?
|
|
29
|
-
|
|
30
|
-
!path.include?("|//")
|
|
28
|
+
!source.lstrip.start_with?("1|")
|
|
31
29
|
end
|
|
32
30
|
|
|
33
31
|
def source_file_pathname
|
|
34
32
|
@source_file_pathname ||= begin
|
|
35
33
|
if path_on_first_line?
|
|
36
|
-
|
|
34
|
+
end_index = self.source.index(/:?\n/)
|
|
35
|
+
if end_index != nil
|
|
36
|
+
end_index -= 1
|
|
37
|
+
path = self.source[0..end_index]
|
|
38
|
+
else
|
|
39
|
+
# Empty file, output just contains path
|
|
40
|
+
path = self.source.sub ":", ""
|
|
41
|
+
end
|
|
37
42
|
path &&= Pathname(path)
|
|
38
43
|
else
|
|
39
44
|
# llvm-cov was run with just one matching source file
|
|
@@ -64,7 +69,16 @@ module Slather
|
|
|
64
69
|
end
|
|
65
70
|
|
|
66
71
|
def source_code_lines
|
|
67
|
-
self.source.split("\n")[(path_on_first_line? ? 1 : 0)..-1]
|
|
72
|
+
lines = self.source.split("\n")[(path_on_first_line? ? 1 : 0)..-1]
|
|
73
|
+
ignore_error_lines(lines)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def ignore_error_lines(lines, line_numbers_first = self.line_numbers_first)
|
|
77
|
+
if line_numbers_first
|
|
78
|
+
lines.reject { |line| line.lstrip.start_with?('|', '--') }
|
|
79
|
+
else
|
|
80
|
+
lines
|
|
81
|
+
end
|
|
68
82
|
end
|
|
69
83
|
|
|
70
84
|
def source_data
|
|
@@ -72,10 +86,7 @@ module Slather
|
|
|
72
86
|
end
|
|
73
87
|
|
|
74
88
|
def all_lines
|
|
75
|
-
|
|
76
|
-
@all_lines = source_code_lines
|
|
77
|
-
end
|
|
78
|
-
@all_lines
|
|
89
|
+
@all_lines ||= source_code_lines
|
|
79
90
|
end
|
|
80
91
|
|
|
81
92
|
def raw_source
|
|
@@ -94,6 +105,9 @@ module Slather
|
|
|
94
105
|
|
|
95
106
|
def line_number_in_line(line, line_numbers_first = self.line_numbers_first)
|
|
96
107
|
if line_numbers_first
|
|
108
|
+
# Skip regex if the number is the first thing in the line
|
|
109
|
+
fastpath_number = line.to_i
|
|
110
|
+
return fastpath_number if fastpath_number != 0
|
|
97
111
|
line =~ /^(\s*)(\d*)/
|
|
98
112
|
group = $2
|
|
99
113
|
else
|
|
@@ -123,7 +137,7 @@ module Slather
|
|
|
123
137
|
end
|
|
124
138
|
|
|
125
139
|
def line_coverage_data
|
|
126
|
-
|
|
140
|
+
all_lines.map do |line|
|
|
127
141
|
coverage_for_line(line, self.line_numbers_first)
|
|
128
142
|
end
|
|
129
143
|
end
|
data/lib/slather/project.rb
CHANGED
|
@@ -44,7 +44,7 @@ module Slather
|
|
|
44
44
|
class Project < Xcodeproj::Project
|
|
45
45
|
|
|
46
46
|
attr_accessor :build_directory, :ignore_list, :ci_service, :coverage_service, :coverage_access_token, :source_directory,
|
|
47
|
-
:output_directory, :xcodeproj, :show_html, :verbose_mode, :input_format, :scheme, :workspace, :binary_file, :binary_basename, :source_files,
|
|
47
|
+
:output_directory, :xcodeproj, :show_html, :verbose_mode, :input_format, :scheme, :workspace, :binary_file, :binary_basename, :arch, :source_files,
|
|
48
48
|
:decimals, :llvm_version, :configuration
|
|
49
49
|
|
|
50
50
|
alias_method :setup_for_coverage, :slather_setup_for_coverage
|
|
@@ -118,24 +118,11 @@ module Slather
|
|
|
118
118
|
|
|
119
119
|
def profdata_coverage_files
|
|
120
120
|
coverage_files = []
|
|
121
|
-
source_files = find_source_files || []
|
|
122
|
-
line_numbers_first = Gem::Version.new(self.llvm_version) >= Gem::Version.new('8.1.0')
|
|
123
121
|
|
|
124
122
|
if self.binary_file
|
|
125
123
|
self.binary_file.each do |binary_path|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
coverage_files.concat(files.map do |source|
|
|
129
|
-
coverage_file = coverage_file_class.new(self, source, line_numbers_first)
|
|
130
|
-
# If a single source file is used, the resulting output does not contain the file name.
|
|
131
|
-
coverage_file.source_file_pathname = source_files.first if source_files.count == 1
|
|
132
|
-
!coverage_file.ignored? ? coverage_file : nil
|
|
133
|
-
end.compact)
|
|
134
|
-
|
|
135
|
-
if !source_files.empty?
|
|
136
|
-
coverage_file_paths = coverage_files.map { |file| file.source_file_pathname }.to_set
|
|
137
|
-
source_files.select! { |path| !coverage_file_paths.include?(path) }
|
|
138
|
-
end
|
|
124
|
+
pathnames_per_binary = pathnames_per_binary(binary_path)
|
|
125
|
+
coverage_files.concat(create_coverage_files_for_binary(binary_path, pathnames_per_binary))
|
|
139
126
|
end
|
|
140
127
|
end
|
|
141
128
|
|
|
@@ -143,6 +130,55 @@ module Slather
|
|
|
143
130
|
end
|
|
144
131
|
private :profdata_coverage_files
|
|
145
132
|
|
|
133
|
+
def pathnames_per_binary(binary_path)
|
|
134
|
+
coverage_json_string = llvm_cov_export_output(binary_path)
|
|
135
|
+
coverage_json = JSON.parse(coverage_json_string)
|
|
136
|
+
coverage_json["data"].reduce([]) do |result, chunk|
|
|
137
|
+
result.concat(chunk["files"].map do |file|
|
|
138
|
+
Pathname(file["filename"]).realpath
|
|
139
|
+
end)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
private :pathnames_per_binary
|
|
143
|
+
|
|
144
|
+
def create_coverage_files_for_binary(binary_path, pathnames_per_binary)
|
|
145
|
+
coverage_files = []
|
|
146
|
+
|
|
147
|
+
begin
|
|
148
|
+
coverage_files.concat(create_coverage_files(binary_path, pathnames_per_binary))
|
|
149
|
+
rescue Errno::E2BIG => e
|
|
150
|
+
# pathnames_per_binary is too big for the OS to handle so it's split in two halfs which are processed independently
|
|
151
|
+
if pathnames_per_binary.count > 1
|
|
152
|
+
left, right = pathnames_per_binary.each_slice( (pathnames_per_binary.size/2.0).round ).to_a
|
|
153
|
+
coverage_files.concat(create_coverage_files_for_binary(binary_path, left))
|
|
154
|
+
coverage_files.concat(create_coverage_files_for_binary(binary_path, right))
|
|
155
|
+
else
|
|
156
|
+
# pathnames_per_binary contains one element which is too big for the OS to handle.
|
|
157
|
+
raise e, "#{e}. A path in your project is close to the E2BIG limit. https://github.com/SlatherOrg/slather/pull/414", e.backtrace
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
coverage_files
|
|
162
|
+
end
|
|
163
|
+
private :create_coverage_files_for_binary
|
|
164
|
+
|
|
165
|
+
def create_coverage_files(binary_path, pathnames)
|
|
166
|
+
line_numbers_first = Gem::Version.new(self.llvm_version) >= Gem::Version.new('8.1.0')
|
|
167
|
+
files = create_profdata(binary_path, pathnames)
|
|
168
|
+
files.map do |source|
|
|
169
|
+
coverage_file = coverage_file_class.new(self, source, line_numbers_first)
|
|
170
|
+
# If a single source file is used, the resulting output does not contain the file name.
|
|
171
|
+
coverage_file.source_file_pathname = pathnames.first if pathnames.count == 1
|
|
172
|
+
!coverage_file.ignored? ? coverage_file : nil
|
|
173
|
+
end.compact
|
|
174
|
+
end
|
|
175
|
+
private :create_coverage_files
|
|
176
|
+
|
|
177
|
+
def create_profdata(binary_path, pathnames)
|
|
178
|
+
profdata_llvm_cov_output(binary_path, pathnames).split("\n\n")
|
|
179
|
+
end
|
|
180
|
+
private :create_profdata
|
|
181
|
+
|
|
146
182
|
def remove_extension(path)
|
|
147
183
|
path.split(".")[0..-2].join(".")
|
|
148
184
|
end
|
|
@@ -155,36 +191,38 @@ module Slather
|
|
|
155
191
|
end
|
|
156
192
|
|
|
157
193
|
def profdata_coverage_dir
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
194
|
+
@profdata_coverage_dir ||= begin
|
|
195
|
+
raise StandardError, "The specified build directory (#{self.build_directory}) does not exist" unless File.exists?(self.build_directory)
|
|
196
|
+
dir = nil
|
|
197
|
+
if self.scheme
|
|
198
|
+
dir = Dir[File.join(build_directory,"/**/CodeCoverage/#{self.scheme}")].first
|
|
199
|
+
else
|
|
200
|
+
dir = Dir[File.join(build_directory,"/**/#{first_product_name}")].first
|
|
201
|
+
end
|
|
165
202
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
203
|
+
if dir == nil
|
|
204
|
+
# Xcode 7.3 moved the location of Coverage.profdata
|
|
205
|
+
dir = Dir[File.join(build_directory,"/**/CodeCoverage")].first
|
|
206
|
+
end
|
|
170
207
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
208
|
+
if dir == nil && Slather.xcode_version[0] >= 9
|
|
209
|
+
# Xcode 9 moved the location of Coverage.profdata
|
|
210
|
+
coverage_files = Dir[File.join(build_directory, "/**/ProfileData/*/Coverage.profdata")]
|
|
174
211
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
212
|
+
if coverage_files.count == 0
|
|
213
|
+
# Look up one directory
|
|
214
|
+
# The ProfileData directory is next to Intermediates.noindex (in previous versions of Xcode the coverage was inside Intermediates)
|
|
215
|
+
coverage_files = Dir[File.join(build_directory, "../**/ProfileData/*/Coverage.profdata")]
|
|
216
|
+
end
|
|
180
217
|
|
|
181
|
-
|
|
182
|
-
|
|
218
|
+
if coverage_files != nil && coverage_files.count != 0
|
|
219
|
+
dir = Pathname.new(coverage_files.first).parent()
|
|
220
|
+
end
|
|
183
221
|
end
|
|
184
|
-
end
|
|
185
222
|
|
|
186
|
-
|
|
187
|
-
|
|
223
|
+
raise StandardError, "No coverage directory found." unless dir != nil
|
|
224
|
+
dir
|
|
225
|
+
end
|
|
188
226
|
end
|
|
189
227
|
|
|
190
228
|
def profdata_file
|
|
@@ -201,6 +239,30 @@ module Slather
|
|
|
201
239
|
end
|
|
202
240
|
private :profdata_file
|
|
203
241
|
|
|
242
|
+
def unsafe_llvm_cov_export_output(binary_path)
|
|
243
|
+
profdata_file_arg = profdata_file
|
|
244
|
+
if profdata_file_arg == nil
|
|
245
|
+
raise StandardError, "No Coverage.profdata files found. Please make sure the \"Code Coverage\" checkbox is enabled in your scheme's Test action or the build_directory property is set."
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
if binary_path == nil
|
|
249
|
+
raise StandardError, "No binary file found."
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
llvm_cov_args = %W(export -instr-profile #{profdata_file_arg} #{binary_path})
|
|
253
|
+
if self.arch
|
|
254
|
+
llvm_cov_args << "--arch" << self.arch
|
|
255
|
+
end
|
|
256
|
+
`xcrun llvm-cov #{llvm_cov_args.shelljoin}`
|
|
257
|
+
end
|
|
258
|
+
private :unsafe_llvm_cov_export_output
|
|
259
|
+
|
|
260
|
+
def llvm_cov_export_output(binary_path)
|
|
261
|
+
output = unsafe_llvm_cov_export_output(binary_path)
|
|
262
|
+
output.valid_encoding? ? output : output.encode!('UTF-8', 'binary', :invalid => :replace, undef: :replace)
|
|
263
|
+
end
|
|
264
|
+
private :llvm_cov_export_output
|
|
265
|
+
|
|
204
266
|
def unsafe_profdata_llvm_cov_output(binary_path, source_files)
|
|
205
267
|
profdata_file_arg = profdata_file
|
|
206
268
|
if profdata_file_arg == nil
|
|
@@ -212,6 +274,9 @@ module Slather
|
|
|
212
274
|
end
|
|
213
275
|
|
|
214
276
|
llvm_cov_args = %W(show -instr-profile #{profdata_file_arg} #{binary_path})
|
|
277
|
+
if self.arch
|
|
278
|
+
llvm_cov_args << "--arch" << self.arch
|
|
279
|
+
end
|
|
215
280
|
`xcrun llvm-cov #{llvm_cov_args.shelljoin} #{source_files.shelljoin}`
|
|
216
281
|
end
|
|
217
282
|
private :unsafe_profdata_llvm_cov_output
|
|
@@ -248,6 +313,7 @@ module Slather
|
|
|
248
313
|
configure_source_directory
|
|
249
314
|
configure_output_directory
|
|
250
315
|
configure_input_format
|
|
316
|
+
configure_arch
|
|
251
317
|
configure_binary_file
|
|
252
318
|
configure_decimals
|
|
253
319
|
|
|
@@ -358,6 +424,8 @@ module Slather
|
|
|
358
424
|
extend(Slather::CoverageService::HtmlOutput)
|
|
359
425
|
when :json
|
|
360
426
|
extend(Slather::CoverageService::JsonOutput)
|
|
427
|
+
when :sonarqube_xml
|
|
428
|
+
extend(Slather::CoverageService::SonarqubeXmlOutput)
|
|
361
429
|
else
|
|
362
430
|
raise ArgumentError, "`#{coverage_service}` is not a valid coverage service. Try `terminal`, `coveralls`, `gutter_json`, `cobertura_xml` or `html`"
|
|
363
431
|
end
|
|
@@ -370,6 +438,10 @@ module Slather
|
|
|
370
438
|
end
|
|
371
439
|
end
|
|
372
440
|
|
|
441
|
+
def configure_arch
|
|
442
|
+
self.arch ||= self.class.yml["arch"] if self.class.yml["arch"]
|
|
443
|
+
end
|
|
444
|
+
|
|
373
445
|
def decimal_f decimal_arg
|
|
374
446
|
configure_decimals unless decimals
|
|
375
447
|
decimal = "%.#{decimals}f" % decimal_arg
|
|
@@ -435,10 +507,17 @@ module Slather
|
|
|
435
507
|
# Sort the matches without the file extension to ensure better matches when there are multiple candidates
|
|
436
508
|
# For example, if the binary_basename is Test then we want Test.app to be matched before Test Helper.app
|
|
437
509
|
File.basename(x, File.extname(x)) <=> File.basename(y, File.extname(y))
|
|
438
|
-
}.
|
|
439
|
-
path.end_with? ".dSYM"
|
|
440
|
-
path.end_with? ".swiftmodule"
|
|
441
|
-
|
|
510
|
+
}.find { |path|
|
|
511
|
+
next if path.end_with? ".dSYM"
|
|
512
|
+
next if path.end_with? ".swiftmodule"
|
|
513
|
+
|
|
514
|
+
if File.directory? path
|
|
515
|
+
path = find_binary_file_in_bundle(path)
|
|
516
|
+
next if path.nil?
|
|
517
|
+
end
|
|
518
|
+
|
|
519
|
+
matches_arch(path)
|
|
520
|
+
}
|
|
442
521
|
|
|
443
522
|
if found_product and File.directory? found_product
|
|
444
523
|
found_binary = find_binary_file_in_bundle(found_product)
|
|
@@ -517,6 +596,16 @@ module Slather
|
|
|
517
596
|
found_buildable_names.uniq
|
|
518
597
|
end
|
|
519
598
|
|
|
599
|
+
def matches_arch(binary_path)
|
|
600
|
+
if self.arch
|
|
601
|
+
lipo_output = `lipo -info "#{binary_path}"`
|
|
602
|
+
archs_in_binary = lipo_output.split(':').last.split(' ')
|
|
603
|
+
archs_in_binary.include? self.arch
|
|
604
|
+
else
|
|
605
|
+
true
|
|
606
|
+
end
|
|
607
|
+
end
|
|
608
|
+
|
|
520
609
|
def find_source_files
|
|
521
610
|
source_files = load_option_array("source_files")
|
|
522
611
|
return if source_files.nil?
|