From: sam.rawlins@... Date: 2014-05-09T17:04:40+00:00 Subject: [ruby-core:62480] [ruby-trunk - Feature #9508] Add method coverage and branch coverage metrics Issue #9508 has been updated by Sam Rawlins. Hi Yusuke, thanks for the comments! I want to first defend the Demand and Use Case. And thank you for the Review comments; I'll apply them ASAP. ## Demand in Ruby Core I think that Ripper is inadequate for these new metrics for the exact reason you mention: if/else code and methods that are all defined within one line, as well as implicit "else". Code like this of course exists everywhere, so a tool would be greatly inadequate if it could not give metrics regarding lines like "return if x.nil?" or "def foo; bar.baz; end". ## Visualization and Analysis I was largely inspired by the visualization and analysis of Istanbul [1], the standard Javascript coverage library. Here is a great example of a coverage report: http://gotwarlost.github.io/istanbul/public/coverage/lcov-report/istanbul/lib/report/html.js.html * On line 79, the report shows that the "else" branch is not taken. * On line 171, the report shows that the "if" branch is not taken, and this if/else is all one line! Line coverage shows that the line _is_ executed, because at a minimum, the line is reached, and the condition is evaluated. * On line 522, the report shows that an implicit "else" branch is not taken. This is important because the line coverage looks fine, but the user is unaware, without Decision Coverage, that no test exercises a false condition in that "if." I think this is perhaps the most exciting and useful example of decision coverage. I'm going to look into your performance notes. Thanks for benchmarking! [1] https://github.com/gotwarlost/istanbul ---------------------------------------- Feature #9508: Add method coverage and branch coverage metrics https://bugs.ruby-lang.org/issues/9508#change-46645 * Author: Sam Rawlins * Status: Feedback * Priority: Normal * Assignee: * Category: * Target version: ---------------------------------------- Since the Coverage extension was introduced in Ruby 1.9, Ruby has had built-in line code coverage. Ruby should support more of the basic code coverage metrics [1]. I have a pull request on GitHub ( https://github.com/ruby/ruby/pull/511 ) to add Method Coverage (Function Coverage) and Branch Coverage. I'd love feedback to improve it. Currently, with this feature, Coverage.result would look like: {"/Users/sam/code/ruby/cov_method.rb" => { lines: [1, 2, 2, 20, nil, nil, 2, 2, 2, nil, 0, nil, nil, nil, 1, 0, nil, nil, 1, 1, nil, nil, 1], methods: {1=>2, 15=>0, 19=>1}, branches: {8=>2, 11=>0} }} which includes * the current Ruby line coverage report, * as well as a method report (The method defined on line 1 was called 2 times; the method on line 15 was called 0 times; ...), * and a branch report (the branch on line 8 was called 2 times; the branch on line 11 was called 0 times). Branches -------- Branches include the bodies of if, elsif, else, unless, and when statements, which are all tracked with this new feature. However, this feature is not aware of void bodies, for example: if foo :ok end will report that only one branch exists in the file. It would be better to declare that there is a branch body on line 2, and a void branch body on line 3, or perhaps line 1. This would require the keys of the [:branch] Hash to be something other than line numbers. Perhaps label_no? Perhaps nd_type(node) paired with line or label_no? More Coverage ------------- I think that Statement Coverage, and Condition Coverage could be added to this feature, using the same techniques. Caveats ------- I was not very clear on the bit-arrays used in ruby.h, and just used values for the new macros that seemed to work. Also, I would much rather use Ranges to identify a branch, so that a Coverage analyzer like SimpleCov won't need any kind of Ruby parser to identify and highlight a full chunk of code as a tested branch, or a not tested branch. I'm trying to find how that could be implemented... [1] Wikipedia has good definitions: http://en.wikipedia.org/wiki/Code_coverage ---Files-------------------------------- pull-request-511.patch (26.7 KB) pull-request-511.patch (38.5 KB) pull-request-511.patch (57 KB) -- https://bugs.ruby-lang.org/