atp 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/config/{environment.rb → boot.rb} +0 -0
- data/config/commands.rb +10 -10
- data/config/version.rb +1 -1
- data/lib/atp.rb +53 -9
- data/lib/atp/and.rb +11 -0
- data/lib/atp/ast/builder.rb +214 -0
- data/lib/atp/ast/extractor.rb +26 -0
- data/lib/atp/ast/factories.rb +13 -0
- data/lib/atp/ast/node.rb +71 -0
- data/lib/atp/flow.rb +140 -0
- data/lib/atp/formatter.rb +20 -0
- data/lib/atp/formatters/basic.rb +18 -0
- data/lib/atp/formatters/datalog.rb +20 -0
- data/lib/atp/not.rb +13 -0
- data/lib/atp/or.rb +11 -0
- data/lib/atp/parser.rb +26 -0
- data/lib/atp/processor.rb +38 -0
- data/lib/atp/processors/condition.rb +174 -0
- data/lib/atp/processors/post_cleaner.rb +43 -0
- data/lib/atp/processors/pre_cleaner.rb +43 -0
- data/lib/atp/processors/relationship.rb +154 -0
- data/lib/atp/program.rb +27 -0
- data/lib/atp/runner.rb +53 -0
- data/lib/atp/validators/condition.rb +4 -0
- metadata +55 -10
- data/config/development.rb +0 -12
- data/config/users.rb +0 -29
- data/lib/atp/top_level.rb +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ca6eaefd174b135c5b39a8b2d287f24cd890814
|
4
|
+
data.tar.gz: 3c379de6d014a88c5dbec902ec85eda2d4d1abd6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec297a8c950f05a49eaa17c359d5c35378aea3e9a1e39f88f3c72906968658dc22e61590357f83b462f25dab699a1577d7d334efdb26d126b0f3694a159eaa9f
|
7
|
+
data.tar.gz: 1fc8899484368c2fc172801ba5bae1968fd9488d52420d0f0c30e1275a9db41783ab2886536317ca5744e2b7222badee59a9e6d5006d373b827f6e90d3bb6d80
|
File without changes
|
data/config/commands.rb
CHANGED
@@ -29,13 +29,13 @@ when "my_command"
|
|
29
29
|
# control flowing back to Origen
|
30
30
|
exit 0
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
32
|
+
# Example of how to make a command to run unit tests, this simply invokes RSpec on
|
33
|
+
# the spec directory
|
34
|
+
when "specs"
|
35
|
+
ARGV.unshift "spec"
|
36
|
+
require "rspec"
|
37
|
+
require "rspec/autorun"
|
38
|
+
exit 0 # This will never be hit on a fail, RSpec will automatically exit 1
|
39
39
|
|
40
40
|
## Example of how to make a command to run diff-based tests
|
41
41
|
#when "examples"
|
@@ -68,9 +68,9 @@ else
|
|
68
68
|
# You probably want to also add the your commands to the help shown via
|
69
69
|
# origen -h, you can do this be assigning the required text to @application_commands
|
70
70
|
# before handing control back to Origen. Un-comment the example below to get started.
|
71
|
-
|
72
|
-
|
71
|
+
@application_commands = <<-EOT
|
72
|
+
specs Run the specs (tests), -c will enable coverage
|
73
|
+
EOT
|
73
74
|
# examples Run the examples (tests), -c will enable coverage
|
74
|
-
# EOT
|
75
75
|
|
76
76
|
end
|
data/config/version.rb
CHANGED
data/lib/atp.rb
CHANGED
@@ -1,15 +1,59 @@
|
|
1
1
|
require 'origen'
|
2
|
-
require_relative '../config/application.rb'
|
2
|
+
require_relative '../config/application.rb'
|
3
3
|
module ATP
|
4
|
+
autoload :Program, 'atp/program'
|
5
|
+
autoload :Flow, 'atp/flow'
|
6
|
+
autoload :Processor, 'atp/processor'
|
7
|
+
autoload :Runner, 'atp/runner'
|
8
|
+
autoload :Formatter, 'atp/formatter'
|
9
|
+
autoload :Parser, 'atp/parser'
|
10
|
+
autoload :AND, 'atp/and'
|
11
|
+
autoload :OR, 'atp/or'
|
12
|
+
autoload :NOT, 'atp/not'
|
4
13
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
# you can do that one manually and the let the wildcard take care of the rest.
|
11
|
-
Dir.glob("#{File.dirname(__FILE__)}/**/*.rb").sort.each do |file|
|
12
|
-
require file
|
14
|
+
module AST
|
15
|
+
autoload :Node, 'atp/ast/node'
|
16
|
+
autoload :Builder, 'atp/ast/builder'
|
17
|
+
autoload :Factories, 'atp/ast/factories'
|
18
|
+
autoload :Extractor, 'atp/ast/extractor'
|
13
19
|
end
|
14
20
|
|
21
|
+
# Processors actually modify the AST to clean and optimize the user input
|
22
|
+
# and to implement the flow control API
|
23
|
+
module Processors
|
24
|
+
autoload :Condition, 'atp/processors/condition'
|
25
|
+
autoload :Relationship, 'atp/processors/relationship'
|
26
|
+
autoload :PreCleaner, 'atp/processors/pre_cleaner'
|
27
|
+
autoload :PostCleaner, 'atp/processors/post_cleaner'
|
28
|
+
end
|
29
|
+
|
30
|
+
# Summarizers extract summary data from the given AST
|
31
|
+
module Summarizers
|
32
|
+
end
|
33
|
+
|
34
|
+
# Validators are run on the processed AST to check it for common errors or
|
35
|
+
# logical issues that will prevent it being rendered to a test program format
|
36
|
+
module Validators
|
37
|
+
autoload :Condition, 'atp/validators/condition'
|
38
|
+
end
|
39
|
+
|
40
|
+
# Formatters are run on the processed AST to display the flow or to render
|
41
|
+
# it to a different format
|
42
|
+
module Formatters
|
43
|
+
autoload :Basic, 'atp/formatters/basic'
|
44
|
+
autoload :Datalog, 'atp/formatters/datalog'
|
45
|
+
autoload :Graph, 'atp/formatters/graph'
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.or(*args)
|
49
|
+
OR.new(*args)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.and(*args)
|
53
|
+
AND.new(*args)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.not(*args)
|
57
|
+
NOT.new(*args)
|
58
|
+
end
|
15
59
|
end
|
data/lib/atp/and.rb
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
module ATP
|
2
|
+
module AST
|
3
|
+
class Builder
|
4
|
+
include Factories
|
5
|
+
|
6
|
+
attr_reader :context
|
7
|
+
|
8
|
+
def flow
|
9
|
+
n0(:flow)
|
10
|
+
end
|
11
|
+
|
12
|
+
def name(str)
|
13
|
+
n(:name, str.to_s)
|
14
|
+
end
|
15
|
+
|
16
|
+
def log(str)
|
17
|
+
n(:log, str.to_s)
|
18
|
+
end
|
19
|
+
|
20
|
+
def render(str)
|
21
|
+
n(:render, str.to_s)
|
22
|
+
end
|
23
|
+
|
24
|
+
def description(str)
|
25
|
+
n(:description, str.to_s)
|
26
|
+
end
|
27
|
+
|
28
|
+
def id(symbol)
|
29
|
+
n(:id, symbol.to_sym)
|
30
|
+
end
|
31
|
+
|
32
|
+
def flow_flag(name, enabled, node)
|
33
|
+
n(:flow_flag, name, enabled, node)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_result(id, passed, node)
|
37
|
+
n(:test_result, id, passed, node)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_executed(id, executed, node)
|
41
|
+
n(:test_executed, id, executed, node)
|
42
|
+
end
|
43
|
+
|
44
|
+
def group(group_name, nodes, options = {})
|
45
|
+
children = [name(group_name)]
|
46
|
+
|
47
|
+
children << id(options[:id].to_s.downcase.to_sym) if options[:id]
|
48
|
+
|
49
|
+
children << on_fail(options[:on_fail]) if options[:on_fail]
|
50
|
+
children << on_pass(options[:on_pass]) if options[:on_pass]
|
51
|
+
|
52
|
+
children << n(:members, *nodes)
|
53
|
+
group = n(:group, *children)
|
54
|
+
|
55
|
+
if options[:conditions]
|
56
|
+
apply_conditions(group, options[:conditions])
|
57
|
+
else
|
58
|
+
group
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def cz(setup, node)
|
63
|
+
n(:cz, setup, node)
|
64
|
+
end
|
65
|
+
|
66
|
+
def new_context
|
67
|
+
@context = { conditions: {} }
|
68
|
+
yield if block_given?
|
69
|
+
@context
|
70
|
+
end
|
71
|
+
|
72
|
+
CONDITION_KEYS = [
|
73
|
+
:if_enabled, :enabled, :enable_flag, :enable, :if_enable,
|
74
|
+
:unless_enabled, :not_enabled, :disabled, :disable, :unless_enable,
|
75
|
+
:if_failed, :unless_passed, :failed,
|
76
|
+
:if_passed, :unless_failed, :passed,
|
77
|
+
:if_ran, :if_executed,
|
78
|
+
:unless_ran, :unless_executed,
|
79
|
+
:job, :jobs, :if_job, :if_jobs,
|
80
|
+
:unless_job, :unless_jobs,
|
81
|
+
:if_any_failed, :unless_all_passed,
|
82
|
+
:if_all_failed, :unless_any_passed,
|
83
|
+
:if_any_passed, :unless_all_failed,
|
84
|
+
:if_all_passed, :unless_any_failed
|
85
|
+
]
|
86
|
+
|
87
|
+
def apply_conditions(node, conditions)
|
88
|
+
conditions.each do |key, value|
|
89
|
+
key = key.to_s.downcase.to_sym
|
90
|
+
context[:conditions][key] = value
|
91
|
+
case key
|
92
|
+
when :if_enabled, :enabled, :enable_flag, :enable, :if_enable
|
93
|
+
node = flow_flag(value, true, node)
|
94
|
+
when :unless_enabled, :not_enabled, :disabled, :disable, :unless_enable
|
95
|
+
node = flow_flag(value, false, node)
|
96
|
+
when :if_failed, :unless_passed, :failed
|
97
|
+
if value.is_a?(Array)
|
98
|
+
fail 'if_failed only accepts one ID, use if_any_failed or if_all_failed for multiple IDs'
|
99
|
+
end
|
100
|
+
node = test_result(value, false, node)
|
101
|
+
when :if_passed, :unless_failed, :passed
|
102
|
+
if value.is_a?(Array)
|
103
|
+
fail 'if_passed only accepts one ID, use if_any_passed or if_all_passed for multiple IDs'
|
104
|
+
end
|
105
|
+
node = test_result(value, true, node)
|
106
|
+
when :if_any_failed, :unless_all_passed
|
107
|
+
node = test_result(value, false, node)
|
108
|
+
when :if_all_failed, :unless_any_passed
|
109
|
+
node = value.reduce(nil) do |nodes, val|
|
110
|
+
test_result(val, false, nodes ? nodes : node)
|
111
|
+
end
|
112
|
+
when :if_any_passed, :unless_all_failed
|
113
|
+
node = test_result(value, true, node)
|
114
|
+
when :if_all_passed, :unless_any_failed
|
115
|
+
node = value.reduce(nil) do |nodes, val|
|
116
|
+
test_result(val, true, nodes ? nodes : node)
|
117
|
+
end
|
118
|
+
when :if_ran, :if_executed
|
119
|
+
node = test_executed(value, true, node)
|
120
|
+
when :unless_ran, :unless_executed
|
121
|
+
node = test_executed(value, false, node)
|
122
|
+
when :job, :jobs, :if_job, :if_jobs
|
123
|
+
# Make sure these are wrapped by an OR, AND jobs doesn't make sense anyway
|
124
|
+
unless value.is_a?(OR)
|
125
|
+
value = ATP.or(value)
|
126
|
+
end
|
127
|
+
node = n(:job, apply_boolean(value), node)
|
128
|
+
when :unless_job, :unless_jobs
|
129
|
+
# Make sure these are wrapped by an OR, AND jobs doesn't make sense anyway
|
130
|
+
unless value.is_a?(OR)
|
131
|
+
value = ATP.or(value)
|
132
|
+
end
|
133
|
+
node = n(:job, apply_boolean(ATP.not(value)), node)
|
134
|
+
else
|
135
|
+
fail "Unknown test condition attribute - #{key} (#{value})"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
node
|
139
|
+
end
|
140
|
+
|
141
|
+
def apply_boolean(value)
|
142
|
+
if value.is_a?(OR)
|
143
|
+
n(:or, *value.map { |v| apply_boolean(v) })
|
144
|
+
elsif value.is_a?(AND)
|
145
|
+
n(:and, *value.map { |v| apply_boolean(v) })
|
146
|
+
elsif value.is_a?(NOT)
|
147
|
+
n(:not, apply_boolean(value.value))
|
148
|
+
else
|
149
|
+
value
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def test(object, options = {})
|
154
|
+
children = [n(:object, object)]
|
155
|
+
|
156
|
+
if n = (options[:name] || options[:tname] || options[:test_name])
|
157
|
+
children << name(n)
|
158
|
+
end
|
159
|
+
if n = (options[:number] || options[:num] || options[:tnum] || options[:test_number])
|
160
|
+
children << number(n)
|
161
|
+
end
|
162
|
+
d = options[:description] || options[:desc]
|
163
|
+
children << description(d) if d
|
164
|
+
children << id(options[:id].to_s.downcase.to_sym) if options[:id]
|
165
|
+
|
166
|
+
children << on_fail(options[:on_fail]) if options[:on_fail]
|
167
|
+
children << on_pass(options[:on_pass]) if options[:on_pass]
|
168
|
+
|
169
|
+
test = n(:test, *children)
|
170
|
+
|
171
|
+
if options[:conditions]
|
172
|
+
apply_conditions(test, options[:conditions])
|
173
|
+
else
|
174
|
+
test
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def on_fail(options = {})
|
179
|
+
children = []
|
180
|
+
if options[:bin] || options[:softbin]
|
181
|
+
children << set_result(:fail, bin: options[:bin], softbin: options[:softbin], description: options[:bin_description])
|
182
|
+
end
|
183
|
+
children << continue if options[:continue]
|
184
|
+
n(:on_fail, *children)
|
185
|
+
end
|
186
|
+
|
187
|
+
def on_pass(options = {})
|
188
|
+
children = []
|
189
|
+
if options[:bin] || options[:softbin]
|
190
|
+
children << set_result(:pass, bin: options[:bin], softbin: options[:softbin], description: options[:bin_description])
|
191
|
+
end
|
192
|
+
children << continue if options[:continue]
|
193
|
+
n(:on_pass, *children)
|
194
|
+
end
|
195
|
+
|
196
|
+
def set_result(type, options = {})
|
197
|
+
children = []
|
198
|
+
children << type
|
199
|
+
children << n(:bin, options[:bin]) if options[:bin]
|
200
|
+
children << n(:softbin, options[:softbin]) if options[:softbin]
|
201
|
+
children << n(:description, options[:description]) if options[:description]
|
202
|
+
n(:set_result, *children)
|
203
|
+
end
|
204
|
+
|
205
|
+
def number(val)
|
206
|
+
n(:number, val.to_i)
|
207
|
+
end
|
208
|
+
|
209
|
+
def continue
|
210
|
+
n0(:continue)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'ast'
|
2
|
+
module ATP
|
3
|
+
module AST
|
4
|
+
class Extractor
|
5
|
+
include ::AST::Processor::Mixin
|
6
|
+
|
7
|
+
attr_reader :types
|
8
|
+
attr_reader :results
|
9
|
+
|
10
|
+
def process(node, types = nil)
|
11
|
+
if types
|
12
|
+
@types = types
|
13
|
+
@results = []
|
14
|
+
# node = AST::Node.new(:wrapper, node) unless node.respond_to?(:to_ast)
|
15
|
+
end
|
16
|
+
super(node) if node.respond_to?(:to_ast)
|
17
|
+
results
|
18
|
+
end
|
19
|
+
|
20
|
+
def handler_missing(node)
|
21
|
+
@results << node if types.include?(node.type)
|
22
|
+
process_all(node.children)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/atp/ast/node.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'ast'
|
2
|
+
module ATP
|
3
|
+
module AST
|
4
|
+
class Node < ::AST::Node
|
5
|
+
include Factories
|
6
|
+
|
7
|
+
def initialize(type, children = [], properties = {})
|
8
|
+
# Always use strings instead of symbols in the AST, makes serializing
|
9
|
+
# back and forward to a string easier
|
10
|
+
children = children.map { |c| c.is_a?(Symbol) ? c.to_s : c }
|
11
|
+
super type, children, properties
|
12
|
+
end
|
13
|
+
|
14
|
+
# Create a new node from the given S-expression (a string)
|
15
|
+
def self.from_sexp(sexp)
|
16
|
+
@parser ||= Parser.new
|
17
|
+
@parser.string_to_ast(sexp)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Adds an empty node of the given type to the children unless another
|
21
|
+
# node of the same type is already present
|
22
|
+
def ensure_node_present(type)
|
23
|
+
if children.any? { |n| n.type == type }
|
24
|
+
self
|
25
|
+
else
|
26
|
+
updated(nil, children + [n0(type)])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the value at the root of an AST node like this:
|
31
|
+
#
|
32
|
+
# node # => (module-def
|
33
|
+
# (module-name
|
34
|
+
# (SCALAR-ID "Instrument"))
|
35
|
+
#
|
36
|
+
# node.value # => "Instrument"
|
37
|
+
#
|
38
|
+
# No error checking is done and the caller is responsible for calling
|
39
|
+
# this only on compatible nodes
|
40
|
+
def value
|
41
|
+
val = children.first
|
42
|
+
val = val.children.first while val.respond_to?(:children)
|
43
|
+
val
|
44
|
+
end
|
45
|
+
|
46
|
+
# Add the given nodes to the children
|
47
|
+
def add(*nodes)
|
48
|
+
updated(nil, children + nodes)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns the first child node of the given type that is found
|
52
|
+
def find(type)
|
53
|
+
nodes = find_all(type)
|
54
|
+
nodes.first
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns an array containing all child nodes of the given type(s)
|
58
|
+
def find_all(*types)
|
59
|
+
Extractor.new.process(self, types)
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_h
|
63
|
+
h = {}
|
64
|
+
children.each do |node|
|
65
|
+
h[node.type] = node.children.map { |n| n.is_a?(AST::Node) ? n.to_h : n }
|
66
|
+
end
|
67
|
+
h
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|