1/************************************************ 2 3 coverage.c - 4 5 $Author: $ 6 7 Copyright (c) 2008 Yusuke Endoh 8 9************************************************/ 10 11#include "ruby.h" 12#include "vm_core.h" 13 14static VALUE rb_coverages = Qundef; 15 16/* 17 * call-seq: 18 * Coverage.start => nil 19 * 20 * Enables coverage measurement. 21 */ 22static VALUE 23rb_coverage_start(VALUE klass) 24{ 25 if (!RTEST(rb_get_coverages())) { 26 if (rb_coverages == Qundef) { 27 rb_coverages = rb_hash_new(); 28 RBASIC(rb_coverages)->klass = 0; 29 } 30 rb_set_coverages(rb_coverages); 31 } 32 return Qnil; 33} 34 35static int 36coverage_result_i(st_data_t key, st_data_t val, st_data_t h) 37{ 38 VALUE path = (VALUE)key; 39 VALUE coverage = (VALUE)val; 40 VALUE coverages = (VALUE)h; 41 coverage = rb_ary_dup(coverage); 42 rb_ary_clear((VALUE)val); 43 rb_ary_freeze(coverage); 44 rb_hash_aset(coverages, path, coverage); 45 return ST_CONTINUE; 46} 47 48/* 49 * call-seq: 50 * Coverage.result => hash 51 * 52 * Returns a hash that contains filename as key and coverage array as value 53 * and disables coverage measurement. 54 */ 55static VALUE 56rb_coverage_result(VALUE klass) 57{ 58 VALUE coverages = rb_get_coverages(); 59 VALUE ncoverages = rb_hash_new(); 60 if (!RTEST(coverages)) { 61 rb_raise(rb_eRuntimeError, "coverage measurement is not enabled"); 62 } 63 st_foreach(RHASH_TBL(coverages), coverage_result_i, ncoverages); 64 rb_hash_freeze(ncoverages); 65 rb_reset_coverages(); 66 return ncoverages; 67} 68 69/* Coverage provides coverage measurement feature for Ruby. 70 * This feature is experimental, so these APIs may be changed in future. 71 * 72 * = Usage 73 * 74 * 1. require "coverage.so" 75 * 2. do Coverage.start 76 * 3. require or load Ruby source file 77 * 4. Coverage.result will return a hash that contains filename as key and 78 * coverage array as value. A coverage array gives, for each line, the 79 * number of line execution by the interpreter. A +nil+ value means 80 * coverage is disabled for this line (lines like +else+ and +end+). 81 * 82 * = Example 83 * 84 * [foo.rb] 85 * s = 0 86 * 10.times do |x| 87 * s += x 88 * end 89 * 90 * if s == 45 91 * p :ok 92 * else 93 * p :ng 94 * end 95 * [EOF] 96 * 97 * require "coverage.so" 98 * Coverage.start 99 * require "foo.rb" 100 * p Coverage.result #=> {"foo.rb"=>[1, 1, 10, nil, nil, 1, 1, nil, 0, nil]} 101 */ 102void 103Init_coverage(void) 104{ 105 VALUE rb_mCoverage = rb_define_module("Coverage"); 106 rb_define_module_function(rb_mCoverage, "start", rb_coverage_start, 0); 107 rb_define_module_function(rb_mCoverage, "result", rb_coverage_result, 0); 108 rb_gc_register_address(&rb_coverages); 109} 110