Ruby  2.0.0p247(2013-06-27revision41674)
ext/coverage/coverage.c
Go to the documentation of this file.
00001 /************************************************
00002 
00003   coverage.c -
00004 
00005   $Author: $
00006 
00007   Copyright (c) 2008 Yusuke Endoh
00008 
00009 ************************************************/
00010 
00011 #include "ruby.h"
00012 #include "vm_core.h"
00013 
00014 static VALUE rb_coverages = Qundef;
00015 
00016 /*
00017  * call-seq:
00018  *    Coverage.start  => nil
00019  *
00020  * Enables coverage measurement.
00021  */
00022 static VALUE
00023 rb_coverage_start(VALUE klass)
00024 {
00025     if (!RTEST(rb_get_coverages())) {
00026         if (rb_coverages == Qundef) {
00027             rb_coverages = rb_hash_new();
00028             RBASIC(rb_coverages)->klass = 0;
00029         }
00030         rb_set_coverages(rb_coverages);
00031     }
00032     return Qnil;
00033 }
00034 
00035 static int
00036 coverage_result_i(st_data_t key, st_data_t val, st_data_t h)
00037 {
00038     VALUE path = (VALUE)key;
00039     VALUE coverage = (VALUE)val;
00040     VALUE coverages = (VALUE)h;
00041     coverage = rb_ary_dup(coverage);
00042     rb_ary_clear((VALUE)val);
00043     rb_ary_freeze(coverage);
00044     rb_hash_aset(coverages, path, coverage);
00045     return ST_CONTINUE;
00046 }
00047 
00048 /*
00049  *  call-seq:
00050  *     Coverage.result  => hash
00051  *
00052  * Returns a hash that contains filename as key and coverage array as value
00053  * and disables coverage measurement.
00054  */
00055 static VALUE
00056 rb_coverage_result(VALUE klass)
00057 {
00058     VALUE coverages = rb_get_coverages();
00059     VALUE ncoverages = rb_hash_new();
00060     if (!RTEST(coverages)) {
00061         rb_raise(rb_eRuntimeError, "coverage measurement is not enabled");
00062     }
00063     st_foreach(RHASH_TBL(coverages), coverage_result_i, ncoverages);
00064     rb_hash_freeze(ncoverages);
00065     rb_reset_coverages();
00066     return ncoverages;
00067 }
00068 
00069 /* Coverage provides coverage measurement feature for Ruby.
00070  * This feature is experimental, so these APIs may be changed in future.
00071  *
00072  * = Usage
00073  *
00074  * 1. require "coverage.so"
00075  * 2. do Coverage.start
00076  * 3. require or load Ruby source file
00077  * 4. Coverage.result will return a hash that contains filename as key and
00078  *    coverage array as value. A coverage array gives, for each line, the
00079  *    number of line execution by the interpreter. A +nil+ value means
00080  *    coverage is disabled for this line (lines like +else+ and +end+).
00081  *
00082  * = Example
00083  *
00084  *   [foo.rb]
00085  *   s = 0
00086  *   10.times do |x|
00087  *     s += x
00088  *   end
00089  *
00090  *   if s == 45
00091  *     p :ok
00092  *   else
00093  *     p :ng
00094  *   end
00095  *   [EOF]
00096  *
00097  *   require "coverage.so"
00098  *   Coverage.start
00099  *   require "foo.rb"
00100  *   p Coverage.result  #=> {"foo.rb"=>[1, 1, 10, nil, nil, 1, 1, nil, 0, nil]}
00101  */
00102 void
00103 Init_coverage(void)
00104 {
00105     VALUE rb_mCoverage = rb_define_module("Coverage");
00106     rb_define_module_function(rb_mCoverage, "start", rb_coverage_start, 0);
00107     rb_define_module_function(rb_mCoverage, "result", rb_coverage_result, 0);
00108     rb_gc_register_address(&rb_coverages);
00109 }
00110