piggly 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +84 -0
- data/Rakefile +19 -0
- data/bin/piggly +245 -0
- data/lib/piggly/compiler/cache.rb +151 -0
- data/lib/piggly/compiler/pretty.rb +67 -0
- data/lib/piggly/compiler/queue.rb +46 -0
- data/lib/piggly/compiler/tags.rb +244 -0
- data/lib/piggly/compiler/trace.rb +91 -0
- data/lib/piggly/compiler.rb +5 -0
- data/lib/piggly/config.rb +43 -0
- data/lib/piggly/filecache.rb +40 -0
- data/lib/piggly/installer.rb +95 -0
- data/lib/piggly/parser/grammar.tt +747 -0
- data/lib/piggly/parser/nodes.rb +319 -0
- data/lib/piggly/parser/parser.rb +11783 -0
- data/lib/piggly/parser/traversal.rb +48 -0
- data/lib/piggly/parser/treetop_ruby19_patch.rb +17 -0
- data/lib/piggly/parser.rb +67 -0
- data/lib/piggly/profile.rb +87 -0
- data/lib/piggly/reporter/html.rb +207 -0
- data/lib/piggly/reporter/piggly.css +187 -0
- data/lib/piggly/reporter/sortable.js +493 -0
- data/lib/piggly/reporter.rb +21 -0
- data/lib/piggly/task.rb +64 -0
- data/lib/piggly/util.rb +28 -0
- data/lib/piggly/version.rb +15 -0
- data/lib/piggly.rb +18 -0
- data/spec/compiler/cache_spec.rb +9 -0
- data/spec/compiler/pretty_spec.rb +9 -0
- data/spec/compiler/queue_spec.rb +3 -0
- data/spec/compiler/rewrite_spec.rb +3 -0
- data/spec/compiler/tags_spec.rb +285 -0
- data/spec/compiler/trace_spec.rb +173 -0
- data/spec/config_spec.rb +58 -0
- data/spec/filecache_spec.rb +70 -0
- data/spec/fixtures/snippets.sql +158 -0
- data/spec/grammar/expression_spec.rb +302 -0
- data/spec/grammar/statements/assignment_spec.rb +70 -0
- data/spec/grammar/statements/exception_spec.rb +52 -0
- data/spec/grammar/statements/if_spec.rb +178 -0
- data/spec/grammar/statements/loop_spec.rb +41 -0
- data/spec/grammar/statements/sql_spec.rb +71 -0
- data/spec/grammar/tokens/comment_spec.rb +58 -0
- data/spec/grammar/tokens/datatype_spec.rb +52 -0
- data/spec/grammar/tokens/identifier_spec.rb +58 -0
- data/spec/grammar/tokens/keyword_spec.rb +44 -0
- data/spec/grammar/tokens/label_spec.rb +40 -0
- data/spec/grammar/tokens/literal_spec.rb +30 -0
- data/spec/grammar/tokens/lval_spec.rb +50 -0
- data/spec/grammar/tokens/number_spec.rb +34 -0
- data/spec/grammar/tokens/sqlkeywords_spec.rb +45 -0
- data/spec/grammar/tokens/string_spec.rb +54 -0
- data/spec/grammar/tokens/whitespace_spec.rb +40 -0
- data/spec/parser_spec.rb +8 -0
- data/spec/profile_spec.rb +5 -0
- data/spec/reporter/html_spec.rb +0 -0
- data/spec/spec_helper.rb +61 -0
- data/spec/spec_suite.rb +5 -0
- metadata +121 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
module Piggly
|
2
|
+
|
3
|
+
#
|
4
|
+
# Routines for traversing a tree; assumes base class defines elements
|
5
|
+
# as a method that returns a list of child nodes
|
6
|
+
#
|
7
|
+
module NodeTraversal
|
8
|
+
def fold_down(init) # :yields: NodeClass => init
|
9
|
+
if elements
|
10
|
+
elements.inject(yield(init, self)) do |state, e|
|
11
|
+
e.fold_down(state){|succ, n| yield(succ, n) }
|
12
|
+
end
|
13
|
+
else
|
14
|
+
yield(init, self)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def count # :yields: NodeClass => boolean
|
19
|
+
fold_down(0){|sum, e| yield(e) ? sum + 1 : sum }
|
20
|
+
end
|
21
|
+
|
22
|
+
def find # :yields: NodeClass => boolean
|
23
|
+
found = false
|
24
|
+
catch :done do
|
25
|
+
fold_down(nil) do |_,e|
|
26
|
+
if yield(e)
|
27
|
+
found = e
|
28
|
+
throw :done
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
found
|
33
|
+
end
|
34
|
+
|
35
|
+
def select # :yields: NodeClass => boolean
|
36
|
+
fold_down([]){|list,e| yield(e) ? list << e : list }
|
37
|
+
end
|
38
|
+
|
39
|
+
def flatten # :yields: NodeClass
|
40
|
+
if block_given?
|
41
|
+
fold_down([]){|list,e| list << yield(e) }
|
42
|
+
else
|
43
|
+
fold_down([]){|list,e| list << e }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Piggly
|
2
|
+
|
3
|
+
#
|
4
|
+
# Pl/pgSQL Parser, returns a tree of NodeClass values (see nodes.rb)
|
5
|
+
#
|
6
|
+
class Parser
|
7
|
+
include FileCache
|
8
|
+
|
9
|
+
class Failure < RuntimeError; end
|
10
|
+
|
11
|
+
# Returns parse tree
|
12
|
+
def self.parse(string)
|
13
|
+
p = parser
|
14
|
+
|
15
|
+
begin
|
16
|
+
# downcase input for case-insensitive parsing,
|
17
|
+
# then restore original string after parsing
|
18
|
+
input = string.downcase
|
19
|
+
tree = p.parse(input)
|
20
|
+
tree or raise Failure, "#{p.failure_reason}"
|
21
|
+
rescue Failure
|
22
|
+
$!.backtrace.clear
|
23
|
+
raise
|
24
|
+
ensure
|
25
|
+
input.replace string
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.parser_path; File.join(File.dirname(__FILE__), 'parser', 'parser.rb') end
|
30
|
+
def self.grammar_path; File.join(File.dirname(__FILE__), 'parser', 'grammar.tt') end
|
31
|
+
def self.nodes_path; File.join(File.dirname(__FILE__), 'parser', 'nodes.rb') end
|
32
|
+
|
33
|
+
def self.stale?(source)
|
34
|
+
File.stale?(cache_path(source), source, grammar_path, parser_path, nodes_path)
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.cache(source)
|
38
|
+
cache = cache_path(source)
|
39
|
+
|
40
|
+
if stale?(source)
|
41
|
+
tree = parse(File.read(source))
|
42
|
+
File.open(cache, 'w+') do |f|
|
43
|
+
Marshal.dump(tree, f)
|
44
|
+
tree
|
45
|
+
end
|
46
|
+
else
|
47
|
+
_ = parser # ensure parser libraries, like nodes.rb, are loaded
|
48
|
+
Marshal.load(File.read(cache))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns treetop parser (recompiled as needed)
|
53
|
+
def self.parser
|
54
|
+
require 'treetop'
|
55
|
+
require 'piggly/parser/treetop_ruby19_patch'
|
56
|
+
require nodes_path
|
57
|
+
|
58
|
+
if File.stale?(parser_path, grammar_path)
|
59
|
+
Treetop::Compiler::GrammarCompiler.new.compile(grammar_path, parser_path)
|
60
|
+
end
|
61
|
+
|
62
|
+
require parser_path
|
63
|
+
::PigglyParser.new
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Piggly
|
2
|
+
|
3
|
+
#
|
4
|
+
# Collection of all Tags
|
5
|
+
#
|
6
|
+
class Profile
|
7
|
+
PATTERN = /WARNING: #{Config.trace_prefix} (#{Tag::PATTERN})(?: (.))?/
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
# Build a notice processor function that records each tag execution
|
12
|
+
def notice_processor
|
13
|
+
proc do |message|
|
14
|
+
if m = PATTERN.match(message)
|
15
|
+
ping(m.captures[0], m.captures[1])
|
16
|
+
else
|
17
|
+
STDERR.puts message
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Register a source file (path) with its list of tags
|
23
|
+
def add(path, tags, cache = nil)
|
24
|
+
tags.each{|t| by_id[t.id] = t }
|
25
|
+
by_file[path] = tags
|
26
|
+
by_cache[cache] = tags if cache
|
27
|
+
end
|
28
|
+
|
29
|
+
# Each tag indexed by unique ID
|
30
|
+
def by_id
|
31
|
+
@by_id ||= Hash.new
|
32
|
+
end
|
33
|
+
|
34
|
+
# Each tag grouped by source file path
|
35
|
+
def by_file
|
36
|
+
@by_file ||= Hash.new
|
37
|
+
end
|
38
|
+
|
39
|
+
# Each tag grouped by FileCache
|
40
|
+
def by_cache
|
41
|
+
@by_cache ||= Hash.new
|
42
|
+
end
|
43
|
+
|
44
|
+
# Record the execution of a coverage tag
|
45
|
+
def ping(tag_id, value=nil)
|
46
|
+
if tag = by_id[tag_id]
|
47
|
+
tag.ping(value)
|
48
|
+
else
|
49
|
+
raise "No tag with id #{tag_id}, perhaps the proc was not compiled with Piggly::Installer.trace_proc, or it has been recompiled with new tag IDs."
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Summarizes coverage for each type of tag (branch, block, loop)
|
54
|
+
def summary(file = nil)
|
55
|
+
summary = Hash.new{|h,k| h[k] = Hash.new }
|
56
|
+
|
57
|
+
if file
|
58
|
+
if by_file.include?(file)
|
59
|
+
grouped = by_file[file].group_by{|t| t.type }
|
60
|
+
else
|
61
|
+
grouped = {}
|
62
|
+
end
|
63
|
+
else
|
64
|
+
grouped = map.group_by{|t| t.type }
|
65
|
+
end
|
66
|
+
|
67
|
+
grouped.each do |type, ts|
|
68
|
+
summary[type][:count] = ts.size
|
69
|
+
summary[type][:percent] = ts.sum{|t| t.to_f } / ts.size
|
70
|
+
end
|
71
|
+
|
72
|
+
summary
|
73
|
+
end
|
74
|
+
|
75
|
+
# Resets each tag's coverage stats
|
76
|
+
def clear
|
77
|
+
by_id.values.each{|t| t.clear }
|
78
|
+
end
|
79
|
+
|
80
|
+
# Write each tag's coverage stats to the disk cache
|
81
|
+
def store
|
82
|
+
by_cache.each{|cache, tags| cache[:tags] = tags }
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
module Piggly
|
2
|
+
|
3
|
+
#
|
4
|
+
# Markup DSL
|
5
|
+
#
|
6
|
+
module HtmlTag
|
7
|
+
unless defined? HTML_REPLACE
|
8
|
+
HTML_REPLACE = { '&' => '&', '"' => '"', '>' => '>', '<' => '<' }
|
9
|
+
HTML_PATTERN = /[&"<>]/
|
10
|
+
end
|
11
|
+
|
12
|
+
def html(output = '')
|
13
|
+
begin
|
14
|
+
@htmltag_output, htmltag_output = output, @htmltag_output
|
15
|
+
# TODO: doctype
|
16
|
+
yield
|
17
|
+
ensure
|
18
|
+
# restore
|
19
|
+
@htmltag_output = htmltag_output
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def tag(name, content = nil, attributes = {})
|
24
|
+
if content.is_a?(Hash) and attributes.empty?
|
25
|
+
content, attributes = nil, content
|
26
|
+
end
|
27
|
+
|
28
|
+
attributes = attributes.inject('') do |string, pair|
|
29
|
+
k, v = pair
|
30
|
+
string << %[ #{k}="#{v}"]
|
31
|
+
end
|
32
|
+
|
33
|
+
if content.nil?
|
34
|
+
if block_given?
|
35
|
+
@htmltag_output << "<#{name}#{attributes}>"
|
36
|
+
yield
|
37
|
+
@htmltag_output << "</#{name}>"
|
38
|
+
else
|
39
|
+
@htmltag_output << "<#{name}#{attributes}/>"
|
40
|
+
end
|
41
|
+
else
|
42
|
+
@htmltag_output << "<#{name}#{attributes}>#{content.to_s}</#{name}>"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
if ''.respond_to?(:fast_xs)
|
47
|
+
def e(string)
|
48
|
+
e.fast_xs
|
49
|
+
end
|
50
|
+
elsif ''.respond_to?(:to_xs)
|
51
|
+
def e(string)
|
52
|
+
e.to_xs
|
53
|
+
end
|
54
|
+
else
|
55
|
+
def e(string)
|
56
|
+
string.gsub(HTML_PATTERN) {|c| HTML_REPLACE[c] }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class HtmlReporter < Reporter
|
62
|
+
extend HtmlTag
|
63
|
+
|
64
|
+
def self.output(path, data, summary)
|
65
|
+
File.open(report_path(path, '.html'), 'w') do |f|
|
66
|
+
html(f) do
|
67
|
+
|
68
|
+
tag :html, :xmlns => 'http://www.w3.org/1999/xhtml' do
|
69
|
+
tag :head do
|
70
|
+
tag :title, "Code Coverage: #{File.basename(path)}"
|
71
|
+
tag :link, :rel => 'stylesheet', :type => 'text/css', :href => 'piggly.css'
|
72
|
+
end
|
73
|
+
|
74
|
+
tag :body do
|
75
|
+
table(path)
|
76
|
+
|
77
|
+
tag :br
|
78
|
+
tag :div, :class => 'listing' do
|
79
|
+
tag :table do
|
80
|
+
tag :tr do
|
81
|
+
tag :td, data.fetch('lines').to_a.map{|n| %[<a href="#L#{n}" id="L#{n}">#{n}</a>] }.join("\n"), :class => 'lines'
|
82
|
+
tag :td, data.fetch('html'), :class => 'code'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
toc(data.fetch('tags'))
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.toc(tags)
|
96
|
+
todo = tags.reject{|t| t.complete? }
|
97
|
+
|
98
|
+
tag :div, :class => 'toc' do
|
99
|
+
tag :a, 'Index', :href => 'index.html'
|
100
|
+
|
101
|
+
unless todo.empty?
|
102
|
+
tag :ol do
|
103
|
+
todo.each do |t|
|
104
|
+
tag(:li, :class => t.type) { tag :a, t.description, :href => "#T#{t.id}" }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.timestamp
|
112
|
+
tag :div, "Generated by piggly #{Piggly::VERSION} at #{Time.now.strftime('%B %d, %Y %H:%M %Z')}", :class => 'timestamp'
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.table(*files)
|
116
|
+
tag :table, :class => 'summary sortable' do
|
117
|
+
tag :tr do
|
118
|
+
tag :th, 'File'
|
119
|
+
tag :th, 'Blocks'
|
120
|
+
tag :th, 'Loops'
|
121
|
+
tag :th, 'Branches'
|
122
|
+
tag :th, 'Block Coverage'
|
123
|
+
tag :th, 'Loop Coverage'
|
124
|
+
tag :th, 'Branch Coverage'
|
125
|
+
end
|
126
|
+
|
127
|
+
files.each_with_index do |name, index|
|
128
|
+
summary = Profile.summary(name)
|
129
|
+
row = index.modulo(2) == 0 ? 'even' : 'odd'
|
130
|
+
|
131
|
+
tag :tr, :class => row do
|
132
|
+
unless summary.include?(:block) or summary.include?(:loop) or summary.include?(:branch)
|
133
|
+
# PigglyParser couldn't parse this file
|
134
|
+
tag :td, File.basename(name), :class => 'file fail'
|
135
|
+
tag(:td, :class => 'count') { tag :span, -1, :style => 'display:none' }
|
136
|
+
tag(:td, :class => 'count') { tag :span, -1, :style => 'display:none' }
|
137
|
+
tag(:td, :class => 'count') { tag :span, -1, :style => 'display:none' }
|
138
|
+
tag(:td, :class => 'pct') { tag :span, -1, :style => 'display:none' }
|
139
|
+
tag(:td, :class => 'pct') { tag :span, -1, :style => 'display:none' }
|
140
|
+
tag(:td, :class => 'pct') { tag :span, -1, :style => 'display:none' }
|
141
|
+
else
|
142
|
+
tag(:td, :class => 'file') { tag :a, File.basename(name), :href => File.basename(name, '.*') + '.html' }
|
143
|
+
tag :td, (summary[:block][:count] || 0), :class => 'count'
|
144
|
+
tag :td, (summary[:loop][:count] || 0), :class => 'count'
|
145
|
+
tag :td, (summary[:branch][:count] || 0), :class => 'count'
|
146
|
+
tag(:td, :class => 'pct') { percent(summary[:block][:percent]) }
|
147
|
+
tag(:td, :class => 'pct') { percent(summary[:loop][:percent]) }
|
148
|
+
tag(:td, :class => 'pct') { percent(summary[:branch][:percent]) }
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.percent(pct)
|
157
|
+
if pct
|
158
|
+
tag :table, :align => 'center' do
|
159
|
+
tag :tr do
|
160
|
+
|
161
|
+
tag :td, '%0.2f%% ' % pct, :class => 'num'
|
162
|
+
tag :td, :class => 'graph' do
|
163
|
+
if pct
|
164
|
+
tag :table, :align => 'right', :class => 'graph' do
|
165
|
+
tag :tr do
|
166
|
+
tag :td, :class => 'covered', :width => (pct/2.0).to_i
|
167
|
+
tag :td, :class => 'uncovered', :width => ((100-pct)/2.0).to_i
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
end
|
175
|
+
else
|
176
|
+
tag :span, -1, :style => 'display:none'
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
class Index < HtmlReporter
|
181
|
+
extend HtmlTag
|
182
|
+
|
183
|
+
def self.output(sources)
|
184
|
+
File.open(File.join(report_path, 'index.html'), 'w') do |f|
|
185
|
+
html(f) do
|
186
|
+
|
187
|
+
tag :html do
|
188
|
+
tag :head do
|
189
|
+
tag :title, 'Piggly PL/pgSQL Code Coverage'
|
190
|
+
tag :link, :rel => 'stylesheet', :type => 'text/css', :href => 'piggly.css'
|
191
|
+
tag :script, '<!-- -->', :type => 'text/javascript', :src => 'sortable.js'
|
192
|
+
end
|
193
|
+
|
194
|
+
tag :body do
|
195
|
+
table(*sources.sort)
|
196
|
+
tag :br
|
197
|
+
timestamp
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
* { margin: 0; padding: 0; }
|
2
|
+
|
3
|
+
body
|
4
|
+
{
|
5
|
+
color: #000;
|
6
|
+
background-color: #fff;
|
7
|
+
padding: 8px;
|
8
|
+
}
|
9
|
+
|
10
|
+
a img { border: 0; }
|
11
|
+
|
12
|
+
div.timestamp { clear: both; }
|
13
|
+
|
14
|
+
div.toc
|
15
|
+
{
|
16
|
+
width: 200px;
|
17
|
+
height: 150px;
|
18
|
+
border: 1px solid #c00;
|
19
|
+
background-color: #fee;
|
20
|
+
padding: 5px;
|
21
|
+
position: fixed;
|
22
|
+
overflow: auto;
|
23
|
+
bottom: 10px;
|
24
|
+
right: 10px;
|
25
|
+
font-family: "Tahoma", "Trebuchet MS", "Arial", sans-serif;
|
26
|
+
}
|
27
|
+
div.toc ol { margin-left: 1.6em; }
|
28
|
+
div.toc a { color: #c00; }
|
29
|
+
div.toc li { font-size: 75%; }
|
30
|
+
div.toc li.branch { }
|
31
|
+
div.toc li.block { }
|
32
|
+
div.toc li.loop { }
|
33
|
+
|
34
|
+
/* main container for line numbers and code */
|
35
|
+
div.listing
|
36
|
+
{
|
37
|
+
background-color: #f9f9f9;
|
38
|
+
border: 1px solid silver;
|
39
|
+
margin: 0 0 1.5em 0;
|
40
|
+
overflow: auto;
|
41
|
+
}
|
42
|
+
|
43
|
+
div.listing table { border-collapse: collapse; }
|
44
|
+
div.listing td.code
|
45
|
+
{
|
46
|
+
vertical-align: top;
|
47
|
+
padding: 2px 4px;
|
48
|
+
white-space: pre;
|
49
|
+
|
50
|
+
margin: 0;
|
51
|
+
width: 100%;
|
52
|
+
float: none;
|
53
|
+
clear: none;
|
54
|
+
overflow: visible;
|
55
|
+
|
56
|
+
color: #000;
|
57
|
+
font-family: "DejaVu Sans Mono", "Monaco", "Consolas", "Nimbus Mono L", "Courier New";
|
58
|
+
font-size: 9pt;
|
59
|
+
}
|
60
|
+
|
61
|
+
/* line numbers */
|
62
|
+
div.listing td.lines
|
63
|
+
{
|
64
|
+
vertical-align: top;
|
65
|
+
padding: 2px 4px;
|
66
|
+
white-space: pre;
|
67
|
+
|
68
|
+
text-align: right;
|
69
|
+
overflow: visible;
|
70
|
+
|
71
|
+
background-color: #def;
|
72
|
+
font-size: 9pt;
|
73
|
+
font-family: "DejaVu Sans Mono", "Monaco", "Consolas", "Nimbus Mono L", "Courier New";
|
74
|
+
}
|
75
|
+
div.listing td.lines a { color: grey; text-decoration: none; }
|
76
|
+
|
77
|
+
table.summary th { padding: 5px; border: 1px solid silver; font-weight: bold; font-size: 12px; background-color: #def; }
|
78
|
+
table.summary td { padding: 5px; font-size: 10pt; }
|
79
|
+
|
80
|
+
table.summary td.file { text-align: left; border: 0; }
|
81
|
+
table.summary td.fail { font-weight: bold; color: #f00; }
|
82
|
+
table.summary td.count { max-width: 50px; min-width: 50px; text-align: right; border: 1px solid silver; }
|
83
|
+
table.summary td.pct { max-width: 100px; min-width: 100px; text-align: right; border: 0; }
|
84
|
+
|
85
|
+
table.summary td.pct td.num { padding: 0; max-width: 50px; min-width: 50px; text-align: right; border: 0; }
|
86
|
+
table.summary td.pct td.graph { padding: 0; max-width: 50px; min-width: 50px; text-align: right; border: 0; }
|
87
|
+
|
88
|
+
table.graph td.uncovered { background-color: #669; border: 0px; padding: 0px; }
|
89
|
+
table.graph td.covered { background-color: #ccf; border: 0px; padding: 0px; }
|
90
|
+
|
91
|
+
table.summary
|
92
|
+
{
|
93
|
+
font-family: "Tahoma", "Trebuchet MS", "Arial", sans-serif;
|
94
|
+
width: 100%;
|
95
|
+
border-spacing: 0;
|
96
|
+
border-collapse: collapse;
|
97
|
+
}
|
98
|
+
|
99
|
+
table.summary td.pct table
|
100
|
+
{
|
101
|
+
font-size: 85%;
|
102
|
+
font-family: "Tahoma", "Trebuchet MS", "Arial", sans-serif;
|
103
|
+
padding: 0;
|
104
|
+
border-spacing: 0;
|
105
|
+
border-collapse: collapse;
|
106
|
+
}
|
107
|
+
|
108
|
+
table.graph
|
109
|
+
{
|
110
|
+
min-width: 50px;
|
111
|
+
max-width: 50px;
|
112
|
+
padding: 0px;
|
113
|
+
border: 1px solid #000;
|
114
|
+
border-spacing: 0px;
|
115
|
+
height: 10px;
|
116
|
+
}
|
117
|
+
|
118
|
+
/* SYNTAX HIGHLIGHTING */
|
119
|
+
|
120
|
+
/* identifier */
|
121
|
+
.tI { color: #666; }
|
122
|
+
|
123
|
+
/* data type */
|
124
|
+
.tD { color: #cc3; font-style: italic; }
|
125
|
+
|
126
|
+
/* keyword */
|
127
|
+
.tK { color: #f30; }
|
128
|
+
|
129
|
+
/* comment */
|
130
|
+
.tC { color: #66f; font-style: italic; }
|
131
|
+
|
132
|
+
/* sql statement */
|
133
|
+
.tQ { color: #6c3; font-style: italic; }
|
134
|
+
|
135
|
+
/* string literal */
|
136
|
+
.tS { color: #390; }
|
137
|
+
|
138
|
+
/* label */
|
139
|
+
.tL { color: #630; font-style: italic; }
|
140
|
+
|
141
|
+
/* dollar quote marker */
|
142
|
+
.tM { }
|
143
|
+
|
144
|
+
/* tagged code blocks */
|
145
|
+
.b { display: block; width: 100%; margin: 0; padding: 0; }
|
146
|
+
.i { display: inline; }
|
147
|
+
|
148
|
+
/* line with incomplete coverage */
|
149
|
+
.lU
|
150
|
+
{
|
151
|
+
display: block;
|
152
|
+
background: #fdd;
|
153
|
+
|
154
|
+
margin: 0px;
|
155
|
+
padding: 0px;
|
156
|
+
border: none;
|
157
|
+
border-left: 2px solid #f00;
|
158
|
+
}
|
159
|
+
|
160
|
+
/* block execution: yes, no */
|
161
|
+
.c0 { font-weight: bold; }
|
162
|
+
.c1 { }
|
163
|
+
|
164
|
+
/* loop coverage */
|
165
|
+
.l0000 { font-weight: bold; }
|
166
|
+
.l0001 { font-weight: bold; }
|
167
|
+
.l0010 { font-weight: bold; }
|
168
|
+
.l0100 { font-weight: bold; }
|
169
|
+
.l0011 { font-weight: bold; }
|
170
|
+
.l0101 { font-weight: bold; }
|
171
|
+
.l0110 { font-weight: bold; }
|
172
|
+
.l0111 { font-weight: bold; }
|
173
|
+
.l1000 { font-weight: bold; }
|
174
|
+
.l1001 { font-weight: bold; }
|
175
|
+
.l1010 { font-weight: bold; }
|
176
|
+
.l1100 { font-weight: bold; }
|
177
|
+
.l1011 { font-weight: bold; }
|
178
|
+
.l1101 { font-weight: bold; }
|
179
|
+
.l1110 { font-weight: bold; }
|
180
|
+
.l1111 { }
|
181
|
+
|
182
|
+
/* branch decisions: true, false */
|
183
|
+
.b00 { font-weight: bold; } /* never evaluated */
|
184
|
+
.b01 { font-weight: bold; color: #060; } /* never evaluates true */
|
185
|
+
.b10 { font-weight: bold; color: #900; } /* never evaluates false */
|
186
|
+
.b11 { }
|
187
|
+
|