rubinius-coverage 2.0.3 → 2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b1b280b252772cabd1b6dae2f74cf7015922d8b8
4
- data.tar.gz: 6c0595e0f08af7f85c9fcfe9b3919ecee56f1626
3
+ metadata.gz: 22c19371e1c8ec5d8177165d91c12f992ebe7d3e
4
+ data.tar.gz: 893646e9c62de4bcc66de954693a37d3c6ff5615
5
5
  SHA512:
6
- metadata.gz: 980cc32e4a44471cf67f227f39d8f466ebcdf65b461b64947909df29af10eff230d806b21e3c2e34d42d2282b7deefa147413249de3102ac80283157c2c67598
7
- data.tar.gz: bcbc07ec393f6dba5189091382493d9e6d7c4197b7e346089890b3a2713d0c6a8a73bb2a5417158c7e2d9dc0f56eb0dfa501fdb114936f9bf541b8c6ebcf7263
6
+ metadata.gz: 02895b2ce0adefd94c062611273d0715be55416eb502ce557982141f2e6bff475dda338c0372e0f1e20b3bd674e805448ccc355154ba8d11bf43f759a385ade7
7
+ data.tar.gz: 12a4dcddd1d91c319186f4ae52edc46dbb404e089101563e60c86e5b2beb58ad1c71e185952e265750fb16213d5c51e8e5b2b677d6116ece850bed4b89c45278
data/Rakefile CHANGED
@@ -1 +1,8 @@
1
1
  require "bundler/gem_tasks"
2
+
3
+ desc "Run the specs"
4
+ task :spec do
5
+ sh "rspec -I spec spec"
6
+ end
7
+
8
+ task :default => :spec
@@ -2,39 +2,186 @@ require "rubinius/coverage/version"
2
2
 
3
3
  module Rubinius
4
4
  class Coverage
5
- def self.loaded(flag)
6
- @loaded = flag
7
- end
5
+ class CFG
6
+ attr_accessor :code, :call_sites, :basic_blocks, :enter, :exit
8
7
 
9
- def self.loaded?
10
- @loaded == true
11
- end
8
+ def initialize(code, call_sites)
9
+ @code = code
10
+ @call_sites = call_sites
11
+ @basic_blocks = Hash.new { |h, k| h[k] = BasicBlock.new k }
12
+ end
12
13
 
13
- def self.load
14
- return if loaded?
14
+ def graph
15
+ iseq = @code.iseq
16
+ total = iseq.size
17
+ i = 0
15
18
 
16
- Rubinius::Tooling.load File.expand_path('../coverage/coverage', __FILE__)
17
- loaded true
19
+ @enter = BasicBlock.new 0
20
+ @enter.left = bb = @basic_blocks[0]
18
21
 
19
- self
20
- end
22
+ @exit = @basic_blocks[total]
23
+
24
+ while i < total
25
+ opcode = InstructionSet[iseq[i]]
26
+
27
+ if @basic_blocks.has_key? i
28
+ bb.exit_ip = i-1
29
+ bb = bb.left = @basic_blocks[i]
30
+ else
31
+ bb.exit_ip = i+opcode.width-1
32
+
33
+ case opcode.control_flow
34
+ when :branch
35
+ bb.left = @basic_blocks[iseq[i+1]]
36
+ bb.left.exit_ip = total
37
+
38
+ next_bb = @basic_blocks[i+opcode.width]
39
+ bb.right = next_bb if opcode.name != :goto
40
+
41
+ bb = next_bb
42
+ when :raise, :return
43
+ bb.left = @exit
44
+ bb = @basic_blocks[i+opcode.width]
45
+ end
46
+ end
47
+
48
+ i += opcode.width
49
+ end
50
+
51
+ @basic_blocks.values.each do |bb|
52
+ # Split if a jump target intersects our range
53
+ i = bb.enter_ip
54
+ while i < bb.exit_ip
55
+ opcode = InstructionSet[iseq[i]]
56
+ i += opcode.width
57
+
58
+ if @basic_blocks.has_key? i
59
+ bb.exit_ip = i-1
60
+
61
+ if opcode.control_flow != :branch
62
+ bb.left = @basic_blocks[i]
63
+ bb.right = nil
64
+ end
65
+
66
+ break
67
+ end
68
+ end
69
+
70
+ bb.coverage @code, @call_sites
71
+ end
72
+
73
+ stack = [@enter]
74
+ cycles = {}
75
+
76
+ until stack.empty?
77
+ bb = stack.shift
78
+
79
+ if left = bb.left
80
+ left.count = bb.count if bb.count > left.count
81
+ unless cycles.has_key? left
82
+ stack << left
83
+ cycles[left] = true
84
+ end
85
+ end
21
86
 
22
- attr_reader :results
87
+ if right = bb.right
88
+ right.count = bb.count if bb.count > right.count
89
+ unless cycles.has_key? right
90
+ stack << right
91
+ cycles[right] = true
92
+ end
93
+ end
94
+ end
23
95
 
24
- def initialize
25
- self.class.load
96
+ # Flow coverage counts backwards
97
+ @basic_blocks.values.each do |bb|
98
+ if bb.count == 0
99
+ if (bb.left and bb.left.count > 0) or
100
+ (bb.right and bb.right.count > 0)
101
+ bb.count = 1
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ class BasicBlock
108
+ attr_accessor :enter_ip, :exit_ip, :left, :right, :lines, :count
109
+
110
+ def initialize(enter_ip)
111
+ @enter_ip = @exit_ip = enter_ip
112
+ @lines = []
113
+ @count = 0
114
+ end
115
+
116
+ def coverage(code, call_sites)
117
+ total = code.lines.size - 2
118
+ i = 0
119
+
120
+ while i < total
121
+ if (@enter_ip < code.lines[i+2] and @exit_ip >= code.lines[i]) or
122
+ (code.lines[i+2] == 0 and @enter_ip == 0)
123
+ line = code.lines[i+1]
124
+ @lines << line unless @lines.include? line
125
+ end
126
+
127
+ i += 2
128
+ end
129
+
130
+ call_sites.each do |cs|
131
+ if cs.ip >= @enter_ip and cs.ip <= @exit_ip
132
+ cs_count = cs.invokes + cs.hits + cs.misses
133
+ @count = cs_count if cs_count > @count
134
+ end
135
+ end
136
+ end
137
+ end
26
138
  end
27
139
 
140
+ # Coverage methods
141
+
28
142
  def start
29
- Rubinius::Tooling.enable
143
+ ObjectSpace.each_object(Rubinius::CallSite) { |cs| cs.reset }
30
144
 
31
- self
145
+ nil
32
146
  end
33
147
 
34
- def stop
35
- @results = Rubinius::Tooling.disable
148
+ def coverage(code)
149
+ call_sites = code.call_sites
150
+ return unless call_sites.any? { |cs| cs.invokes + cs.hits + cs.misses > 0 }
151
+
152
+ cfg = CFG.new code, call_sites
153
+ cfg.graph
154
+
155
+ counts = {}
156
+
157
+ total = code.lines.size
158
+ i = 1
159
+
160
+ while i < total
161
+ counts[code.lines[i]] = 0
162
+ i += 2
163
+ end
164
+
165
+ cfg.basic_blocks.values.each do |bb|
166
+ bb.lines.each { |l| counts[l] = bb.count }
167
+ end
168
+
169
+ counts
170
+ end
171
+
172
+ def result
173
+ code_coverage = Hash.new { |h, k| h[k] = [] }
174
+
175
+ ObjectSpace.each_object(Rubinius::CompiledCode) do |code|
176
+ lines = code_coverage[code.file.to_s]
177
+ counts = coverage code
178
+ next unless counts
179
+
180
+ counts.each { |line, count| lines[line] = count }
181
+ end
36
182
 
37
- self
183
+ code_coverage.delete_if { |k, v| v.empty? }
184
+ code_coverage
38
185
  end
39
186
  end
40
187
  end
@@ -1,5 +1,5 @@
1
1
  module Rubinius
2
2
  class Coverage
3
- VERSION = "2.0.3"
3
+ VERSION = "2.1"
4
4
  end
5
5
  end
@@ -13,10 +13,10 @@ Gem::Specification.new do |spec|
13
13
 
14
14
  spec.files = `git ls-files`.split($/)
15
15
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
- spec.extensions = ["ext/rubinius/coverage/extconf.rb"]
17
16
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
17
  spec.require_paths = ["lib"]
19
18
 
20
19
  spec.add_development_dependency "bundler", "~> 1.3"
21
20
  spec.add_development_dependency "rake", "~> 10.0"
21
+ spec.add_development_dependency "rspec", "~> 3"
22
22
  end
@@ -0,0 +1,99 @@
1
+ require "spec_helper"
2
+
3
+ module CoverageSpecs
4
+ class DoubleBranch
5
+ def m
6
+ a = 1
7
+ if a == 2
8
+ 3
9
+ else
10
+ 2
11
+ end
12
+
13
+ 4
14
+ end
15
+ end
16
+ end
17
+
18
+ describe Rubinius::Coverage do
19
+ context "with a single branch" do
20
+ let(:obj) { CoverageSpecs::DoubleBranch.new }
21
+ let(:code) { obj.method(:m).executable }
22
+
23
+ describe Rubinius::Coverage::CFG do
24
+ let(:cfg) { Rubinius::Coverage::CFG.new code, code.call_sites }
25
+
26
+ before do
27
+ cfg.graph
28
+ end
29
+
30
+ describe "#graph" do
31
+ it "creates five BasicBlock instances" do
32
+ expect(cfg.basic_blocks.size).to eql(5)
33
+ end
34
+
35
+ it "creates a basic block at IP 0-13" do
36
+ bb = cfg.basic_blocks[0]
37
+
38
+ expect(bb.enter_ip).to eql(0)
39
+ expect(bb.exit_ip).to eql(13)
40
+ end
41
+
42
+ it "creates a basic block at IP 14-17" do
43
+ bb = cfg.basic_blocks[14]
44
+
45
+ expect(bb.enter_ip).to eql(14)
46
+ expect(bb.exit_ip).to eql(17)
47
+ end
48
+
49
+ it "creates a basic block at IP 18-19" do
50
+ bb = cfg.basic_blocks[18]
51
+
52
+ expect(bb.enter_ip).to eql(18)
53
+ expect(bb.exit_ip).to eql(19)
54
+ end
55
+
56
+ it "creates a basic block at IP 20-23" do
57
+ bb = cfg.basic_blocks[20]
58
+
59
+ expect(bb.enter_ip).to eql(20)
60
+ expect(bb.exit_ip).to eql(23)
61
+ end
62
+
63
+ it "set the count of the times the basic block was executed" do
64
+ obj.m
65
+ cfg.graph
66
+
67
+ bb = cfg.basic_blocks[0]
68
+
69
+ expect(bb.count).to eql(1)
70
+ end
71
+
72
+ it "sets the lines covered by the basic block" do
73
+ lines = cfg.basic_blocks[0].lines
74
+
75
+ expect(lines.size).to eql(3)
76
+ expect(lines[0]).to eql(5)
77
+ expect(lines[1]).to eql(6)
78
+ expect(lines[2]).to eql(7)
79
+ end
80
+ end
81
+ end
82
+
83
+ describe "#coverage" do
84
+ it "returns a map of source code lines to execution counts" do
85
+ coverage = Rubinius::Coverage.new.coverage code
86
+
87
+ expect(coverage.size).to eql(7)
88
+ expect(coverage[5]).to eql(1)
89
+ expect(coverage[6]).to eql(1)
90
+ expect(coverage[7]).to eql(1)
91
+ expect(coverage[8]).to eql(1)
92
+ # TODO: fix bug generating line info for lines 9, 11, 12 in the code
93
+ # above.
94
+ expect(coverage[10]).to eql(1)
95
+ expect(coverage[13]).to eql(1)
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,96 @@
1
+ require "spec_helper"
2
+
3
+ module CoverageSpecs
4
+ class LoopBranch
5
+ def m
6
+ i = 1
7
+ while i < 10
8
+ 2
9
+ i += 1
10
+ end
11
+
12
+ 4
13
+ end
14
+ end
15
+ end
16
+
17
+ describe Rubinius::Coverage do
18
+ context "with a loop branch" do
19
+ let(:obj) { CoverageSpecs::LoopBranch.new }
20
+ let(:code) { obj.method(:m).executable }
21
+
22
+ describe Rubinius::Coverage::CFG do
23
+ let(:cfg) { Rubinius::Coverage::CFG.new code, code.call_sites }
24
+
25
+ before do
26
+ cfg.graph
27
+ end
28
+
29
+ describe "#graph" do
30
+ it "creates five BasicBlock instances" do
31
+ expect(cfg.basic_blocks.size).to eql(5)
32
+ end
33
+
34
+ it "creates a basic block at IP 0-4" do
35
+ bb = cfg.basic_blocks[0]
36
+
37
+ expect(bb.enter_ip).to eql(0)
38
+ expect(bb.exit_ip).to eql(4)
39
+ end
40
+
41
+ it "creates a basic block at IP 5-13" do
42
+ bb = cfg.basic_blocks[5]
43
+
44
+ expect(bb.enter_ip).to eql(5)
45
+ expect(bb.exit_ip).to eql(13)
46
+ end
47
+
48
+ it "creates a basic block at IP 14-29" do
49
+ bb = cfg.basic_blocks[14]
50
+
51
+ expect(bb.enter_ip).to eql(14)
52
+ expect(bb.exit_ip).to eql(29)
53
+ end
54
+
55
+ it "creates a basic block at IP 30-34" do
56
+ bb = cfg.basic_blocks[30]
57
+
58
+ expect(bb.enter_ip).to eql(30)
59
+ expect(bb.exit_ip).to eql(34)
60
+ end
61
+
62
+ it "set the count of the times the basic block was executed" do
63
+ obj.m
64
+ cfg.graph
65
+
66
+ bb = cfg.basic_blocks[0]
67
+
68
+ expect(bb.count).to eql(1)
69
+ end
70
+
71
+ it "sets the lines covered by the basic block" do
72
+ lines = cfg.basic_blocks[0].lines
73
+
74
+ expect(lines.size).to eql(2)
75
+ expect(lines[0]).to eql(5)
76
+ expect(lines[1]).to eql(6)
77
+ end
78
+ end
79
+ end
80
+
81
+ describe "#coverage" do
82
+ it "returns a map of source code lines to execution counts" do
83
+ coverage = Rubinius::Coverage.new.coverage code
84
+
85
+ expect(coverage.size).to eql(7)
86
+ expect(coverage[5]).to eql(1)
87
+ expect(coverage[6]).to eql(1)
88
+ expect(coverage[7]).to eql(10)
89
+ expect(coverage[8]).to eql(9)
90
+ expect(coverage[9]).to eql(9)
91
+ # TODO: fix bug generating line info for lines 10, 11, 12 in the code
92
+ # above.
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,96 @@
1
+ require "spec_helper"
2
+
3
+ module CoverageSpecs
4
+ class SingleBranch
5
+ def m
6
+ a = 1
7
+ if a == 2
8
+ 3
9
+ end
10
+
11
+ 4
12
+ end
13
+ end
14
+ end
15
+
16
+ describe Rubinius::Coverage do
17
+ context "with a single branch" do
18
+ let(:obj) { CoverageSpecs::SingleBranch.new }
19
+ let(:code) { obj.method(:m).executable }
20
+
21
+ describe Rubinius::Coverage::CFG do
22
+ let(:cfg) { Rubinius::Coverage::CFG.new code, code.call_sites }
23
+
24
+ before do
25
+ cfg.graph
26
+ end
27
+
28
+ describe "#graph" do
29
+ it "creates five BasicBlock instances" do
30
+ expect(cfg.basic_blocks.size).to eql(5)
31
+ end
32
+
33
+ it "creates a basic block at IP 0-13" do
34
+ bb = cfg.basic_blocks[0]
35
+
36
+ expect(bb.enter_ip).to eql(0)
37
+ expect(bb.exit_ip).to eql(13)
38
+ end
39
+
40
+ it "creates a basic block at IP 14-17" do
41
+ bb = cfg.basic_blocks[14]
42
+
43
+ expect(bb.enter_ip).to eql(14)
44
+ expect(bb.exit_ip).to eql(17)
45
+ end
46
+
47
+ it "creates a basic block at IP 18-18" do
48
+ bb = cfg.basic_blocks[18]
49
+
50
+ expect(bb.enter_ip).to eql(18)
51
+ expect(bb.exit_ip).to eql(18)
52
+ end
53
+
54
+ it "creates a basic block at IP 19-22" do
55
+ bb = cfg.basic_blocks[19]
56
+
57
+ expect(bb.enter_ip).to eql(19)
58
+ expect(bb.exit_ip).to eql(22)
59
+ end
60
+
61
+ it "set the count of the times the basic block was executed" do
62
+ obj.m
63
+ cfg.graph
64
+
65
+ bb = cfg.basic_blocks[0]
66
+
67
+ expect(bb.count).to eql(1)
68
+ end
69
+
70
+ it "sets the lines covered by the basic block" do
71
+ lines = cfg.basic_blocks[0].lines
72
+
73
+ expect(lines.size).to eql(3)
74
+ expect(lines[0]).to eql(5)
75
+ expect(lines[1]).to eql(6)
76
+ expect(lines[2]).to eql(7)
77
+ end
78
+ end
79
+ end
80
+
81
+ describe "#coverage" do
82
+ it "returns a map of source code lines to execution counts" do
83
+ coverage = Rubinius::Coverage.new.coverage code
84
+
85
+ expect(coverage.size).to eql(6)
86
+ expect(coverage[5]).to eql(1)
87
+ expect(coverage[6]).to eql(1)
88
+ expect(coverage[7]).to eql(1)
89
+ expect(coverage[8]).to eql(1)
90
+ # TODO: fix bug generating line info for lines 9, 10 in the code
91
+ # above.
92
+ expect(coverage[11]).to eql(1)
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,73 @@
1
+ require "spec_helper"
2
+
3
+ module CoverageSpecs
4
+ class Single
5
+ def m
6
+ a = 1
7
+ b = 2
8
+ c = a + b
9
+ c.to_s
10
+ end
11
+ end
12
+ end
13
+
14
+ describe Rubinius::Coverage do
15
+ context "with a single basic block" do
16
+ let(:obj) { CoverageSpecs::Single.new }
17
+ let(:code) { obj.method(:m).executable }
18
+
19
+ describe Rubinius::Coverage::CFG do
20
+ let(:cfg) { Rubinius::Coverage::CFG.new code, code.call_sites }
21
+
22
+ before do
23
+ cfg.graph
24
+ end
25
+
26
+ describe "#graph" do
27
+ it "creates a single BasicBlock instance" do
28
+ expect(cfg.basic_blocks.size).to eql(2)
29
+ end
30
+
31
+ it "sets the enter and exit IP for the basic block" do
32
+ bb = cfg.basic_blocks[0]
33
+
34
+ expect(bb.enter_ip).to eql(0)
35
+ expect(bb.exit_ip).to eql(24)
36
+ end
37
+
38
+ it "set the count of the times the basic block was executed" do
39
+ obj.m
40
+ cfg.graph
41
+
42
+ bb = cfg.basic_blocks[0]
43
+
44
+ expect(bb.count).to eql(1)
45
+ end
46
+
47
+ it "sets the lines covered by the basic block" do
48
+ lines = cfg.basic_blocks[0].lines
49
+
50
+ expect(lines.size).to eql(5)
51
+ expect(lines[0]).to eql(5)
52
+ expect(lines[1]).to eql(6)
53
+ expect(lines[2]).to eql(7)
54
+ expect(lines[3]).to eql(8)
55
+ expect(lines[4]).to eql(9)
56
+ end
57
+ end
58
+ end
59
+
60
+ describe "#coverage" do
61
+ it "returns a map of source code lines to execution counts" do
62
+ coverage = Rubinius::Coverage.new.coverage code
63
+
64
+ expect(coverage.size).to eql(5)
65
+ expect(coverage[5]).to eql(1)
66
+ expect(coverage[6]).to eql(1)
67
+ expect(coverage[7]).to eql(1)
68
+ expect(coverage[8]).to eql(1)
69
+ expect(coverage[9]).to eql(1)
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1 @@
1
+ require "rubinius/coverage"
metadata CHANGED
@@ -1,22 +1,22 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubinius-coverage
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: '2.1'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Shirai
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-15 00:00:00.000000000 Z
11
+ date: 2016-05-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: bundler
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
18
  version: '1.3'
19
+ name: bundler
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
@@ -25,12 +25,12 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.3'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rake
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
30
  - - "~>"
32
31
  - !ruby/object:Gem::Version
33
32
  version: '10.0'
33
+ name: rake
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
@@ -38,12 +38,25 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3'
47
+ name: rspec
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3'
41
55
  description: Rubinius coverage tool.
42
56
  email:
43
57
  - brixen@gmail.com
44
58
  executables: []
45
- extensions:
46
- - ext/rubinius/coverage/extconf.rb
59
+ extensions: []
47
60
  extra_rdoc_files: []
48
61
  files:
49
62
  - ".gitignore"
@@ -51,11 +64,14 @@ files:
51
64
  - LICENSE
52
65
  - README.md
53
66
  - Rakefile
54
- - ext/rubinius/coverage/coverage.cpp
55
- - ext/rubinius/coverage/extconf.rb
56
67
  - lib/rubinius/coverage.rb
57
68
  - lib/rubinius/coverage/version.rb
58
69
  - rubinius-coverage.gemspec
70
+ - spec/basic_block/double_branch_spec.rb
71
+ - spec/basic_block/loop_spec.rb
72
+ - spec/basic_block/single_branch_spec.rb
73
+ - spec/basic_block/single_spec.rb
74
+ - spec/spec_helper.rb
59
75
  homepage: https://github.com/rubinius/rubinius-coverage
60
76
  licenses:
61
77
  - BSD
@@ -76,9 +92,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
92
  version: '0'
77
93
  requirements: []
78
94
  rubyforge_project:
79
- rubygems_version: 2.0.7
95
+ rubygems_version: 2.6.2
80
96
  signing_key:
81
97
  specification_version: 4
82
98
  summary: Rubinius coverage tool.
83
- test_files: []
84
- has_rdoc:
99
+ test_files:
100
+ - spec/basic_block/double_branch_spec.rb
101
+ - spec/basic_block/loop_spec.rb
102
+ - spec/basic_block/single_branch_spec.rb
103
+ - spec/basic_block/single_spec.rb
104
+ - spec/spec_helper.rb
@@ -1,163 +0,0 @@
1
- #include <rbxti.hpp>
2
- #include <rbxti/atomic.hpp>
3
- #include <rbx_config.h>
4
-
5
- #include <iostream>
6
- #ifdef RBX_HAVE_TR1
7
- #include <tr1/unordered_map>
8
- #define std_unordered_map std::tr1::unordered_map
9
- #else
10
- #include <unordered_map>
11
- #define std_unordered_map std::unordered_map
12
- #endif
13
-
14
- using namespace rbxti;
15
-
16
- #if defined(RBX_HAVE_TR1) && !defined(RBX_HAVE_TR1_HASH)
17
- namespace std {
18
- namespace tr1 {
19
- template <>
20
- struct hash<r_mint> {
21
- size_t operator()(const r_mint id) const {
22
- return id;
23
- }
24
- };
25
- }
26
- }
27
- #endif
28
-
29
- namespace coverage {
30
-
31
- typedef std_unordered_map<int, int> InstructionCoverageMap;
32
- typedef std_unordered_map<r_mint, InstructionCoverageMap*> CoverageMap;
33
-
34
- class Coverage {
35
- CoverageMap coverage_map_;
36
- rbxti::SpinLock lock_;
37
-
38
- public:
39
- Coverage() { }
40
- ~Coverage();
41
-
42
- void lock() {
43
- lock_.lock();
44
- }
45
-
46
- void unlock() {
47
- lock_.unlock();
48
- }
49
-
50
- void add(Env* env, r_mint id, int ip);
51
- robject results(Env* env);
52
- };
53
-
54
- Coverage::~Coverage() {
55
- for(CoverageMap::iterator i = coverage_map_.begin();
56
- i != coverage_map_.end();
57
- i++) {
58
- delete i->second;
59
- }
60
- }
61
-
62
- void Coverage::add(Env* env, r_mint id, int ip) {
63
- lock();
64
-
65
- InstructionCoverageMap *map;
66
- CoverageMap::iterator i = coverage_map_.find(id);
67
-
68
- if(i == coverage_map_.end()) {
69
- map = new InstructionCoverageMap;
70
- coverage_map_[id] = map;
71
- } else {
72
- map = i->second;
73
- }
74
-
75
- InstructionCoverageMap::iterator j = map->find(ip);
76
-
77
- if(j == map->end()) {
78
- (*map)[ip] = 1;
79
- } else {
80
- (*map)[ip] += 1;
81
- }
82
-
83
- unlock();
84
- }
85
-
86
- static void ccode_iterator(Env* env, rcompiled_code code, void* data) {
87
- rtable map = (rtable)data;
88
- r_mint id = env->method_id(code);
89
-
90
- bool found = false;
91
- robject obj = env->table_fetch(map, env->integer_new(id), &found);
92
- if(!found) return;
93
-
94
- rtable attr = env->cast_to_rtable(obj);
95
- if(!attr) return;
96
-
97
- env->table_store(attr, env->symbol("code"), code);
98
- }
99
-
100
- robject Coverage::results(Env* env) {
101
- rtable coverage_map = env->table_new();
102
-
103
- for(CoverageMap::iterator i = coverage_map_.begin();
104
- i != coverage_map_.end();
105
- i++) {
106
- InstructionCoverageMap* map = i->second;
107
- rtable method_map = env->table_new();
108
-
109
- for(InstructionCoverageMap::iterator j = map->begin();
110
- j != map->end();
111
- j++) {
112
- env->table_store(method_map,
113
- env->integer_new(j->first),
114
- env->integer_new(j->second));
115
- }
116
-
117
- rtable attr = env->table_new();
118
- env->table_store(attr, env->symbol("counts"), method_map);
119
-
120
- env->table_store(coverage_map, env->integer_new(i->first), attr);
121
- }
122
-
123
- env->find_all_compiled_code(ccode_iterator, (void*)coverage_map);
124
-
125
- return coverage_map;
126
- }
127
-
128
- namespace {
129
- void coverage_enable(Env* env) {
130
- Coverage* coverage = new Coverage;
131
- env->set_global_tool_data(coverage);
132
- }
133
-
134
- robject coverage_results(Env* env) {
135
- Coverage* coverage = reinterpret_cast<Coverage*>(env->global_tool_data());
136
-
137
- env->set_tool_at_ip(NULL);
138
- env->set_global_tool_data(NULL);
139
-
140
- robject results = coverage->results(env);
141
- delete coverage;
142
-
143
- return results;
144
- }
145
-
146
- void coverage_at_ip(Env* env, rmachine_code mcode, int ip) {
147
- Coverage* coverage = reinterpret_cast<Coverage*>(env->global_tool_data());
148
-
149
- if(!coverage) return;
150
-
151
- coverage->add(env, env->machine_code_id(mcode), ip);
152
- }
153
- }
154
-
155
- extern "C" int Tool_Init(Env* env) {
156
- env->set_tool_enable(coverage_enable);
157
- env->set_tool_results(coverage_results);
158
-
159
- env->set_tool_at_ip(coverage_at_ip);
160
-
161
- return 1;
162
- }
163
- }
@@ -1,3 +0,0 @@
1
- require 'mkmf'
2
-
3
- create_makefile 'rubinius/coverage/coverage'