piggly 1.2.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +40 -8
- data/bin/piggly +5 -2
- data/lib/piggly/parser/grammar.tt +2 -2
- data/lib/piggly/parser/parser.rb +33 -22
- data/lib/piggly/task.rb +2 -2
- data/lib/piggly/version.rb +2 -2
- metadata +2 -2
data/README.markdown
CHANGED
@@ -1,29 +1,54 @@
|
|
1
|
-
# Piggly - PostgreSQL PL/pgSQL stored
|
1
|
+
# Piggly - PostgreSQL PL/pgSQL stored-procedure code coverage for Ruby
|
2
|
+
|
3
|
+
## Purpose
|
4
|
+
|
5
|
+
PL/pgSQL doesn't have much in the way of developer tools, and writing automated tests for
|
6
|
+
stored procedures can go much better when you know what you haven't tested. Code coverage
|
7
|
+
allows you to see which parts of your code haven't been executed.
|
2
8
|
|
3
9
|
## What's Piggly?
|
4
|
-
|
5
|
-
|
10
|
+
|
11
|
+
Piggly is a tool written in Ruby to track code coverage of PostgreSQL's PL/pgSQL stored
|
12
|
+
procedures. It reports on code coverage to help you identify untested parts of your code. You
|
13
|
+
write tests in Ruby against your stored procedures and run them with piggly.
|
14
|
+
|
15
|
+
## How Does It Work?
|
16
|
+
|
17
|
+
Piggly tracks the execution of PostgreSQL's PL/pgSQL stored procedures by recompiling
|
18
|
+
the stored procedure with instrumentation code that uses RAISE WARNING to notify the
|
19
|
+
client of an execution event (e.g., a branch condition evaluating to true or false). It records
|
20
|
+
these events and generates prettified source code that is annotated with coverage details.
|
6
21
|
|
7
22
|
## Features
|
23
|
+
|
8
24
|
* Branch, block, and loop coverage analysis
|
9
25
|
* Instrumenting source-to-source compiler
|
10
26
|
* Low test execution overhead
|
11
27
|
* Reduced compilation times by use of disk caching
|
12
|
-
* Readable and easily
|
13
|
-
*
|
28
|
+
* Readable and easily-navigable reports (see example/piggly/reports/index.html)
|
29
|
+
* Possible to aggregate coverage across multiple runs
|
14
30
|
* Test::Unit and RSpec compatible
|
15
31
|
|
16
32
|
## Limitations
|
33
|
+
|
17
34
|
* Cannot parse aggregate definitions (but helper functions are fine)
|
18
35
|
* Cannot parse nested dollar-quoted strings, eg $A$ ... $B$ ... $B$ ... $A$
|
19
36
|
* Report generation is resource intensive and slow
|
37
|
+
* SQL statements are not instrumented, so their branches (COALESCE, WHERE-clauses, etc) aren't tracked
|
38
|
+
* Not all PL/pgSQL grammar is currently supported, but this is easily addressed
|
20
39
|
|
21
40
|
## Requirements
|
41
|
+
|
22
42
|
* [Treetop] [2]
|
23
|
-
* Stored procedures stored on the filesystem, defined
|
43
|
+
* Stored procedures stored on the filesystem, defined as `CREATE OR REPLACE FUNCTION`
|
24
44
|
* The [ruby-pg driver] [3], and for the time being, ActiveRecord (some workaround should be possible)
|
25
45
|
|
46
|
+
## How to Install
|
47
|
+
|
48
|
+
$ gem install piggly
|
49
|
+
|
26
50
|
## Usage
|
51
|
+
|
27
52
|
Assume your stored procedures are in proc/, and the tests that should be exercising your
|
28
53
|
stored procedures are in spec/.
|
29
54
|
|
@@ -57,16 +82,17 @@ stored procedures are in spec/.
|
|
57
82
|
-rw-r--r-- 1 kputnam kputnam 1.3K 2010-04-19 14:25 piggly/reports/index.html
|
58
83
|
|
59
84
|
Note the compilation can be slow on the first run, but on subsequent runs it shouldn't need
|
60
|
-
to
|
85
|
+
to compile everything again. If a file is added or changed (based on mtime), it will be recompiled.
|
61
86
|
|
62
87
|
Piggly can also be run from Rake, with a task like:
|
88
|
+
require 'piggly/task'
|
63
89
|
|
64
90
|
namespace :spec do
|
65
91
|
Piggly::Task.new(:piggly => 'db:test:prepare') do |t|
|
66
92
|
t.libs.push 'spec'
|
67
93
|
|
68
94
|
t.test_files = FileList['spec/**/*_spec.rb']
|
69
|
-
t.proc_files = FileList['
|
95
|
+
t.proc_files = FileList['proc/*.sql']
|
70
96
|
|
71
97
|
# this can be used if piggly is frozen in a Rails application
|
72
98
|
t.libs.concat Dir['vendor/gems/*/lib/'].sort.reverse
|
@@ -76,9 +102,15 @@ Piggly can also be run from Rake, with a task like:
|
|
76
102
|
|
77
103
|
$ rake spec:piggly
|
78
104
|
|
105
|
+
## Bugs & Issues
|
106
|
+
|
107
|
+
Please report any issues on the [github tracker] [4]
|
108
|
+
|
79
109
|
## Author
|
110
|
+
|
80
111
|
* Kyle Putnam <putnam.kyle@gmail.com>
|
81
112
|
|
82
113
|
[1]: http://github.com/relevance/rcov/
|
83
114
|
[2]: http://github.com/nathansobo/treetop
|
84
115
|
[3]: http://bitbucket.org/ged/ruby-pg/
|
116
|
+
[4]: http://github.com/kputnam/piggly/issues
|
data/bin/piggly
CHANGED
@@ -26,6 +26,7 @@ module Piggly
|
|
26
26
|
uninstall_procs(sources)
|
27
27
|
create_index(sources)
|
28
28
|
create_reports(sources)
|
29
|
+
exit! 0 # avoid running tests again
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
@@ -172,10 +173,12 @@ module Piggly
|
|
172
173
|
end
|
173
174
|
|
174
175
|
def execute_tests
|
175
|
-
if defined?
|
176
|
+
if defined? Test::Unit::AutoRunner
|
177
|
+
Test::Unit::AutoRunner.run
|
178
|
+
elsif defined? Spec::Runner
|
176
179
|
Spec::Runner.run
|
177
180
|
else
|
178
|
-
Test::Unit
|
181
|
+
raise "Neither RSpec nor Test::Unit were detected"
|
179
182
|
end
|
180
183
|
end
|
181
184
|
|
@@ -13,7 +13,7 @@ grammar Piggly
|
|
13
13
|
procedureHeader
|
14
14
|
name:tIdentifier tSpace?
|
15
15
|
parameters:parameterList tSpace
|
16
|
-
procedureReturn
|
16
|
+
procedureReturn
|
17
17
|
return:tType tSpace kwAS tSpace
|
18
18
|
procedureBody
|
19
19
|
procedureFooter <Procedure>
|
@@ -24,7 +24,7 @@ grammar Piggly
|
|
24
24
|
end
|
25
25
|
|
26
26
|
rule procedureReturn
|
27
|
-
'returns' tSpace 'setof'? <TextNode>
|
27
|
+
'returns' tSpace ( 'setof' tSpace )? <TextNode>
|
28
28
|
end
|
29
29
|
|
30
30
|
rule procedureBody
|
data/lib/piggly/parser/parser.rb
CHANGED
@@ -61,32 +61,28 @@ module Piggly
|
|
61
61
|
elements[5]
|
62
62
|
end
|
63
63
|
|
64
|
-
def
|
64
|
+
def return
|
65
65
|
elements[6]
|
66
66
|
end
|
67
67
|
|
68
|
-
def
|
68
|
+
def tSpace2
|
69
69
|
elements[7]
|
70
70
|
end
|
71
71
|
|
72
|
-
def
|
72
|
+
def kwAS
|
73
73
|
elements[8]
|
74
74
|
end
|
75
75
|
|
76
|
-
def
|
76
|
+
def tSpace3
|
77
77
|
elements[9]
|
78
78
|
end
|
79
79
|
|
80
|
-
def tSpace4
|
81
|
-
elements[10]
|
82
|
-
end
|
83
|
-
|
84
80
|
def procedureBody
|
85
|
-
elements[
|
81
|
+
elements[10]
|
86
82
|
end
|
87
83
|
|
88
84
|
def procedureFooter
|
89
|
-
elements[
|
85
|
+
elements[11]
|
90
86
|
end
|
91
87
|
end
|
92
88
|
|
@@ -125,27 +121,23 @@ module Piggly
|
|
125
121
|
r7 = _nt_procedureReturn
|
126
122
|
s0 << r7
|
127
123
|
if r7
|
128
|
-
r8 =
|
124
|
+
r8 = _nt_tType
|
129
125
|
s0 << r8
|
130
126
|
if r8
|
131
|
-
r9 =
|
127
|
+
r9 = _nt_tSpace
|
132
128
|
s0 << r9
|
133
129
|
if r9
|
134
|
-
r10 =
|
130
|
+
r10 = _nt_kwAS
|
135
131
|
s0 << r10
|
136
132
|
if r10
|
137
|
-
r11 =
|
133
|
+
r11 = _nt_tSpace
|
138
134
|
s0 << r11
|
139
135
|
if r11
|
140
|
-
r12 =
|
136
|
+
r12 = _nt_procedureBody
|
141
137
|
s0 << r12
|
142
138
|
if r12
|
143
|
-
r13 =
|
139
|
+
r13 = _nt_procedureFooter
|
144
140
|
s0 << r13
|
145
|
-
if r13
|
146
|
-
r14 = _nt_procedureFooter
|
147
|
-
s0 << r14
|
148
|
-
end
|
149
141
|
end
|
150
142
|
end
|
151
143
|
end
|
@@ -280,6 +272,12 @@ module Piggly
|
|
280
272
|
def tSpace
|
281
273
|
elements[1]
|
282
274
|
end
|
275
|
+
end
|
276
|
+
|
277
|
+
module ProcedureReturn1
|
278
|
+
def tSpace
|
279
|
+
elements[1]
|
280
|
+
end
|
283
281
|
|
284
282
|
end
|
285
283
|
|
@@ -307,11 +305,24 @@ module Piggly
|
|
307
305
|
r2 = _nt_tSpace
|
308
306
|
s0 << r2
|
309
307
|
if r2
|
308
|
+
i4, s4 = index, []
|
310
309
|
if has_terminal?('setof', false, index)
|
311
|
-
|
310
|
+
r5 = instantiate_node(SyntaxNode,input, index...(index + 5))
|
312
311
|
@index += 5
|
313
312
|
else
|
314
313
|
terminal_parse_failure('setof')
|
314
|
+
r5 = nil
|
315
|
+
end
|
316
|
+
s4 << r5
|
317
|
+
if r5
|
318
|
+
r6 = _nt_tSpace
|
319
|
+
s4 << r6
|
320
|
+
end
|
321
|
+
if s4.last
|
322
|
+
r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
|
323
|
+
r4.extend(ProcedureReturn0)
|
324
|
+
else
|
325
|
+
@index = i4
|
315
326
|
r4 = nil
|
316
327
|
end
|
317
328
|
if r4
|
@@ -324,7 +335,7 @@ module Piggly
|
|
324
335
|
end
|
325
336
|
if s0.last
|
326
337
|
r0 = instantiate_node(TextNode,input, i0...index, s0)
|
327
|
-
r0.extend(
|
338
|
+
r0.extend(ProcedureReturn1)
|
328
339
|
else
|
329
340
|
@index = i0
|
330
341
|
r0 = nil
|
data/lib/piggly/task.rb
CHANGED
@@ -23,7 +23,7 @@ module Piggly
|
|
23
23
|
@test_files = []
|
24
24
|
@proc_files = []
|
25
25
|
@ruby_opts = []
|
26
|
-
@
|
26
|
+
@report_dir = 'piggly/report'
|
27
27
|
@cache_root = 'piggly/cache'
|
28
28
|
@piggly_path = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'bin', 'piggly'))
|
29
29
|
@piggly_opts = ''
|
@@ -47,7 +47,7 @@ module Piggly
|
|
47
47
|
|
48
48
|
ruby opts.join(' ') + ' ' +
|
49
49
|
@piggly_opts + ' ' +
|
50
|
-
%{-o #{quote @
|
50
|
+
%{-o #{quote @report_dir} } +
|
51
51
|
%{-c #{quote @cache_root} } +
|
52
52
|
proc_files.map{|s| %[-s "#{s}" ] }.join +
|
53
53
|
test_files.map{|f| quote(f) }.join(' ')
|
data/lib/piggly/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: piggly
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kyle Putnam
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-04-
|
12
|
+
date: 2010-04-22 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|