rcov 0.5.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ a = 1
2
+ if a == 2
3
+ b = 1
4
+ else
5
+ b = 2
6
+ end
7
+ 10.times{ b += 1 }
@@ -0,0 +1,5 @@
1
+ module Rcov; module Test; module Temporary; module Sample02
2
+ def self.foo(a,b)
3
+ a + b
4
+ end
5
+ end end end end
@@ -0,0 +1,20 @@
1
+
2
+ module Rcov; module Test; module Temporary; class Sample03
3
+ def f1 # MUST NOT CHANGE the position or the tests will break
4
+ 10.times { f2 }
5
+ end
6
+
7
+ def f2; 1 end
8
+
9
+ def f3
10
+ 10.times{ f1 }
11
+ 100.times{ f2 }
12
+ end
13
+
14
+ def self.g1
15
+ 10.times{ g2 }
16
+ end
17
+
18
+ def self.g2; 1 end
19
+ # safe from here ...
20
+ end end end end
@@ -0,0 +1,172 @@
1
+
2
+
3
+ require 'test/unit'
4
+ require 'rcov'
5
+
6
+ class Test_CallSiteAnalyzer < Test::Unit::TestCase
7
+
8
+ sample_file = File.join(File.dirname(__FILE__), "sample_03.rb")
9
+ load sample_file
10
+
11
+ def setup
12
+ @a = Rcov::CallSiteAnalyzer.new
13
+ @o = Rcov::Test::Temporary::Sample03.new
14
+ end
15
+
16
+ def verify_callsites_equal(expected, actual)
17
+ callsites = expected.inject({}) do |s,(desc, count)|
18
+ s[Rcov::CallSiteAnalyzer::CallSite.new(desc)] = count
19
+ s
20
+ end
21
+ assert_equal(callsites, actual)
22
+ end
23
+
24
+ def verify_defsite_equal(expected, actual)
25
+ assert_equal(Rcov::CallSiteAnalyzer::DefSite.new(*expected), actual)
26
+ end
27
+
28
+ def test_callsite_compute_raw_difference
29
+ src = [
30
+ { ["Foo", "foo"] => {"bar" => 1},
31
+ ["Foo", "bar"] => {"baz" => 10} },
32
+ { ["Foo", "foo"] => ["foo.rb", 10] }
33
+ ]
34
+ dst = [
35
+ { ["Foo", "foo"] => {"bar" => 1, "fubar" => 10},
36
+ ["Foo", "baz"] => {"baz" => 10} },
37
+ { ["Foo", "foo"] => ["fooredef.rb", 10],
38
+ ["Foo", "baz"] => ["foo.rb", 20]}
39
+ ]
40
+ expected = [
41
+ { ["Foo", "foo"] => {"fubar" => 10},
42
+ ["Foo", "baz"] => {"baz" => 10} },
43
+ { ["Foo", "foo"] => ["fooredef.rb", 10],
44
+ ["Foo", "baz"] => ["foo.rb", 20] }
45
+ ]
46
+
47
+ assert_equal(expected,
48
+ @a.instance_eval{ compute_raw_data_difference(src, dst) } )
49
+ end
50
+
51
+ def test_return_values_when_no_match
52
+ @a.run_hooked{ @o.f1 }
53
+ assert_equal(nil, @a.defsite("Foobar#bogus"))
54
+ assert_equal(nil, @a.defsite("Foobar", "bogus"))
55
+ assert_equal(nil, @a.callsites("Foobar", "bogus"))
56
+ assert_equal(nil, @a.callsites("Foobar.bogus"))
57
+ assert_equal(nil, @a.callsites("<Class:Foobar>", "bogus"))
58
+ end
59
+
60
+ def test_basic_defsite_recording
61
+ @a.run_hooked{ @o.f1 }
62
+ verify_defsite_equal(["./test/sample_03.rb", 3],
63
+ @a.defsite("Rcov::Test::Temporary::Sample03", "f1"))
64
+ verify_defsite_equal(["./test/sample_03.rb", 7],
65
+ @a.defsite("Rcov::Test::Temporary::Sample03", "f2"))
66
+ verify_defsite_equal(["./test/sample_03.rb", 7],
67
+ @a.defsite("Rcov::Test::Temporary::Sample03#f2"))
68
+ end
69
+
70
+ def test_basic_callsite_recording
71
+ @a.run_hooked{ @o.f1 }
72
+ assert(@a.analyzed_classes.include?("Rcov::Test::Temporary::Sample03"))
73
+ assert_equal(%w[f1 f2], @a.analyzed_methods("Rcov::Test::Temporary::Sample03"))
74
+ verify_callsites_equal({["./test/sample_03.rb:4:in `f1'"] => 10},
75
+ @a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
76
+ verify_callsites_equal({["./test/sample_03.rb:4:in `f1'"] => 10},
77
+ @a.callsites("Rcov::Test::Temporary::Sample03#f2"))
78
+ end
79
+
80
+ def test_basic_callsite_recording_API
81
+ @a.run_hooked{ @o.f1 }
82
+ assert(@a.analyzed_classes.include?("Rcov::Test::Temporary::Sample03"))
83
+ assert_equal(%w[f1 f2], @a.analyzed_methods("Rcov::Test::Temporary::Sample03"))
84
+ verify_callsites_equal({["./test/sample_03.rb:4:in `f1'"] => 10},
85
+ @a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
86
+ callsites = @a.callsites("Rcov::Test::Temporary::Sample03", "f2")
87
+ callsite = callsites.keys[0]
88
+ assert_equal("./test/sample_03.rb", callsite.file)
89
+ assert_equal(4, callsite.line)
90
+ assert_equal("f1", callsite.calling_method)
91
+ end
92
+
93
+ def test_basic_callsite_recording_with_singleton_classes
94
+ @a.run_hooked{ @o.class.g1 }
95
+ assert(@a.analyzed_classes.include?("#<Class:Rcov::Test::Temporary::Sample03>"))
96
+ assert_equal(%w[g1 g2], @a.analyzed_methods("#<Class:Rcov::Test::Temporary::Sample03>"))
97
+ verify_callsites_equal({["./test/sample_03.rb:15:in `g1'"] => 10},
98
+ @a.callsites("Rcov::Test::Temporary::Sample03.g2"))
99
+ verify_callsites_equal({["./test/sample_03.rb:15:in `g1'"] => 10},
100
+ @a.callsites("#<Class:Rcov::Test::Temporary::Sample03>","g2"))
101
+ end
102
+
103
+
104
+ def test_differential_callsite_recording
105
+ @a.run_hooked{ @o.f1 }
106
+ assert(@a.analyzed_classes.include?("Rcov::Test::Temporary::Sample03"))
107
+ assert_equal(%w[f1 f2], @a.analyzed_methods("Rcov::Test::Temporary::Sample03"))
108
+ verify_callsites_equal({["./test/sample_03.rb:4:in `f1'"] => 10},
109
+ @a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
110
+
111
+ @a.run_hooked{ @o.f1 }
112
+ assert(@a.analyzed_classes.include?("Rcov::Test::Temporary::Sample03"))
113
+ assert_equal(%w[f1 f2], @a.analyzed_methods("Rcov::Test::Temporary::Sample03"))
114
+ verify_callsites_equal({["./test/sample_03.rb:4:in `f1'"] => 20},
115
+ @a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
116
+
117
+ @a.run_hooked{ @o.f3 }
118
+ assert_equal(%w[f1 f2 f3], @a.analyzed_methods("Rcov::Test::Temporary::Sample03"))
119
+ verify_callsites_equal({["./test/sample_03.rb:4:in `f1'"] => 120,
120
+ ["./test/sample_03.rb:11:in `f3'"]=>100 },
121
+ @a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
122
+ end
123
+
124
+ def test_reset
125
+ @a.run_hooked do
126
+ 10.times{ @o.f1 }
127
+ @a.reset
128
+ @o.f1
129
+ end
130
+ assert(@a.analyzed_classes.include?("Rcov::Test::Temporary::Sample03"))
131
+ assert_equal(%w[f1 f2], @a.analyzed_methods("Rcov::Test::Temporary::Sample03"))
132
+ verify_callsites_equal({["./test/sample_03.rb:4:in `f1'"] => 10},
133
+ @a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
134
+
135
+ end
136
+
137
+ def test_nested_callsite_recording
138
+ a = Rcov::CallSiteAnalyzer.new
139
+ b = Rcov::CallSiteAnalyzer.new
140
+ a.run_hooked do
141
+ b.run_hooked { @o.f1 }
142
+ assert(b.analyzed_classes.include?("Rcov::Test::Temporary::Sample03"))
143
+ assert_equal(%w[f1 f2], b.analyzed_methods("Rcov::Test::Temporary::Sample03"))
144
+ verify_callsites_equal({["./test/sample_03.rb:4:in `f1'"] => 10},
145
+ b.callsites("Rcov::Test::Temporary::Sample03", "f2"))
146
+
147
+ @o.f1
148
+ assert_equal(%w[f1 f2], b.analyzed_methods("Rcov::Test::Temporary::Sample03"))
149
+ verify_callsites_equal({["./test/sample_03.rb:4:in `f1'"] => 10},
150
+ b.callsites("Rcov::Test::Temporary::Sample03", "f2"))
151
+
152
+ assert(a.analyzed_classes.include?("Rcov::Test::Temporary::Sample03"))
153
+ assert_equal(%w[f1 f2], a.analyzed_methods("Rcov::Test::Temporary::Sample03"))
154
+ verify_callsites_equal({["./test/sample_03.rb:4:in `f1'"] => 20},
155
+ a.callsites("Rcov::Test::Temporary::Sample03", "f2"))
156
+ end
157
+ b.run_hooked{ @o.f3 }
158
+ assert_equal(%w[f1 f2 f3], b.analyzed_methods("Rcov::Test::Temporary::Sample03"))
159
+ verify_callsites_equal({["./test/sample_03.rb:4:in `f1'"] => 110,
160
+ ["./test/sample_03.rb:11:in `f3'"]=>100 },
161
+ b.callsites("Rcov::Test::Temporary::Sample03", "f2"))
162
+ end
163
+
164
+ def test_expand_name
165
+ assert_equal(["Foo", "foo"], @a.instance_eval{ expand_name("Foo#foo") })
166
+ assert_equal(["Foo", "foo"], @a.instance_eval{ expand_name("Foo", "foo") })
167
+ assert_equal(["#<Class:Foo>", "foo"],
168
+ @a.instance_eval{ expand_name("Foo.foo") })
169
+ assert_equal(["#<Class:Foo>", "foo"],
170
+ @a.instance_eval{ expand_name("#<Class:Foo>", "foo") })
171
+ end
172
+ end
@@ -0,0 +1,183 @@
1
+
2
+ require 'test/unit'
3
+ require 'rcov'
4
+
5
+ class Test_CodeCoverageAnalyzer < Test::Unit::TestCase
6
+ LINES = <<-EOF.to_a
7
+ puts 1
8
+ if foo
9
+ bar
10
+ baz
11
+ end
12
+ 5.times do
13
+ foo
14
+ bar if baz
15
+ end
16
+ EOF
17
+
18
+ def setup
19
+ if defined? Rcov::Test::Temporary
20
+ Rcov::Test::Temporary.constants.each do |name|
21
+ Rcov::Test::Temporary.module_eval{ remove_const(name) }
22
+ end
23
+ end
24
+ end
25
+
26
+ def test_refine_coverage_info
27
+ analyzer = Rcov::CodeCoverageAnalyzer.new
28
+ cover = [1, 1, nil, nil, 0, 5, 5, 5, 0]
29
+ line_info, marked_info,
30
+ count_info = analyzer.instance_eval{ refine_coverage_info(LINES, cover) }
31
+ assert_equal(LINES.map{|l| l.chomp}, line_info)
32
+ assert_equal([true] * 2 + [false] * 3 + [true] * 3 + [false], marked_info)
33
+ assert_equal([1, 1, 0, 0, 0, 5, 5, 5, 0], count_info)
34
+ end
35
+
36
+ def test_analyzed_files_no_analysis
37
+ analyzer = Rcov::CodeCoverageAnalyzer.new
38
+ assert_equal([], analyzer.analyzed_files)
39
+ end
40
+
41
+ def test_raw_coverage_info
42
+ sample_file = File.join(File.dirname(__FILE__), "sample_01.rb")
43
+ lines = File.readlines(sample_file)
44
+ analyzer = Rcov::CodeCoverageAnalyzer.new
45
+ analyzer.run_hooked{ load sample_file }
46
+
47
+ assert_equal(lines, SCRIPT_LINES__[sample_file][0, lines.size])
48
+ assert(analyzer.analyzed_files.include?(sample_file))
49
+ line_info, cov_info, count_info = analyzer.data(sample_file)
50
+ assert_equal(lines.map{|l| l.chomp}, line_info)
51
+ assert_equal([true, true, false, false, true, false, true], cov_info)
52
+ assert_equal([1, 2, 0, 0, 1, 0, 11], count_info)
53
+ analyzer.reset
54
+ assert_equal(nil, analyzer.data(sample_file))
55
+ assert_equal([], analyzer.analyzed_files)
56
+ end
57
+
58
+ def test_script_lines_workaround_detects_correctly
59
+ analyzer = Rcov::CodeCoverageAnalyzer.new
60
+ lines = ["puts a", "foo", "bar"] * 3
61
+ coverage = [true] * 3 + [false] * 6
62
+ counts = [1] * 3 + [0] * 6
63
+ nlines, ncoverage, ncounts = analyzer.instance_eval do
64
+ script_lines_workaround(lines, coverage, counts)
65
+ end
66
+
67
+ assert_equal(["puts a", "foo", "bar"], nlines)
68
+ assert_equal([true, true, true], ncoverage)
69
+ assert_equal([1, 1, 1], ncounts)
70
+ end
71
+
72
+ def test_script_lines_workaround_no_false_positives
73
+ analyzer = Rcov::CodeCoverageAnalyzer.new
74
+ lines = ["puts a", "foo", "bar"] * 2 + ["puts a", "foo", "baz"]
75
+ coverage = [true] * 9
76
+ counts = [1] * 9
77
+ nlines, ncoverage, ncounts = analyzer.instance_eval do
78
+ script_lines_workaround(lines, coverage, counts)
79
+ end
80
+ assert_equal(lines, nlines)
81
+ assert_equal(coverage, ncoverage)
82
+ assert_equal(counts, ncounts)
83
+ end
84
+
85
+ def test_differential_coverage_data
86
+ sample_file = File.join(File.dirname(__FILE__), "sample_01.rb")
87
+ lines = File.readlines(sample_file)
88
+ analyzer = Rcov::CodeCoverageAnalyzer.new
89
+ analyzer.run_hooked{ load sample_file }
90
+ line_info, cov_info, count_info = analyzer.data(sample_file)
91
+ assert_equal([1, 2, 0, 0, 1, 0, 11], count_info)
92
+
93
+ analyzer.reset
94
+
95
+ sample_file = File.join(File.dirname(__FILE__), "sample_02.rb")
96
+ analyzer.run_hooked{ load sample_file }
97
+ line_info, cov_info, count_info = analyzer.data(sample_file)
98
+ assert_equal([8, 1, 0, 0, 0], count_info)
99
+
100
+ analyzer.reset
101
+ assert_equal([], analyzer.analyzed_files)
102
+ analyzer.run_hooked{ Rcov::Test::Temporary::Sample02.foo(1, 1) }
103
+ line_info, cov_info, count_info = analyzer.data(sample_file)
104
+ assert_equal([0, 1, 1, 1, 0], count_info)
105
+ analyzer.run_hooked do
106
+ 10.times{ Rcov::Test::Temporary::Sample02.foo(1, 1) }
107
+ end
108
+ line_info, cov_info, count_info = analyzer.data(sample_file)
109
+ assert_equal([0, 11, 11, 11, 0], count_info)
110
+ 10.times{ analyzer.run_hooked{ Rcov::Test::Temporary::Sample02.foo(1, 1) } }
111
+ line_info, cov_info, count_info = analyzer.data(sample_file)
112
+ assert_equal([0, 21, 21, 21, 0], count_info)
113
+
114
+ count_info2 = nil
115
+ 10.times do |i|
116
+ analyzer.run_hooked do
117
+ Rcov::Test::Temporary::Sample02.foo(1, 1)
118
+ line_info, cov_info, count_info = analyzer.data(sample_file) if i == 3
119
+ line_info2, cov_info2, count_info2 = analyzer.data(sample_file)
120
+ end
121
+ end
122
+ assert_equal([0, 25, 25, 25, 0], count_info)
123
+ assert_equal([0, 31, 31, 31, 0], count_info2)
124
+ end
125
+
126
+ def test_nested_analyzer_blocks
127
+ a1 = Rcov::CodeCoverageAnalyzer.new
128
+ a2 = Rcov::CodeCoverageAnalyzer.new
129
+
130
+ sample_file = File.join(File.dirname(__FILE__), "sample_02.rb")
131
+ load sample_file
132
+
133
+ a1.run_hooked do
134
+ 100.times{ Rcov::Test::Temporary::Sample02.foo(1, 1) }
135
+ a2.run_hooked do
136
+ 10.times{ Rcov::Test::Temporary::Sample02.foo(1, 1) }
137
+ end
138
+ 100.times{ Rcov::Test::Temporary::Sample02.foo(1, 1) }
139
+ end
140
+
141
+ a2.run_hooked do
142
+ 100.times{ Rcov::Test::Temporary::Sample02.foo(1, 1) }
143
+ 10.times{ a1.run_hooked { Rcov::Test::Temporary::Sample02.foo(1, 1) } }
144
+ end
145
+
146
+ a1.install_hook
147
+ Rcov::Test::Temporary::Sample02.foo(1, 1)
148
+ a1.remove_hook
149
+
150
+ a2.install_hook
151
+ Rcov::Test::Temporary::Sample02.foo(1, 1)
152
+ a2.remove_hook
153
+
154
+ _, _, counts1 = a1.data(sample_file)
155
+ _, _, counts2 = a2.data(sample_file)
156
+ assert_equal([0, 221, 221, 221, 0], counts1)
157
+ assert_equal([0, 121, 121, 121, 0], counts2)
158
+ end
159
+
160
+ def test_reset
161
+ a1 = Rcov::CodeCoverageAnalyzer.new
162
+
163
+ sample_file = File.join(File.dirname(__FILE__), "sample_02.rb")
164
+ load sample_file
165
+
166
+ a1.run_hooked do
167
+ 100.times do |i|
168
+ Rcov::Test::Temporary::Sample02.foo(1, 1)
169
+ a1.reset if i == 49
170
+ end
171
+ end
172
+
173
+ assert_equal([0, 50, 50, 50, 0], a1.data(sample_file)[2])
174
+ end
175
+
176
+ def test_compute_raw_difference
177
+ first = {"a" => [1,1,1,1,1]}
178
+ last = {"a" => [2,1,5,2,1], "b" => [1,2,3,4,5]}
179
+ a = Rcov::CodeCoverageAnalyzer.new
180
+ assert_equal({"a" => [1,0,4,1,0], "b" => [1,2,3,4,5]},
181
+ a.instance_eval{ compute_raw_data_difference(first, last)} )
182
+ end
183
+ end
@@ -0,0 +1,403 @@
1
+
2
+ require 'test/unit'
3
+ require 'rcov'
4
+
5
+ class Test_FileStatistics < Test::Unit::TestCase
6
+ def test_trailing_end_is_inferred
7
+ verify_everything_marked "trailing end", <<-EOF
8
+ 1 class X
9
+ 1 def foo
10
+ 2 "foo"
11
+ 0 end
12
+ 0 end
13
+ EOF
14
+ verify_everything_marked "trailing end with comments", <<-EOF
15
+ 1 class X
16
+ 1 def foo
17
+ 2 "foo"
18
+ 0 end
19
+ 0 # foo bar
20
+ 0 =begin
21
+ 0 ....
22
+ 0 =end
23
+ 0 end
24
+ EOF
25
+ end
26
+
27
+ def test_begin_ensure_else_case_are_inferred
28
+ verify_everything_marked "begin ensure else case", <<-EOF
29
+ 0 begin
30
+ # bleh
31
+ 2 puts a
32
+ 0 begin
33
+ 2 raise "foo"
34
+ 0 rescue Exception => e
35
+ 2 puts b
36
+ 0 ensure
37
+ 2 puts c
38
+ 0 end
39
+ 2 if a()
40
+ 1 b
41
+ 0 else
42
+ 1 c
43
+ 0 end
44
+ 0 case
45
+ 2 when bar =~ /foo/
46
+ 1 puts "bar"
47
+ 0 else
48
+ 1 puts "baz"
49
+ 0 end
50
+ 0 end
51
+ EOF
52
+ end
53
+
54
+ def test_rescue_is_inferred
55
+ verify_everything_marked "rescue", <<-EOF
56
+ 0 begin
57
+ 1 foo
58
+ 0 rescue
59
+ 1 puts "bar"
60
+ 0 end
61
+ EOF
62
+ end
63
+
64
+ def test_code_metrics_are_computed_correctly
65
+ lines, coverage, counts = code_info_from_string <<-EOF
66
+ 1 a = 1
67
+ 0 # this is a comment
68
+ 1 if bar
69
+ 0 b = 2
70
+ 0 end
71
+ 0 =begin
72
+ 0 this too
73
+ 0 bleh
74
+ 0 =end
75
+ 0 puts <<EOF
76
+ 0 bleh
77
+ 0 EOF
78
+ 3 c.times{ i += 1}
79
+ EOF
80
+ sf = Rcov::FileStatistics.new("metrics", lines, counts)
81
+ assert_in_delta(0.307, sf.total_coverage, 0.01)
82
+ assert_in_delta(0.375, sf.code_coverage, 0.01)
83
+ assert_equal(8, sf.num_code_lines)
84
+ assert_equal(13, sf.num_lines)
85
+ assert_equal([true, :inferred, true, false, false, false, false, false,
86
+ false, false, false, false, true], sf.coverage.to_a)
87
+ end
88
+
89
+ def test_merge
90
+ lines, coverage, counts = code_info_from_string <<-EOF
91
+ 1 a = 1
92
+ 1 if bar
93
+ 0 b = 2
94
+ 0 end
95
+ 0 puts <<EOF
96
+ 0 bleh
97
+ 0 EOF
98
+ 3 c.times{ i += 1}
99
+ EOF
100
+ sf = Rcov::FileStatistics.new("merge", lines, counts)
101
+ lines, coverage, counts = code_info_from_string <<-EOF
102
+ 1 a = 1
103
+ 1 if bar
104
+ 1 b = 2
105
+ 0 end
106
+ 1 puts <<EOF
107
+ 0 bleh
108
+ 0 EOF
109
+ 10 c.times{ i += 1}
110
+ EOF
111
+ sf2 = Rcov::FileStatistics.new("merge", lines, counts)
112
+ expected = [true, true, true, :inferred, true, :inferred, :inferred, true]
113
+ assert_equal(expected, sf2.coverage.to_a)
114
+ sf.merge(sf2.lines, sf2.coverage, sf2.counts)
115
+ assert_equal(expected, sf.coverage.to_a)
116
+ assert_equal([2, 2, 1, 0, 1, 0, 0, 13], sf.counts)
117
+ end
118
+
119
+ def test_heredocs_basic
120
+ verify_everything_marked "heredocs-basic.rb", <<-EOF
121
+ 1 puts 1 + 1
122
+ 1 puts <<HEREDOC
123
+ 0 first line of the heredoc
124
+ 0 not marked
125
+ 0 but should be
126
+ 0 HEREDOC
127
+ 1 puts 1
128
+ EOF
129
+ verify_everything_marked "squote", <<-EOF
130
+ 1 puts <<'HEREDOC'
131
+ 0 first line of the heredoc
132
+ 0 HEREDOC
133
+ EOF
134
+ verify_everything_marked "dquote", <<-EOF
135
+ 1 puts <<"HEREDOC"
136
+ 0 first line of the heredoc
137
+ 0 HEREDOC
138
+ EOF
139
+ verify_everything_marked "xquote", <<-EOF
140
+ 1 puts <<`HEREDOC`
141
+ 0 first line of the heredoc
142
+ 0 HEREDOC
143
+ EOF
144
+ verify_everything_marked "stuff-after-heredoc", <<-EOF
145
+ 1 full_message = build_message(msg, <<EOT, object1, object2)
146
+ 0 <?> and <?> do not contain the same elements
147
+ 0 EOT
148
+ EOF
149
+ end
150
+
151
+ def test_heredocs_multiple
152
+ verify_everything_marked "multiple-unquoted", <<-EOF
153
+ 1 puts <<HEREDOC, <<HERE2
154
+ 0 first line of the heredoc
155
+ 0 HEREDOC
156
+ 0 second heredoc
157
+ 0 HERE2
158
+ EOF
159
+ verify_everything_marked "multiple-quoted", <<-EOF
160
+ 1 puts <<'HEREDOC', <<`HERE2`, <<"HERE3"
161
+ 0 first line of the heredoc
162
+ 0 HEREDOC
163
+ 0 second heredoc
164
+ 0 HERE2
165
+ 0 dsfdsfffd
166
+ 0 HERE3
167
+ EOF
168
+ verify_everything_marked "same-identifier", <<-EOF
169
+ 1 puts <<H, <<H
170
+ 0 foo
171
+ 0 H
172
+ 0 bar
173
+ 0 H
174
+ EOF
175
+ verify_everything_marked "stuff-after-heredoc", <<-EOF
176
+ 1 full_message = build_message(msg, <<EOT, object1, object2, <<EOT)
177
+ 0 <?> and <?> do not contain the same elements
178
+ 0 EOT
179
+ 0 <?> and <?> are foo bar baz
180
+ 0 EOT
181
+ EOF
182
+ end
183
+ def test_ignore_non_heredocs
184
+ verify_marked_exactly "bitshift-numeric", [0], <<-EOF
185
+ 1 puts 1<<2
186
+ 0 return if foo
187
+ 0 do_stuff()
188
+ 0 2
189
+ EOF
190
+ verify_marked_exactly "bitshift-symbolic", [0], <<-EOF
191
+ 1 puts 1<<LSHIFT
192
+ 0 return if bar
193
+ 0 do_stuff()
194
+ 0 LSHIFT
195
+ EOF
196
+ verify_marked_exactly "bitshift-symbolic-multi", 0..3, <<-EOF
197
+ 1 puts <<EOF, 1<<LSHIFT
198
+ 0 random text
199
+ 0 EOF
200
+ 1 return if bar
201
+ 0 puts "foo"
202
+ 0 LSHIFT
203
+ EOF
204
+ verify_marked_exactly "bitshift-symshift-evil", 0..2, <<-EOF
205
+ 1 foo = 1
206
+ 1 puts foo<<CONS
207
+ 1 return if bar
208
+ 0 foo + baz
209
+ EOF
210
+ end
211
+
212
+ def test_handle_multiline_expressions
213
+ verify_everything_marked "expression", <<-EOF
214
+ 1 puts 1, 2.
215
+ 0 abs +
216
+ 0 1 -
217
+ 0 1 *
218
+ 0 1 /
219
+ 0 1, 1 <
220
+ 0 2, 3 >
221
+ 0 4 %
222
+ 0 3 &&
223
+ 0 true ||
224
+ 0 foo <<
225
+ 0 bar(
226
+ 0 baz[
227
+ 0 {
228
+ 0 1,2}] =
229
+ 0 1 )
230
+ EOF
231
+ verify_everything_marked "boolean expression", <<-EOF
232
+ 1 x = (foo and
233
+ 0 bar) or
234
+ 0 baz
235
+ EOF
236
+ verify_marked_exactly "code blocks", [0, 3, 6], <<-EOF
237
+ 1 x = foo do # stuff
238
+ 0 baz
239
+ 0 end
240
+ 1 bar do |x|
241
+ 0 baz
242
+ 0 end
243
+ 1 bar {|a, b| # bleh | +1
244
+ 0 baz
245
+ 0 }
246
+ EOF
247
+ verify_everything_marked "escaped linebreaks", <<-EOF
248
+ 1 def t2
249
+ 0 puts \\
250
+ 1 "foo"
251
+ 0 end
252
+ 0 end
253
+ EOF
254
+ end
255
+
256
+ def test_handle_multiline_expression_1st_line_ends_in_block_header
257
+ # excerpt taken from mongrel/handlers.rb
258
+ verify_everything_marked "multiline with block starting on 1st", <<-EOF
259
+ 1 uris = listener.classifier.handler_map
260
+ 0 results << table("handlers", uris.map {|uri,handlers|
261
+ 1 [uri,
262
+ 0 "<pre>" +
263
+ 1 handlers.map {|h| h.class.to_s }.join("\n") +
264
+ 0 "</pre>"
265
+ 0 ]
266
+ 1 })
267
+ EOF
268
+ end
269
+
270
+ def test_handle_multiple_block_end_delimiters_in_empty_line
271
+ verify_everything_marked "multiline with }) delimiter, forward", <<-EOF
272
+ 1 assert(@c.config == {
273
+ 0 'host' => 'myhost.tld',
274
+ 0 'port' => 1234
275
+ 0 })
276
+ EOF
277
+ verify_everything_marked "multiline with }) delimiter, backwards", <<-EOF
278
+ 0 assert(@c.config == {
279
+ 0 'host' => 'myhost.tld',
280
+ 0 'port' => 1234
281
+ 1 })
282
+ EOF
283
+ end
284
+
285
+ STRING_DELIMITER_PAIRS = [
286
+ %w-%{ }-, %w-%q{ }-, %w-%Q{ }-, %w{%[ ]}, %w{%q[ ]},
287
+ %w{%( )}, %w{%Q( )}, %w{%Q[ ]}, %w{%q! !}, %w{%! !},
288
+ ]
289
+
290
+ def test_multiline_strings_basic
291
+ STRING_DELIMITER_PAIRS.each do |s_delim, e_delim|
292
+ verify_everything_marked "multiline strings, basic #{s_delim}", <<-EOF
293
+ 1 PATTERN_TEXT = #{s_delim}
294
+ 0 NUMBERS = 'one|two|three|four|five'
295
+ 0 ON_OFF = 'on|off'
296
+ 0 #{e_delim}
297
+ EOF
298
+ end
299
+ STRING_DELIMITER_PAIRS.each do |s_delim, e_delim|
300
+ verify_marked_exactly "multiline strings, escaped #{s_delim}", [0], <<-EOF
301
+ 1 PATTERN_TEXT = #{s_delim} foooo bar baz \\#{e_delim} baz #{e_delim}
302
+ 0 NUMBERS = 'one|two|three|four|five'
303
+ 0 ON_OFF = 'on|off'
304
+ EOF
305
+
306
+ verify_marked_exactly "multiline strings, #{s_delim}, interpolation",
307
+ [0], <<-EOF
308
+ 1 PATTERN_TEXT = #{s_delim} \#{#{s_delim} foo #{e_delim}} \\#{e_delim} baz #{e_delim}
309
+ 0 NUMBERS = 'one|two|three|four|five'
310
+ 0 ON_OFF = 'on|off'
311
+ EOF
312
+ end
313
+ end
314
+
315
+ def test_multiline_strings_escaped_delimiter
316
+ STRING_DELIMITER_PAIRS.each do |s_delim, e_delim|
317
+ verify_everything_marked "multiline, escaped #{s_delim}", <<-EOF
318
+ 1 PATTERN_TEXT = #{s_delim} foo \\#{e_delim}
319
+ 0 NUMBERS = 'one|two|three|four|five'
320
+ 0 ON_OFF = 'on|off'
321
+ 0 #{e_delim}
322
+ EOF
323
+ end
324
+ end
325
+
326
+ def test_handle_multiline_expressions_with_heredocs
327
+ verify_everything_marked "multiline and heredocs", <<-EOF
328
+ 1 puts <<EOF +
329
+ 0 testing
330
+ 0 one two three
331
+ 0 EOF
332
+ 0 somevar
333
+ EOF
334
+ end
335
+
336
+ def test_begin_end_comment_blocks
337
+ verify_everything_marked "=begin/=end", <<-EOF
338
+ 1 x = foo
339
+ 0 =begin
340
+ 0 return if bar(x)
341
+ 0 =end
342
+ 1 y = 1
343
+ EOF
344
+ end
345
+
346
+ def test_is_code_p
347
+ verify_is_code "basic", [true] + [false] * 5 + [true], <<-EOF
348
+ 1 x = foo
349
+ 0 =begin
350
+ 0 return if bar
351
+ 0 =end
352
+ 0 # foo
353
+ 0 # bar
354
+ 1 y = 1
355
+ EOF
356
+ end
357
+
358
+ def test_is_code_p_tricky_heredocs
359
+ verify_is_code "tricky heredocs", [true] * 4, <<-EOF
360
+ 2 x = foo <<EOF and return
361
+ 0 =begin
362
+ 0 EOF
363
+ 0 z = x + 1
364
+ EOF
365
+ end
366
+
367
+ def verify_is_code(testname, is_code_arr, str)
368
+ lines, coverage, counts = code_info_from_string str
369
+
370
+ sf = Rcov::FileStatistics.new(testname, lines, counts)
371
+ is_code_arr.each_with_index do |val,i|
372
+ assert_equal(val, sf.is_code?(i),
373
+ "Unable to detect =begin comments properly: #{lines[i].inspect}")
374
+ end
375
+ end
376
+
377
+ def verify_marked_exactly(testname, marked_indices, str)
378
+ lines, coverage, counts = code_info_from_string(str)
379
+
380
+ sf = Rcov::FileStatistics.new(testname, lines, counts)
381
+ lines.size.times do |i|
382
+ if marked_indices.include? i
383
+ assert(sf.coverage[i], "Test #{testname}; " +
384
+ "line should have been marked: #{lines[i].inspect}.")
385
+ else
386
+ assert(!sf.coverage[i], "Test #{testname}; " +
387
+ "line should not have been marked: #{lines[i].inspect}.")
388
+ end
389
+ end
390
+ end
391
+
392
+ def verify_everything_marked(testname, str)
393
+ verify_marked_exactly(testname, (0...str.size).to_a, str)
394
+ end
395
+
396
+
397
+ def code_info_from_string(str)
398
+ str = str.gsub(/^\s*/,"")
399
+ [ str.map{|line| line.sub(/^\d+ /, "") },
400
+ str.map{|line| line[/^\d+/].to_i > 0},
401
+ str.map{|line| line[/^\d+/].to_i } ]
402
+ end
403
+ end