atp 0.8.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -13,7 +13,9 @@ module ATP
13
13
  if node.find(:name)
14
14
  @output += node.find(:name).value
15
15
  else
16
- @output += node.find(:object).value['Test']
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"
@@ -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)
@@ -25,6 +25,7 @@ module ATP
25
25
  process_all(node)
26
26
  end
27
27
  end
28
+ alias_method :on_group, :on_test
28
29
 
29
30
  def on_id(node)
30
31
  if @add_ids
@@ -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 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] }
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 = n(:inline, optimize(process_all(nodes)))
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, state])
59
- result = n(:inline, optimize(process_all(nodes)))
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, state] + optimize(process_all(nodes)))
78
+ result = node.updated(nil, [flag] + optimize(process_all(nodes)))
65
79
  else
66
- conditions_to_remove << node.updated(nil, [flag, state])
67
- result = node.updated(nil, [flag, state] + optimize(process_all(nodes)))
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
- 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
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
- node.respond_to?(:type) &&
121
- [:flow_flag, :run_flag, :test_result, :group, :job, :test_executed].include?(node.type)
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
- flag, state, *children = *node
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, state])
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