atp 0.8.0 → 1.0.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/commands.rb +5 -7
- data/config/version.rb +2 -2
- data/lib/atp.rb +45 -14
- data/lib/atp/ast/node.rb +18 -9
- data/lib/atp/flow.rb +558 -151
- data/lib/atp/flow_api.rb +26 -0
- data/lib/atp/formatters/basic.rb +3 -1
- data/lib/atp/processor.rb +0 -16
- data/lib/atp/processors/add_ids.rb +1 -0
- data/lib/atp/processors/adjacent_if_combiner.rb +97 -0
- data/lib/atp/processors/append_to.rb +27 -0
- data/lib/atp/processors/apply_post_group_actions.rb +50 -0
- data/lib/atp/processors/condition.rb +38 -37
- data/lib/atp/processors/continue_implementer.rb +35 -0
- data/lib/atp/processors/else_remover.rb +31 -0
- data/lib/atp/processors/empty_branch_remover.rb +17 -0
- data/lib/atp/processors/extract_set_flags.rb +18 -0
- data/lib/atp/processors/flag_optimizer.rb +214 -0
- data/lib/atp/processors/flattener.rb +58 -0
- data/lib/atp/processors/flow_id.rb +10 -4
- data/lib/atp/processors/on_pass_fail_remover.rb +39 -0
- data/lib/atp/processors/one_flag_per_test.rb +79 -0
- data/lib/atp/processors/pre_cleaner.rb +13 -8
- data/lib/atp/processors/redundant_condition_remover.rb +28 -0
- data/lib/atp/processors/relationship.rb +91 -53
- data/lib/atp/runner.rb +41 -31
- data/lib/atp/validator.rb +19 -0
- data/lib/atp/validators/duplicate_ids.rb +2 -2
- data/lib/atp/validators/jobs.rb +12 -10
- data/lib/atp/validators/missing_ids.rb +14 -8
- metadata +15 -5
- data/lib/atp/ast/builder.rb +0 -397
- data/lib/atp/ast/factories.rb +0 -17
- data/lib/atp/processors/post_cleaner.rb +0 -43
data/lib/atp/flow_api.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
module ATP
|
2
|
+
module FlowAPI
|
3
|
+
def atp=(atp)
|
4
|
+
@atp = atp
|
5
|
+
end
|
6
|
+
|
7
|
+
def atp
|
8
|
+
@atp
|
9
|
+
end
|
10
|
+
|
11
|
+
([:test, :bin, :pass, :continue, :cz, :log, :sub_test, :volatile, :set_flag, :enable, :disable, :render,
|
12
|
+
:context_changed?] +
|
13
|
+
ATP::Flow::CONDITION_KEYS.keys).each do |method|
|
14
|
+
define_method method do |*args, &block|
|
15
|
+
options = args.pop if args.last.is_a?(Hash)
|
16
|
+
options ||= {}
|
17
|
+
add_meta!(options) if respond_to?(:add_meta!, true)
|
18
|
+
add_description!(options) if respond_to?(:add_description!, true)
|
19
|
+
args << options
|
20
|
+
atp.send(method, *args, &block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
alias_method :logprint, :log
|
25
|
+
end
|
26
|
+
end
|
data/lib/atp/formatters/basic.rb
CHANGED
@@ -13,7 +13,9 @@ module ATP
|
|
13
13
|
if node.find(:name)
|
14
14
|
@output += node.find(:name).value
|
15
15
|
else
|
16
|
-
|
16
|
+
obj = node.find(:object).value
|
17
|
+
obj = obj['Test'] unless obj.is_a?(String)
|
18
|
+
@output += obj
|
17
19
|
end
|
18
20
|
@output += ' F' if node.find(:failed)
|
19
21
|
@output += "\n"
|
data/lib/atp/processor.rb
CHANGED
@@ -44,22 +44,6 @@ module ATP
|
|
44
44
|
node.updated(nil, process_all(node.children))
|
45
45
|
end
|
46
46
|
|
47
|
-
def n(type, children)
|
48
|
-
ATP::AST::Node.new(type, children)
|
49
|
-
end
|
50
|
-
|
51
|
-
def n0(type)
|
52
|
-
n(type, [])
|
53
|
-
end
|
54
|
-
|
55
|
-
def n1(type, arg)
|
56
|
-
n(type, [arg])
|
57
|
-
end
|
58
|
-
|
59
|
-
def n2(type, arg1, arg2)
|
60
|
-
n(type, [arg1, arg2])
|
61
|
-
end
|
62
|
-
|
63
47
|
def extract_volatiles(flow)
|
64
48
|
@volatiles = {}
|
65
49
|
if v = flow.find(:volatile)
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module ATP
|
2
|
+
module Processors
|
3
|
+
# This combines adjacent if flag nodes where the flag is in the opposite state
|
4
|
+
#
|
5
|
+
# s(:flow,
|
6
|
+
# s(:name, "prb1"),
|
7
|
+
# s(:if_flag, "SOME_FLAG",
|
8
|
+
# s(:test,
|
9
|
+
# s(:name, "test1"))),
|
10
|
+
# s(:unless_flag, "SOME_FLAG",
|
11
|
+
# s(:test,
|
12
|
+
# s(:name, "test2"))))
|
13
|
+
#
|
14
|
+
# s(:flow,
|
15
|
+
# s(:name, "prb1"),
|
16
|
+
# s(:if_flag, "SOME_FLAG",
|
17
|
+
# s(:test,
|
18
|
+
# s(:name, "test1"))),
|
19
|
+
# s(:else,
|
20
|
+
# s(:test,
|
21
|
+
# s(:name, "test2"))))
|
22
|
+
#
|
23
|
+
# See here for an example of the kind of flow level effect it has:
|
24
|
+
# https://github.com/Origen-SDK/origen_testers/issues/43
|
25
|
+
class AdjacentIfCombiner < ATP::Processor
|
26
|
+
class SetRunFlagFinder < ATP::Processor
|
27
|
+
def contains?(node, flag_name)
|
28
|
+
@result = false
|
29
|
+
@flag_name = flag_name
|
30
|
+
process_all(node)
|
31
|
+
@result
|
32
|
+
end
|
33
|
+
|
34
|
+
def on_set_flag(node)
|
35
|
+
if node.to_a[0] == @flag_name
|
36
|
+
@result = true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
alias_method :on_enable, :on_set_flag
|
40
|
+
alias_method :on_disable, :on_set_flag
|
41
|
+
end
|
42
|
+
|
43
|
+
def on_flow(node)
|
44
|
+
extract_volatiles(node)
|
45
|
+
name, *nodes = *node
|
46
|
+
node.updated(nil, [name] + optimize(process_all(nodes)))
|
47
|
+
end
|
48
|
+
|
49
|
+
def on_group(node)
|
50
|
+
name, *nodes = *node
|
51
|
+
node.updated(nil, [name] + optimize(process_all(nodes)))
|
52
|
+
end
|
53
|
+
|
54
|
+
def on_unnamed_collection(node)
|
55
|
+
node.updated(nil, optimize(process_all(node.children)))
|
56
|
+
end
|
57
|
+
alias_method :on_on_fail, :on_unnamed_collection
|
58
|
+
alias_method :on_on_pass, :on_unnamed_collection
|
59
|
+
|
60
|
+
def optimize(nodes)
|
61
|
+
results = []
|
62
|
+
node1 = nil
|
63
|
+
nodes.each do |node2|
|
64
|
+
if node1
|
65
|
+
if opposite_flag_states?(node1, node2) && safe_to_combine?(node1, node2)
|
66
|
+
results << combine(node1, node2)
|
67
|
+
node1 = nil
|
68
|
+
else
|
69
|
+
results << node1
|
70
|
+
node1 = node2
|
71
|
+
end
|
72
|
+
else
|
73
|
+
node1 = node2
|
74
|
+
end
|
75
|
+
end
|
76
|
+
results << node1 if node1
|
77
|
+
results
|
78
|
+
end
|
79
|
+
|
80
|
+
def combine(node1, node2)
|
81
|
+
node1.updated(nil, process_all(node1.children) + [node2.updated(:else, process_all(node2.to_a[1..-1]))])
|
82
|
+
end
|
83
|
+
|
84
|
+
def opposite_flag_states?(node1, node2)
|
85
|
+
((node1.type == :if_flag && node2.type == :unless_flag) || (node1.type == :unless_flag && node2.type == :if_flag) ||
|
86
|
+
(node1.type == :if_enabled && node2.type == :unless_enabled) || (node1.type == :unless_enabled && node2.type == :if_enabled)) &&
|
87
|
+
node1.to_a[0] == node2.to_a[0]
|
88
|
+
end
|
89
|
+
|
90
|
+
def safe_to_combine?(node1, node2)
|
91
|
+
# Nodes won't be collapsed if node1 touches the shared run flag, i.e. if there is any chance
|
92
|
+
# that by the time it would naturally execute node2, the flag could have been changed by node1
|
93
|
+
!volatile?(node1.to_a[0]) && !SetRunFlagFinder.new.contains?(node1, node1.to_a[0])
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ATP
|
2
|
+
module Processors
|
3
|
+
# Appends the given node to the node with the given ID, if it exists
|
4
|
+
# somewhere within the given parent node
|
5
|
+
class AppendTo < Processor
|
6
|
+
def run(parent, node, id, options = {})
|
7
|
+
@to_be_appended = node
|
8
|
+
@id_of_to_be_appended_to = id
|
9
|
+
@found = false
|
10
|
+
process(parent)
|
11
|
+
end
|
12
|
+
|
13
|
+
def succeeded?
|
14
|
+
@found
|
15
|
+
end
|
16
|
+
|
17
|
+
def handler_missing(node)
|
18
|
+
if node.id == @id_of_to_be_appended_to
|
19
|
+
@found = true
|
20
|
+
node.updated(nil, node.children + [@to_be_appended])
|
21
|
+
else
|
22
|
+
node.updated(nil, process_all(node.children))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module ATP
|
2
|
+
module Processors
|
3
|
+
# This removes on_pass/fail operations from groups and applies them to all
|
4
|
+
# contained tests
|
5
|
+
class ApplyPostGroupActions < Processor
|
6
|
+
def run(node)
|
7
|
+
@on_pass = []
|
8
|
+
@on_fail = []
|
9
|
+
process(node)
|
10
|
+
end
|
11
|
+
|
12
|
+
def on_group(node)
|
13
|
+
on_pass = node.find(:on_pass)
|
14
|
+
on_fail = node.find(:on_fail)
|
15
|
+
@on_pass << on_pass
|
16
|
+
@on_fail << on_fail
|
17
|
+
node = node.remove(on_pass) if on_pass
|
18
|
+
node = node.remove(on_fail) if on_fail
|
19
|
+
node = node.updated(nil, process_all(node.children))
|
20
|
+
@on_fail.pop
|
21
|
+
@on_pass.pop
|
22
|
+
node
|
23
|
+
end
|
24
|
+
|
25
|
+
def on_test(node)
|
26
|
+
node = node.ensure_node_present(:on_pass) if @on_pass.any? { |n| n }
|
27
|
+
node = node.ensure_node_present(:on_fail) if @on_fail.any? { |n| n }
|
28
|
+
node.updated(nil, process_all(node.children))
|
29
|
+
end
|
30
|
+
|
31
|
+
def on_on_pass(node)
|
32
|
+
@on_pass.each do |on_pass|
|
33
|
+
if on_pass
|
34
|
+
node = node.updated(nil, node.children + process_all(on_pass.children))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
node
|
38
|
+
end
|
39
|
+
|
40
|
+
def on_on_fail(node)
|
41
|
+
@on_fail.each do |on_fail|
|
42
|
+
if on_fail
|
43
|
+
node = node.updated(nil, node.children + process_all(on_fail.children))
|
44
|
+
end
|
45
|
+
end
|
46
|
+
node
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -48,45 +48,44 @@ module ATP
|
|
48
48
|
node.updated(nil, optimize(process_all(node.children)))
|
49
49
|
end
|
50
50
|
|
51
|
-
def
|
52
|
-
|
53
|
-
if conditions_to_remove.any? { |c| node.type == c.type && c.to_a == [
|
51
|
+
def on_group(node)
|
52
|
+
name, *nodes = *node
|
53
|
+
if conditions_to_remove.any? { |c| node.type == c.type && c.to_a == [name] }
|
54
|
+
conditions_to_remove << node.updated(nil, [name])
|
55
|
+
result = node.updated(:inline, optimize(process_all(nodes)))
|
56
|
+
conditions_to_remove.pop
|
57
|
+
else
|
58
|
+
conditions_to_remove << node.updated(nil, [name])
|
59
|
+
result = node.updated(nil, [name] + optimize(process_all(nodes)))
|
60
|
+
conditions_to_remove.pop
|
61
|
+
end
|
62
|
+
result
|
63
|
+
end
|
64
|
+
|
65
|
+
def on_condition_node(node)
|
66
|
+
flag, *nodes = *node
|
67
|
+
if conditions_to_remove.any? { |c| node.type == c.type && c.to_a == [flag] }
|
54
68
|
if volatile?(flag)
|
55
|
-
result =
|
69
|
+
result = node.updated(:inline, optimize(process_all(nodes)))
|
56
70
|
else
|
57
71
|
# This ensures any duplicate conditions matching the current one get removed
|
58
|
-
conditions_to_remove << node.updated(nil, [flag
|
59
|
-
result =
|
72
|
+
conditions_to_remove << node.updated(nil, [flag])
|
73
|
+
result = node.updated(:inline, optimize(process_all(nodes)))
|
60
74
|
conditions_to_remove.pop
|
61
75
|
end
|
62
76
|
else
|
63
77
|
if volatile?(flag)
|
64
|
-
result = node.updated(nil, [flag
|
78
|
+
result = node.updated(nil, [flag] + optimize(process_all(nodes)))
|
65
79
|
else
|
66
|
-
conditions_to_remove << node.updated(nil, [flag
|
67
|
-
result = node.updated(nil, [flag
|
80
|
+
conditions_to_remove << node.updated(nil, [flag])
|
81
|
+
result = node.updated(nil, [flag] + optimize(process_all(nodes)))
|
68
82
|
conditions_to_remove.pop
|
69
83
|
end
|
70
84
|
end
|
71
85
|
result
|
72
86
|
end
|
73
|
-
|
74
|
-
|
75
|
-
alias_method :on_run_flag, :on_flow_flag
|
76
|
-
alias_method :on_test_executed, :on_flow_flag
|
77
|
-
|
78
|
-
def on_group(node)
|
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
|
84
|
-
else
|
85
|
-
conditions_to_remove << node.updated(nil, [name])
|
86
|
-
result = node.updated(nil, [name] + optimize(process_all(nodes)))
|
87
|
-
conditions_to_remove.pop
|
88
|
-
end
|
89
|
-
result
|
87
|
+
ATP::Flow::CONDITION_NODE_TYPES.each do |type|
|
88
|
+
alias_method "on_#{type}", :on_condition_node unless method_defined?("on_#{type}")
|
90
89
|
end
|
91
90
|
|
92
91
|
def optimize(nodes)
|
@@ -117,8 +116,8 @@ module ATP
|
|
117
116
|
end
|
118
117
|
|
119
118
|
def condition_node?(node)
|
120
|
-
|
121
|
-
|
119
|
+
# [:flow_flag, :run_flag, :test_result, :group, :job, :test_executed].include?(node.type)
|
120
|
+
node.respond_to?(:type) && ATP::Flow::CONDITION_KEYS[node.type]
|
122
121
|
end
|
123
122
|
|
124
123
|
def combine(node1, node2)
|
@@ -143,16 +142,14 @@ module ATP
|
|
143
142
|
|
144
143
|
def conditions(node)
|
145
144
|
result = []
|
146
|
-
if [:flow_flag, :run_flag].include?(node.type)
|
147
|
-
|
145
|
+
# if [:flow_flag, :run_flag].include?(node.type)
|
146
|
+
if [:if_enabled, :unless_enabled, :if_flag, :unless_flag].include?(node.type)
|
147
|
+
flag, *children = *node
|
148
148
|
unless volatile?(flag)
|
149
|
-
result << node.updated(nil, [flag
|
149
|
+
result << node.updated(nil, [flag])
|
150
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
|
151
|
+
result += conditions(children.first) if children.first && children.size == 1
|
152
|
+
# elsif [:test_result, :job, :test_executed].include?(node.type)
|
156
153
|
elsif node.type == :group
|
157
154
|
name, *children = *node
|
158
155
|
# Sometimes a group can have an ID
|
@@ -161,7 +158,11 @@ module ATP
|
|
161
158
|
else
|
162
159
|
result << node.updated(nil, [name])
|
163
160
|
end
|
164
|
-
result += conditions(children.first) if children.first
|
161
|
+
result += conditions(children.first) if children.first && children.size == 1
|
162
|
+
elsif ATP::Flow::CONDITION_NODE_TYPES.include?(node.type)
|
163
|
+
flag, *children = *node
|
164
|
+
result << node.updated(nil, [flag])
|
165
|
+
result += conditions(children.first) if children.first && children.size == 1
|
165
166
|
end
|
166
167
|
result
|
167
168
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module ATP
|
2
|
+
module Processors
|
3
|
+
# Implements continue on a fail branch for V93K by removing any bin nodes that are
|
4
|
+
# siblings of continue nodes. The continue nodes are also removed in the process since
|
5
|
+
# they have now served their function.
|
6
|
+
class ContinueImplementer < ATP::Processor
|
7
|
+
# Delete any on-fail child if it's 'empty'
|
8
|
+
def on_on_fail(node)
|
9
|
+
if cont = node.find(:continue) || @continue
|
10
|
+
node = node.updated(nil, node.children - [cont] - node.find_all(:set_result))
|
11
|
+
end
|
12
|
+
node.updated(nil, process_all(node.children))
|
13
|
+
end
|
14
|
+
|
15
|
+
def on_group(node)
|
16
|
+
f = node.find(:on_fail)
|
17
|
+
if f && f.find(:continue)
|
18
|
+
with_continue do
|
19
|
+
node = node.updated(nil, process_all(node.children))
|
20
|
+
end
|
21
|
+
node
|
22
|
+
else
|
23
|
+
node.updated(nil, process_all(node.children))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def with_continue
|
28
|
+
orig = @continue
|
29
|
+
@continue = true
|
30
|
+
yield
|
31
|
+
@continue = orig
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ATP
|
2
|
+
module Processors
|
3
|
+
# Removes embedded else nodes and converts them to the equivalent inverse condition
|
4
|
+
# node at the same level as the parent node
|
5
|
+
class ElseRemover < Processor
|
6
|
+
def run(node)
|
7
|
+
process(node)
|
8
|
+
end
|
9
|
+
|
10
|
+
def on_condition_node(node)
|
11
|
+
if e = node.find(:else)
|
12
|
+
n1 = node.remove(e)
|
13
|
+
if node.type.to_s =~ /if_/
|
14
|
+
type = node.type.to_s.sub('if_', 'unless_').to_sym
|
15
|
+
elsif node.type.to_s =~ /unless_/
|
16
|
+
type = node.type.to_s.sub('unless_', 'if_').to_sym
|
17
|
+
else
|
18
|
+
fail "Don't know how to inverse: #{node.type}"
|
19
|
+
end
|
20
|
+
n2 = e.updated(type, [n1.to_a[0]] + e.children)
|
21
|
+
node.updated(:inline, [n1, n2])
|
22
|
+
else
|
23
|
+
node.updated(nil, process_all(node.children))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
ATP::Flow::CONDITION_NODE_TYPES.each do |type|
|
27
|
+
alias_method "on_#{type}", :on_condition_node unless method_defined?("on_#{type}")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ATP
|
2
|
+
module Processors
|
3
|
+
# Removes any empty on_pass and on_fail branches
|
4
|
+
class EmptyBranchRemover < Processor
|
5
|
+
# Delete any on-fail child if it's 'empty'
|
6
|
+
def on_test(node)
|
7
|
+
if on_pass = node.find(:on_pass)
|
8
|
+
node = node.remove(on_pass) if on_pass.children.empty?
|
9
|
+
end
|
10
|
+
if on_fail = node.find(:on_fail)
|
11
|
+
node = node.remove(on_fail) if on_fail.children.empty?
|
12
|
+
end
|
13
|
+
node = node.updated(nil, process_all(node.children))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|