Class: Rcov::FileStatistics
- Inherits:
-
Object
- Object
- Rcov::FileStatistics
- Defined in:
- lib/rcov.rb
Overview
A FileStatistics object associates a filename to:
-
its source code
-
the per-line coverage information after correction using rcov’s heuristics
-
the per-line execution counts
A FileStatistics object can be therefore be built given the filename, the associated source code, and an array holding execution counts (i.e. how many times each line has been executed).
FileStatistics is relatively intelligent: it handles normal comments, =begin/=end, heredocs, many multiline-expressions… It uses a number of heuristics to determine what is code and what is a comment, and to refine the initial (incomplete) coverage information.
Basic usage is as follows:
sf = FileStatistics.new("foo.rb", ["puts 1", "if true &&", " false",
"puts 2", "end"], [1, 1, 0, 0, 0])
sf.num_lines # => 5
sf.num_code_lines # => 5
sf.coverage[2] # => true
sf.coverage[3] # => :inferred
sf.code_coverage # => 0.6
The array of strings representing the source code and the array of execution counts would normally be obtained from a Rcov::CodeCoverageAnalyzer.
Instance Attribute Summary collapse
-
#counts ⇒ Object
readonly
Returns the value of attribute counts.
-
#coverage ⇒ Object
readonly
Returns the value of attribute coverage.
-
#lines ⇒ Object
readonly
Returns the value of attribute lines.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
Instance Method Summary collapse
-
#code_coverage ⇒ Object
Code coverage rate: fraction of lines of code executed, relative to the total amount of lines of code (loc).
- #code_coverage_for_report ⇒ Object
-
#initialize(name, lines, counts, comments_run_by_default = false) ⇒ FileStatistics
constructor
A new instance of FileStatistics.
-
#is_code?(lineno) ⇒ Boolean
Returns true if the given line number corresponds to code, as opposed to a comment (either # or =begin/=end blocks).
-
#merge(lines, coverage, counts) ⇒ Object
Merge code coverage and execution count information.
-
#num_code_lines ⇒ Object
Number of lines of code (loc).
-
#num_lines ⇒ Object
Total number of lines.
-
#total_coverage ⇒ Object
Total coverage rate if comments are also considered “executable”, given as a fraction, i.e.
- #total_coverage_for_report ⇒ Object
Constructor Details
#initialize(name, lines, counts, comments_run_by_default = false) ⇒ FileStatistics
Returns a new instance of FileStatistics.
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/rcov.rb', line 95 def initialize(name, lines, counts, comments_run_by_default = false) @name = name @lines = lines initial_coverage = counts.map{|x| (x || 0) > 0 ? true : false } @coverage = CoverageInfo.new initial_coverage @counts = counts @is_begin_comment = nil # points to the line defining the heredoc identifier # but only if it was marked (we don't care otherwise) @heredoc_start = Array.new(lines.size, false) @multiline_string_start = Array.new(lines.size, false) extend_heredocs find_multiline_strings precompute_coverage comments_run_by_default end |
Instance Attribute Details
#counts ⇒ Object (readonly)
Returns the value of attribute counts.
94 95 96 |
# File 'lib/rcov.rb', line 94 def counts @counts end |
#coverage ⇒ Object (readonly)
Returns the value of attribute coverage.
94 95 96 |
# File 'lib/rcov.rb', line 94 def coverage @coverage end |
#lines ⇒ Object (readonly)
Returns the value of attribute lines.
94 95 96 |
# File 'lib/rcov.rb', line 94 def lines @lines end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
94 95 96 |
# File 'lib/rcov.rb', line 94 def name @name end |
Instance Method Details
#code_coverage ⇒ Object
Code coverage rate: fraction of lines of code executed, relative to the total amount of lines of code (loc). Returns a float from 0 to 1.0.
145 146 147 148 149 150 151 |
# File 'lib/rcov.rb', line 145 def code_coverage indices = (0...@lines.size).select{|i| is_code? i } return 0 if indices.size == 0 count = 0 indices.each {|i| count += 1 if @coverage[i] } 1.0 * count / indices.size end |
#code_coverage_for_report ⇒ Object
153 154 155 |
# File 'lib/rcov.rb', line 153 def code_coverage_for_report code_coverage * 100 end |
#is_code?(lineno) ⇒ Boolean
Returns true if the given line number corresponds to code, as opposed to a comment (either # or =begin/=end blocks).
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
# File 'lib/rcov.rb', line 173 def is_code?(lineno) unless @is_begin_comment @is_begin_comment = Array.new(@lines.size, false) pending = [] state = :code @lines.each_with_index do |line, index| case state when :code if /^=begin\b/ =~ line state = :comment pending << index end when :comment pending << index if /^=end\b/ =~ line state = :code pending.each{|idx| @is_begin_comment[idx] = true} pending.clear end end end end @lines[lineno] && !@is_begin_comment[lineno] && @lines[lineno] !~ /^\s*(#|$)/ end |
#merge(lines, coverage, counts) ⇒ Object
Merge code coverage and execution count information. As for code coverage, a line will be considered
-
covered for sure (true) if it is covered in either
selfor in thecoveragearray -
considered
:inferredif the neitherselfnor thecoveragearray indicate that it was definitely executed, but it wasinferredin either one -
not covered (
false) if it was uncovered in both
Execution counts are just summated on a per-line basis.
121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/rcov.rb', line 121 def merge(lines, coverage, counts) coverage.each_with_index do |v, idx| case @coverage[idx] when :inferred @coverage[idx] = v || @coverage[idx] when false @coverage[idx] ||= v end end counts.each_with_index{|v, idx| @counts[idx] += v } precompute_coverage false end |
#num_code_lines ⇒ Object
Number of lines of code (loc).
162 163 164 |
# File 'lib/rcov.rb', line 162 def num_code_lines (0...@lines.size).select{|i| is_code? i}.size end |
#num_lines ⇒ Object
Total number of lines.
167 168 169 |
# File 'lib/rcov.rb', line 167 def num_lines @lines.size end |
#total_coverage ⇒ Object
Total coverage rate if comments are also considered “executable”, given as a fraction, i.e. from 0 to 1.0. A comment is attached to the code following it (RDoc-style): it will be considered executed if the the next statement was executed.
138 139 140 141 |
# File 'lib/rcov.rb', line 138 def total_coverage return 0 if @coverage.size == 0 @coverage.inject(0.0) {|s,a| s + (a ? 1:0) } / @coverage.size end |
#total_coverage_for_report ⇒ Object
157 158 159 |
# File 'lib/rcov.rb', line 157 def total_coverage_for_report total_coverage * 100 end |