code that has been reached

  • Thread starter Simon Strandgaard
  • Start date
S

Simon Strandgaard

Does there exists a tool for Ruby which records which parts
of code (preferable the nodes in the AST) there has been reached?

Eventually with some statistics on how many times each part
has been executed?
 
R

Robert Klemme

Simon Strandgaard said:
Does there exists a tool for Ruby which records which parts
of code (preferable the nodes in the AST) there has been reached?

Eventually with some statistics on how many times each part
has been executed?

I don't know such a tool but two things come to mind:

- You can use the profiler for timings (alternatively use "benchmark",
which has less performance overhead).

- You can use set_trace_function() to build the statistics.

Regards

robert
 
H

Hal Fulton

Simon said:
Does there exists a tool for Ruby which records which parts
of code (preferable the nodes in the AST) there has been reached?

Eventually with some statistics on how many times each part
has been executed?

There is coverage.rb in RAA. It's very basic, but it works fine
"out of the box" and has been useful to me.

It doesn't measure stats, but it does show what code has been
hit and what has not, and dumps it in ANSI.

Hal
 
S

Simon Strandgaard

There is coverage.rb in RAA. It's very basic, but it works fine
"out of the box" and has been useful to me.

It doesn't measure stats, but it does show what code has been
hit and what has not, and dumps it in ANSI.

Wew, this is really a short piece of code.. amazing that it can be done in
only 45 lines of ruby code!

If I do "cat report.txt" then my terminal just scrolls for 10 seconds,
which is much larger than what my terminal history can remember.
If I pipe it into "less" then the coloring disappears. How do you view
ANSI files?

I think I will improve it (because I need it in conjunction with unittest)
* Add counters to each line.
* Fancy HTML output.

Has this been done before?
Other ideas?
Eventually make a rubyforge project out of it?
 
N

nobu.nokada

Hi,

At Wed, 4 Feb 2004 00:30:04 +0900,
Simon said:
If I do "cat report.txt" then my terminal just scrolls for 10 seconds,
which is much larger than what my terminal history can remember.
If I pipe it into "less" then the coloring disappears. How do you view
ANSI files?

less -r
 
S

Simon Strandgaard

At Wed, 4 Feb 2004 00:30:04 +0900,


less -r

Thanks..

I have done some improvements to the original 'coverage.rb', so that
HTML is now generated. For an example have a look at:
http://neoneye.dk/parser.rb.coverage.html

As you may notice comments/arrays appears as if they are not executed!
How can I fix this?

--
Simon Strandgaard

module PrettyCoverage
class HTML
def initialize
@files = {}
end
def execute
puts "execute"
@files.each{|file, line_marked|
create_file(file, line_marked)
}
create_file_index
end
def mk_filename(name)
name+".coverage.html"
end
def create_file_index
output_filename = "index.html"
rows = []
@files.each{|file, line_marked|
filename = mk_filename(file)
rows << "<tr><td><a href=\"#{filename}\">#{file}</a></td></tr>"
}
result = rows.join("\n")
body = "<table>#{result}</table>"
title = "coverage"
css = <<EOCSS
body {
background-color: rgb(180, 180, 180);
}
div.marked {
background-color: rgb(185, 200, 200);
}
div.overview {
border-bottom: 8px solid black;
}
EOCSS
html = <<EOHTML
<html><head><title>#{title}</title>
<style type="text/css">#{css}</style></head>
<body>#{body}</body></html>
EOHTML
File.open(output_filename, "w+") do |f|
f.puts html
end
end
def add_file(file, line_marked)
percent = calc_coverage(line_marked)
printf("file=#{file} coverage=%02.1f%\n", percent)
@files[file] = line_marked
end
def calc_coverage(line_marked)
marked = line_marked.transpose[1]
n = marked.inject(0) {|r, i| (i) ? (r+1) : r }
percent = n.to_f * 100 / marked.size
end
def format_overview(file, line_marked)
percent = "%02.1f" % calc_coverage(line_marked)
html = <<EOHTML
<div class="overview">
<table>
<tr><td>filename</td><td><tt>#{file}</tt></td></tr>
<tr><td>coverage</td><td>#{percent}</td></tr>
</table>
</div>
EOHTML
html
end
def format_lines(line_marked)
result = ""
last = nil
end_of_div = ""
format_line = "%#{line_marked.size.to_s.size}d"
line_no = 1
line_marked.each {|(line, marked)|
if marked != last
result += end_of_div
case marked
when true
result += "<div class=\"marked\">"
end_of_div = "</div>"
when false
end_of_div = ""
end
end
result += (format_line % line_no) + " " + line + "\n"
last = marked
line_no += 1
}
result += end_of_div
"<pre>#{result}</pre>"
end
def create_file(file, line_marked)
output_filename = mk_filename(file)
puts "outputting #{output_filename.inspect}"
body =
format_overview(file, line_marked) +
format_lines(line_marked)
title = file + " - coverage"
css = <<EOCSS
body {
background-color: rgb(180, 180, 180);
}
div.marked {
background-color: rgb(185, 200, 200);
}
div.overview {
border-bottom: 8px solid black;
}
EOCSS
html = <<EOHTML
<html><head><title>#{title}</title>
<style type="text/css">#{css}</style></head>
<body>#{body}</body></html>
EOHTML
File.open(output_filename, "w+") do |f|
f.puts html
end
end
end
end

SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__

module COVERAGE__
COVER = {}
def self.trace_func(event, file, line, id, binding, klass)
case event
when 'c-call', 'c-return', 'class'
return
end
COVER[file] ||= []
COVER[file][line] ||= 0
COVER[file][line] += 1
end

END {
set_trace_func(nil)
printer = PrettyCoverage::HTML.new
COVER.each do |file, lines|
next if SCRIPT_LINES__.has_key?(file) == false
lines = SCRIPT_LINES__[file]
covers = COVER[file]
line_status = []
0.upto(lines.size - 1) do |c|
line = lines[c].chomp
marked = false
if covers[c + 1]
marked = true
elsif /^\s*(?:begin\s*(?:#.*)?|ensure\s*(?:#.*)?|else\s*(?:#.*)?)$/ =~ line and covers[c + 1 + 1]
covers[c + 1] = covers[c + 1 + 1]
marked = true
elsif /^\s*(?:end|})\s*$/ =~ line && covers[c + 1 - 1]
covers[c + 1] = covers[c + 1 - 1]
marked = true
end
line_status << [line, marked]
end
printer.add_file(file, line_status)
end
printer.execute
}

set_trace_func(COVERAGE__.method:)trace_func).to_proc)
end
 
R

Robert Klemme

Simon Strandgaard said:
Thanks..

I have done some improvements to the original 'coverage.rb', so that
HTML is now generated. For an example have a look at:
http://neoneye.dk/parser.rb.coverage.html

As you may notice comments/arrays appears as if they are not executed!
How can I fix this?

Dunno whether it's worth the effort. I guess, comments could be fixed by
identifying regions of comment lines and marking them as reached if the
line above and below is reached. For arrays you could try to find the
matching "[" for a closing "]" and mark all lines in between if the line
of the closing "]" is marked.

Apart from that: nice output!

Regards

robert
--
Simon Strandgaard

module PrettyCoverage
class HTML
def initialize
@files = {}
end
def execute
puts "execute"
@files.each{|file, line_marked|
create_file(file, line_marked)
}
create_file_index
end
def mk_filename(name)
name+".coverage.html"
end
def create_file_index
output_filename = "index.html"
rows = []
@files.each{|file, line_marked|
filename = mk_filename(file)
rows << "<tr><td><a href=\"#{filename}\">#{file}</a></td></tr>"
}
result = rows.join("\n")
body = "<table>#{result}</table>"
title = "coverage"
css = <<EOCSS
body {
background-color: rgb(180, 180, 180);
}
div.marked {
background-color: rgb(185, 200, 200);
}
div.overview {
border-bottom: 8px solid black;
}
EOCSS
html = <<EOHTML
<html><head><title>#{title}</title>
<style type="text/css">#{css}</style></head>
<body>#{body}</body></html>
EOHTML
File.open(output_filename, "w+") do |f|
f.puts html
end
end
def add_file(file, line_marked)
percent = calc_coverage(line_marked)
printf("file=#{file} coverage=%02.1f%\n", percent)
@files[file] = line_marked
end
def calc_coverage(line_marked)
marked = line_marked.transpose[1]
n = marked.inject(0) {|r, i| (i) ? (r+1) : r }
percent = n.to_f * 100 / marked.size
end
def format_overview(file, line_marked)
percent = "%02.1f" % calc_coverage(line_marked)
html = <<EOHTML
<div class="overview">
<table>
<tr><td>filename</td><td><tt>#{file}</tt></td></tr>
<tr><td>coverage</td><td>#{percent}</td></tr>
</table>
</div>
EOHTML
html
end
def format_lines(line_marked)
result = ""
last = nil
end_of_div = ""
format_line = "%#{line_marked.size.to_s.size}d"
line_no = 1
line_marked.each {|(line, marked)|
if marked != last
result += end_of_div
case marked
when true
result += "<div class=\"marked\">"
end_of_div = "</div>"
when false
end_of_div = ""
end
end
result += (format_line % line_no) + " " + line + "\n"
last = marked
line_no += 1
}
result += end_of_div
"<pre>#{result}</pre>"
end
def create_file(file, line_marked)
output_filename = mk_filename(file)
puts "outputting #{output_filename.inspect}"
body =
format_overview(file, line_marked) +
format_lines(line_marked)
title = file + " - coverage"
css = <<EOCSS
body {
background-color: rgb(180, 180, 180);
}
div.marked {
background-color: rgb(185, 200, 200);
}
div.overview {
border-bottom: 8px solid black;
}
EOCSS
html = <<EOHTML
<html><head><title>#{title}</title>
<style type="text/css">#{css}</style></head>
<body>#{body}</body></html>
EOHTML
File.open(output_filename, "w+") do |f|
f.puts html
end
end
end
end

SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__

module COVERAGE__
COVER = {}
def self.trace_func(event, file, line, id, binding, klass)
case event
when 'c-call', 'c-return', 'class'
return
end
COVER[file] ||= []
COVER[file][line] ||= 0
COVER[file][line] += 1
end

END {
set_trace_func(nil)
printer = PrettyCoverage::HTML.new
COVER.each do |file, lines|
next if SCRIPT_LINES__.has_key?(file) == false
lines = SCRIPT_LINES__[file]
covers = COVER[file]
line_status = []
0.upto(lines.size - 1) do |c|
line = lines[c].chomp
marked = false
if covers[c + 1]
marked = true
elsif
/^\s*(?:begin\s*(?:#.*)?|ensure\s*(?:#.*)?|else\s*(?:#.*)?)$/ =~ line and
covers[c + 1 + 1]
covers[c + 1] = covers[c + 1 + 1]
marked = true
elsif /^\s*(?:end|})\s*$/ =~ line && covers[c + 1 - 1]
covers[c + 1] = covers[c + 1 - 1]
marked = true
end
line_status << [line, marked]
end
printer.add_file(file, line_status)
end
printer.execute
}

set_trace_func(COVERAGE__.method:)trace_func).to_proc)
end
 
S

Simon Strandgaard

Simon Strandgaard said:
Thanks..

I have done some improvements to the original 'coverage.rb', so that
HTML is now generated. For an example have a look at:
http://neoneye.dk/parser.rb.coverage.html

As you may notice comments/arrays appears as if they are not executed!
How can I fix this?

Dunno whether it's worth the effort. I guess, comments could be fixed by
identifying regions of comment lines and marking them as reached if the
line above and below is reached. For arrays you could try to find the
matching "[" for a closing "]" and mark all lines in between if the line
of the closing "]" is marked.

Apart from that: nice output!

Ok.. I now propagate the marked status to comments.. output is much better
now. Still Arrays/Hashes/=begin=end needs to be fixed.

Try compare the new output agains the old:
http://neoneye.dk/parser.rb.coverage.ver2.html

Suggestions for improvements is welcome.. also patches is welcome.

For the courius; try to execute the attached code by
requiring it on the commandline.
ruby -rcoverage helloworld.rb
That should output a 'helloworld.rb.coverage.html' file.

--
Simon Strandgaard

module PrettyCoverage
class HTML
def initialize
@files = {}
end
def execute
puts "execute"
create_file_index
@files.each{|file, line_marked|
create_file(file, line_marked)
}
end
def mk_filename(name)
name+".coverage.html"
end
def create_file_index
output_filename = "index.html"
rows = []
@files.each{|file, line_marked|
filename = mk_filename(file)
rows << "<tr><td><a href=\"#{filename}\">#{file}</a></td></tr>"
}
result = rows.join("\n")
body = "<table>#{result}</table>"
title = "coverage"
css = <<EOCSS
body {
background-color: rgb(180, 180, 180);
}
div.marked {
background-color: rgb(185, 200, 200);
}
div.overview {
border-bottom: 8px solid black;
}
EOCSS
html = <<EOHTML
<html><head><title>#{title}</title>
<style type="text/css">#{css}</style></head>
<body>#{body}</body></html>
EOHTML
File.open(output_filename, "w+") do |f|
f.puts html
end
end
def add_file(file, line_marked)
percent = calc_coverage(line_marked)
printf("file=#{file} coverage=%02.1f%\n", percent)

# comments and empty lines.. we must
# propagate marked-value backwards
line_marked << ["", false]
(line_marked.size).downto(1) do |index|
line, marked = line_marked[index-1]
next_line, next_marked = line_marked[index]
if line =~ /^\s*(#|$)/ and marked == false
marked = next_marked
#line = "hest" + line
line_marked[index-1] = [line, marked]
end
end
line_marked.pop

@files[file] = line_marked
end
def calc_coverage(line_marked)
marked = line_marked.transpose[1]
n = marked.inject(0) {|r, i| (i) ? (r+1) : r }
percent = n.to_f * 100 / marked.size
end
def format_overview(file, line_marked)
percent = "%02.1f" % calc_coverage(line_marked)
html = <<EOHTML
<div class="overview">
<table>
<tr><td>filename</td><td><tt>#{file}</tt></td></tr>
<tr><td>coverage</td><td>#{percent}</td></tr>
</table>
</div>
EOHTML
html
end
def format_lines(line_marked)
result = ""
last = nil
end_of_div = ""
format_line = "%#{line_marked.size.to_s.size}d"
line_no = 1
line_marked.each {|(line, marked)|
if marked != last
result += end_of_div
case marked
when true
result += "<div class=\"marked\">"
end_of_div = "</div>"
when false
end_of_div = ""
end
end
result += (format_line % line_no) + " " + line + "\n"
last = marked
line_no += 1
}
result += end_of_div
"<pre>#{result}</pre>"
end
def create_file(file, line_marked)
output_filename = mk_filename(file)
puts "outputting #{output_filename.inspect}"
body =
format_overview(file, line_marked) +
format_lines(line_marked)
title = file + " - coverage"
css = <<EOCSS
body {
background-color: rgb(180, 180, 180);
}
div.marked {
background-color: rgb(185, 200, 200);
}
div.overview {
border-bottom: 8px solid black;
}
EOCSS
html = <<EOHTML
<html><head><title>#{title}</title>
<style type="text/css">#{css}</style></head>
<body>#{body}</body></html>
EOHTML
File.open(output_filename, "w+") do |f|
f.puts html
end
end
end
end

SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__

module COVERAGE__
COVER = {}
def self.trace_func(event, file, line, id, binding, klass)
case event
when 'c-call', 'c-return', 'class'
return
end
COVER[file] ||= []
COVER[file][line] ||= 0
COVER[file][line] += 1
end

END {
set_trace_func(nil)
printer = PrettyCoverage::HTML.new
COVER.each do |file, lines|
next if SCRIPT_LINES__.has_key?(file) == false
lines = SCRIPT_LINES__[file]
covers = COVER[file]
line_status = []
0.upto(lines.size - 1) do |c|
line = lines[c].chomp
marked = false
if covers[c + 1]
marked = true
elsif /^\s*(?:begin\s*(?:#.*)?|ensure\s*(?:#.*)?|else\s*(?:#.*)?)$/ =~ line and covers[c + 1 + 1]
covers[c + 1] = covers[c + 1 + 1]
marked = true
elsif /^\s*(?:end|})\s*$/ =~ line && covers[c + 1 - 1]
covers[c + 1] = covers[c + 1 - 1]
marked = true
end
line_status << [line, marked]
end
printer.add_file(file, line_status)
end
printer.execute
}

set_trace_func(COVERAGE__.method:)trace_func).to_proc)
end
 
R

Robert Klemme

Simon Strandgaard said:
Simon Strandgaard said:
30:04 +0900,
Simon Strandgaard wrote:
If I do "cat report.txt" then my terminal just scrolls for 10 seconds,
which is much larger than what my terminal history can remember.
If I pipe it into "less" then the coloring disappears. How do you view
ANSI files?

less -r

Thanks..

I have done some improvements to the original 'coverage.rb', so that
HTML is now generated. For an example have a look at:
http://neoneye.dk/parser.rb.coverage.html

As you may notice comments/arrays appears as if they are not executed!
How can I fix this?

Dunno whether it's worth the effort. I guess, comments could be fixed by
identifying regions of comment lines and marking them as reached if the
line above and below is reached. For arrays you could try to find the
matching "[" for a closing "]" and mark all lines in between if the line
of the closing "]" is marked.

Apart from that: nice output!

Ok.. I now propagate the marked status to comments.. output is much better
now. Still Arrays/Hashes/=begin=end needs to be fixed.

Try compare the new output agains the old:
http://neoneye.dk/parser.rb.coverage.ver2.html

Suggestions for improvements is welcome.. also patches is welcome.

Apparently "end" lines are not reported so the comment is marked "not
reached" in line 72. Maybe it's better to check the reached status of the
last line before a comment region. This should also be easier to do.

Regards

robert
For the courius; try to execute the attached code by
requiring it on the commandline.
ruby -rcoverage helloworld.rb
That should output a 'helloworld.rb.coverage.html' file.

--
Simon Strandgaard

module PrettyCoverage
class HTML
def initialize
@files = {}
end
def execute
puts "execute"
create_file_index
@files.each{|file, line_marked|
create_file(file, line_marked)
}
end
def mk_filename(name)
name+".coverage.html"
end
def create_file_index
output_filename = "index.html"
rows = []
@files.each{|file, line_marked|
filename = mk_filename(file)
rows << "<tr><td><a href=\"#{filename}\">#{file}</a></td></tr>"
}
result = rows.join("\n")
body = "<table>#{result}</table>"
title = "coverage"
css = <<EOCSS
body {
background-color: rgb(180, 180, 180);
}
div.marked {
background-color: rgb(185, 200, 200);
}
div.overview {
border-bottom: 8px solid black;
}
EOCSS
html = <<EOHTML
<html><head><title>#{title}</title>
<style type="text/css">#{css}</style></head>
<body>#{body}</body></html>
EOHTML
File.open(output_filename, "w+") do |f|
f.puts html
end
end
def add_file(file, line_marked)
percent = calc_coverage(line_marked)
printf("file=#{file} coverage=%02.1f%\n", percent)

# comments and empty lines.. we must
# propagate marked-value backwards
line_marked << ["", false]
(line_marked.size).downto(1) do |index|
line, marked = line_marked[index-1]
next_line, next_marked = line_marked[index]
if line =~ /^\s*(#|$)/ and marked == false
marked = next_marked
#line = "hest" + line
line_marked[index-1] = [line, marked]
end
end
line_marked.pop

@files[file] = line_marked
end
def calc_coverage(line_marked)
marked = line_marked.transpose[1]
n = marked.inject(0) {|r, i| (i) ? (r+1) : r }
percent = n.to_f * 100 / marked.size
end
def format_overview(file, line_marked)
percent = "%02.1f" % calc_coverage(line_marked)
html = <<EOHTML
<div class="overview">
<table>
<tr><td>filename</td><td><tt>#{file}</tt></td></tr>
<tr><td>coverage</td><td>#{percent}</td></tr>
</table>
</div>
EOHTML
html
end
def format_lines(line_marked)
result = ""
last = nil
end_of_div = ""
format_line = "%#{line_marked.size.to_s.size}d"
line_no = 1
line_marked.each {|(line, marked)|
if marked != last
result += end_of_div
case marked
when true
result += "<div class=\"marked\">"
end_of_div = "</div>"
when false
end_of_div = ""
end
end
result += (format_line % line_no) + " " + line + "\n"
last = marked
line_no += 1
}
result += end_of_div
"<pre>#{result}</pre>"
end
def create_file(file, line_marked)
output_filename = mk_filename(file)
puts "outputting #{output_filename.inspect}"
body =
format_overview(file, line_marked) +
format_lines(line_marked)
title = file + " - coverage"
css = <<EOCSS
body {
background-color: rgb(180, 180, 180);
}
div.marked {
background-color: rgb(185, 200, 200);
}
div.overview {
border-bottom: 8px solid black;
}
EOCSS
html = <<EOHTML
<html><head><title>#{title}</title>
<style type="text/css">#{css}</style></head>
<body>#{body}</body></html>
EOHTML
File.open(output_filename, "w+") do |f|
f.puts html
end
end
end
end

SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__

module COVERAGE__
COVER = {}
def self.trace_func(event, file, line, id, binding, klass)
case event
when 'c-call', 'c-return', 'class'
return
end
COVER[file] ||= []
COVER[file][line] ||= 0
COVER[file][line] += 1
end

END {
set_trace_func(nil)
printer = PrettyCoverage::HTML.new
COVER.each do |file, lines|
next if SCRIPT_LINES__.has_key?(file) == false
lines = SCRIPT_LINES__[file]
covers = COVER[file]
line_status = []
0.upto(lines.size - 1) do |c|
line = lines[c].chomp
marked = false
if covers[c + 1]
marked = true
elsif
/^\s*(?:begin\s*(?:#.*)?|ensure\s*(?:#.*)?|else\s*(?:#.*)?)$/ =~ line and
covers[c + 1 + 1]
covers[c + 1] = covers[c + 1 + 1]
marked = true
elsif /^\s*(?:end|})\s*$/ =~ line && covers[c + 1 - 1]
covers[c + 1] = covers[c + 1 - 1]
marked = true
end
line_status << [line, marked]
end
printer.add_file(file, line_status)
end
printer.execute
}

set_trace_func(COVERAGE__.method:)trace_func).to_proc)
end
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,142
Messages
2,570,819
Members
47,367
Latest member
mahdiharooniir

Latest Threads

Top