Class: Rcov::CodeCoverageAnalyzer

Inherits:
DifferentialAnalyzer show all
Defined in:
lib/rcov.rb

Overview

A CodeCoverageAnalyzer is responsible for tracing code execution and returning code coverage and execution count information.

Note that you must require 'rcov' before the code you want to analyze is parsed (i.e. before it gets loaded or required). You can do that by either invoking ruby with the -rrcov command-line option or just:

require 'rcov'
require 'mycode'
# ....

Example

analyzer = Rcov::CodeCoverageAnalyzer.new
analyzer.run_hooked do 
  do_foo  
  # all the code executed as a result of this method call is traced
end
# ....

analyzer.run_hooked do 
  do_bar
  # the code coverage information generated in this run is aggregated
  # to the previously recorded one
end

analyzer.analyzed_files   # => ["foo.rb", "bar.rb", ... ]
lines, marked_info, count_info = analyzer.data("foo.rb")

In this example, two pieces of code are monitored, and the data generated in both runs are aggregated. lines is an array of strings representing the source code of foo.rb. marked_info is an array holding false, true values indicating whether the corresponding lines of code were reported as executed by Ruby. count_info is an array of integers representing how many times each line of code has been executed (more precisely, how many events where reported by Ruby — a single line might correspond to several events, e.g. many method calls).

You can have several CodeCoverageAnalyzer objects at a time, and it is possible to nest the #run_hooked / #install_hook/#remove_hook blocks: each analyzer will manage its data separately. Note however that no special provision is taken to ignore code executed “inside” the CodeCoverageAnalyzer class. At any rate this will not pose a problem since it’s easy to ignore it manually: just don’t do

lines, coverage, counts = analyzer.data("/path/to/lib/rcov.rb")

if you’re not interested in that information.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCodeCoverageAnalyzer

Returns a new instance of CodeCoverageAnalyzer.



574
575
576
577
578
# File 'lib/rcov.rb', line 574

def initialize
  @script_lines__ = SCRIPT_LINES__
  super(:install_coverage_hook, :remove_coverage_hook,
        :reset_coverage)
end

Class Method Details

.hook_levelObject

defined this way instead of attr_accessor so that it’s covered



567
568
569
# File 'lib/rcov.rb', line 567

def self.hook_level      # :nodoc:
  @hook_level 
end

.hook_level=(x) ⇒ Object

:nodoc:



570
571
572
# File 'lib/rcov.rb', line 570

def self.hook_level=(x)  # :nodoc: 
  @hook_level = x 
end

Instance Method Details

#analyzed_filesObject

Return an array with the names of the files whose code was executed inside the block given to #run_hooked or between #install_hook and #remove_hook.



582
583
584
585
586
587
# File 'lib/rcov.rb', line 582

def analyzed_files
  update_script_lines__
  raw_data_relative.select do |file, lines|
    @script_lines__.has_key?(file)
  end.map{|fname,| fname}
end

#data(filename) ⇒ Object

Return the available data about the requested file, or nil if none of its code was executed or it cannot be found. The return value is an array with three elements:

lines, marked_info, count_info = analyzer.data("foo.rb")

lines is an array of strings representing the source code of foo.rb. marked_info is an array holding false, true values indicating whether the corresponding lines of code were reported as executed by Ruby. count_info is an array of integers representing how many times each line of code has been executed (more precisely, how many events where reported by Ruby — a single line might correspond to several events, e.g. many method calls).

The returned data corresponds to the aggregation of all the statistics collected in each #run_hooked or #install_hook/#remove_hook runs. You can reset the data at any time with #reset to start from scratch.



604
605
606
607
608
609
610
611
612
# File 'lib/rcov.rb', line 604

def data(filename)
  raw_data = raw_data_relative
  update_script_lines__
  unless @script_lines__.has_key?(filename) && 
         raw_data.has_key?(filename)
    return nil 
  end
  refine_coverage_info(@script_lines__[filename], raw_data[filename])
end

#data_matching(filename_re) ⇒ Object

Data for the first file matching the given regexp. See #data.



616
617
618
619
620
621
622
623
624
# File 'lib/rcov.rb', line 616

def data_matching(filename_re)
  raw_data = raw_data_relative
  update_script_lines__

  match = raw_data.keys.sort.grep(filename_re).first
  return nil unless match

  refine_coverage_info(@script_lines__[match], raw_data[match])
end

#dump_coverage_info(formatters) ⇒ Object

:nodoc:



648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
# File 'lib/rcov.rb', line 648

def dump_coverage_info(formatters) # :nodoc:
  update_script_lines__
  raw_data_relative.each do |file, lines|
    next if @script_lines__.has_key?(file) == false
    lines = @script_lines__[file]
    raw_coverage_array = raw_data_relative[file]

    line_info, marked_info, 
      count_info = refine_coverage_info(lines, raw_coverage_array)
    formatters.each do |formatter|
      formatter.add_file(file, line_info, marked_info, count_info)
    end
  end
  formatters.each{|formatter| formatter.execute}
end

#install_hookObject

Start monitoring execution to gather code coverage and execution count information. Such data will be collected until #remove_hook is called.

Use #run_hooked instead if possible.



634
# File 'lib/rcov.rb', line 634

def install_hook; super end

#marshal_dumpObject

:nodoc:



770
771
772
773
774
775
776
777
# File 'lib/rcov.rb', line 770

def marshal_dump # :nodoc:
  # @script_lines__ is updated just before serialization so as to avoid
  # missing files in SCRIPT_LINES__
  ivs = {}
  update_script_lines__
  instance_variables.each{|iv| ivs[iv] = instance_variable_get(iv)}
  ivs
end

#marshal_load(ivs) ⇒ Object

:nodoc:



779
780
781
# File 'lib/rcov.rb', line 779

def marshal_load(ivs) # :nodoc:
  ivs.each_pair{|iv, val| instance_variable_set(iv, val)}
end

#remove_hookObject

Stop collecting code coverage and execution count information. #remove_hook will also stop collecting info if it is run inside a #run_hooked block.



639
# File 'lib/rcov.rb', line 639

def remove_hook; super end

#resetObject

Remove the data collected so far. The coverage and execution count “history” will be erased, and further collection will start from scratch: no code is considered executed, and therefore all execution counts are 0. Right after #reset, #analyzed_files will return an empty array, and #data(filename) will return nil.



646
# File 'lib/rcov.rb', line 646

def reset; super end

#run_hookedObject

Execute the code in the given block, monitoring it in order to gather information about which code was executed.



628
# File 'lib/rcov.rb', line 628

def run_hooked; super end