require 'test/unit'
require 'rcov'
class Test_FileStatistics < Test::Unit::TestCase
def test_trailing_end_is_inferred
verify_everything_marked "trailing end", <<-EOF
1 class X
1 def foo
2 "foo"
0 end
0 end
EOF
verify_everything_marked "trailing end with comments", <<-EOF
1 class X
1 def foo
2 "foo"
0 end
0 # foo bar
0 =begin
0 ....
0 =end
0 end
EOF
end
def test_begin_ensure_else_case_are_inferred
verify_everything_marked "begin ensure else case", <<-EOF
0 begin
# bleh
2 puts a
0 begin
2 raise "foo"
0 rescue Exception => e
2 puts b
0 ensure
2 puts c
0 end
2 if a()
1 b
0 else
1 c
0 end
0 case
2 when bar =~ /foo/
1 puts "bar"
0 else
1 puts "baz"
0 end
0 end
EOF
end
def test_rescue_is_inferred
verify_everything_marked "rescue", <<-EOF
0 begin
1 foo
0 rescue
1 puts "bar"
0 end
EOF
end
def test_code_metrics_are_computed_correctly
lines, coverage, counts = code_info_from_string <<-EOF
1 a = 1
0 # this is a comment
1 if bar
0 b = 2
0 end
0 =begin
0 this too
0 bleh
0 =end
0 puts <<EOF
0 bleh
0 EOF
3 c.times{ i += 1}
EOF
sf = Rcov::FileStatistics.new("metrics", lines, counts)
assert_in_delta(0.307, sf.total_coverage, 0.01)
assert_in_delta(0.375, sf.code_coverage, 0.01)
assert_equal(8, sf.num_code_lines)
assert_equal(13, sf.num_lines)
assert_equal([true, :inferred, true, false, false, false, false, false,
false, false, false, false, true], sf.coverage.to_a)
end
def test_merge
lines, coverage, counts = code_info_from_string <<-EOF
1 a = 1
1 if bar
0 b = 2
0 end
1 puts <<EOF
0 bleh
0 EOF
3 c.times{ i += 1}
EOF
sf = Rcov::FileStatistics.new("merge", lines, counts)
lines, coverage, counts = code_info_from_string <<-EOF
1 a = 1
1 if bar
1 b = 2
0 end
1 puts <<EOF
0 bleh
0 EOF
10 c.times{ i += 1}
EOF
sf2 = Rcov::FileStatistics.new("merge", lines, counts)
expected = [true, true, true, :inferred, true, :inferred, :inferred, true]
assert_equal(expected, sf2.coverage.to_a)
sf.merge(sf2.lines, sf2.coverage, sf2.counts)
assert_equal(expected, sf.coverage.to_a)
assert_equal([2, 2, 1, 0, 2, 0, 0, 13], sf.counts)
end
def test_last_comment_block_is_marked
verify_everything_marked "last comment block", <<-EOF
1 a = 1
1 b = 1
0 # foo
0 # bar baz
EOF
verify_everything_marked "last comment block, =begin/=end", <<-EOF
1 a = 1
2 b = 1
0 # fooo
0 =begin
0 bar baz
0 =end
EOF
verify_everything_marked "last comment block, __END__", <<-EOF
1 a = 1
2 b = 1
0 # fooo
0 =begin
0 bar baz
0 =end
__END__
EOF
end
def test_heredocs_basic
verify_everything_marked "heredocs-basic.rb", <<-EOF
1 puts 1 + 1
1 puts <<HEREDOC
0 first line of the heredoc
0 not marked
0 but should be
0 HEREDOC
1 puts 1
EOF
verify_everything_marked "squote", <<-EOF
1 puts <<'HEREDOC'
0 first line of the heredoc
0 HEREDOC
EOF
verify_everything_marked "dquote", <<-EOF
1 puts <<"HEREDOC"
0 first line of the heredoc
0 HEREDOC
EOF
verify_everything_marked "xquote", <<-EOF
1 puts <<`HEREDOC`
0 first line of the heredoc
0 HEREDOC
EOF
verify_everything_marked "stuff-after-heredoc", <<-EOF
1 full_message = build_message(msg, <<EOT, object1, object2)
0 <?> and <?> do not contain the same elements
0 EOT
EOF
end
def test_heredocs_multiple
verify_everything_marked "multiple-unquoted", <<-EOF
1 puts <<HEREDOC, <<HERE2
0 first line of the heredoc
0 HEREDOC
0 second heredoc
0 HERE2
EOF
verify_everything_marked "multiple-quoted", <<-EOF
1 puts <<'HEREDOC', <<`HERE2`, <<"HERE3"
0 first line of the heredoc
0 HEREDOC
0 second heredoc
0 HERE2
0 dsfdsfffd
0 HERE3
EOF
verify_everything_marked "same-identifier", <<-EOF
1 puts <<H, <<H
0 foo
0 H
0 bar
0 H
EOF
verify_everything_marked "stuff-after-heredoc", <<-EOF
1 full_message = build_message(msg, <<EOT, object1, object2, <<EOT)
0 <?> and <?> do not contain the same elements
0 EOT
0 <?> and <?> are foo bar baz
0 EOT
EOF
end
def test_ignore_non_heredocs
verify_marked_exactly "bitshift-numeric", [0], <<-EOF
1 puts 1<<2
0 return if foo
0 do_stuff()
0 2
EOF
verify_marked_exactly "bitshift-symbolic", [0], <<-EOF
1 puts 1<<LSHIFT
0 return if bar
0 do_stuff()
0 LSHIFT
EOF
verify_marked_exactly "bitshift-symbolic-multi", 0..3, <<-EOF
1 puts <<EOF, 1<<LSHIFT
0 random text
0 EOF
1 return if bar
0 puts "foo"
0 LSHIFT
EOF
verify_marked_exactly "bitshift-symshift-evil", 0..2, <<-EOF
1 foo = 1
1 puts foo<<CONS
1 return if bar
0 foo + baz
EOF
end
def test_heredocs_with_interpolation_alone_in_method
verify_everything_marked "lonely heredocs with interpolation", <<-'EOS'
1 def to_s
0 <<-EOF
1 #{name}
0 #{street}
0 #{city}, #{state}
0 #{zip}
0 EOF
0 end
EOS
end
def test_handle_multiline_expressions
verify_everything_marked "expression", <<-EOF
1 puts 1, 2.
0 abs +
0 1 -
0 1 *
0 1 /
0 1, 1 <
0 2, 3 >
0 4 %
0 3 &&
0 true ||
0 foo <<
0 bar(
0 baz[
0 {
0 1,2}] =
0 1 )
EOF
verify_everything_marked "boolean expression", <<-EOF
1 x = (foo and
0 bar) or
0 baz
EOF
verify_marked_exactly "code blocks", [0, 3, 6], <<-EOF
1 x = foo do # stuff
0 baz
0 end
1 bar do |x|
0 baz
0 end
1 bar {|a, b| # bleh | +1
0 baz
0 }
EOF
verify_everything_marked "escaped linebreaks", <<-EOF
1 def t2
0 puts \\
1 "foo"
0 end
0 end
EOF
end
def test_handle_multiline_blocks_first_not_marked
verify_everything_marked "multiline block first not marked", <<-'EOF'
1 blah = Array.new
1 10.times do
0 blah << lambda do |f|
1 puts "I should say #{f}!"
0 end
0 end
EOF
end
def test_handle_multiline_blocks_last_line_not_marked
verify_everything_marked "multiline block last not marked", <<-'EOF'
1 blee = [1, 2, 3]
0 blee.map! do |e|
1 [e, e]
0 end.flatten!
1 p blee
EOF
end
def test_handle_multiline_data_with_trailing_stuff_on_last_line
verify_everything_marked "multiline data hash", <<-'EOF'
1 @review = Review.new({
0 :product_id => params[:id],
0 :user => current_user
0 }.merge(params[:review])) #red
1 @review.save
EOF
end
def test_handle_multiline_expression_1st_line_ends_in_block_header
# excerpt taken from mongrel/handlers.rb
verify_everything_marked "multiline with block starting on 1st", <<-EOF
1 uris = listener.classifier.handler_map
0 results << table("handlers", uris.map {|uri,handlers|
1 [uri,
0 "<pre>" +
1 handlers.map {|h| h.class.to_s }.join("\n") +
0 "</pre>"
0 ]
1 })
EOF
end
def test_handle_multiple_block_end_delimiters_in_empty_line
verify_everything_marked "multiline with }) delimiter, forward", <<-EOF
1 assert(@c.config == {
0 'host' => 'myhost.tld',
0 'port' => 1234
0 })
EOF
verify_everything_marked "multiline with }) delimiter, backwards", <<-EOF
0 assert(@c.config == {
0 'host' => 'myhost.tld',
0 'port' => 1234
1 })
EOF
end
STRING_DELIMITER_PAIRS = [
%w-%{ }-, %w-%q{ }-, %w-%Q{ }-, %w{%[ ]}, %w{%q[ ]},
%w{%( )}, %w{%Q( )}, %w{%Q[ ]}, %w{%q! !}, %w{%! !},
]
def test_multiline_strings_basic
STRING_DELIMITER_PAIRS.each do |s_delim, e_delim|
verify_everything_marked "multiline strings, basic #{s_delim}", <<-EOF
1 PATTERN_TEXT = #{s_delim}
0 NUMBERS = 'one|two|three|four|five'
0 ON_OFF = 'on|off'
0 #{e_delim}
EOF
end
STRING_DELIMITER_PAIRS.each do |s_delim, e_delim|
verify_marked_exactly "multiline strings, escaped #{s_delim}", [0], <<-EOF
1 PATTERN_TEXT = #{s_delim} foooo bar baz \\#{e_delim} baz #{e_delim}
0 NUMBERS = 'one|two|three|four|five'
0 ON_OFF = 'on|off'
EOF
verify_marked_exactly "multiline strings, #{s_delim}, interpolation",
[0], <<-EOF
1 PATTERN_TEXT = #{s_delim} \#{#{s_delim} foo #{e_delim}} \\#{e_delim} baz #{e_delim}
0 NUMBERS = 'one|two|three|four|five'
0 ON_OFF = 'on|off'
EOF
end
end
def test_multiline_strings_escaped_delimiter
STRING_DELIMITER_PAIRS.each do |s_delim, e_delim|
verify_everything_marked "multiline, escaped #{s_delim}", <<-EOF
1 PATTERN_TEXT = #{s_delim} foo \\#{e_delim}
0 NUMBERS = 'one|two|three|four|five'
0 ON_OFF = 'on|off'
0 #{e_delim}
EOF
end
end
def test_handle_multiline_expressions_with_heredocs
verify_everything_marked "multiline and heredocs", <<-EOF
1 puts <<EOF +
0 testing
0 one two three
0 EOF
0 somevar
EOF
end
def test_begin_end_comment_blocks
verify_everything_marked "=begin/=end", <<-EOF
1 x = foo
0 =begin
0 return if bar(x)
0 =end
1 y = 1
EOF
end
def test_is_code_p
verify_is_code "basic", [true] + [false] * 5 + [true], <<-EOF
1 x = foo
0 =begin
0 return if bar
0 =end
0 # foo
0 # bar
1 y = 1
EOF
end
def test_is_code_p_tricky_heredocs
verify_is_code "tricky heredocs", [true] * 4, <<-EOF
2 x = foo <<EOF and return
0 =begin
0 EOF
0 z = x + 1
EOF
end
def verify_is_code(testname, is_code_arr, str)
lines, coverage, counts = code_info_from_string str
sf = Rcov::FileStatistics.new(testname, lines, counts)
is_code_arr.each_with_index do |val,i|
assert_equal(val, sf.is_code?(i),
"Unable to detect =begin comments properly: #{lines[i].inspect}")
end
end
def verify_marked_exactly(testname, marked_indices, str)
lines, coverage, counts = code_info_from_string(str)
sf = Rcov::FileStatistics.new(testname, lines, counts)
lines.size.times do |i|
if marked_indices.include? i
assert(sf.coverage[i], "Test #{testname}; " +
"line should have been marked: #{lines[i].inspect}.")
else
assert(!sf.coverage[i], "Test #{testname}; " +
"line should not have been marked: #{lines[i].inspect}.")
end
end
end
def verify_everything_marked(testname, str)
verify_marked_exactly(testname, (0...str.size).to_a, str)
end
def code_info_from_string(str)
str = str.gsub(/^\s*/,"")
[ str.map{|line| line.sub(/^\d+ /, "") },
str.map{|line| line[/^\d+/].to_i > 0},
str.map{|line| line[/^\d+/].to_i } ]
end
end
syntax highlighted by Code2HTML, v. 0.9.1