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,30 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Piggly
|
|
4
|
+
describe Parser, "tokens" do
|
|
5
|
+
include GrammarHelper
|
|
6
|
+
|
|
7
|
+
describe "literals" do
|
|
8
|
+
it "can be a cast call on a string" do
|
|
9
|
+
node = parse(:tLiteral, "cast('100.00' as numeric(10, 2))")
|
|
10
|
+
node = parse(:tLiteral, "cast( '100.00' as numeric (10, 2) )")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "can be a cast call on a number" do
|
|
14
|
+
node = parse(:tLiteral, "cast(100.00 as character varying(8))")
|
|
15
|
+
node = parse(:tLiteral, "cast( 100.00 as character varying (8) )")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "can be a ::cast on a string" do
|
|
19
|
+
node = parse(:tLiteral, "'100'::int")
|
|
20
|
+
node = parse(:tLiteral, "'100' :: int")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "can be a ::cast on a number" do
|
|
24
|
+
node = parse(:tLiteral, '100 :: varchar')
|
|
25
|
+
node = parse(:tLiteral, '100::varchar')
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Piggly
|
|
4
|
+
describe Parser, "tokens" do
|
|
5
|
+
include GrammarHelper
|
|
6
|
+
|
|
7
|
+
describe "l-values" do
|
|
8
|
+
it "can be a simple identifier" do
|
|
9
|
+
parse(:lValue, 'id').should be_a(Parser::Nodes::Assignable)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "can be an attribute accessor" do
|
|
13
|
+
parse(:lValue, 'record.id').should be_a(Parser::Nodes::Assignable)
|
|
14
|
+
parse(:lValue, 'public.dataset.id').should be_a(Parser::Nodes::Assignable)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "can use quoted attributes" do
|
|
18
|
+
parse(:lValue, 'record."ID"').should be_a(Parser::Nodes::Assignable)
|
|
19
|
+
parse(:lValue, '"schema name"."table name"."column name"').should be_a(Parser::Nodes::Assignable)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "can be an array accessor" do
|
|
23
|
+
parse(:lValue, 'names[0]').should be_a(Parser::Nodes::Assignable)
|
|
24
|
+
parse(:lValue, 'names[1000]').should be_a(Parser::Nodes::Assignable)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "can contain comments in array accessors" do
|
|
28
|
+
node = parse(:lValue, 'names[3 /* comment */]')
|
|
29
|
+
node.should be_a(Parser::Nodes::Assignable)
|
|
30
|
+
node.count{|e| e.comment? }.should == 1
|
|
31
|
+
|
|
32
|
+
node = parse(:lValue, "names[9 -- comment \n]")
|
|
33
|
+
node.should be_a(Parser::Nodes::Assignable)
|
|
34
|
+
node.count{|e| e.comment? }.should == 1
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "can be an array accessed by another l-value" do
|
|
38
|
+
parse(:lValue, 'names[face.id]').should be_a(Parser::Nodes::Assignable)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "can be a nested array access"
|
|
42
|
+
# names[faces[0].id].id doesn't work because it requires context-sensitivity [faces[0]
|
|
43
|
+
|
|
44
|
+
it "can be a multi-dimensional array access" do
|
|
45
|
+
parse(:lValue, 'data[10][2][0]').should be_a(Parser::Nodes::Assignable)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Piggly
|
|
4
|
+
describe Parser, "tokens" do
|
|
5
|
+
include GrammarHelper
|
|
6
|
+
|
|
7
|
+
describe "numbers" do
|
|
8
|
+
it "can be an integer in binary notation" do
|
|
9
|
+
node = parse(:tNumber, "B'0'")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "can be an integer in hexadecimal notation" do
|
|
13
|
+
node = parse(:tNumber, "X'F'")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "can be an integer in decimal notation" do
|
|
17
|
+
node = parse(:tNumber, '11223344556677889900')
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "can be a real number in decimial notation" do
|
|
21
|
+
node = parse(:tNumber, '3.2267')
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "can be a real number in scientific notation" do
|
|
25
|
+
node = parse(:tNumber, '1.3e3')
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "can be an integer in scientific notation" do
|
|
29
|
+
node = parse(:tNumber, '5e4')
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Piggly
|
|
4
|
+
|
|
5
|
+
describe Parser, "statements" do
|
|
6
|
+
include GrammarHelper
|
|
7
|
+
|
|
8
|
+
describe "SQL keywords" do
|
|
9
|
+
it "parse successfully" do
|
|
10
|
+
GrammarHelper::SQLWORDS.test_each do |k|
|
|
11
|
+
parse(:sqlKeyword, k).source_text.should == k
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "cannot have trailing characters" do
|
|
16
|
+
GrammarHelper::SQLWORDS.each do |k|
|
|
17
|
+
expect{ parse(:sqlKeyword, "#{k}abc") }.to raise_error(Piggly::Parser::Failure)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "cannot have preceeding characters" do
|
|
22
|
+
GrammarHelper::SQLWORDS.each do |k|
|
|
23
|
+
expect{ parse(:sqlKeyword, "#{k}abc") }.to raise_error(Piggly::Parser::Failure)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "are terminated by symbols" do
|
|
28
|
+
GrammarHelper::SQLWORDS.test_each do |k|
|
|
29
|
+
node, rest = parse_some(:sqlKeyword, "#{k}+")
|
|
30
|
+
node.source_text.should == k
|
|
31
|
+
rest.should == '+'
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "are terminated by spaces" do
|
|
36
|
+
GrammarHelper::SQLWORDS.test_each do |k|
|
|
37
|
+
node, rest = parse_some(:sqlKeyword, "#{k} ")
|
|
38
|
+
node.source_text.should == k
|
|
39
|
+
rest.should == ' '
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Piggly
|
|
4
|
+
describe Parser, "tokens" do
|
|
5
|
+
include GrammarHelper
|
|
6
|
+
|
|
7
|
+
describe "strings" do
|
|
8
|
+
it "can be enclosed within single quotes" do
|
|
9
|
+
["''", "'abc'", "'abc xyz'"].test_each do |s|
|
|
10
|
+
parse(:tString, s).should be_string
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "cannot be nested within single quotes" do
|
|
15
|
+
node, rest = parse_some(:tString, "'abc 'xyz' tuv'")
|
|
16
|
+
node.should be_string
|
|
17
|
+
rest.should == "xyz' tuv'"
|
|
18
|
+
|
|
19
|
+
node, rest = parse_some(:tString, "'can't'")
|
|
20
|
+
node.should be_string
|
|
21
|
+
rest.should == "t'"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "can contain escaped single quotes" do
|
|
25
|
+
["''''", "'can''t'", "'abc '' xyz'"].test_each do |s|
|
|
26
|
+
parse(:tString, s).should be_string
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "can be enclosed with $$ tags" do
|
|
31
|
+
["$$$$", "$$ abc $$", "$T$ abc $T$", "$tt$ abc $tt$"].test_each do |s|
|
|
32
|
+
parse(:tString, s).should be_string
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "must have matching start and end $$ tags"
|
|
37
|
+
|
|
38
|
+
it "can be nested within $$ tags"
|
|
39
|
+
|
|
40
|
+
it "can embed $$ strings within single-quoted strings" do
|
|
41
|
+
["'ab $$ xyz $$ cd'", "'a $b$ c $b$ d'"].test_each do |s|
|
|
42
|
+
parse(:tString, s).should be_string
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "can embed single-quote strings within $$ strings" do
|
|
47
|
+
["$$ 'abc' $$", "$ABC$ 'ab''cd' $ABC$"].test_each do |s|
|
|
48
|
+
parse(:tString, s).should be_string
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Piggly
|
|
4
|
+
describe Parser, "tokens" do
|
|
5
|
+
include GrammarHelper
|
|
6
|
+
|
|
7
|
+
describe "white space" do
|
|
8
|
+
it "includes spaces" do
|
|
9
|
+
node, rest = parse_some(:tSpace, " ")
|
|
10
|
+
rest.should == ''
|
|
11
|
+
node.source_text.should == " "
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "includes tabs" do
|
|
15
|
+
node, rest = parse_some(:tSpace, "\t\t")
|
|
16
|
+
rest.should == ''
|
|
17
|
+
node.source_text.should == "\t\t"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "includes line feeds" do
|
|
21
|
+
node, rest = parse_some(:tSpace, "\f\f")
|
|
22
|
+
rest.should == ''
|
|
23
|
+
node.source_text.should == "\f\f"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "includes line breaks" do
|
|
27
|
+
node, rest = parse_some(:tSpace, "\n\n")
|
|
28
|
+
rest.should == ''
|
|
29
|
+
node.source_text.should == "\n\n"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "includes carriage returns" do
|
|
33
|
+
node, rest = parse_some(:tSpace, "\r\r")
|
|
34
|
+
rest.should == ''
|
|
35
|
+
node.source_text.should == "\r\r"
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Piggly
|
|
4
|
+
|
|
5
|
+
describe Installer do
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
@config = Config.new
|
|
9
|
+
@connection = double('connection')
|
|
10
|
+
@installer = Installer.new(@config, @connection)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe "trace" do
|
|
14
|
+
it "compiles, executes, and profiles the procedure" do
|
|
15
|
+
untraced = 'create or replace function x(char)'
|
|
16
|
+
traced = 'create or replace function f(int)'
|
|
17
|
+
|
|
18
|
+
result = {:tags => double, :code => traced}
|
|
19
|
+
profile = double('profile')
|
|
20
|
+
|
|
21
|
+
compiler = double('compiler', :compile => result)
|
|
22
|
+
expect(Compiler::TraceCompiler).to receive(:new).
|
|
23
|
+
and_return(compiler)
|
|
24
|
+
|
|
25
|
+
procedure = double('procedure', :oid => 'oid', :source => untraced)
|
|
26
|
+
expect(procedure).to receive(:definition).
|
|
27
|
+
with(traced).and_return(traced)
|
|
28
|
+
|
|
29
|
+
expect(@connection).to receive(:exec).
|
|
30
|
+
with(traced)
|
|
31
|
+
|
|
32
|
+
expect(profile).to receive(:add).
|
|
33
|
+
with(procedure, result[:tags], result)
|
|
34
|
+
|
|
35
|
+
@installer.trace(procedure, profile)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe "untrace" do
|
|
40
|
+
it "executes the original definition" do
|
|
41
|
+
untraced = 'create or replace function x(char)'
|
|
42
|
+
procedure = double(:oid => 'oid', :source => untraced)
|
|
43
|
+
|
|
44
|
+
expect(procedure).to receive(:definition).
|
|
45
|
+
and_return(untraced)
|
|
46
|
+
|
|
47
|
+
expect(@connection).to receive(:exec).
|
|
48
|
+
with(untraced)
|
|
49
|
+
|
|
50
|
+
@installer.untrace(procedure)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe "install_trace_support"
|
|
55
|
+
describe "uninstall_trace_support"
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Piggly
|
|
4
|
+
|
|
5
|
+
# load support code
|
|
6
|
+
Parser.parser
|
|
7
|
+
|
|
8
|
+
describe NodeClass do
|
|
9
|
+
describe "source_text"
|
|
10
|
+
describe "named?"
|
|
11
|
+
|
|
12
|
+
context "untagged node" do
|
|
13
|
+
describe "tagged?"
|
|
14
|
+
describe "tag_id"
|
|
15
|
+
describe "tag"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
context "tagged node" do
|
|
19
|
+
describe "tagged?"
|
|
20
|
+
describe "tag_id"
|
|
21
|
+
describe "tag"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe Parser::Nodes::Expression do
|
|
26
|
+
describe "tag" do
|
|
27
|
+
context "untagged node" do
|
|
28
|
+
context "named :cond" do
|
|
29
|
+
context "with parent.while?"
|
|
30
|
+
context "with parent.loop?"
|
|
31
|
+
context "with parent.branch?"
|
|
32
|
+
context "with some other type of parent"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context "not named :cond" do
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe Parser::Nodes::Sql do
|
|
42
|
+
describe "tag" do
|
|
43
|
+
context "untagged node" do
|
|
44
|
+
context "named :cond" do
|
|
45
|
+
context "with parent.for?"
|
|
46
|
+
context "with some other parent"
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context "not named :cond"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe Parser::Nodes::TKeyword do
|
|
55
|
+
describe "tag" do
|
|
56
|
+
context "untagged node" do
|
|
57
|
+
context "named :cond" do
|
|
58
|
+
context "with parent.loop?"
|
|
59
|
+
context "with some other parent"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
context "not named :cond"
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe Parser::Nodes::Terminal do
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
describe Parser::Nodes::NotImplemented do
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Piggly
|
|
4
|
+
|
|
5
|
+
describe Parser do
|
|
6
|
+
|
|
7
|
+
describe "parse" do
|
|
8
|
+
it "returns a thunk" do
|
|
9
|
+
tree = nil
|
|
10
|
+
|
|
11
|
+
expect do
|
|
12
|
+
tree = Parser.parse('input')
|
|
13
|
+
end.not_to raise_error
|
|
14
|
+
|
|
15
|
+
expect(tree.thunk?).to be_truthy
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
context "when the thunk is evaluated" do
|
|
19
|
+
before do
|
|
20
|
+
@parser = double('PigglyParser')
|
|
21
|
+
allow(Parser).to receive(:parser).and_return(@parser)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "downcases input string before parsing" do
|
|
25
|
+
input = 'SOURCE CODE'
|
|
26
|
+
|
|
27
|
+
allow(@parser).to receive(:failure_reason)
|
|
28
|
+
expect(@parser).to receive(:parse).
|
|
29
|
+
with(input.downcase)
|
|
30
|
+
|
|
31
|
+
begin
|
|
32
|
+
Parser.parse(input).force!
|
|
33
|
+
rescue Parser::Failure
|
|
34
|
+
# don't care
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
context "when parser fails" do
|
|
39
|
+
it "raises Parser::Failure" do
|
|
40
|
+
input = 'SOURCE CODE'
|
|
41
|
+
reason = 'expecting someone else'
|
|
42
|
+
|
|
43
|
+
expect(@parser).to receive(:parse).
|
|
44
|
+
and_return(nil)
|
|
45
|
+
expect(@parser).to receive(:failure_reason).
|
|
46
|
+
and_return(reason)
|
|
47
|
+
|
|
48
|
+
expect do
|
|
49
|
+
Parser.parse('SOURCE CODE').force!
|
|
50
|
+
end.to raise_error(Parser::Failure, reason)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context "when parser succeeds" do
|
|
55
|
+
it "returns parser's result" do
|
|
56
|
+
input = 'SOURCE CODE'
|
|
57
|
+
tree = double('NodeClass', :message => 'result')
|
|
58
|
+
|
|
59
|
+
expect(@parser).to receive(:parse).
|
|
60
|
+
and_return(tree)
|
|
61
|
+
|
|
62
|
+
expect(Parser.parse('SOURCE CODE').message).to eq(tree.message)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
describe "parser" do
|
|
70
|
+
|
|
71
|
+
context "when the grammar is older than the generated parser" do
|
|
72
|
+
before do
|
|
73
|
+
allow(Util::File).to receive(:stale?).and_return(false)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "does not regenerate the parser" do
|
|
77
|
+
expect(Treetop::Compiler::GrammarCompiler).not_to receive(:new)
|
|
78
|
+
# expect(Parser).to receive(:require).
|
|
79
|
+
# with(Parser.parser_path)
|
|
80
|
+
|
|
81
|
+
Parser.parser
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "returns an instance of PigglyParser" do
|
|
85
|
+
expect(Parser.parser).to be_a(PigglyParser)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
context "when the generated parser is older than the grammar" do
|
|
90
|
+
before do
|
|
91
|
+
# Reset the cached parser
|
|
92
|
+
Piggly::Parser.instance_variable_set(:@parser, nil)
|
|
93
|
+
allow(Util::File).to receive(:stale?).and_return(true)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "regenerates the parser and loads it" do
|
|
97
|
+
compiler = double('GrammarCompiler')
|
|
98
|
+
expect(compiler).to receive(:compile).
|
|
99
|
+
with(Parser.grammar_path, Parser.parser_path)
|
|
100
|
+
|
|
101
|
+
expect(Treetop::Compiler::GrammarCompiler).to receive(:new).
|
|
102
|
+
and_return(compiler)
|
|
103
|
+
|
|
104
|
+
expect(Piggly::Parser).to receive(:load).
|
|
105
|
+
with(Parser.parser_path).and_call_original
|
|
106
|
+
|
|
107
|
+
result = Parser.parser
|
|
108
|
+
expect(result).to be_a(PigglyParser)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "returns an instance of PigglyParser" do
|
|
112
|
+
expect(Parser.parser).to be_a(PigglyParser)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
end
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Piggly
|
|
4
|
+
|
|
5
|
+
describe Profile do
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
@profile = Profile.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe "notice_processor" do
|
|
12
|
+
before do
|
|
13
|
+
@config = double('config', :trace_prefix => 'PIGGLY')
|
|
14
|
+
@stderr = double('stderr').as_null_object
|
|
15
|
+
@callback = @profile.notice_processor(@config, @stderr)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "returns a function" do
|
|
19
|
+
expect(@callback).to be_a(Proc)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
context "when message matches PATTERN" do
|
|
23
|
+
context "with no optional value" do
|
|
24
|
+
it "pings the corresponding tag" do
|
|
25
|
+
message = "WARNING: #{@config.trace_prefix} 0123456789abcdef"
|
|
26
|
+
expect(@profile).to receive(:ping).
|
|
27
|
+
with('0123456789abcdef', nil)
|
|
28
|
+
|
|
29
|
+
@callback.call(message)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
context "with an optional value" do
|
|
34
|
+
it "pings the corresponding tag" do
|
|
35
|
+
message = "WARNING: #{@config.trace_prefix} 0123456789abcdef X"
|
|
36
|
+
expect(@profile).to receive(:ping).
|
|
37
|
+
with('0123456789abcdef', 'X')
|
|
38
|
+
|
|
39
|
+
@callback.call(message)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context "when message doesn't match PATTERN" do
|
|
45
|
+
it "prints the message to stderr" do
|
|
46
|
+
message = "WARNING: Parameter was NULL and I don't like it!"
|
|
47
|
+
expect(@stderr).to receive(:puts).with("unknown trace: #{message}")
|
|
48
|
+
@callback.call(message)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe "add" do
|
|
54
|
+
before do
|
|
55
|
+
@first = double('first tag', :id => 'first')
|
|
56
|
+
@second = double('second tag', :id => 'second')
|
|
57
|
+
@third = double('third tag', :id => 'third')
|
|
58
|
+
@cache = double('Compiler::Cacheable::CacheDirectory')
|
|
59
|
+
|
|
60
|
+
@procedure = Dumper::SkeletonProcedure.allocate
|
|
61
|
+
allow(@procedure).to receive(:oid).and_return('oid')
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
context "without cache parameter" do
|
|
65
|
+
it "indexes each tag by id" do
|
|
66
|
+
@profile.add(@procedure, [@first, @second, @third])
|
|
67
|
+
expect(@profile[@first.id]).to eq(@first)
|
|
68
|
+
expect(@profile[@second.id]).to eq(@second)
|
|
69
|
+
expect(@profile[@third.id]).to eq(@third)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "indexes each tag by procedure" do
|
|
73
|
+
@profile.add(@procedure, [@first, @second, @third])
|
|
74
|
+
expect(@profile[@procedure]).to eq([@first, @second, @third])
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
context "with cache parameter" do
|
|
79
|
+
it "indexes each tag by id" do
|
|
80
|
+
@profile.add(@procedure, [@first, @second, @third], @cache)
|
|
81
|
+
expect(@profile[@first.id]).to eq(@first)
|
|
82
|
+
expect(@profile[@second.id]).to eq(@second)
|
|
83
|
+
expect(@profile[@third.id]).to eq(@third)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "indexes each tag by procedure" do
|
|
87
|
+
@profile.add(@procedure, [@first, @second, @third])
|
|
88
|
+
expect(@profile[@procedure]).to eq([@first, @second, @third])
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
describe "ping" do
|
|
94
|
+
context "when tag isn't in the profile" do
|
|
95
|
+
it "raises an exception" do
|
|
96
|
+
expect do
|
|
97
|
+
@profile.ping('0123456789abcdef')
|
|
98
|
+
end.to raise_error('No tag with id 0123456789abcdef')
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
context "when tag is in the profile" do
|
|
103
|
+
before do
|
|
104
|
+
@tag = double('tag', :id => '0123456789abcdef')
|
|
105
|
+
procedure = double('procedure', :oid => nil)
|
|
106
|
+
@profile.add(procedure, [@tag])
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "calls ping on the corresponding tag" do
|
|
110
|
+
expect(@tag).to receive(:ping).with('X')
|
|
111
|
+
@profile.ping(@tag.id, 'X')
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
describe "summary" do
|
|
117
|
+
context "when given a procedure" do
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
context "when not given a procedure" do
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
describe "clear" do
|
|
125
|
+
before do
|
|
126
|
+
@first = double('first tag', :id => 'first')
|
|
127
|
+
@second = double('second tag', :id => 'second')
|
|
128
|
+
@third = double('third tag', :id => 'third')
|
|
129
|
+
procedure = double('procedure', :oid => nil)
|
|
130
|
+
|
|
131
|
+
@profile.add(procedure, [@first, @second, @third])
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "calls clear on each tag" do
|
|
135
|
+
expect(@first).to receive(:clear)
|
|
136
|
+
expect(@second).to receive(:clear)
|
|
137
|
+
expect(@third).to receive(:clear)
|
|
138
|
+
@profile.clear
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
describe "store" do
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
describe "empty?" do
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
describe "difference" do
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
end
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
File without changes
|