rcov 0.5.0.1-mswin32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/test/sample_01.rb ADDED
@@ -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 }
data/test/sample_02.rb ADDED
@@ -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
data/test/sample_03.rb ADDED
@@ -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