atp 0.7.0 → 0.8.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/version.rb +1 -1
- data/lib/atp.rb +0 -1
- data/lib/atp/ast/builder.rb +99 -0
- data/lib/atp/flow.rb +32 -10
- data/lib/atp/processor.rb +43 -0
- data/lib/atp/processors/condition.rb +95 -98
- metadata +2 -3
- data/lib/atp/processors/condition_extractor.rb +0 -46
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f75bbab3b302da47d1dee34b1d3ee5ff9e19fbf8
|
4
|
+
data.tar.gz: bdd796b0790974ab59638e3eb1c3a6d0978838e4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c75c86487c1fa3db9cd8ec84b754850b4cb308c6cd5bd6c2fbc96342bf300d433154e66787b66bd896b484677f6c367102b641f9bdd5166f2b8be1a62a054767
|
7
|
+
data.tar.gz: eb3547a04a6b3ceea52ac58c831d5d320a1c818ffd161195207f858b0b30b592853ab94edeae371684221def67a0ee7075ee8c8ca7bb6e6af7890469b58e59b5
|
data/config/version.rb
CHANGED
data/lib/atp.rb
CHANGED
@@ -21,7 +21,6 @@ module ATP
|
|
21
21
|
# and to implement the flow control API
|
22
22
|
module Processors
|
23
23
|
autoload :Condition, 'atp/processors/condition'
|
24
|
-
autoload :ConditionExtractor, 'atp/processors/condition_extractor'
|
25
24
|
autoload :Relationship, 'atp/processors/relationship'
|
26
25
|
autoload :PreCleaner, 'atp/processors/pre_cleaner'
|
27
26
|
autoload :PostCleaner, 'atp/processors/post_cleaner'
|
data/lib/atp/ast/builder.rb
CHANGED
@@ -14,6 +14,24 @@ module ATP
|
|
14
14
|
n(:flow, name(str))
|
15
15
|
end
|
16
16
|
|
17
|
+
# Ensures the given flow ast has a volatile node, then adds the
|
18
|
+
# given flags to it
|
19
|
+
def add_volatile_flags(flow, flags)
|
20
|
+
name, *nodes = *flow
|
21
|
+
if nodes[0] && nodes[0].type == :volatile
|
22
|
+
v = nodes.shift
|
23
|
+
else
|
24
|
+
v = n0(:volatile)
|
25
|
+
end
|
26
|
+
existing = v.children.map { |f| f.type == :flag ? f.value : nil }.compact
|
27
|
+
new = []
|
28
|
+
flags.each do |flag|
|
29
|
+
new << n(:flag, flag) unless existing.include?(flag)
|
30
|
+
end
|
31
|
+
v = v.updated(nil, v.children + new)
|
32
|
+
flow.updated(nil, [name, v] + nodes)
|
33
|
+
end
|
34
|
+
|
17
35
|
def name(str)
|
18
36
|
n(:name, str.to_s)
|
19
37
|
end
|
@@ -220,6 +238,55 @@ module ATP
|
|
220
238
|
|
221
239
|
children << id(options[:id].to_s.downcase.to_sym) if options[:id]
|
222
240
|
|
241
|
+
if levels = options[:level] || options[:levels]
|
242
|
+
levels = [levels] unless levels.is_a?(Array)
|
243
|
+
levels.each do |l|
|
244
|
+
children << level(l[:name], l[:value], l[:unit] || l[:units])
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
if lims = options[:limit] || options[:limits]
|
249
|
+
lims = [lims] unless lims.is_a?(Array)
|
250
|
+
lims.each do |l|
|
251
|
+
children << limit(l[:value], l[:rule], l[:unit] || l[:units])
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
if pins = options[:pin] || options[:pins]
|
256
|
+
pins = [pins] unless pins.is_a?(Array)
|
257
|
+
pins.each do |p|
|
258
|
+
if p.is_a?(Hash)
|
259
|
+
children << pin(p[:name])
|
260
|
+
else
|
261
|
+
children << pin(p)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
if pats = options[:pattern] || options[:patterns]
|
267
|
+
pats = [pats] unless pats.is_a?(Array)
|
268
|
+
pats.each do |p|
|
269
|
+
if p.is_a?(Hash)
|
270
|
+
children << pattern(p[:name], p[:path])
|
271
|
+
else
|
272
|
+
children << pattern(p)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
if options[:meta]
|
278
|
+
attrs = []
|
279
|
+
options[:meta].each { |k, v| attrs << attribute(k, v) }
|
280
|
+
children << n(:meta, *attrs)
|
281
|
+
end
|
282
|
+
|
283
|
+
if subs = options[:sub_test] || options[:sub_tests]
|
284
|
+
subs = [subs] unless subs.is_a?(Array)
|
285
|
+
subs.each do |s|
|
286
|
+
children << s.updated(:sub_test, nil)
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
223
290
|
children << on_fail(options[:on_fail]) if options[:on_fail]
|
224
291
|
children << on_pass(options[:on_pass]) if options[:on_pass]
|
225
292
|
|
@@ -232,6 +299,38 @@ module ATP
|
|
232
299
|
end
|
233
300
|
end
|
234
301
|
|
302
|
+
def pattern(name, path = nil)
|
303
|
+
if path
|
304
|
+
n(:pattern, name, path)
|
305
|
+
else
|
306
|
+
n(:pattern, name)
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
def attribute(name, value)
|
311
|
+
n(:attribute, name, value)
|
312
|
+
end
|
313
|
+
|
314
|
+
def level(name, value, units = nil)
|
315
|
+
if units
|
316
|
+
n(:level, name, value, units)
|
317
|
+
else
|
318
|
+
n(:level, name, value)
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
def limit(value, rule, units = nil)
|
323
|
+
if units
|
324
|
+
n(:limit, value, rule, units)
|
325
|
+
else
|
326
|
+
n(:limit, value, rule)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def pin(name)
|
331
|
+
n(:pin, name)
|
332
|
+
end
|
333
|
+
|
235
334
|
def on_fail(options = {})
|
236
335
|
children = []
|
237
336
|
if options[:bin] || options[:softbin]
|
data/lib/atp/flow.rb
CHANGED
@@ -41,6 +41,14 @@ module ATP
|
|
41
41
|
ast
|
42
42
|
end
|
43
43
|
|
44
|
+
# Indicate the that given flags should be considered volatile (can change at any time), which will
|
45
|
+
# prevent them from been touched by the optimization algorithms
|
46
|
+
def volatile(*flags)
|
47
|
+
options = flags.pop if flags.last.is_a?(Hash)
|
48
|
+
flags = flags.flatten
|
49
|
+
@raw = builder.add_volatile_flags(@raw, flags)
|
50
|
+
end
|
51
|
+
|
44
52
|
# Group all tests generated within the given block
|
45
53
|
#
|
46
54
|
# @example
|
@@ -104,6 +112,16 @@ module ATP
|
|
104
112
|
t
|
105
113
|
end
|
106
114
|
|
115
|
+
# Equivalent to calling test, but returns a sub_test node instead of adding it to the flow.
|
116
|
+
# It will also ignore any condition nodes that would normally wrap the equivalent flow.test call.
|
117
|
+
#
|
118
|
+
# This is a helper to create sub_tests for inclusion in a top-level test node.
|
119
|
+
def sub_test(instance, options = {})
|
120
|
+
options[:return] = true
|
121
|
+
options[:ignore_all_conditions] = true
|
122
|
+
test(instance, options)
|
123
|
+
end
|
124
|
+
|
107
125
|
def bin(number, options = {})
|
108
126
|
extract_meta!(options)
|
109
127
|
t = apply_open_conditions(options) do |options|
|
@@ -268,19 +286,23 @@ module ATP
|
|
268
286
|
end
|
269
287
|
|
270
288
|
def apply_open_conditions(options)
|
271
|
-
if options[:
|
272
|
-
options
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
289
|
+
if options[:ignore_all_conditions]
|
290
|
+
yield(options)
|
291
|
+
else
|
292
|
+
if options[:context] == :current
|
293
|
+
options[:conditions] = builder.context[:conditions]
|
294
|
+
end
|
295
|
+
builder.new_context
|
296
|
+
t = yield(options)
|
297
|
+
unless options[:context] == :current
|
298
|
+
unless options[:dont_apply_conditions]
|
299
|
+
open_conditions.each do |conditions|
|
300
|
+
t = builder.apply_conditions(t, conditions)
|
301
|
+
end
|
280
302
|
end
|
281
303
|
end
|
304
|
+
t
|
282
305
|
end
|
283
|
-
t
|
284
306
|
end
|
285
307
|
|
286
308
|
def extract_meta!(options)
|
data/lib/atp/processor.rb
CHANGED
@@ -23,6 +23,23 @@ module ATP
|
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
# Some of our processors remove a wrapping node from the AST, returning
|
27
|
+
# a node of type :inline containing the children which should be inlined.
|
28
|
+
# Here we override the default version of this method to deal with handlers
|
29
|
+
# that return an inline node in place of a regular node.
|
30
|
+
def process_all(nodes)
|
31
|
+
results = []
|
32
|
+
nodes.to_a.each do |node|
|
33
|
+
n = process(node)
|
34
|
+
if n.respond_to?(:type) && n.type == :inline
|
35
|
+
results += n.children
|
36
|
+
else
|
37
|
+
results << n
|
38
|
+
end
|
39
|
+
end
|
40
|
+
results
|
41
|
+
end
|
42
|
+
|
26
43
|
def handler_missing(node)
|
27
44
|
node.updated(nil, process_all(node.children))
|
28
45
|
end
|
@@ -42,5 +59,31 @@ module ATP
|
|
42
59
|
def n2(type, arg1, arg2)
|
43
60
|
n(type, [arg1, arg2])
|
44
61
|
end
|
62
|
+
|
63
|
+
def extract_volatiles(flow)
|
64
|
+
@volatiles = {}
|
65
|
+
if v = flow.find(:volatile)
|
66
|
+
@volatiles[:flags] = Array(v.find_all(:flag)).map(&:value)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def volatile_flags
|
71
|
+
unless @volatiles
|
72
|
+
fail 'You must first call extract_volatiles(node) from your on_flow hander method'
|
73
|
+
end
|
74
|
+
@volatiles[:flags] || []
|
75
|
+
end
|
76
|
+
|
77
|
+
# Returns true if the given flag name has been marked as volatile
|
78
|
+
def volatile?(flag)
|
79
|
+
result = volatile_flags.any? { |f| clean_flag(f) == clean_flag(flag) }
|
80
|
+
result
|
81
|
+
end
|
82
|
+
|
83
|
+
def clean_flag(flag)
|
84
|
+
flag = flag.dup.to_s
|
85
|
+
flag[0] = '' if flag[0] == '$'
|
86
|
+
flag.downcase
|
87
|
+
end
|
45
88
|
end
|
46
89
|
end
|
@@ -43,134 +43,131 @@ module ATP
|
|
43
43
|
# (name "test4")))))))
|
44
44
|
#
|
45
45
|
class Condition < Processor
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
# Bit of a hack - To get all of the nested conditions optimized away it is necessary
|
50
|
-
# to execute this recursively a few times. This guard ensures that the recursion is
|
51
|
-
# only performed on the top-level and not on every process operation.
|
52
|
-
if @top_level_called
|
53
|
-
super
|
54
|
-
else
|
55
|
-
@top_level_called = true
|
56
|
-
ast1 = nil
|
57
|
-
ast2 = node
|
58
|
-
while ast1 != ast2
|
59
|
-
ast1 = super(ast2)
|
60
|
-
ast2 = super(ast1)
|
61
|
-
end
|
62
|
-
@top_level_called = false
|
63
|
-
ast1
|
64
|
-
end
|
46
|
+
def on_flow(node)
|
47
|
+
extract_volatiles(node)
|
48
|
+
node.updated(nil, optimize(process_all(node.children)))
|
65
49
|
end
|
66
50
|
|
67
|
-
def
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
51
|
+
def on_flow_flag(node)
|
52
|
+
flag, state, *nodes = *node
|
53
|
+
if conditions_to_remove.any? { |c| node.type == c.type && c.to_a == [flag, state] }
|
54
|
+
if volatile?(flag)
|
55
|
+
result = n(:inline, optimize(process_all(nodes)))
|
56
|
+
else
|
57
|
+
# This ensures any duplicate conditions matching the current one get removed
|
58
|
+
conditions_to_remove << node.updated(nil, [flag, state])
|
59
|
+
result = n(:inline, optimize(process_all(nodes)))
|
60
|
+
conditions_to_remove.pop
|
61
|
+
end
|
76
62
|
else
|
77
|
-
|
63
|
+
if volatile?(flag)
|
64
|
+
result = node.updated(nil, [flag, state] + optimize(process_all(nodes)))
|
65
|
+
else
|
66
|
+
conditions_to_remove << node.updated(nil, [flag, state])
|
67
|
+
result = node.updated(nil, [flag, state] + optimize(process_all(nodes)))
|
68
|
+
conditions_to_remove.pop
|
69
|
+
end
|
78
70
|
end
|
71
|
+
result
|
79
72
|
end
|
80
|
-
alias_method :
|
81
|
-
alias_method :
|
82
|
-
alias_method :
|
83
|
-
alias_method :
|
73
|
+
alias_method :on_test_result, :on_flow_flag
|
74
|
+
alias_method :on_job, :on_flow_flag
|
75
|
+
alias_method :on_run_flag, :on_flow_flag
|
76
|
+
alias_method :on_test_executed, :on_flow_flag
|
84
77
|
|
85
78
|
def on_group(node)
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
if condition_to_be_removed?(node)
|
92
|
-
process_all(children)
|
79
|
+
name, *nodes = *node
|
80
|
+
if conditions_to_remove.any? { |c| node.type == c.type && c.to_a == [name] }
|
81
|
+
conditions_to_remove << node.updated(nil, [name])
|
82
|
+
result = n(:inline, optimize(process_all(nodes)))
|
83
|
+
conditions_to_remove.pop
|
93
84
|
else
|
94
|
-
node.updated(nil, [name]
|
85
|
+
conditions_to_remove << node.updated(nil, [name])
|
86
|
+
result = node.updated(nil, [name] + optimize(process_all(nodes)))
|
87
|
+
conditions_to_remove.pop
|
95
88
|
end
|
89
|
+
result
|
96
90
|
end
|
97
91
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
if
|
103
|
-
|
92
|
+
def optimize(nodes)
|
93
|
+
results = []
|
94
|
+
node1 = nil
|
95
|
+
nodes.each do |node2|
|
96
|
+
if node1
|
97
|
+
if can_be_combined?(node1, node2)
|
98
|
+
node1 = process(combine(node1, node2))
|
99
|
+
else
|
100
|
+
results << node1
|
101
|
+
node1 = node2
|
102
|
+
end
|
103
|
+
else
|
104
|
+
node1 = node2
|
104
105
|
end
|
105
106
|
end
|
107
|
+
results << node1 if node1
|
108
|
+
results
|
106
109
|
end
|
107
110
|
|
108
|
-
def
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
if node1.type == node2.type
|
114
|
-
if node1.type == :group
|
115
|
-
node1.to_a.take(1) == node2.to_a.take(1)
|
116
|
-
else
|
117
|
-
node1.to_a.take(2) == node2.to_a.take(2)
|
118
|
-
end
|
111
|
+
def can_be_combined?(node1, node2)
|
112
|
+
if condition_node?(node1) && condition_node?(node2)
|
113
|
+
!(conditions(node1) & conditions(node2)).empty?
|
114
|
+
else
|
115
|
+
false
|
119
116
|
end
|
120
117
|
end
|
121
118
|
|
122
|
-
def
|
123
|
-
node.
|
119
|
+
def condition_node?(node)
|
120
|
+
node.respond_to?(:type) &&
|
121
|
+
[:flow_flag, :run_flag, :test_result, :group, :job, :test_executed].include?(node.type)
|
124
122
|
end
|
125
123
|
|
126
|
-
def
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
124
|
+
def combine(node1, node2)
|
125
|
+
common = conditions(node1) & conditions(node2)
|
126
|
+
common.each { |condition| conditions_to_remove << condition }
|
127
|
+
node1 = process(node1)
|
128
|
+
node1 = [node1] unless node1.is_a?(Array)
|
129
|
+
node2 = process(node2)
|
130
|
+
node2 = [node2] unless node2.is_a?(Array)
|
131
|
+
common.size.times { conditions_to_remove.pop }
|
131
132
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
test_a = nil
|
137
|
-
ConditionExtractor.new.run(nodes).each do |cond_b, test_b|
|
138
|
-
if cond_a
|
139
|
-
common = cond_a & cond_b
|
140
|
-
if common.empty?
|
141
|
-
result << combine(cond_a, extract_common_embedded_conditions(test_a))
|
142
|
-
cond_a = cond_b
|
143
|
-
test_a = test_b
|
144
|
-
else
|
145
|
-
a = combine(cond_a - common, test_a)
|
146
|
-
b = combine(cond_b - common, test_b)
|
147
|
-
cond_a = common
|
148
|
-
test_a = [a, b].flatten
|
149
|
-
end
|
133
|
+
node = nil
|
134
|
+
common.reverse_each do |condition|
|
135
|
+
if node
|
136
|
+
node = condition.updated(nil, condition.children + [node])
|
150
137
|
else
|
151
|
-
|
152
|
-
test_a = test_b
|
138
|
+
node = condition.updated(nil, condition.children + node1 + node2)
|
153
139
|
end
|
154
140
|
end
|
155
|
-
|
156
|
-
nodes
|
157
|
-
else
|
158
|
-
result << combine(cond_a, extract_common_embedded_conditions(test_a))
|
159
|
-
result.flatten
|
160
|
-
end
|
141
|
+
node
|
161
142
|
end
|
162
143
|
|
163
|
-
def
|
164
|
-
|
165
|
-
|
166
|
-
|
144
|
+
def conditions(node)
|
145
|
+
result = []
|
146
|
+
if [:flow_flag, :run_flag].include?(node.type)
|
147
|
+
flag, state, *children = *node
|
148
|
+
unless volatile?(flag)
|
149
|
+
result << node.updated(nil, [flag, state])
|
167
150
|
end
|
151
|
+
result += conditions(children.first) if children.first
|
152
|
+
elsif [:test_result, :job, :test_executed].include?(node.type)
|
153
|
+
flag, state, *children = *node
|
154
|
+
result << node.updated(nil, [flag, state])
|
155
|
+
result += conditions(children.first) if children.first
|
156
|
+
elsif node.type == :group
|
157
|
+
name, *children = *node
|
158
|
+
# Sometimes a group can have an ID
|
159
|
+
if children.first.try(:type) == :id
|
160
|
+
result << node.updated(nil, [name, children.shift])
|
161
|
+
else
|
162
|
+
result << node.updated(nil, [name])
|
163
|
+
end
|
164
|
+
result += conditions(children.first) if children.first
|
168
165
|
end
|
169
|
-
|
166
|
+
result
|
170
167
|
end
|
171
168
|
|
172
|
-
def
|
173
|
-
@
|
169
|
+
def conditions_to_remove
|
170
|
+
@conditions_to_remove ||= []
|
174
171
|
end
|
175
172
|
end
|
176
173
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: atp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen McGinty
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: origen
|
@@ -77,7 +77,6 @@ files:
|
|
77
77
|
- lib/atp/processors/add_ids.rb
|
78
78
|
- lib/atp/processors/add_set_result.rb
|
79
79
|
- lib/atp/processors/condition.rb
|
80
|
-
- lib/atp/processors/condition_extractor.rb
|
81
80
|
- lib/atp/processors/flow_id.rb
|
82
81
|
- lib/atp/processors/marshal.rb
|
83
82
|
- lib/atp/processors/post_cleaner.rb
|
@@ -1,46 +0,0 @@
|
|
1
|
-
module ATP
|
2
|
-
module Processors
|
3
|
-
class ConditionExtractor < Processor
|
4
|
-
attr_reader :results, :conditions
|
5
|
-
|
6
|
-
def run(nodes)
|
7
|
-
@results = []
|
8
|
-
@conditions = []
|
9
|
-
process_all(nodes)
|
10
|
-
@results
|
11
|
-
end
|
12
|
-
|
13
|
-
def on_boolean_condition(node)
|
14
|
-
children = node.children.dup
|
15
|
-
name = children.shift
|
16
|
-
state = children.shift
|
17
|
-
conditions << node.updated(nil, [name, state])
|
18
|
-
process_all(children)
|
19
|
-
conditions.pop
|
20
|
-
end
|
21
|
-
alias_method :on_flow_flag, :on_boolean_condition
|
22
|
-
alias_method :on_test_result, :on_boolean_condition
|
23
|
-
alias_method :on_test_executed, :on_boolean_condition
|
24
|
-
alias_method :on_job, :on_boolean_condition
|
25
|
-
alias_method :on_run_flag, :on_boolean_condition
|
26
|
-
|
27
|
-
def on_group(node)
|
28
|
-
sig = node.children.select { |n| [:id, :name, :on_fail, :on_pass].include?(n.try(:type)) }
|
29
|
-
children = node.children.dup
|
30
|
-
conditions << node.updated(nil, sig)
|
31
|
-
process_all(children - sig)
|
32
|
-
conditions.pop
|
33
|
-
end
|
34
|
-
|
35
|
-
def on_test(node)
|
36
|
-
results << [conditions.uniq, node]
|
37
|
-
end
|
38
|
-
alias_method :on_log, :on_test
|
39
|
-
alias_method :on_enable_flow_flag, :on_test
|
40
|
-
alias_method :on_disable_flow_flag, :on_test
|
41
|
-
alias_method :on_cz, :on_test
|
42
|
-
alias_method :on_set_result, :on_test
|
43
|
-
alias_method :on_render, :on_test
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|