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.
@@ -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