# module Coverage

`Coverage` provides coverage measurement feature for Ruby. This feature is experimental, so these APIs may be changed in future.

# Usage¶ ↑

1. require “coverage”

2. do `Coverage.start`

3. require or load Ruby source file

4. `Coverage.result` will return a hash that contains filename as key and coverage array as value. A coverage array gives, for each line, the number of line execution by the interpreter. A `nil` value means coverage is disabled for this line (lines like `else` and `end`).

# Example¶ ↑

    [foo.rb]
    s = 0
    10.times do |x|
      s += x
    end

    if s == 45
      p :ok
    else
      p :ng
    end
    [EOF]

    require "coverage"
    Coverage.start
    require "foo.rb"
    p Coverage.result  #=> {"foo.rb"=>[1, 1, 10, nil, nil, 1, 1, nil, 0, nil]}

### Public Class Methods

peek_result → hash click to toggle source

Returns a hash that contains filename as key and coverage array as value. This is the same as `Coverage.result(stop: false, clear: false)`.

    {
      "file.rb" => [1, 2, nil],
      ...
    }

    static VALUE
    rb_coverage_peek_result(VALUE klass)
    {
        VALUE coverages = rb_get_coverages();
        VALUE ncoverages = rb_hash_new();
        if (!RTEST(coverages)) {
            rb_raise(rb_eRuntimeError, "coverage measurement is not enabled");
        }
        st_foreach(RHASH_TBL(coverages), coverage_peek_result_i, ncoverages);

        if (current_mode & COVERAGE_TARGET_METHODS) {
            rb_objspace_each_objects(method_coverage_i, &ncoverages);
        }

        rb_hash_freeze(ncoverages);
        return ncoverages;
    }

result(stop: true, clear: true) → hash click to toggle source

Returns a hash that contains filename as key and coverage array as value. If `clear` is true, it clears the counters to zero. If `stop` is true, it disables coverage measurement.

    static VALUE
    rb_coverage_result(int argc, VALUE *argv, VALUE klass)
    {
        VALUE ncoverages;
        VALUE opt;
        int stop = 1, clear = 1;

        rb_scan_args(argc, argv, "01", &opt);

        if (argc == 1) {
            opt = rb_convert_type(opt, T_HASH, "Hash", "to_hash");
            stop = RTEST(rb_hash_lookup(opt, ID2SYM(rb_intern("stop"))));
            clear = RTEST(rb_hash_lookup(opt, ID2SYM(rb_intern("clear"))));
        }

        ncoverages = rb_coverage_peek_result(klass);
        if (stop && !clear) {
            rb_warn("stop implies clear");
            clear = 1;
        }
        if (clear) {
            rb_clear_coverages();
            if (!NIL_P(me2counter)) rb_hash_foreach(me2counter, clear_me2counter_i, Qnil);
        }
        if (stop) {
            rb_reset_coverages();
            me2counter = Qnil;
        }
        return ncoverages;
    }

running? → bool click to toggle source

Returns true if coverage stats are currently being collected (after `Coverage.start` call, but before `Coverage.result` call)

    static VALUE
    rb_coverage_running(VALUE klass)
    {
        VALUE coverages = rb_get_coverages();
        return RTEST(coverages) ? Qtrue : Qfalse;
    }

start → nil click to toggle source

Enables coverage measurement.

    static VALUE
    rb_coverage_start(int argc, VALUE *argv, VALUE klass)
    {
        VALUE coverages, opt;
        int mode;

        rb_scan_args(argc, argv, "01", &opt);

        if (argc == 0) {
            mode = 0; /* compatible mode */
        }
        else if (opt == ID2SYM(rb_intern("all"))) {
            mode = COVERAGE_TARGET_LINES | COVERAGE_TARGET_BRANCHES | COVERAGE_TARGET_METHODS;
        }
        else {
            mode = 0;
            opt = rb_convert_type(opt, T_HASH, "Hash", "to_hash");

            if (RTEST(rb_hash_lookup(opt, ID2SYM(rb_intern("lines")))))
                mode |= COVERAGE_TARGET_LINES;
            if (RTEST(rb_hash_lookup(opt, ID2SYM(rb_intern("branches")))))
                mode |= COVERAGE_TARGET_BRANCHES;
            if (RTEST(rb_hash_lookup(opt, ID2SYM(rb_intern("methods")))))
                mode |= COVERAGE_TARGET_METHODS;
            if (RTEST(rb_hash_lookup(opt, ID2SYM(rb_intern("oneshot_lines"))))) {
                if (mode & COVERAGE_TARGET_LINES)
                    rb_raise(rb_eRuntimeError, "cannot enable lines and oneshot_lines simultaneously");
                mode |= COVERAGE_TARGET_LINES;
                mode |= COVERAGE_TARGET_ONESHOT_LINES;
            }
        }

        if (mode & COVERAGE_TARGET_METHODS) {
            me2counter = rb_ident_hash_new();
        }
        else {
            me2counter = Qnil;
        }

        coverages = rb_get_coverages();
        if (!RTEST(coverages)) {
            coverages = rb_hash_new();
            rb_obj_hide(coverages);
            current_mode = mode;
            if (mode == 0) mode = COVERAGE_TARGET_LINES;
            rb_set_coverages(coverages, mode, me2counter);
        }
        else if (current_mode != mode) {
            rb_raise(rb_eRuntimeError, "cannot change the measuring target during coverage measurement");
        }
        return Qnil;
    }