gcovtools 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8314cd41c5ead47cae359e181b5021016ddb7e23
4
+ data.tar.gz: 565783cb5e96dedff1a27c229da4b86aa2fa6bad
5
+ SHA512:
6
+ metadata.gz: 13767da67d715e9cda49872f549f1ee415113c82cefaff960e43e239149eae0e32faeeb5054b661733899a5013892c6d50b581b58fec43675c0afaa5699a56d4
7
+ data.tar.gz: 5aa48a5638137f9613de783e944a41100b5cdc5283e6230f46a04bb811daa2ed2a44c348b253721eca06161ee3de9ad235bc51ca774755f4b0c8567001d9a392
data/.gitignore ADDED
@@ -0,0 +1,37 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ # for a library or gem, you might want to ignore these files since the code is
28
+ # intended to run in multiple environments; otherwise, check them in:
29
+ Gemfile.lock
30
+ .ruby-version
31
+ .ruby-gemset
32
+
33
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
+ .rvmrc
35
+
36
+ ## Emacs
37
+ *~
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.0
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Mattias Bergbom
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,25 @@
1
+ gcovtools
2
+ ======
3
+
4
+ ![Travis CI Status](https://travis-ci.org/mattiasbergbom/gcovtools.svg)
5
+
6
+ **gcovtools** provides various tools and utilities for processing coverage data emitted from [llvm-cov](http://llvm.org/docs/CommandGuide/llvm-cov.html).
7
+
8
+ Quick Start
9
+ -----------
10
+
11
+ First, unless you haven't already done so, compile your project using ```clang --coverage``` and digest the output using ```llvm-cov``` (see the `src` dir for examples). You should end up with one or more ```.gcov``` files.
12
+
13
+ Next, install the gem:
14
+
15
+ ```gem install gcovtools```
16
+
17
+ This should furnish you with a ```gcovtools``` executable in your path.
18
+
19
+ Finally, execute ```gcovtools``` in one of multiple possible ways. For instance, generate a HTML coverage report:
20
+
21
+ ```gcovtools convert --format html *.gcov > coverage.html```
22
+
23
+ Disclaimer
24
+ ----------
25
+ This is a work in progress.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ Dir['tasks/**/*.rake'].sort.each { |lib| load lib }
2
+
data/bin/gcovtools ADDED
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "thor"
4
+ require 'mixlib/cli'
5
+
6
+ require_relative '../lib/logging'
7
+ require_relative '../lib/gcovtools'
8
+ require_relative '../lib/ansii_formatter'
9
+ require_relative '../lib/xml_formatter'
10
+ require_relative '../lib/html_formatter'
11
+ require_relative '../lib/json_formatter'
12
+ require_relative '../lib/version'
13
+
14
+ class Util
15
+ def Util.opt_wrap(s, width=61)
16
+ s.gsub(/(.{1,#{width}})(\s+|\Z)/, "\\1\n # ")
17
+ end
18
+ end
19
+
20
+ class MyCLI < Thor
21
+
22
+ class_option :verbose, :type => :boolean, :desc => "Be verbose"
23
+ desc "report FILES", "generate a coverage report from one or more gcov FILES"
24
+
25
+ method_option :recursive, :type => :boolean, :desc => "Search for input files recursively in the directory/ies specified."
26
+
27
+ method_option :include,
28
+ :desc => ::Util.opt_wrap("A list of regex filters which specify which files to include in the report. Will filter on the actual filename (taking into account any path mangling done by llvm-cov) as well as the 'Source' meta attribute in the GCOVTOOLS data.
29
+ Available presets:
30
+ :xcode - Xcode system headers
31
+ :linux - Linux system headers
32
+ "),
33
+ :type => :array
34
+
35
+ method_option :exclude,
36
+ :desc => ::Util.opt_wrap("A list of regex filters which specify which files NOT to include in the report. Will filter on the actual filename (taking into account any path mangling done by llvm-cov) as well as the 'Source' meta attribute in the GCOVTOOLS data. The filters will be applied in the order inclusive-exclusive, where an empty/unspecified filter means to include all files encountered.
37
+
38
+ Available presets:
39
+ :xcode - Xcode system headers
40
+ :linux - Linux system headers
41
+ "),
42
+ :type => :array
43
+
44
+ method_option :inclusive,
45
+ :desc => ::Util.opt_wrap("Filter inclusively instead of exclusively (which is the default)."),
46
+ :type => :boolean
47
+
48
+ method_option :format,
49
+ :aliases => "-f",
50
+ :desc => ::Util.opt_wrap("The output format (ascii, html, xml, json)"),
51
+ :default => "ascii"
52
+
53
+ method_option :css,
54
+ :aliases => "-c",
55
+ :desc => ::Util.opt_wrap("CSS file to reference in HTML output.")
56
+
57
+ method_option :xsl,
58
+ :aliases => "-x",
59
+ :desc => ::Util.opt_wrap("XSL file to reference in XML output.")
60
+
61
+ method_option :recursive,
62
+ :aliases => "-r",
63
+ :desc => ::Util.opt_wrap("Recursively load all .gcov files in the given directory"),
64
+ :type => :boolean
65
+
66
+ method_option :verbose,
67
+ :aliases => "-v",
68
+ :desc => ::Util.opt_wrap("Verbose output"),
69
+ :type => :boolean
70
+
71
+ # --------------------------------------------------------------------------------------- #
72
+ # Generate report
73
+ # --------------------------------------------------------------------------------------- #
74
+ def report(*filenames)
75
+
76
+ fail "Got no filename" unless filenames
77
+
78
+ if options[:verbose]
79
+ GCOVTOOLS::logger.level = Logger::INFO
80
+ end
81
+
82
+ GCOVTOOLS::logger.info "gcovtools v#{GCOVTOOLS::VERSION}"
83
+
84
+ proj = GCOVTOOLS::Project.new
85
+
86
+ filter = {
87
+ :include => [],
88
+ :exclude => []
89
+ }
90
+
91
+ [:include,:exclude].each do |verb|
92
+
93
+ if !options[verb].nil?
94
+ options[verb].each do |f|
95
+ filter[verb] << case f
96
+ when ":xcode" then /Developer\/(Toolchains|Platforms)\/.*\/usr\/include\//
97
+ when ":linux" then /\/usr\/include\//
98
+ when nil then nil
99
+ else /#{f}/
100
+ end
101
+ end # each f
102
+ end
103
+ GCOVTOOLS::logger.info "#{verb.to_s}: #{filter[verb]}"
104
+ end
105
+
106
+ filenames.each do |filename|
107
+ GCOVTOOLS::logger.info "processing: #{filename}"
108
+ if File.directory? filename
109
+ proj.add_dir filename, :recursive => options[:recursive], :include => filter[:include], :exclude => filter[:exclude]
110
+ elsif File.file? filename
111
+ proj.add_file filename, :include => filter[:include], :exclude => filter[:exclude]
112
+ end
113
+ end
114
+
115
+ GCOVTOOLS::logger.info "project has #{proj.files.count} files after filtering"
116
+ GCOVTOOLS::logger.info "#{proj.files.map(&:name).join("\n")}"
117
+
118
+ case options[:format].to_sym
119
+ when :ascii then
120
+ formatter = GCOVTOOLS::ANSIIFormatter.new proj
121
+ formatter.print
122
+ when :html then
123
+ formatter = GCOVTOOLS::HTMLFormatter.new( proj, :css => options[:css] )
124
+ formatter.print
125
+ when :xml then
126
+ formatter = GCOVTOOLS::XMLFormatter.new( proj, :xsl => options[:xsl] )
127
+ formatter.print
128
+ when :json then
129
+ formatter = GCOVTOOLS::JSONFormatter.new proj
130
+ formatter.print
131
+ else
132
+ fail "Invalid output format: #{options[:format]}"
133
+ end
134
+ end
135
+
136
+ end
137
+
138
+ MyCLI.start(ARGV)
data/gcovtools.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ require File.expand_path('../lib/version.rb', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+
5
+ gem.name = 'gcovtools'
6
+ gem.version = GCOVTOOLS::VERSION
7
+ gem.date = '2014-12-09'
8
+ gem.summary = "gcov parser and formatter"
9
+ gem.description = "gcovtools digests .gcov files generated by llvm-cov and translates them into various common formats"
10
+ gem.authors = ["Mattias Bergbom"]
11
+ gem.email = 'mattias.bergbom@gmail.com'
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.executables = ["gcovtools"]
14
+ gem.homepage = 'http://rubygems.org/gems/gcovtools'
15
+ gem.license = 'MIT'
16
+ gem.required_ruby_version = '>= 2.0'
17
+
18
+ gem.add_development_dependency 'rspec'
19
+ gem.add_development_dependency 'rake'
20
+ gem.add_development_dependency 'rubygems-tasks'
21
+ gem.add_development_dependency 'simplecov'
22
+
23
+ gem.add_runtime_dependency 'terminal-table'
24
+ gem.add_runtime_dependency 'term-ansicolor'
25
+ gem.add_runtime_dependency 'thor'
26
+ gem.add_runtime_dependency 'gyoku', '~> 1.0'
27
+
28
+ end
@@ -0,0 +1,34 @@
1
+ require 'term/ansicolor'
2
+ include Term::ANSIColor
3
+
4
+ require_relative './project'
5
+ require_relative './file'
6
+ require_relative './line'
7
+
8
+ module GCOVTOOLS
9
+
10
+ class ANSIIFormatter
11
+
12
+ def initialize project
13
+ @project = project
14
+ end
15
+
16
+ def print
17
+
18
+ @project.files.each do |file|
19
+ puts "#{white}#{bold}=== #{file.meta['Source']} ===#{reset}"
20
+ file.lines.select{|line| line.number > 0}.each do |line|
21
+ col = case line.count
22
+ when :none then dark+white
23
+ when :missed then black+on_red
24
+ else green
25
+ end
26
+ puts col + line.text + reset
27
+ end
28
+ end
29
+
30
+ end
31
+
32
+ end
33
+
34
+ end
data/lib/file.rb ADDED
@@ -0,0 +1,149 @@
1
+ require_relative './line'
2
+ require 'pathname'
3
+
4
+ class TrueClass
5
+ def to_i
6
+ return 1
7
+ end
8
+ end
9
+
10
+ class FalseClass
11
+ def to_i
12
+ return 0
13
+ end
14
+ end
15
+
16
+ module GCOVTOOLS
17
+
18
+ class File
19
+
20
+ attr_reader :name, :lines, :meta, :stats
21
+
22
+ def initialize name
23
+ fail "name required" unless name and name.is_a? String
24
+ @name = name
25
+ @lines = {}
26
+ @meta = {}
27
+ @stats = {}
28
+ _update_stats
29
+ end
30
+
31
+ # return lines as array, in order by number
32
+ def lines
33
+ @lines.sort.map{|key,val|val}
34
+ end
35
+
36
+ def add_lines &block
37
+ fail "add_lines requires a block" unless block_given?
38
+ @adding = true
39
+ yield
40
+ @adding = false
41
+ _update_stats
42
+ end
43
+
44
+ def _update_stats
45
+ @stats = {
46
+ :missed_lines => 0,
47
+ :exec_lines => 0,
48
+ :empty_lines => 0,
49
+ :total_exec => 0,
50
+ :total_lines => 0,
51
+ :lines => 0,
52
+ :coverage => 0.0,
53
+ :hits_per_line => 0.0
54
+ }
55
+
56
+ @lines.each do |index,line|
57
+ @stats[:missed_lines] += (line.state == :missed).to_i
58
+ @stats[:exec_lines] += (line.state == :exec).to_i
59
+ @stats[:total_exec] += (line.count.is_a?(Integer) ? line.count : 0 )
60
+ @stats[:empty_lines] += (line.state == :none).to_i
61
+ end
62
+
63
+ @stats[:lines] = @stats[:exec_lines] + @stats[:missed_lines]
64
+ @stats[:total_lines] = @stats[:lines] + @stats[:empty_lines]
65
+
66
+ if @stats[:lines] > 0
67
+ @stats[:coverage] = @stats[:exec_lines].to_f / @stats[:lines].to_f
68
+ @stats[:hits_per_line] = @stats[:total_exec].to_f / @stats[:lines]
69
+ else
70
+ @stats[:coverage] = 1
71
+ @stats[:hits_per_line] = 0
72
+ end
73
+
74
+ @stats[:coverage_s] = sprintf("%0.01f%",100.0*@stats[:coverage])
75
+ @stats[:hits_per_line_s] = sprintf("%0.02f",@stats[:hits_per_line])
76
+
77
+ end
78
+
79
+ def _add_line line
80
+ if line.number == 0
81
+ key,val = /([^:]+):(.*)$/.match(line.text).to_a[1..2]
82
+ @meta[key] = val
83
+ else
84
+ @lines[line.number] = line
85
+ end
86
+ end
87
+
88
+ def <<(line)
89
+ fail "need to be in add_lines block" unless @adding
90
+ _add_line line
91
+ end
92
+
93
+ def self.load filename
94
+ files = []
95
+ file = nil
96
+ ::File.open(filename, "r") do |file_handle|
97
+ file_handle.each_line do |line_|
98
+ line = GCOVTOOLS::Line.parse(line_)
99
+ if line.number == 0
100
+ key,val = /([^:]+):(.*)$/.match(line.text).to_a[1..2]
101
+ if key == 'Source'
102
+ if !file.nil?
103
+ file._update_stats
104
+ files << file
105
+ end # if
106
+ file = GCOVTOOLS::File.new val
107
+ end # if source
108
+ end # if line == 0
109
+ file._add_line line
110
+ end # each line
111
+ end# file_handle
112
+ if file
113
+ file._update_stats
114
+ files << file
115
+ end # if file
116
+ files
117
+ end
118
+
119
+ def self.demangle filename
120
+ result = filename.dup
121
+ if start = result.index(/###/)
122
+ result = result[start..-1]
123
+ end
124
+
125
+ result.gsub!( /(###|#|\^|\.gcov$)/, {"###"=>"/","#"=>"/","^"=>"..",".gcov"=>""} )
126
+ result = ::Pathname.new(result).cleanpath.to_s
127
+ result
128
+ end
129
+
130
+ def merge! other
131
+ other.lines.each do |line|
132
+ if @lines.has_key? line.number
133
+ @lines[line.number].merge! line
134
+ else
135
+ @lines[line.number] = line
136
+ end
137
+ end
138
+ _update_stats
139
+ end
140
+
141
+ def merge other
142
+ result = self.dup
143
+ result.merge! other
144
+ result
145
+ end
146
+
147
+ end # class File
148
+
149
+ end
data/lib/gcovtools.rb ADDED
@@ -0,0 +1,4 @@
1
+ require_relative './line'
2
+ require_relative './file'
3
+ require_relative './project'
4
+ require_relative './version'
@@ -0,0 +1,84 @@
1
+
2
+ require_relative './project'
3
+ require_relative './file'
4
+ require_relative './line'
5
+
6
+ require 'erb'
7
+ require 'cgi'
8
+
9
+ module GCOVTOOLS
10
+
11
+ class HTMLFormatter
12
+
13
+ def get_binding # this is only a helper method to access the objects binding method
14
+ binding
15
+ end
16
+
17
+ def initialize project, va={}
18
+ @project = project
19
+ @css = va[:css]
20
+
21
+ if !@css
22
+ @csslink = <<EOF
23
+ <style>
24
+
25
+ </style>
26
+ EOF
27
+ else
28
+ @csslink = "<link rel=\"stylesheet\" href=\"#{@css}\" />"
29
+ end
30
+
31
+ @template = ::File.read(::File.join(::File.dirname(__FILE__),"html_view.html.erb"))
32
+ end # initialize
33
+
34
+ def class_of line
35
+ case line.count
36
+ when :none then "irrelevant"
37
+ when :missed then "missed"
38
+ else "ok"
39
+ end
40
+ end
41
+
42
+ def class_of_stat value, error_comp, warning_comp=nil
43
+ if eval("#{value}#{error_comp}")
44
+ return "value_error"
45
+ elsif !warning_comp.nil? and eval("#{value}#{warning_comp}")
46
+ return "value_warning"
47
+ else
48
+ return "value_ok"
49
+ end
50
+ end
51
+
52
+ def class_of_file file, error_level, warning_level=nil
53
+ if file.stats[:coverage] <= error_level
54
+ return "header error"
55
+ elsif !warning_level.nil? and file.stats[:coverage] < warning_level
56
+ return "header warning"
57
+ else
58
+ return "header ok"
59
+ end
60
+ end
61
+
62
+ def count_of line
63
+ case line.count
64
+ when :none then ""
65
+ when :missed then "<strong>miss</strong>"
66
+ else line.count
67
+ end
68
+ end
69
+
70
+ def encode text
71
+ CGI.escapeHTML( text )
72
+ end
73
+
74
+ def print
75
+
76
+ renderer = ERB.new( @template )
77
+
78
+ puts renderer.result(self.get_binding)
79
+
80
+ end # HTMLFormatter#print
81
+
82
+ end # HTMLFormatter
83
+
84
+ end # GCOVTOOLS