piggly-nsd 2.3.3
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.
- checksums.yaml +7 -0
- data/README.md +170 -0
- data/Rakefile +33 -0
- data/bin/piggly +8 -0
- data/lib/piggly/command/base.rb +148 -0
- data/lib/piggly/command/report.rb +162 -0
- data/lib/piggly/command/trace.rb +90 -0
- data/lib/piggly/command/untrace.rb +78 -0
- data/lib/piggly/command.rb +8 -0
- data/lib/piggly/compiler/cache_dir.rb +119 -0
- data/lib/piggly/compiler/coverage_report.rb +63 -0
- data/lib/piggly/compiler/trace_compiler.rb +117 -0
- data/lib/piggly/compiler.rb +7 -0
- data/lib/piggly/config.rb +80 -0
- data/lib/piggly/dumper/index.rb +121 -0
- data/lib/piggly/dumper/qualified_name.rb +36 -0
- data/lib/piggly/dumper/qualified_type.rb +141 -0
- data/lib/piggly/dumper/reified_procedure.rb +172 -0
- data/lib/piggly/dumper/skeleton_procedure.rb +112 -0
- data/lib/piggly/dumper.rb +9 -0
- data/lib/piggly/installer.rb +137 -0
- data/lib/piggly/parser/grammar.tt +748 -0
- data/lib/piggly/parser/nodes.rb +378 -0
- data/lib/piggly/parser/traversal.rb +50 -0
- data/lib/piggly/parser/treetop_ruby19_patch.rb +21 -0
- data/lib/piggly/parser.rb +69 -0
- data/lib/piggly/profile.rb +108 -0
- data/lib/piggly/reporter/base.rb +106 -0
- data/lib/piggly/reporter/html_dsl.rb +63 -0
- data/lib/piggly/reporter/index.rb +114 -0
- data/lib/piggly/reporter/procedure.rb +129 -0
- data/lib/piggly/reporter/resources/highlight.js +38 -0
- data/lib/piggly/reporter/resources/piggly.css +515 -0
- data/lib/piggly/reporter/resources/sortable.js +493 -0
- data/lib/piggly/reporter.rb +8 -0
- data/lib/piggly/tags.rb +280 -0
- data/lib/piggly/task.rb +215 -0
- data/lib/piggly/util/blankslate.rb +114 -0
- data/lib/piggly/util/cacheable.rb +19 -0
- data/lib/piggly/util/enumerable.rb +44 -0
- data/lib/piggly/util/file.rb +17 -0
- data/lib/piggly/util/process_queue.rb +96 -0
- data/lib/piggly/util/thunk.rb +39 -0
- data/lib/piggly/util.rb +9 -0
- data/lib/piggly/version.rb +15 -0
- data/lib/piggly.rb +20 -0
- data/spec/examples/compiler/cacheable_spec.rb +190 -0
- data/spec/examples/compiler/report_spec.rb +25 -0
- data/spec/examples/compiler/trace_spec.rb +123 -0
- data/spec/examples/config_spec.rb +63 -0
- data/spec/examples/dumper/index_spec.rb +199 -0
- data/spec/examples/dumper/procedure_spec.rb +116 -0
- data/spec/examples/grammar/expression_spec.rb +302 -0
- data/spec/examples/grammar/statements/assignment_spec.rb +70 -0
- data/spec/examples/grammar/statements/declaration_spec.rb +21 -0
- data/spec/examples/grammar/statements/exception_spec.rb +78 -0
- data/spec/examples/grammar/statements/if_spec.rb +191 -0
- data/spec/examples/grammar/statements/loop_spec.rb +41 -0
- data/spec/examples/grammar/statements/sql_spec.rb +71 -0
- data/spec/examples/grammar/tokens/comment_spec.rb +58 -0
- data/spec/examples/grammar/tokens/datatype_spec.rb +58 -0
- data/spec/examples/grammar/tokens/identifier_spec.rb +74 -0
- data/spec/examples/grammar/tokens/keyword_spec.rb +44 -0
- data/spec/examples/grammar/tokens/label_spec.rb +40 -0
- data/spec/examples/grammar/tokens/literal_spec.rb +30 -0
- data/spec/examples/grammar/tokens/lval_spec.rb +50 -0
- data/spec/examples/grammar/tokens/number_spec.rb +34 -0
- data/spec/examples/grammar/tokens/sqlkeywords_spec.rb +45 -0
- data/spec/examples/grammar/tokens/string_spec.rb +54 -0
- data/spec/examples/grammar/tokens/whitespace_spec.rb +40 -0
- data/spec/examples/installer_spec.rb +59 -0
- data/spec/examples/parser/nodes_spec.rb +73 -0
- data/spec/examples/parser/traversal_spec.rb +14 -0
- data/spec/examples/parser_spec.rb +118 -0
- data/spec/examples/profile_spec.rb +153 -0
- data/spec/examples/reporter/html/dsl_spec.rb +0 -0
- data/spec/examples/reporter/html/index_spec.rb +0 -0
- data/spec/examples/reporter/html_spec.rb +1 -0
- data/spec/examples/reporter_spec.rb +0 -0
- data/spec/examples/tags_spec.rb +285 -0
- data/spec/examples/task_spec.rb +0 -0
- data/spec/examples/util/cacheable_spec.rb +41 -0
- data/spec/examples/util/enumerable_spec.rb +64 -0
- data/spec/examples/util/file_spec.rb +40 -0
- data/spec/examples/util/process_queue_spec.rb +16 -0
- data/spec/examples/util/thunk_spec.rb +59 -0
- data/spec/examples/version_spec.rb +0 -0
- data/spec/issues/007_spec.rb +25 -0
- data/spec/issues/008_spec.rb +73 -0
- data/spec/issues/018_spec.rb +25 -0
- data/spec/issues/028_spec.rb +48 -0
- data/spec/issues/032_spec.rb +98 -0
- data/spec/issues/036_spec.rb +41 -0
- data/spec/spec_helper.rb +312 -0
- data/spec/spec_suite.rb +5 -0
- metadata +162 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Piggly
|
|
4
|
+
|
|
5
|
+
describe Tags::AbstractTag do
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
describe Tags::EvaluationTag do
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe Tags::BlockTag do
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe Tags::UnconditionalBranchTag do
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe Tags::ConditionalLoopTag do
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe Tags::UnconditionalLoopTag do
|
|
21
|
+
before do
|
|
22
|
+
@tag = Tags::UnconditionalLoopTag.new('for-loop')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "starts with state 00 (0b0000)" do
|
|
26
|
+
# - terminates normally
|
|
27
|
+
# - pass through
|
|
28
|
+
# - iterate only once
|
|
29
|
+
# - iterate more than once
|
|
30
|
+
@tag.state.should == 0b0000
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "detects state 01 (0b0001)" do
|
|
34
|
+
# - terminates normally
|
|
35
|
+
# - pass through
|
|
36
|
+
# - iterate only once
|
|
37
|
+
# + iterate more than once
|
|
38
|
+
|
|
39
|
+
# two iterations
|
|
40
|
+
@tag.ping('t')
|
|
41
|
+
@tag.ping('t')
|
|
42
|
+
@tag.ping('f')
|
|
43
|
+
|
|
44
|
+
@tag.state.should == 0b0001
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "detects state 02 (0b0010)" do
|
|
48
|
+
# - terminates normally
|
|
49
|
+
# - pass through
|
|
50
|
+
# + iterate only once
|
|
51
|
+
# - iterate more than once
|
|
52
|
+
|
|
53
|
+
# one iteration
|
|
54
|
+
@tag.ping('t')
|
|
55
|
+
@tag.ping('f')
|
|
56
|
+
|
|
57
|
+
@tag.state.should == 0b0010
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "detects state 03 (0b0011)" do
|
|
61
|
+
# - terminates normally
|
|
62
|
+
# - pass through
|
|
63
|
+
# + iterate only once
|
|
64
|
+
# + iterate more than once
|
|
65
|
+
|
|
66
|
+
# one iteration
|
|
67
|
+
@tag.ping('t')
|
|
68
|
+
@tag.ping('f')
|
|
69
|
+
|
|
70
|
+
# two iterations
|
|
71
|
+
@tag.ping('t')
|
|
72
|
+
@tag.ping('t')
|
|
73
|
+
@tag.ping('f')
|
|
74
|
+
|
|
75
|
+
@tag.state.should == 0b0011
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "detects state 04 (0b0100)" do
|
|
79
|
+
# - terminates normally
|
|
80
|
+
# + pass through
|
|
81
|
+
# - iterate only once
|
|
82
|
+
# - iterate more than once
|
|
83
|
+
|
|
84
|
+
# zero iterations
|
|
85
|
+
@tag.ping('f')
|
|
86
|
+
|
|
87
|
+
@tag.state.should == 0b0100
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "detects state 05 (0b0101)" do
|
|
91
|
+
# - terminates normally
|
|
92
|
+
# + pass through
|
|
93
|
+
# - iterate only once
|
|
94
|
+
# + iterate more than once
|
|
95
|
+
|
|
96
|
+
# zero iterations
|
|
97
|
+
@tag.ping('f')
|
|
98
|
+
|
|
99
|
+
# two iterations
|
|
100
|
+
@tag.ping('t')
|
|
101
|
+
@tag.ping('t')
|
|
102
|
+
@tag.ping('f')
|
|
103
|
+
|
|
104
|
+
@tag.state.should == 0b0101
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it "detects state 06 (0b0110)" do
|
|
108
|
+
# - terminates normally
|
|
109
|
+
# + pass through
|
|
110
|
+
# + iterate only once
|
|
111
|
+
# - iterate more than once
|
|
112
|
+
|
|
113
|
+
# zero iterations
|
|
114
|
+
@tag.ping('f')
|
|
115
|
+
|
|
116
|
+
# one iteration
|
|
117
|
+
@tag.ping('t')
|
|
118
|
+
@tag.ping('f')
|
|
119
|
+
|
|
120
|
+
@tag.state.should == 0b0110
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "detects state 07 (0b0111)" do
|
|
124
|
+
# - terminates normally
|
|
125
|
+
# + pass through
|
|
126
|
+
# + iterate only once
|
|
127
|
+
# + iterate more than once
|
|
128
|
+
|
|
129
|
+
# zero iterations
|
|
130
|
+
@tag.ping('f')
|
|
131
|
+
|
|
132
|
+
# one iteration
|
|
133
|
+
@tag.ping('t')
|
|
134
|
+
@tag.ping('f')
|
|
135
|
+
|
|
136
|
+
# two iterations
|
|
137
|
+
@tag.ping('t')
|
|
138
|
+
@tag.ping('t')
|
|
139
|
+
@tag.ping('f')
|
|
140
|
+
|
|
141
|
+
@tag.state.should == 0b0111
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "detects state 08 (0b1000)" do
|
|
145
|
+
# + terminates normally
|
|
146
|
+
# - pass through
|
|
147
|
+
# - iterate only once
|
|
148
|
+
# - iterate more than once
|
|
149
|
+
|
|
150
|
+
# TODO invalid
|
|
151
|
+
@tag.ping('@')
|
|
152
|
+
|
|
153
|
+
@tag.state.should == 0b1000
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
it "detects state 09 (0b1001)" do
|
|
157
|
+
# + terminates normally
|
|
158
|
+
# - pass through
|
|
159
|
+
# - iterate only once
|
|
160
|
+
# + iterate more than once
|
|
161
|
+
|
|
162
|
+
# iterate twice
|
|
163
|
+
@tag.ping('t')
|
|
164
|
+
@tag.ping('@')
|
|
165
|
+
@tag.ping('t')
|
|
166
|
+
@tag.ping('@')
|
|
167
|
+
@tag.ping('f')
|
|
168
|
+
|
|
169
|
+
@tag.state.should == 0b1001
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
it "detects state 10 (0b1010)" do
|
|
173
|
+
# + terminates normally
|
|
174
|
+
# - pass through
|
|
175
|
+
# + iterate only once
|
|
176
|
+
# - iterate more than once
|
|
177
|
+
|
|
178
|
+
# iterate once
|
|
179
|
+
@tag.ping('t')
|
|
180
|
+
@tag.ping('@')
|
|
181
|
+
@tag.ping('f')
|
|
182
|
+
|
|
183
|
+
@tag.state.should == 0b1010
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it "detects state 11 (0b1011)" do
|
|
187
|
+
# + terminates normally
|
|
188
|
+
# - pass through
|
|
189
|
+
# + iterate only once
|
|
190
|
+
# + iterate more than once
|
|
191
|
+
|
|
192
|
+
# iterate once
|
|
193
|
+
@tag.ping('t')
|
|
194
|
+
@tag.ping('@')
|
|
195
|
+
@tag.ping('f')
|
|
196
|
+
|
|
197
|
+
# iterate twice
|
|
198
|
+
@tag.ping('t')
|
|
199
|
+
@tag.ping('@')
|
|
200
|
+
@tag.ping('t')
|
|
201
|
+
@tag.ping('@')
|
|
202
|
+
@tag.ping('f')
|
|
203
|
+
|
|
204
|
+
@tag.state.should == 0b1011
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
it "detects state 12 (0b1100)" do
|
|
208
|
+
# + terminates normally
|
|
209
|
+
# + pass through
|
|
210
|
+
# - iterate only once
|
|
211
|
+
# - iterate more than once
|
|
212
|
+
|
|
213
|
+
# TODO invalid
|
|
214
|
+
@tag.ping('@')
|
|
215
|
+
@tag.ping('f')
|
|
216
|
+
|
|
217
|
+
@tag.state.should == 0b1100
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
it "detects state 13 (0b1101)" do
|
|
221
|
+
# + terminates normally
|
|
222
|
+
# + pass through
|
|
223
|
+
# - iterate only once
|
|
224
|
+
# + iterate more than once
|
|
225
|
+
|
|
226
|
+
# iterate twice
|
|
227
|
+
@tag.ping('t')
|
|
228
|
+
@tag.ping('@')
|
|
229
|
+
@tag.ping('t')
|
|
230
|
+
@tag.ping('@')
|
|
231
|
+
@tag.ping('f')
|
|
232
|
+
|
|
233
|
+
# pass through
|
|
234
|
+
@tag.ping('f')
|
|
235
|
+
|
|
236
|
+
@tag.state.should == 0b1101
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
it "detects state 14 (0b1110)" do
|
|
240
|
+
# + terminates normally
|
|
241
|
+
# + pass through
|
|
242
|
+
# + iterate only once
|
|
243
|
+
# - iterate more than once
|
|
244
|
+
|
|
245
|
+
# pass through
|
|
246
|
+
@tag.ping('f')
|
|
247
|
+
|
|
248
|
+
# iterate once
|
|
249
|
+
@tag.ping('t')
|
|
250
|
+
@tag.ping('@')
|
|
251
|
+
@tag.ping('f')
|
|
252
|
+
|
|
253
|
+
@tag.state.should == 0b1110
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
it "detects state 15 (0b1111)" do
|
|
257
|
+
# + terminates normally
|
|
258
|
+
# + pass through
|
|
259
|
+
# + iterate only once
|
|
260
|
+
# + iterate more than once
|
|
261
|
+
|
|
262
|
+
# pass through
|
|
263
|
+
@tag.ping('f')
|
|
264
|
+
|
|
265
|
+
# iterate once
|
|
266
|
+
@tag.ping('t')
|
|
267
|
+
@tag.ping('@')
|
|
268
|
+
@tag.ping('f')
|
|
269
|
+
|
|
270
|
+
# iterate twice
|
|
271
|
+
@tag.ping('t')
|
|
272
|
+
@tag.ping('@')
|
|
273
|
+
@tag.ping('t')
|
|
274
|
+
@tag.ping('@')
|
|
275
|
+
@tag.ping('f')
|
|
276
|
+
|
|
277
|
+
@tag.state.should == 0b1111
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
describe Tags::ConditionalBranchTag do
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
end
|
|
File without changes
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Piggly
|
|
4
|
+
|
|
5
|
+
=begin
|
|
6
|
+
describe Util::Cacheable do
|
|
7
|
+
|
|
8
|
+
class ExampleClass; include Piggly::Util::Cacheable; end
|
|
9
|
+
class ExampleCacheClass; include Piggly::Util::Cacheable; end
|
|
10
|
+
class PigglyExampleClassHTML; include Piggly::Util::Cacheable; end
|
|
11
|
+
class PigglyExampleHTMLClass; include Piggly::Util::Cacheable; end
|
|
12
|
+
class HTMLPiggly; include Piggly::Util::Cacheable; end
|
|
13
|
+
class ExampleRedefined
|
|
14
|
+
include Piggly::Util::Cacheable
|
|
15
|
+
def self.cache_path(file)
|
|
16
|
+
'redefined'
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
before do
|
|
21
|
+
Config.stub(:cache_root).and_return('/')
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "installs class methods" do
|
|
25
|
+
ExampleClass.should respond_to(:cache_path)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "uses class name as cache subdirectory" do
|
|
29
|
+
FileUtils.should_receive(:makedirs).at_least(:once)
|
|
30
|
+
|
|
31
|
+
ExampleClass.cache_path('a.ext').should =~ %r(/Example/a.ext$)
|
|
32
|
+
ExampleCacheClass.cache_path('a.ext').should =~ %r(/ExampleCache/a.ext$)
|
|
33
|
+
PigglyExampleClassHTML.cache_path('a.ext').should =~ %r(/PigglyExampleClassHTML/a.ext$)
|
|
34
|
+
PigglyExampleHTMLClass.cache_path('a.ext').should =~ %r(/PigglyExampleHTML/a.ext$)
|
|
35
|
+
HTMLPiggly.cache_path('a.ext').should =~ %r(/HTML/a.ext$)
|
|
36
|
+
ExampleRedefined.cache_path('a.ext').should == 'redefined'
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
=end
|
|
40
|
+
|
|
41
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Piggly::Util
|
|
4
|
+
|
|
5
|
+
describe Enumerable do
|
|
6
|
+
before do
|
|
7
|
+
@hash = {:a => '%', :b => '#'}
|
|
8
|
+
@array = %w(a b c d)
|
|
9
|
+
@range = 'w'..'z'
|
|
10
|
+
@empty = []
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe "count" do
|
|
14
|
+
it "should default to `size' when no block is given" do
|
|
15
|
+
Enumerable.count(@hash).should == 2
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "should count items that satisfied block" do
|
|
19
|
+
Enumerable.count(@hash){ true }.should == @hash.size
|
|
20
|
+
Enumerable.count(@array){ false }.should == 0
|
|
21
|
+
Enumerable.count(@empty){ true }.should == @empty.size
|
|
22
|
+
Enumerable.count(@range){|c| c < 'z' }.should == 3
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe "sum" do
|
|
27
|
+
it "should append when no block is given" do
|
|
28
|
+
Enumerable.sum(@range).should == 'wxyz'
|
|
29
|
+
Enumerable.sum(@array).should == 'abcd'
|
|
30
|
+
Enumerable.sum(@empty).should == 0
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "should use block return value" do
|
|
34
|
+
Enumerable.sum(@range){ 100 }.should == 400
|
|
35
|
+
Enumerable.sum(@empty){ 100 }.should == 0
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe "group_by" do
|
|
40
|
+
it "should return a Hash" do
|
|
41
|
+
Enumerable.group_by(@array){ nil }.should be_a(Hash)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "should collect elements into subcollections" do
|
|
45
|
+
Enumerable.group_by(@array){ :a }.should == { :a => @array }
|
|
46
|
+
Enumerable.group_by(@array){|x| x <= 'b'}.should == { true => %w(a b), false => %w(c d) }
|
|
47
|
+
Enumerable.group_by(@range){|x| x.to_i }.should == { 0 => %w(w x y z) }
|
|
48
|
+
Enumerable.group_by(@empty){ false }.should == {}
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
describe "index_by" do
|
|
53
|
+
it "should return a Hash" do
|
|
54
|
+
Enumerable.index_by(@array){ nil }.should be_a(Hash)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "should collect only one element per group" do
|
|
58
|
+
Enumerable.index_by(@array){ nil }.should == { nil => 'd' }
|
|
59
|
+
Enumerable.index_by(@range){|x| x }.should == { 'w' => 'w', 'x' => 'x', 'y' => 'y', 'z' => 'z' }
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Piggly::Util
|
|
4
|
+
|
|
5
|
+
describe File, "cache invalidation" do
|
|
6
|
+
before do
|
|
7
|
+
mtime = Hash['a' => 1, 'b' => 2, 'c' => 3]
|
|
8
|
+
allow(::File).to receive(:mtime) { |f| mtime.fetch(f) }
|
|
9
|
+
allow(::File).to receive(:exist?) { |f| mtime.include?(f) }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "invalidates non-existant cache file" do
|
|
13
|
+
expect(File.stale?('d', 'a')).to eq(true)
|
|
14
|
+
expect(File.stale?('d', 'a', 'b')).to eq(true)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "performs validation using file mtimes" do
|
|
18
|
+
expect(File.stale?('c', 'b')).not_to be_truthy
|
|
19
|
+
expect(File.stale?('c', 'a')).not_to be_truthy
|
|
20
|
+
expect(File.stale?('c', 'b', 'a')).not_to be_truthy
|
|
21
|
+
expect(File.stale?('c', 'a', 'b')).not_to be_truthy
|
|
22
|
+
|
|
23
|
+
expect(File.stale?('b', 'a')).not_to be_truthy
|
|
24
|
+
expect(File.stale?('b', 'c')).to be_truthy
|
|
25
|
+
expect(File.stale?('b', 'a', 'c')).to be_truthy
|
|
26
|
+
expect(File.stale?('b', 'c', 'a')).to be_truthy
|
|
27
|
+
|
|
28
|
+
expect(File.stale?('a', 'b')).to be_truthy
|
|
29
|
+
expect(File.stale?('a', 'c')).to be_truthy
|
|
30
|
+
expect(File.stale?('a', 'b', 'c')).to be_truthy
|
|
31
|
+
expect(File.stale?('a', 'c', 'b')).to be_truthy
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "assumes sources exist" do
|
|
35
|
+
expect{ File.stale?('a', 'd') }.to raise_error(StandardError)
|
|
36
|
+
expect{ File.stale?('c', 'a', 'x') }.to raise_error(StandardError)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Piggly
|
|
4
|
+
|
|
5
|
+
describe Util::Thunk do
|
|
6
|
+
|
|
7
|
+
context "not already evaluated" do
|
|
8
|
+
before do
|
|
9
|
+
@work = double('computation')
|
|
10
|
+
@thunk = Util::Thunk.new { @work.evaluate }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "responds to thunk? without evaluating" do
|
|
14
|
+
expect(@work).not_to receive(:evaluate)
|
|
15
|
+
expect(@thunk.thunk?).to be_truthy
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "evaluates when force! is explicitly called" do
|
|
19
|
+
expect(@work).to receive(:evaluate).and_return(@work)
|
|
20
|
+
expect(@thunk.force!).to eq(@work)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "evaluates when some other method is called" do
|
|
24
|
+
expect(@work).to receive(:evaluate).and_return(@work)
|
|
25
|
+
expect(@work).to receive(:something).and_return(@work)
|
|
26
|
+
expect(@thunk.something).to eq(@work)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
context "previously evaluated" do
|
|
31
|
+
before do
|
|
32
|
+
@work = double('computation')
|
|
33
|
+
allow(@work).to receive(:evaluate).and_return(@work)
|
|
34
|
+
|
|
35
|
+
@thunk = Util::Thunk.new { @work.evaluate }
|
|
36
|
+
@thunk.force!
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "responds to thunk? without evaluating" do
|
|
40
|
+
expect(@work).not_to receive(:evaluate)
|
|
41
|
+
expect(@thunk.thunk?).to be_truthy
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "should not re-evaluate when force! is called" do
|
|
45
|
+
expect(@work).not_to receive(:evaluate)
|
|
46
|
+
@thunk.force!
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "should not re-evaluate when some other method is called" do
|
|
50
|
+
expect(@work).not_to receive(:evaluate)
|
|
51
|
+
expect(@work).to receive(:something).and_return(@work)
|
|
52
|
+
expect(@thunk.something).to eq(@work)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
|
|
File without changes
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
module Piggly
|
|
4
|
+
describe "github issue #7" do
|
|
5
|
+
include GrammarHelper
|
|
6
|
+
|
|
7
|
+
it "can loop over dynamic query results" do
|
|
8
|
+
node = parse(:stmtForLoop, "FOR r IN EXECUTE 'SELECT * FROM pg_user;' LOOP END LOOP;")
|
|
9
|
+
node.should be_statement
|
|
10
|
+
|
|
11
|
+
cond = node.find{|e| e.named?(:cond) }
|
|
12
|
+
cond.source_text.should == "EXECUTE 'SELECT * FROM pg_user;' "
|
|
13
|
+
cond.should be_sql
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "can loop over dynamic query results when query contains the word 'LOOP'" do
|
|
17
|
+
node = parse(:stmtForLoop, "FOR r IN EXECUTE 'SELECT * FROM pg_user.LOOP;' LOOP END LOOP;")
|
|
18
|
+
node.should be_statement
|
|
19
|
+
|
|
20
|
+
cond = node.find{|e| e.named?(:cond) }
|
|
21
|
+
cond.source_text.should == "EXECUTE 'SELECT * FROM pg_user.LOOP;' "
|
|
22
|
+
cond.should be_sql
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
module Piggly
|
|
4
|
+
|
|
5
|
+
describe "github issue #8" do
|
|
6
|
+
include GrammarHelper
|
|
7
|
+
|
|
8
|
+
context "with declare" do
|
|
9
|
+
it "doesn't require a space before the := symbol" do
|
|
10
|
+
node, rest = parse_some(:stmtDeclare, "declare a text:= 10; begin")
|
|
11
|
+
# node.count{|e| e.assignment? }.should == 1
|
|
12
|
+
rest.should == "begin"
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "doesn't require a space after the := symbol" do
|
|
16
|
+
node, rest = parse_some(:stmtDeclare, "declare a text :=10;")
|
|
17
|
+
rest.should == ""
|
|
18
|
+
# node.count{|e| e.assignment? }.should == 1
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "doesn't require a space after the := symbol" do
|
|
22
|
+
node, rest = parse_some(:stmtDeclare, "declare a text :=10; begin")
|
|
23
|
+
# node.count{|e| e.assignment? }.should == 1
|
|
24
|
+
rest.should == "begin"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "allows escaped strings" do
|
|
28
|
+
node, rest = parse_some(:stmtDeclare, "declare a text :=E'\\001abc'; begin")
|
|
29
|
+
# node.count{|e| e.assignment? }.should == 1
|
|
30
|
+
rest.should == "begin"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "allows escaped octal characters" do
|
|
34
|
+
node, rest = parse_some(:stmtDeclare, "declare a text :=E'\\001abc'; begin")
|
|
35
|
+
# node.count{|e| e.assignment? }.should == 1
|
|
36
|
+
rest.should == "begin"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
context "without declare" do
|
|
41
|
+
it "doesn't require a space before the := symbol" do
|
|
42
|
+
node, rest = parse_some(:statement, "a:= 10; begin")
|
|
43
|
+
node.count{|e| e.assignment? }.should == 1
|
|
44
|
+
rest.should == "begin"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "doesn't require a space after the := symbol" do
|
|
48
|
+
node = parse(:statement, "a :=10;")
|
|
49
|
+
node.should be_statement
|
|
50
|
+
node.count{|e| e.assignment? }.should == 1
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "doesn't require a space after the := symbol" do
|
|
54
|
+
node, rest = parse_some(:statement, "a :=10; begin")
|
|
55
|
+
node.count{|e| e.assignment? }.should == 1
|
|
56
|
+
rest.should == "begin"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "allows escaped strings" do
|
|
60
|
+
node, rest = parse_some(:statement, "a :=E'\\001abc'; begin")
|
|
61
|
+
node.count{|e| e.assignment? }.should == 1
|
|
62
|
+
rest.should == "begin"
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "allows escaped octal characters" do
|
|
66
|
+
node, rest = parse_some(:statement, "a :=E'\\001abc'; begin")
|
|
67
|
+
node.count{|e| e.assignment? }.should == 1
|
|
68
|
+
rest.should == "begin"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
module Piggly
|
|
4
|
+
describe "github issue #18" do
|
|
5
|
+
include GrammarHelper
|
|
6
|
+
|
|
7
|
+
it "can parse the example" do
|
|
8
|
+
body = <<-SQL
|
|
9
|
+
DECLARE
|
|
10
|
+
schema TEXT = 'pg_catalog';
|
|
11
|
+
r RECORD;
|
|
12
|
+
BEGIN
|
|
13
|
+
FOR r IN EXECUTE 'SELECT * FROM ' || quote_ident(schema) || 'pg_user;'
|
|
14
|
+
LOOP
|
|
15
|
+
-- do nothing
|
|
16
|
+
END LOOP;
|
|
17
|
+
END;
|
|
18
|
+
SQL
|
|
19
|
+
|
|
20
|
+
node = parse(:start, body)
|
|
21
|
+
node.count{|e| e.for? }.should == 1
|
|
22
|
+
node.count{|e| e.comment? }.should == 1
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
module Piggly
|
|
4
|
+
describe "github issue #28" do
|
|
5
|
+
include GrammarHelper
|
|
6
|
+
|
|
7
|
+
it "can parse a GET STACKED DIAGNOSTICS statement" do
|
|
8
|
+
body = 'GET STACKED DIAGNOSTICS text_var1 = MESSAGE_TEXT, text_var2 = PG_EXCEPTION_DETAIL, text_var3 = PG_EXCEPTION_HINT;'
|
|
9
|
+
|
|
10
|
+
node = parse(:statement, body)
|
|
11
|
+
node.should be_statement
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "can parse a procedure with GET STACKED DIAGNOSTICS" do
|
|
15
|
+
body = <<-SQL
|
|
16
|
+
DECLARE
|
|
17
|
+
text_var1 text;
|
|
18
|
+
text_var2 text;
|
|
19
|
+
text_var3 text;
|
|
20
|
+
BEGIN
|
|
21
|
+
RETURN 1/0;
|
|
22
|
+
EXCEPTION WHEN SQLSTATE '22012' THEN
|
|
23
|
+
GET STACKED DIAGNOSTICS text_var1 = MESSAGE_TEXT,
|
|
24
|
+
text_var2 = PG_EXCEPTION_DETAIL,
|
|
25
|
+
text_var3 = PG_EXCEPTION_HINT;
|
|
26
|
+
END
|
|
27
|
+
SQL
|
|
28
|
+
|
|
29
|
+
node = parse(:start, body.strip)
|
|
30
|
+
node.count{|e| e.branch? }.should == 1 # catch
|
|
31
|
+
node.find{|e| e.branch? }.body.source_text.strip.should =~ /^GET.+HINT;/m
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "can parse WITH <> AS <> SELECT <> SQL query" do
|
|
35
|
+
body = <<-SQL
|
|
36
|
+
DECLARE
|
|
37
|
+
BEGIN
|
|
38
|
+
WITH n AS (SELECT first_name FROM users where id > 1000)
|
|
39
|
+
SELECT * FROM people WHERE people.first_name = n.first_name;
|
|
40
|
+
RETURN 1;
|
|
41
|
+
END
|
|
42
|
+
SQL
|
|
43
|
+
|
|
44
|
+
node = parse(:start, body.strip.downcase)
|
|
45
|
+
node.count{|e| e.sql? }.should == 1
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|