Ruby 1.9.3p327(2012-11-10revision37606)
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.
00079  *
00080  * = Example
00081  *
00082  *   [foo.rb]
00083  *   s = 0
00084  *   10.times do |x|
00085  *     s += x
00086  *   end
00087  *
00088  *   if s == 45
00089  *     p :ok
00090  *   else
00091  *     p :ng
00092  *   end
00093  *   [EOF]
00094  *
00095  *   require "coverage.so"
00096  *   Coverage.start
00097  *   require "foo.rb"
00098  *   p Coverage.result  #=> {"foo.rb"=>[1, 1, 10, nil, nil, 1, 1, nil, 0, nil]}
00099  */
00100 void
00101 Init_coverage(void)
00102 {
00103     VALUE rb_mCoverage = rb_define_module("Coverage");
00104     rb_define_module_function(rb_mCoverage, "start", rb_coverage_start, 0);
00105     rb_define_module_function(rb_mCoverage, "result", rb_coverage_result, 0);
00106     rb_gc_register_address(&rb_coverages);
00107 }
00108