slather 2.4.4 → 2.4.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f140d82b4571c441455df1b9eb9c247f8f52e310
4
- data.tar.gz: eeaac677b8b341cb92479c16cbdd2bd6254c85de
2
+ SHA256:
3
+ metadata.gz: 1e8bb7fa0d1346a2a81a47272a1f55d2625a8457d8c4b88a82f2b737792aa39a
4
+ data.tar.gz: a375044a21453e30695adf31c20f5a9ea885091d1eb3ac6fafc3f3ef9d44d752
5
5
  SHA512:
6
- metadata.gz: ebac089dfe9785ab980a86d6f3020a9c700f01edd1d3dcdb170c82faccc553cb5a4d7143a30c6432af7c606de9902fd42737f12233d136240aeb01e0ce415a21
7
- data.tar.gz: e3a00efe762b6062a33ef42d30cbdadc4b03444f3f36538bc23b98988659587aace4a6d9fa346ab8a7d5367072fded337dd600efff2e28d5181fd98b366ff10c
6
+ metadata.gz: 9a9dddfd5dcf8160cd31327f170030f3520c2a885b7c56f6f2d7d470e5442b8c49c3f30ba289664767cc43d597415c2309654699a5ac2fd59db90ac5bc796697
7
+ data.tar.gz: 5f67d766eb09e18df9a2bf1016f49a3a7a7f912be2bf5e05ed31c925540fb51ccaef34e53f1dffaed6aadfef827a3e69aa1c7144fa30a024f9f72a1ce2d47605
data/.gitignore CHANGED
@@ -46,4 +46,8 @@ html
46
46
  *.gcno
47
47
 
48
48
  # JetBrains IDE
49
- .idea/
49
+ .idea/
50
+
51
+ # Test output
52
+ report.llcov
53
+ report.json
@@ -1,20 +1,10 @@
1
1
  language: objective-c
2
2
  script: bundle exec rake
3
- osx_image: xcode8.3
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
- - source ~/.rvm/scripts/rvm
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
@@ -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
- [lampietti](https://github.com/sgtsquiggs) [#354](https://github.com/SlatherOrg/slather/pull/354)
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:
@@ -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;di;i++)if(h.test(f[i].className)){if(c)return f[i];d[j]=f[i],j++}return d}}()}),a.register("javve-get-attribute/index.js",function(a,b,c){c.exports=function(a,b){var c=a.getAttribute&&a.getAttribute(b)||null;if(!c)for(var d=a.attributes,e=d.length,f=0;e>f;f++)void 0!==b[f]&&b[f].nodeName===b&&(c=b[f].nodeValue);return c}}),a.register("javve-natural-sort/index.js",function(a,b,c){c.exports=function(a,b,c){var d,e,f=/(^-?[0-9]+(\.?[0-9]*)[df]?e?[0-9]?$|^0x[0-9a-f]+$|[0-9]+)/gi,g=/(^[ ]*|[ ]*$)/g,h=/(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,i=/^0x[0-9a-f]+$/i,j=/^0/,c=c||{},k=function(a){return c.insensitive&&(""+a).toLowerCase()||""+a},l=k(a).replace(g,"")||"",m=k(b).replace(g,"")||"",n=l.replace(f,"\x00$1\x00").replace(/\0$/,"").replace(/^\0/,"").split("\x00"),o=m.replace(f,"\x00$1\x00").replace(/\0$/,"").replace(/^\0/,"").split("\x00"),p=parseInt(l.match(i))||1!=n.length&&l.match(h)&&Date.parse(l),q=parseInt(m.match(i))||p&&m.match(h)&&Date.parse(m)||null,r=c.desc?-1:1;if(q){if(q>p)return-1*r;if(p>q)return 1*r}for(var s=0,t=Math.max(n.length,o.length);t>s;s++){if(d=!(n[s]||"").match(j)&&parseFloat(n[s])||n[s]||0,e=!(o[s]||"").match(j)&&parseFloat(o[s])||o[s]||0,isNaN(d)!==isNaN(e))return isNaN(d)?1:-1;if(typeof d!=typeof e&&(d+="",e+=""),e>d)return-1*r;if(d>e)return 1*r}return 0}}),a.register("javve-to-string/index.js",function(a,b,c){c.exports=function(a){return a=void 0===a?"":a,a=null===a?"":a,a=a.toString()}}),a.register("component-type/index.js",function(a,b,c){var d=Object.prototype.toString;c.exports=function(a){switch(d.call(a)){case"[object Date]":return"date";case"[object RegExp]":return"regexp";case"[object Arguments]":return"arguments";case"[object Array]":return"array";case"[object Error]":return"error"}return null===a?"null":void 0===a?"undefined":a!==a?"nan":a&&1===a.nodeType?"element":typeof a.valueOf()}}),a.register("list.js/index.js",function(a,b,c){!function(a,d){"use strict";var e=a.document,f=b("get-by-class"),g=b("extend"),h=b("indexof"),i=function(a,c,i){var j,k=this,l=b("./src/item")(k),m=b("./src/add-async")(k),n=b("./src/parse")(k);j={start:function(){k.listClass="list",k.searchClass="search",k.sortClass="sort",k.page=200,k.i=1,k.items=[],k.visibleItems=[],k.matchingItems=[],k.searched=!1,k.filtered=!1,k.handlers={updated:[]},k.plugins={},k.helpers={getByClass:f,extend:g,indexOf:h},g(k,c),k.listContainer="string"==typeof a?e.getElementById(a):a,k.listContainer&&(k.list=f(k.listContainer,k.listClass,!0),k.templater=b("./src/templater")(k),k.search=b("./src/search")(k),k.filter=b("./src/filter")(k),k.sort=b("./src/sort")(k),this.items(),k.update(),this.plugins())},items:function(){n(k.list),i!==d&&k.add(i)},plugins:function(){for(var a=0;af;f++){var h=null;a[f]instanceof l?(h=a[f],h.reload()):(e=k.items.length>k.page?!0:!1,h=new l(a[f],d,e)),k.items.push(h),c.push(h)}return k.update(),c},this.show=function(a,b){return this.i=a,this.page=b,k.update(),k},this.remove=function(a,b,c){for(var d=0,e=0,f=k.items.length;f>e;e++)k.items[e].values()[a]==b&&(k.templater.remove(k.items[e],c),k.items.splice(e,1),f--,e--,d++);return k.update(),d},this.get=function(a,b){for(var c=[],d=0,e=k.items.length;e>d;d++){var f=k.items[d];f.values()[a]==b&&c.push(f)}return c},this.size=function(){return k.items.length},this.clear=function(){return k.templater.clear(),k.items=[],k},this.on=function(a,b){return k.handlers[a].push(b),k},this.off=function(a,b){var c=k.handlers[a],d=h(c,b);return d>-1&&c.splice(d,1),k},this.trigger=function(a){for(var b=k.handlers[a].length;b--;)k.handlers[a][b](k);return k},this.reset={filter:function(){for(var a=k.items,b=a.length;b--;)a[b].filtered=!1;return k},search:function(){for(var a=k.items,b=a.length;b--;)a[b].found=!1;return k}},this.update=function(){var a=k.items,b=a.length;k.visibleItems=[],k.matchingItems=[],k.templater.clear();for(var c=0;b>c;c++)a[c].matching()&&k.matchingItems.length+1>=k.i&&k.visibleItems.lengthb;b++)j.item(a.items[b])},item:function(a){a.found=!1;for(var b=0,d=c.length;d>b;b++)if(j.values(a.values(),c[b]))return a.found=!0,void 0},values:function(a,c){return a.hasOwnProperty(c)&&(b=f(a[c]).toLowerCase(),""!==g&&b.search(g)>-1)?!0:!1},reset:function(){a.reset.search(),a.searched=!1}},k=function(b){return a.trigger("searchStart"),i.resetList(),i.setSearchString(b),i.setOptions(arguments),i.setColumns(),""===g?j.reset():(a.searched=!0,h?h(g,c):j.list()),a.update(),a.trigger("searchComplete"),a.visibleItems};return a.handlers.searchStart=a.handlers.searchStart||[],a.handlers.searchComplete=a.handlers.searchComplete||[],d.bind(e(a.listContainer,a.searchClass),"keyup",function(b){var c=b.target||b.srcElement,d=""===c.value&&!a.searched;d||k(c.value)}),d.bind(e(a.listContainer,a.searchClass),"input",function(a){var b=a.target||a.srcElement;""===b.value&&k("")}),a.helpers.toString=f,k}}),a.register("list.js/src/sort.js",function(a,b,c){var d=b("natural-sort"),e=b("classes"),f=b("events"),g=b("get-by-class"),h=b("get-attribute");c.exports=function(a){a.sortFunction=a.sortFunction||function(a,b,c){return c.desc="desc"==c.order?!0:!1,d(a.values()[c.valueName],b.values()[c.valueName],c)};var b={els:void 0,clear:function(){for(var a=0,c=b.els.length;c>a;a++)e(b.els[a]).remove("asc"),e(b.els[a]).remove("desc")},getOrder:function(a){var b=h(a,"data-order");return"asc"==b||"desc"==b?b:e(a).has("desc")?"asc":e(a).has("asc")?"desc":"asc"},getInSensitive:function(a,b){var c=h(a,"data-insensitive");b.insensitive="true"===c?!0:!1},setOrder:function(a){for(var c=0,d=b.els.length;d>c;c++){var f=b.els[c];if(h(f,"data-sort")===a.valueName){var g=h(f,"data-order");"asc"==g||"desc"==g?g==a.order&&e(f).add(a.order):e(f).add(a.order)}}}},c=function(){a.trigger("sortStart"),options={};var c=arguments[0].currentTarget||arguments[0].srcElement||void 0;c?(options.valueName=h(c,"data-sort"),b.getInSensitive(c,options),options.order=b.getOrder(c)):(options=arguments[1]||options,options.valueName=arguments[0],options.order=options.order||"asc",options.insensitive="undefined"==typeof options.insensitive?!0:options.insensitive),b.clear(),b.setOrder(options),options.sortFunction=options.sortFunction||a.sortFunction,a.items.sort(function(a,b){return options.sortFunction(a,b,options)}),a.update(),a.trigger("sortComplete")};return a.handlers.sortStart=a.handlers.sortStart||[],a.handlers.sortComplete=a.handlers.sortComplete||[],b.els=g(a.listContainer,a.sortClass),f.bind(b.els,"click",c),a.on("searchStart",b.clear),a.on("filterStart",b.clear),a.helpers.classes=e,a.helpers.naturalSort=d,a.helpers.events=f,a.helpers.getAttribute=h,c}}),a.register("list.js/src/item.js",function(a,b,c){c.exports=function(a){return function(b,c,d){var e=this;this._values={},this.found=!1,this.filtered=!1;var f=function(b,c,d){if(void 0===c)d?e.values(b,d):e.values(b);else{e.elm=c;var f=a.templater.get(e,b);e.values(f)}};this.values=function(b,c){if(void 0===b)return e._values;for(var d in b)e._values[d]=b[d];c!==!0&&a.templater.set(e,e.values())},this.show=function(){a.templater.show(e)},this.hide=function(){a.templater.hide(e)},this.matching=function(){return a.filtered&&a.searched&&e.found&&e.filtered||a.filtered&&!a.searched&&e.filtered||!a.filtered&&a.searched&&e.found||!a.filtered&&!a.searched},this.visible=function(){return e.elm.parentNode==a.list?!0:!1},f(b,c,d)}}}),a.register("list.js/src/templater.js",function(a,b,c){var d=b("get-by-class"),e=function(a){function b(b){if(void 0===b){for(var c=a.list.childNodes,d=0,e=c.length;e>d;d++)if(void 0===c[d].data)return c[d];return null}if(-1!==b.indexOf("<")){var f=document.createElement("div");return f.innerHTML=b,f.firstChild}return document.getElementById(a.item)}var c=b(a.item),e=this;this.get=function(a,b){e.create(a);for(var c={},f=0,g=b.length;g>f;f++){var h=d(a.elm,b[f],!0);c[b[f]]=h?h.innerHTML:""}return c},this.set=function(a,b){if(!e.create(a))for(var c in b)if(b.hasOwnProperty(c)){var f=d(a.elm,c,!0);f&&("IMG"===f.tagName&&""!==b[c]?f.src=b[c]:f.innerHTML=b[c])}},this.create=function(a){if(void 0!==a.elm)return!1;var b=c.cloneNode(!0);return b.removeAttribute("id"),a.elm=b,e.set(a,a.values()),!0},this.remove=function(b){a.list.removeChild(b.elm)},this.show=function(b){e.create(b),a.list.appendChild(b.elm)},this.hide=function(b){void 0!==b.elm&&b.elm.parentNode===a.list&&a.list.removeChild(b.elm)},this.clear=function(){if(a.list.hasChildNodes())for(;a.list.childNodes.length>=1;)a.list.removeChild(a.list.firstChild)}};c.exports=function(a){return new e(a)}}),a.register("list.js/src/filter.js",function(a,b,c){c.exports=function(a){return a.handlers.filterStart=a.handlers.filterStart||[],a.handlers.filterComplete=a.handlers.filterComplete||[],function(b){if(a.trigger("filterStart"),a.i=1,a.reset.filter(),void 0===b)a.filtered=!1;else{a.filtered=!0;for(var c=a.items,d=0,e=c.length;e>d;d++){var f=c[d];f.filtered=b(f)?!0:!1}}return a.update(),a.trigger("filterComplete"),a.visibleItems}}}),a.register("list.js/src/add-async.js",function(a,b,c){c.exports=function(a){return function(b,c,d){var e=b.splice(0,100);d=d||[],d=d.concat(a.add(e)),b.length>0?setTimeout(function(){addAsync(b,c,d)},10):(a.update(),c(d))}}}),a.register("list.js/src/parse.js",function(a,b,c){c.exports=function(a){var c=b("./item")(a),d=function(a){for(var b=a.childNodes,c=[],d=0,e=b.length;e>d;d++)void 0===b[d].data&&c.push(b[d]);return c},e=function(b,d){for(var e=0,f=b.length;f>e;e++)a.items.push(new c(d,b[e]))},f=function(b,c){var d=b.splice(0,100);e(d,c),b.length>0?setTimeout(function(){init.items.indexAsync(b,c)},10):a.update()};return function(){var b=d(a.list),c=a.valueNames;a.indexAsync?f(b,c):e(b,c)}}}),a.alias("component-classes/index.js","list.js/deps/classes/index.js"),a.alias("component-classes/index.js","classes/index.js"),a.alias("component-indexof/index.js","component-classes/deps/indexof/index.js"),a.alias("segmentio-extend/index.js","list.js/deps/extend/index.js"),a.alias("segmentio-extend/index.js","extend/index.js"),a.alias("component-indexof/index.js","list.js/deps/indexof/index.js"),a.alias("component-indexof/index.js","indexof/index.js"),a.alias("javve-events/index.js","list.js/deps/events/index.js"),a.alias("javve-events/index.js","events/index.js"),a.alias("component-event/index.js","javve-events/deps/event/index.js"),a.alias("timoxley-to-array/index.js","javve-events/deps/to-array/index.js"),a.alias("javve-get-by-class/index.js","list.js/deps/get-by-class/index.js"),a.alias("javve-get-by-class/index.js","get-by-class/index.js"),a.alias("javve-get-attribute/index.js","list.js/deps/get-attribute/index.js"),a.alias("javve-get-attribute/index.js","get-attribute/index.js"),a.alias("javve-natural-sort/index.js","list.js/deps/natural-sort/index.js"),a.alias("javve-natural-sort/index.js","natural-sort/index.js"),a.alias("javve-to-string/index.js","list.js/deps/to-string/index.js"),a.alias("javve-to-string/index.js","list.js/deps/to-string/index.js"),a.alias("javve-to-string/index.js","to-string/index.js"),a.alias("javve-to-string/index.js","javve-to-string/index.js"),a.alias("component-type/index.js","list.js/deps/type/index.js"),a.alias("component-type/index.js","type/index.js"),"object"==typeof exports?module.exports=a("list.js"):"function"==typeof define&&define.amd?define(function(){return a("list.js")}):this.List=a("list.js")}();
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;o0?setTimeout(function(){e(r,n,i)},1):(t.update(),n(i))};return e}},function(t,e){t.exports=function(t){return t.handlers.filterStart=t.handlers.filterStart||[],t.handlers.filterComplete=t.handlers.filterComplete||[],function(e){if(t.trigger("filterStart"),t.i=1,t.reset.filter(),void 0===e)t.filtered=!1;else{t.filtered=!0;for(var r=t.items,n=0,i=r.length;nv.page,a=new m(t[i],void 0,n),v.items.push(a),r.push(a)}return v.update(),r}},this.show=function(t,e){return this.i=t,this.page=e,v.update(),v},this.remove=function(t,e,r){for(var n=0,i=0,s=v.items.length;i-1&&r.splice(n,1),v},this.trigger=function(t){for(var e=v.handlers[t].length;e--;)v.handlers[t][e](v);return v},this.reset={filter:function(){for(var t=v.items,e=t.length;e--;)t[e].filtered=!1;return v},search:function(){for(var t=v.items,e=t.length;e--;)t[e].found=!1;return v}},this.update=function(){var t=v.items,e=t.length;v.visibleItems=[],v.matchingItems=[],v.templater.clear();for(var r=0;r=v.i&&v.visibleItems.lengthe},innerWindow:function(t,e,r){return t>=e-r&&t<=e+r},dotted:function(t,e,r,n,i,s,a){return this.dottedLeft(t,e,r,n,i,s)||this.dottedRight(t,e,r,n,i,s,a)},dottedLeft:function(t,e,r,n,i,s){return e==r+1&&!this.innerWindow(e,i,s)&&!this.right(e,n)},dottedRight:function(t,e,r,n,i,s,a){return!t.items[a-1].values().dotted&&(e==n&&!this.innerWindow(e,i,s)&&!this.right(e,n))}},a=function(e,r,n){i.bind(e,"click",function(){t.show((r-1)*n+1,n)})};return function(r){var n=new s(t.listContainer.id,{listClass:r.paginationClass||"pagination",item:"
  • ",valueNames:["page","dotted"],searchClass:"pagination-search-that-is-not-supposed-to-exist",sortClass:"pagination-sort-that-is-not-supposed-to-exist"});t.on("updated",function(){e(n,r)}),e(n,r)}}},function(t,e,r){t.exports=function(t){var e=r(2)(t),n=function(t){for(var e=t.childNodes,r=[],n=0,i=e.length;n0?setTimeout(function(){s(e,r)},1):(t.update(),t.trigger("parseComplete"))};return t.handlers.parseComplete=t.handlers.parseComplete||[],function(){var e=n(t.list),r=t.valueNames;t.indexAsync?s(e,r):i(e,r)}}},function(t,e){t.exports=function(t){var e,r,n,i,s={resetList:function(){t.i=1,t.templater.clear(),i=void 0},setOptions:function(t){2==t.length&&t[1]instanceof Array?r=t[1]:2==t.length&&"function"==typeof t[1]?(r=void 0,i=t[1]):3==t.length?(r=t[1],i=t[2]):r=void 0},setColumns:function(){0!==t.items.length&&void 0===r&&(r=void 0===t.searchColumns?s.toArray(t.items[0].values()):t.searchColumns)},setSearchString:function(e){e=t.utils.toString(e).toLowerCase(),e=e.replace(/[-[\]{}()*+?.,\\^$|#]/g,"\\$&"),n=e},toArray:function(t){var e=[];for(var r in t)e.push(r);return e}},a={list:function(){for(var e=0,r=t.items.length;e-1))},reset:function(){t.reset.search(),t.searched=!1}},o=function(e){return t.trigger("searchStart"),s.resetList(),s.setSearchString(e),s.setOptions(arguments),s.setColumns(),""===n?a.reset():(t.searched=!0,i?i(n,r):a.list()),t.update(),t.trigger("searchComplete"),t.visibleItems};return t.handlers.searchStart=t.handlers.searchStart||[],t.handlers.searchComplete=t.handlers.searchComplete||[],t.utils.events.bind(t.utils.getByClass(t.listContainer,t.searchClass),"keyup",function(e){var r=e.target||e.srcElement,n=""===r.value&&!t.searched;n||o(r.value)}),t.utils.events.bind(t.utils.getByClass(t.listContainer,t.searchClass),"input",function(t){var e=t.target||t.srcElement;""===e.value&&o("")}),o}},function(t,e){t.exports=function(t){var e={els:void 0,clear:function(){for(var r=0,n=e.els.length;r]/g.exec(e)){var s=document.createElement("tbody");return s.innerHTML=e,s.firstChild}if(e.indexOf("<")!==-1){var a=document.createElement("div");return a.innerHTML=e,a.firstChild}var o=document.getElementById(t.item);if(o)return o}},this.get=function(e,n){r.create(e);for(var i={},s=0,a=n.length;s=1;)t.list.removeChild(t.list.firstChild)},n()};t.exports=function(t){return new r(t)}},function(t,e){t.exports=function(t,e){var r=t.getAttribute&&t.getAttribute(e)||null;if(!r)for(var n=t.attributes,i=n.length,s=0;s=48&&t<=57}function i(t,e){for(var r=(t+="").length,i=(e+="").length,s=0,l=0;s32)return!1;var o=i,l=function(){var t,r={};for(t=0;t=p;b--){var w=l[t.charAt(b-1)];if(0===g?y[b]=(y[b+1]<<1|1)&w:y[b]=(y[b+1]<<1|1)&w|((v[b+1]|v[b])<<1|1)|v[b+1],y[b]&f){var x=n(g,b-1);if(x<=u){if(u=x,c=b-1,!(c>o))break;p=Math.max(1,2*o-c)}}}if(n(g+1,o)>u)break;v=y}return!(c<0)}}]);
    @@ -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
    @@ -43,6 +43,7 @@ module Slather
    43
    43
      end
    44
    44
     
    45
    45
      total_percentage = decimal_f([(total_project_lines_tested / total_project_lines.to_f) * 100.0])
    46
    + puts "Tested #{total_project_lines_tested}/#{total_project_lines} statements"
    46
    47
      puts "Test Coverage: #{total_percentage}%"
    47
    48
      end
    48
    49
     
    @@ -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
    - path = self.source.split("\n")[0].sub ":", ""
    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
    - path = self.source.split("\n")[0].sub ":", ""
    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
    - if @all_lines == nil
    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
    - source_code_lines.map do |line|
    140
    + all_lines.map do |line|
    127
    141
      coverage_for_line(line, self.line_numbers_first)
    128
    142
      end
    129
    143
      end
    @@ -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
    - files = profdata_llvm_cov_output(binary_path, source_files).split("\n\n")
    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
    - raise StandardError, "The specified build directory (#{self.build_directory}) does not exist" unless File.exists?(self.build_directory)
    159
    - dir = nil
    160
    - if self.scheme
    161
    - dir = Dir[File.join(build_directory,"/**/CodeCoverage/#{self.scheme}")].first
    162
    - else
    163
    - dir = Dir[File.join(build_directory,"/**/#{first_product_name}")].first
    164
    - end
    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
    - if dir == nil
    167
    - # Xcode 7.3 moved the location of Coverage.profdata
    168
    - dir = Dir[File.join(build_directory,"/**/CodeCoverage")].first
    169
    - end
    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
    - if dir == nil && Slather.xcode_version[0] >= 9
    172
    - # Xcode 9 moved the location of Coverage.profdata
    173
    - coverage_files = Dir[File.join(build_directory, "/**/ProfileData/*/Coverage.profdata")]
    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
    - if coverage_files.count == 0
    176
    - # Look up one directory
    177
    - # The ProfileData directory is next to Intermediates.noindex (in previous versions of Xcode the coverage was inside Intermediates)
    178
    - coverage_files = Dir[File.join(build_directory, "../**/ProfileData/*/Coverage.profdata")]
    179
    - end
    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
    - if coverage_files != nil
    182
    - dir = Pathname.new(coverage_files.first).parent()
    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
    - raise StandardError, "No coverage directory found." unless dir != nil
    187
    - dir
    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
    - }.reject { |path|
    439
    - path.end_with? ".dSYM"
    440
    - path.end_with? ".swiftmodule"
    441
    - }.first
    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?