edgecase-ocov 1.0
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/README.rdoc +3 -0
- data/Rakefile +68 -0
- data/bin/ocov +7 -0
- data/lib/ocov.rb +12 -0
- data/lib/ocov/gcov.rb +49 -0
- data/lib/ocov/project.rb +95 -0
- data/lib/ocov/source_line.rb +23 -0
- data/lib/ocov/target.rb +7 -0
- data/lib/ocov/templates/file.html.erb +24 -0
- data/lib/ocov/templates/index.html.erb +72 -0
- metadata +67 -0
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# Rakefile for ocov -*- ruby -*-
|
2
|
+
begin
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
require 'rake/testtask'
|
6
|
+
require 'rake/rdoctask'
|
7
|
+
rescue Exception
|
8
|
+
nil
|
9
|
+
end
|
10
|
+
|
11
|
+
if `ruby -Ilib -rocov -e "print OCov.version"` =~ /([0-9.]+)$/
|
12
|
+
CURRENT_VERSION = $1
|
13
|
+
else
|
14
|
+
CURRENT_VERSION = '0.0.0'
|
15
|
+
end
|
16
|
+
|
17
|
+
PKG_FILES = FileList['[A-Z]*',
|
18
|
+
'README.rdoc',
|
19
|
+
'bin/*',
|
20
|
+
'lib/**/*.rb',
|
21
|
+
'lib/ocov/templates/*.erb',
|
22
|
+
'doc/**/*'
|
23
|
+
]
|
24
|
+
|
25
|
+
desc 'Generate documentation for magic bus'
|
26
|
+
rd = Rake::RDocTask.new(:rdoc) do |rdoc|
|
27
|
+
rdoc.rdoc_dir = 'html'
|
28
|
+
rdoc.template = 'doc/jamis.rb'
|
29
|
+
rdoc.rdoc_dir = 'rdoc'
|
30
|
+
rdoc.title = 'ocov'
|
31
|
+
rdoc.options << '--line-numbers' << '--inline-source' << '--main' << 'README.rdoc' << '--title' << 'Magic Bus'
|
32
|
+
rdoc.rdoc_files.include('README.rdoc', 'lib/**/*.rb', 'doc/**/*.rdoc')
|
33
|
+
end
|
34
|
+
|
35
|
+
if !defined?(Gem)
|
36
|
+
puts "Package target requires RubyGEMs"
|
37
|
+
else
|
38
|
+
spec = Gem::Specification.new do |s|
|
39
|
+
s.name = 'ocov'
|
40
|
+
s.version = CURRENT_VERSION
|
41
|
+
s.summary = 'C0 coverage report tool for Objective-C'
|
42
|
+
s.executables = ['ocov']
|
43
|
+
s.files = PKG_FILES.to_a
|
44
|
+
s.require_path = 'lib'
|
45
|
+
s.has_rdoc = true
|
46
|
+
s.extra_rdoc_files = rd.rdoc_files.reject {|fn| fn =~ /\.rb$/}.to_a
|
47
|
+
s.rdoc_options = rd.options
|
48
|
+
|
49
|
+
s.author = "EdgeCase, LLC"
|
50
|
+
s.email = "scott@edgecase.com"
|
51
|
+
s.homepage = "http://github.com/edgecase/ocov/tree/master"
|
52
|
+
end
|
53
|
+
|
54
|
+
package_task = Rake::GemPackageTask.new(spec) do |pkg|
|
55
|
+
pkg.need_zip = true
|
56
|
+
pkg.need_tar = true
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
desc "Run all tests"
|
61
|
+
task :default => [:test]
|
62
|
+
|
63
|
+
Rake::TestTask.new(:test) do |t|
|
64
|
+
t.test_files = FileList['test/test*.rb']
|
65
|
+
t.warning = true
|
66
|
+
t.verbose = false
|
67
|
+
end
|
68
|
+
|
data/bin/ocov
ADDED
data/lib/ocov.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'ocov', 'project')
|
2
|
+
require File.join(File.dirname(__FILE__), 'ocov', 'gcov')
|
3
|
+
require File.join(File.dirname(__FILE__), 'ocov', 'source_line')
|
4
|
+
require File.join(File.dirname(__FILE__), 'ocov', 'target')
|
5
|
+
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
module OCov
|
9
|
+
def self.version
|
10
|
+
"1.0"
|
11
|
+
end
|
12
|
+
end
|
data/lib/ocov/gcov.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
module OCov
|
2
|
+
class GCov
|
3
|
+
attr_reader :name
|
4
|
+
attr_reader :lines
|
5
|
+
attr_reader :lines_of_code
|
6
|
+
attr_reader :coverage
|
7
|
+
|
8
|
+
def initialize(build_path, class_file)
|
9
|
+
@class_file = class_file
|
10
|
+
@build_path = build_path
|
11
|
+
@name = File.basename(class_file)
|
12
|
+
@lines = []
|
13
|
+
@coverage = 100.00
|
14
|
+
@lines_of_code = 0
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
run_gcov
|
19
|
+
parse_gcov_output
|
20
|
+
cleanup
|
21
|
+
end
|
22
|
+
|
23
|
+
def total_lines
|
24
|
+
lines.size
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def run_gcov
|
29
|
+
results = `gcov -o "#{@build_path}" "#{@class_file}"`
|
30
|
+
if results =~ /Lines executed:(\d+\.\d+)% of (\d+)/
|
31
|
+
@lines_of_code = $2.to_i
|
32
|
+
@coverage = $1.to_f
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_gcov_output
|
37
|
+
gcov_file = File.open("#{File.basename(@class_file)}.gcov")
|
38
|
+
gcov_file.readlines.each do |line|
|
39
|
+
if OCov::SourceLine.parsable?(line)
|
40
|
+
@lines << OCov::SourceLine.new(line)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def cleanup
|
46
|
+
FileUtils.rm_f("#{File.basename(@class_file)}.gcov")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/ocov/project.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module OCov
|
4
|
+
class Project
|
5
|
+
attr_reader :name
|
6
|
+
attr_reader :files
|
7
|
+
|
8
|
+
def initialize(project_path)
|
9
|
+
@project_path = project_path
|
10
|
+
@files = []
|
11
|
+
|
12
|
+
determine_name_from_xcode_file
|
13
|
+
end
|
14
|
+
|
15
|
+
def analyze_and_report
|
16
|
+
analyze
|
17
|
+
|
18
|
+
FileUtils.rm_rf('coverage')
|
19
|
+
FileUtils.mkdir('coverage')
|
20
|
+
|
21
|
+
template = ERB.new(open(File.join(File.dirname(__FILE__), 'templates', 'index.html.erb')).read)
|
22
|
+
f = open('coverage/index.html', 'w')
|
23
|
+
f.write(template.result(binding))
|
24
|
+
f.close
|
25
|
+
|
26
|
+
files.each do |file|
|
27
|
+
template = ERB.new(open(File.join(File.dirname(__FILE__), 'templates', 'file.html.erb')).read)
|
28
|
+
f = open("coverage/#{file.name.gsub('.', '_')}.html", 'w')
|
29
|
+
f.write(template.result(file.send(:binding)))
|
30
|
+
f.close
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def analyze
|
35
|
+
class_files.each do |file|
|
36
|
+
gcov = OCov::GCov.new(build_path, file)
|
37
|
+
gcov.run
|
38
|
+
@files << gcov
|
39
|
+
end
|
40
|
+
@files.sort! { |a, b| b.coverage <=> a.coverage }
|
41
|
+
end
|
42
|
+
|
43
|
+
def total_coverage
|
44
|
+
(total_lines_covered.to_f / total_lines_of_code) * 100
|
45
|
+
end
|
46
|
+
|
47
|
+
def total_lines_covered
|
48
|
+
files.inject(0) { |sum, file| sum + ((file.coverage / 100.0) * file.lines_of_code).to_i }
|
49
|
+
end
|
50
|
+
|
51
|
+
def total_lines
|
52
|
+
files.inject(0) { |sum, file| sum + file.total_lines }
|
53
|
+
end
|
54
|
+
|
55
|
+
def total_lines_of_code
|
56
|
+
files.inject(0) { |sum, file| sum + file.lines_of_code }
|
57
|
+
end
|
58
|
+
|
59
|
+
def classes_path
|
60
|
+
File.join(@project_path, 'Classes')
|
61
|
+
end
|
62
|
+
|
63
|
+
def build_path
|
64
|
+
File.join(@project_path, 'build', "#{@name}.build", 'Debug-iphonesimulator', "#{OCov::Target.name}.build", 'Objects-normal', 'i386')
|
65
|
+
end
|
66
|
+
|
67
|
+
def class_files
|
68
|
+
Dir.glob(File.join(classes_path, '*.m')).inject([]) do |arr, file|
|
69
|
+
arr << file if File.basename(file) !~ /(AppDelegate|ViewController)\.m$/
|
70
|
+
arr
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def gcda_files
|
75
|
+
Dir.glob(File.join(build_path, '*.gcda')).inject([]) do |arr, file|
|
76
|
+
arr << file if File.basename(file) !~ /^(GTM|Test)/
|
77
|
+
arr
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
private
|
86
|
+
def determine_name_from_xcode_file
|
87
|
+
xcode_file = Dir.glob(File.join(@project_path, '*.xcodeproj')).first
|
88
|
+
if xcode_file
|
89
|
+
@name = File.basename(xcode_file, '.xcodeproj')
|
90
|
+
else
|
91
|
+
raise "Unable to determine project name"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module OCov
|
2
|
+
class SourceLine
|
3
|
+
def self.parsable?(line)
|
4
|
+
!(line =~ / -: 0:/)
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize(line)
|
8
|
+
@line = line
|
9
|
+
end
|
10
|
+
|
11
|
+
def covered?
|
12
|
+
!(@line =~ /^ #####:/)
|
13
|
+
end
|
14
|
+
|
15
|
+
def source_line
|
16
|
+
@line.strip.split(':')[2..-1].join(':')
|
17
|
+
end
|
18
|
+
|
19
|
+
def line_number
|
20
|
+
@line.split(':')[1].to_i
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/ocov/target.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title><%= file.name %> - C0 code coverage</title>
|
4
|
+
<style type="text/css">
|
5
|
+
span { width: 100%; display: block;}
|
6
|
+
|
7
|
+
span.covered {
|
8
|
+
background-color: rgb(185, 210, 200);
|
9
|
+
}
|
10
|
+
|
11
|
+
span.uncovered {
|
12
|
+
background-color: rgb(225, 110, 110);
|
13
|
+
}
|
14
|
+
</style>
|
15
|
+
</head>
|
16
|
+
<body>
|
17
|
+
<h1>C0 code coverage information for <%= name %></h1>
|
18
|
+
<p>Generated on <%= Time.now %> with <a href="http://github.com/edgecase/ocov/tree/master">ocov <%= OCov.version %></a></p>
|
19
|
+
<hr />
|
20
|
+
<pre>
|
21
|
+
<% file.lines.each do |line| %><span class="<%= line.covered? ? 'covered' : 'uncovered' %>"><%= '% 3d' % line.line_number %>: <%= line.source_line %></span><% end %>
|
22
|
+
</pre>
|
23
|
+
</body>
|
24
|
+
</html>
|
@@ -0,0 +1,72 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title><%= name %> C0 code coverage</title>
|
4
|
+
<style type="text/css">
|
5
|
+
.graph_outer {
|
6
|
+
height: 12px;
|
7
|
+
background: red;
|
8
|
+
width: 100px;
|
9
|
+
border: 1px solid #808080;
|
10
|
+
float:right;
|
11
|
+
}
|
12
|
+
.graph_inner {
|
13
|
+
height: 12px;
|
14
|
+
background: #00F000;
|
15
|
+
}
|
16
|
+
table.report { border-collapse: collapse; width: 100%; }
|
17
|
+
th {
|
18
|
+
background: #dcecff;
|
19
|
+
border: #d0d0d0 1px solid;
|
20
|
+
font-weight: bold;
|
21
|
+
text-align: center;
|
22
|
+
}
|
23
|
+
table.report td { border: #d0d0d0 1px solid; }
|
24
|
+
td.value { text-align: right; }
|
25
|
+
th.filename { width: 55%; }
|
26
|
+
</style>
|
27
|
+
</head>
|
28
|
+
<body>
|
29
|
+
<h1>C0 code coverage information for <%= name %></h1>
|
30
|
+
<p>Generated on <%= Time.now %> with <a href="http://github.com/edgecase/ocov/tree/master">ocov <%= OCov.version %></a></p>
|
31
|
+
<hr />
|
32
|
+
<table class="report">
|
33
|
+
<thead>
|
34
|
+
<th class="filename">Name</th>
|
35
|
+
<th>Total Lines</th>
|
36
|
+
<th>Lines of Code</th>
|
37
|
+
<th>Coverage</th>
|
38
|
+
</thead>
|
39
|
+
<tbody>
|
40
|
+
<tr>
|
41
|
+
<td>TOTAL</td>
|
42
|
+
<td class="value"><%= total_lines %></td>
|
43
|
+
<td class="value"><%= total_lines_of_code %></td>
|
44
|
+
<td>
|
45
|
+
<table>
|
46
|
+
<tr>
|
47
|
+
<td class="value" style="border: 0px; width: 50px;"><%= '%.1f' % total_coverage %>%</td>
|
48
|
+
<td style="border: 0px;"><div class="graph_outer"><div class="graph_inner" style="width: <%= '%d' % total_coverage %>%;"></div></div></td>
|
49
|
+
</tr>
|
50
|
+
</table>
|
51
|
+
</td>
|
52
|
+
</tr>
|
53
|
+
|
54
|
+
<% files.each do |file| %>
|
55
|
+
<tr>
|
56
|
+
<td><a href="<%= file.name.gsub('.', '_') %>.html"><%= file.name %></a></td>
|
57
|
+
<td class="value"><%= file.total_lines %></td>
|
58
|
+
<td class="value"><%= file.lines_of_code %></td>
|
59
|
+
<td>
|
60
|
+
<table>
|
61
|
+
<tr>
|
62
|
+
<td class="value" style="border: 0px; width: 50px;"><%= '%.1f' % file.coverage %>%</td>
|
63
|
+
<td style="border: 0px;"><div class="graph_outer"><div class="graph_inner" style="width: <%= '%d' % file.coverage %>%;"></div></div></td>
|
64
|
+
</tr>
|
65
|
+
</table>
|
66
|
+
</td>
|
67
|
+
</tr>
|
68
|
+
<% end %>
|
69
|
+
</tbody>
|
70
|
+
</table>
|
71
|
+
</body>
|
72
|
+
</html>
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: edgecase-ocov
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "1.0"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- EdgeCase, LLC
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-01-11 00:00:00 -08:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: scott@edgecase.com
|
18
|
+
executables:
|
19
|
+
- ocov
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
files:
|
25
|
+
- Rakefile
|
26
|
+
- README.rdoc
|
27
|
+
- bin/ocov
|
28
|
+
- lib/ocov/gcov.rb
|
29
|
+
- lib/ocov/project.rb
|
30
|
+
- lib/ocov/source_line.rb
|
31
|
+
- lib/ocov/target.rb
|
32
|
+
- lib/ocov.rb
|
33
|
+
- lib/ocov/templates/file.html.erb
|
34
|
+
- lib/ocov/templates/index.html.erb
|
35
|
+
has_rdoc: true
|
36
|
+
homepage: http://github.com/edgecase/ocov/tree/master
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options:
|
39
|
+
- --line-numbers
|
40
|
+
- --inline-source
|
41
|
+
- --main
|
42
|
+
- README.rdoc
|
43
|
+
- --title
|
44
|
+
- Magic Bus
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.2.0
|
63
|
+
signing_key:
|
64
|
+
specification_version: 2
|
65
|
+
summary: C0 coverage report tool for Objective-C
|
66
|
+
test_files: []
|
67
|
+
|