Module: Coverage

Defined in:
lib/coverage.rb,
coverage.c

Class Method Summary collapse

Class Method Details

.line_stub(file) ⇒ Object



4
5
6
7
8
9
10
11
12
13
# File 'lib/coverage.rb', line 4

def self.line_stub(file)
  lines = File.foreach(file).map { nil }
  iseqs = [RubyVM::InstructionSequence.compile_file(file)]
  until iseqs.empty?
    iseq = iseqs.pop
    iseq.trace_points.each {|n, type| lines[n - 1] = 0 if type == :line }
    iseq.each_child {|child| iseqs << child }
  end
  lines
end

.peek_resultHash

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],
  ...
}

Returns:

  • (Hash)


347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
# File 'coverage.c', line 347

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");
    }
    OBJ_WB_UNPROTECT(coverages);

    rb_hash_foreach(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

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.

Returns:

  • (Hash)


401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
# File 'coverage.c', line 401

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

    if (current_state == IDLE) {
        rb_raise(rb_eRuntimeError, "coverage measurement is not enabled");
    }

    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) {
        if (current_state == RUNNING) {
            rb_coverage_suspend(klass);
        }
        rb_reset_coverages();
        me2counter = Qnil;
        current_state = IDLE;
    }
    return ncoverages;
}

.resumenil

Start/resume the coverage measurement.

Caveat: Currently, only process-global coverage measurement is supported. You cannot measure per-thread coverage. If your process has multiple thread, using Coverage.resume/suspend to capture code coverage executed from only a limited code block, may yield misleading results.

Returns:

  • (nil)


139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'coverage.c', line 139

VALUE
rb_coverage_resume(VALUE klass)
{
    if (current_state == IDLE) {
        rb_raise(rb_eRuntimeError, "coverage measurement is not set up yet");
    }
    if (current_state == RUNNING) {
        rb_raise(rb_eRuntimeError, "coverage measurement is already running");
    }
    rb_resume_coverages();
    current_state = RUNNING;
    return Qnil;
}

.running?Boolean

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

Returns:

  • (Boolean)


465
466
467
468
469
# File 'coverage.c', line 465

static VALUE
rb_coverage_running(VALUE klass)
{
    return current_state == RUNNING ? Qtrue : Qfalse;
}

.setupnil .setup(: all) ⇒ nil .setup(lines: bool, branches: bool, methods: bool, eval: bool) ⇒ nil .setup(oneshot_lines: true) ⇒ nil

Set up the coverage measurement.

Note that this method does not start the measurement itself. Use Coverage.resume to start the measurement.

You may want to use Coverage.start to setup and then start the measurement.

Overloads:

  • .setupnil

    Returns:

    • (nil)
  • .setup(: all) ⇒ nil

    Returns:

    • (nil)
  • .setup(lines: bool, branches: bool, methods: bool, eval: bool) ⇒ nil

    Returns:

    • (nil)
  • .setup(oneshot_lines: true) ⇒ nil

    Returns:

    • (nil)


67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'coverage.c', line 67

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

    if (current_state != IDLE) {
        rb_raise(rb_eRuntimeError, "coverage measurement is already setup");
    }

    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 | COVERAGE_TARGET_EVAL;
    }
    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 (RTEST(rb_hash_lookup(opt, ID2SYM(rb_intern("eval")))))
            mode |= COVERAGE_TARGET_EVAL;
    }

    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);
        current_state = SUSPENDED;
    }
    else if (current_mode != mode) {
        rb_raise(rb_eRuntimeError, "cannot change the measuring target during coverage measurement");
    }

    return Qnil;
}

.startnil .start(: all) ⇒ nil .start(lines: bool, branches: bool, methods: bool, eval: bool) ⇒ nil .start(oneshot_lines: true) ⇒ nil

Enables the coverage measurement. See the documentation of Coverage class in detail. This is equivalent to Coverage.setup and Coverage.resume.

Overloads:

  • .startnil

    Returns:

    • (nil)
  • .start(: all) ⇒ nil

    Returns:

    • (nil)
  • .start(lines: bool, branches: bool, methods: bool, eval: bool) ⇒ nil

    Returns:

    • (nil)
  • .start(oneshot_lines: true) ⇒ nil

    Returns:

    • (nil)


164
165
166
167
168
169
170
# File 'coverage.c', line 164

static VALUE
rb_coverage_start(int argc, VALUE *argv, VALUE klass)
{
    rb_coverage_setup(argc, argv, klass);
    rb_coverage_resume(klass);
    return Qnil;
}

.stateObject

Returns the state of the coverage measurement.



447
448
449
450
451
452
453
454
455
456
# File 'coverage.c', line 447

static VALUE
rb_coverage_state(VALUE klass)
{
    switch (current_state) {
        case IDLE: return ID2SYM(rb_intern("idle"));
        case SUSPENDED: return ID2SYM(rb_intern("suspended"));
        case RUNNING: return ID2SYM(rb_intern("running"));
    }
    return Qnil;
}

.supported?(mode) ⇒ Boolean

Returns true if coverage measurement is supported for the given mode.

The mode should be one of the following symbols: :lines, :oneshot_lines, :branches, :methods, :eval.

Example:

Coverage.supported?(:lines)  #=> true
Coverage.supported?(:all)    #=> false

Returns:

  • (Boolean)


39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'coverage.c', line 39

static VALUE
rb_coverage_supported(VALUE self, VALUE _mode)
{
    ID mode = RB_SYM2ID(_mode);

    return RBOOL(
        mode == rb_intern("lines") ||
        mode == rb_intern("oneshot_lines") ||
        mode == rb_intern("branches") ||
        mode == rb_intern("methods") ||
        mode == rb_intern("eval")
    );
}

.suspendnil

Suspend the coverage measurement. You can use Coverage.resume to restart the measurement.

Returns:

  • (nil)


382
383
384
385
386
387
388
389
390
391
# File 'coverage.c', line 382

VALUE
rb_coverage_suspend(VALUE klass)
{
    if (current_state != RUNNING) {
        rb_raise(rb_eRuntimeError, "coverage measurement is not running");
    }
    rb_suspend_coverages();
    current_state = SUSPENDED;
    return Qnil;
}