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,28 @@
1
+ module ATP
2
+ module Processors
3
+ # Removes any conditions nodes that are nested within other condition
4
+ # nodes that specify the same condition
5
+ class RedundantConditionRemover < Processor
6
+ def run(node)
7
+ @conditions = []
8
+ process(node)
9
+ end
10
+
11
+ def on_condition_node(node)
12
+ sig = [node.type, node.to_a[0]]
13
+ if @conditions.include?(sig)
14
+ flag, *nodes = *node
15
+ node.updated(:inline, process_all(nodes))
16
+ else
17
+ @conditions << sig
18
+ node = node.updated(nil, process_all(node.children))
19
+ @conditions.pop
20
+ node
21
+ end
22
+ end
23
+ ATP::Flow::CONDITION_NODE_TYPES.each do |type|
24
+ alias_method "on_#{type}", :on_condition_node unless method_defined?("on_#{type}")
25
+ end
26
+ end
27
+ end
28
+ end
@@ -11,49 +11,52 @@ module ATP
11
11
  class ExtractTestResults < Processor
12
12
  attr_reader :results
13
13
 
14
- def on_test_result(node)
15
- ids, state, *children = *node
14
+ def on_if_failed(node)
15
+ ids, *children = *node
16
16
  unless ids.is_a?(Array)
17
17
  ids = [ids]
18
18
  end
19
19
  ids.each do |id|
20
20
  results[id] ||= {}
21
- if state
22
- results[id][:passed] = true
23
- else
24
- results[id][:failed] = true
25
- end
21
+ results[id][:failed] = true
26
22
  end
27
23
  process_all(children)
28
24
  end
25
+ alias_method :on_if_any_failed, :on_if_failed
26
+ alias_method :on_if_all_failed, :on_if_failed
29
27
 
30
- def on_test_executed(node)
31
- id, state, *children = *node
32
- id, state = *node
28
+ def on_if_passed(node)
29
+ ids, *children = *node
30
+ unless ids.is_a?(Array)
31
+ ids = [ids]
32
+ end
33
+ ids.each do |id|
34
+ results[id] ||= {}
35
+ results[id][:passed] = true
36
+ end
37
+ process_all(children)
38
+ end
39
+ alias_method :on_if_any_passed, :on_if_passed
40
+ alias_method :on_if_all_passed, :on_if_passed
41
+
42
+ def on_if_ran(node)
43
+ id, *children = *node
33
44
  results[id] ||= {}
34
- results[id][:executed] = true
45
+ results[id][:ran] = true
35
46
  process_all(children)
36
47
  end
48
+ alias_method :on_unless_ran, :on_if_ran
37
49
 
38
50
  def results
39
51
  @results ||= {}.with_indifferent_access
40
52
  end
41
53
  end
42
54
 
43
- def process(node)
44
- # On first call extract the test_result nodes from the given AST,
45
- # then process as normal thereafter
46
- if @first_call_done
47
- result = super
48
- else
49
- @first_call_done = true
50
- t = ExtractTestResults.new
51
- t.process(node)
52
- @test_results = t.results || {}
53
- result = super
54
- @first_call_done = false
55
- end
56
- result
55
+ def run(node)
56
+ t = ExtractTestResults.new
57
+ t.process(node)
58
+ @test_results = t.results || {}
59
+ process(node)
57
60
  end
58
61
 
59
62
  def add_pass_flag(id, node)
@@ -61,7 +64,7 @@ module ATP
61
64
  node = node.ensure_node_present(:on_fail)
62
65
  node.updated(nil, node.children.map do |n|
63
66
  if n.type == :on_pass
64
- n = n.add n2(:set_run_flag, "#{id}_PASSED", :auto_generated)
67
+ n = n.add node.updated(:set_flag, ["#{id}_PASSED", :auto_generated])
65
68
  elsif n.type == :on_fail
66
69
  n.ensure_node_present(:continue)
67
70
  else
@@ -74,7 +77,7 @@ module ATP
74
77
  node = node.ensure_node_present(:on_fail)
75
78
  node.updated(nil, node.children.map do |n|
76
79
  if n.type == :on_fail
77
- n = n.add n2(:set_run_flag, "#{id}_FAILED", :auto_generated)
80
+ n = n.add node.updated(:set_flag, ["#{id}_FAILED", :auto_generated])
78
81
  n.ensure_node_present(:continue)
79
82
  else
80
83
  n
@@ -82,16 +85,27 @@ module ATP
82
85
  end)
83
86
  end
84
87
 
85
- def add_executed_flag(id, node)
86
- node = node.ensure_node_present(:on_fail)
87
- node = node.ensure_node_present(:on_pass)
88
- node.updated(nil, node.children.map do |n|
89
- if n.type == :on_pass || n.type == :on_fail
90
- n = n.add n2(:set_run_flag, "#{id}_RAN", :auto_generated)
88
+ def add_ran_flags(id, node)
89
+ set_flag = node.updated(:set_flag, ["#{id}_RAN", :auto_generated])
90
+ # For a group, set a flag immediately upon entry to the group to signal that
91
+ # it ran to later tests
92
+ if node.type == :group
93
+ name, id, *nodes = *node
94
+ if id.type == :id
95
+ nodes.unshift(set_flag)
96
+ nodes.unshift(id)
91
97
  else
92
- n
98
+ nodes.unshift(id)
99
+ nodes.unshift(set_flag)
93
100
  end
94
- end)
101
+ node.updated(nil, [name] + nodes)
102
+ # For a test, set a flag immediately after the referenced test has executed
103
+ # but don't change its pass/fail handling
104
+ elsif node.type == :test
105
+ node.updated(:inline, [node, set_flag])
106
+ else
107
+ fail "Don't know how to add ran flag to #{node.type}"
108
+ end
95
109
  end
96
110
 
97
111
  # Set flags depending on the result on tests which have dependents later
@@ -102,7 +116,7 @@ module ATP
102
116
  if test_results[nid]
103
117
  node = add_pass_flag(nid, node) if test_results[nid][:passed]
104
118
  node = add_fail_flag(nid, node) if test_results[nid][:failed]
105
- node = add_executed_flag(nid, node) if test_results[nid][:executed]
119
+ node = add_ran_flags(nid, node) if test_results[nid][:ran]
106
120
  end
107
121
  if node.type == :group
108
122
  node.updated(nil, process_all(node))
@@ -112,26 +126,50 @@ module ATP
112
126
  end
113
127
  alias_method :on_group, :on_test
114
128
 
115
- # Remove test_result nodes and replace with references to the flags set
116
- # up stream by the parent node
117
- def on_test_result(node)
118
- children = node.children.dup
119
- id = children.shift
120
- state = children.shift
121
- if state
122
- n(:run_flag, [id_to_flag(id, 'PASSED'), true] + process_all(children))
123
- else
124
- n(:run_flag, [id_to_flag(id, 'FAILED'), true] + process_all(children))
129
+ def on_if_failed(node)
130
+ id, *children = *node
131
+ node.updated(:if_flag, [id_to_flag(id, 'FAILED')] + process_all(children))
132
+ end
133
+ alias_method :on_if_any_failed, :on_if_failed
134
+
135
+ def on_if_all_failed(node)
136
+ ids, *children = *node
137
+ ids.reverse_each.with_index do |id, i|
138
+ if i == 0
139
+ node = node.updated(:if_flag, [id_to_flag(id, 'FAILED')] + process_all(children))
140
+ else
141
+ node = node.updated(:if_flag, [id_to_flag(id, 'FAILED'), node])
142
+ end
143
+ end
144
+ node
145
+ end
146
+
147
+ def on_if_passed(node)
148
+ id, *children = *node
149
+ node.updated(:if_flag, [id_to_flag(id, 'PASSED')] + process_all(children))
150
+ end
151
+ alias_method :on_if_any_passed, :on_if_passed
152
+
153
+ def on_if_all_passed(node)
154
+ ids, *children = *node
155
+ ids.reverse_each.with_index do |id, i|
156
+ if i == 0
157
+ node = node.updated(:if_flag, [id_to_flag(id, 'PASSED')] + process_all(children))
158
+ else
159
+ node = node.updated(:if_flag, [id_to_flag(id, 'PASSED'), node])
160
+ end
125
161
  end
162
+ node
163
+ end
164
+
165
+ def on_if_ran(node)
166
+ id, *children = *node
167
+ node.updated(:if_flag, [id_to_flag(id, 'RAN')] + process_all(children))
126
168
  end
127
169
 
128
- # Remove test_result nodes and replace with references to the flags set
129
- # up stream by the parent node
130
- def on_test_executed(node)
131
- children = node.children.dup
132
- id = children.shift
133
- state = children.shift
134
- n(:run_flag, [id_to_flag(id, 'RAN'), state] + children)
170
+ def on_unless_ran(node)
171
+ id, *children = *node
172
+ node.updated(:unless_flag, [id_to_flag(id, 'RAN')] + process_all(children))
135
173
  end
136
174
 
137
175
  # Returns the ID of the give test node (if any), caller is responsible
@@ -6,8 +6,8 @@ module ATP
6
6
  class Runner < Processor
7
7
  def run(node, options = {})
8
8
  options = {
9
- evaluate_flow_flags: true,
10
- evaluate_run_flags: true,
9
+ evaluate_enables: true,
10
+ evaluate_flags: true,
11
11
  evaluate_set_result: true
12
12
  }.merge(options)
13
13
  @options = options
@@ -31,11 +31,12 @@ module ATP
31
31
  container << node
32
32
  end
33
33
 
34
- def on_flow_flag(node)
35
- if @options[:evaluate_flow_flags]
36
- flag, enabled, *nodes = *node
34
+ def on_if_flag(node)
35
+ if @options[:evaluate_flags]
36
+ flag, *nodes = *node
37
37
  flag = [flag].flatten
38
- active = flag.any? { |f| flow_flags.include?(f) }
38
+ enabled = node.type == :if_flag
39
+ active = flag.any? { |f| set_flags.include?(f) }
39
40
  if (enabled && active) || (!enabled && !active)
40
41
  process_all(nodes)
41
42
  end
@@ -43,15 +44,17 @@ module ATP
43
44
  c = open_container do
44
45
  process_all(node.children)
45
46
  end
46
- container << node.updated(nil, node.children.take(2) + c)
47
+ container << node.updated(nil, node.children.take(1) + c)
47
48
  end
48
49
  end
50
+ alias_method :on_unless_flag, :on_if_flag
49
51
 
50
- def on_run_flag(node)
51
- if @options[:evaluate_run_flags]
52
- flag, enabled, *nodes = *node
52
+ def on_if_enabled(node)
53
+ if @options[:evaluate_enables]
54
+ flag, *nodes = *node
53
55
  flag = [flag].flatten
54
- active = flag.any? { |f| run_flags.include?(f) }
56
+ enabled = node.type == :if_enabled
57
+ active = flag.any? { |f| set_enables.include?(f) }
55
58
  if (enabled && active) || (!enabled && !active)
56
59
  process_all(nodes)
57
60
  end
@@ -59,16 +62,21 @@ module ATP
59
62
  c = open_container do
60
63
  process_all(node.children)
61
64
  end
62
- container << node.updated(nil, node.children.take(2) + c)
65
+ container << node.updated(nil, node.children.take(1) + c)
63
66
  end
64
67
  end
68
+ alias_method :on_unless_enabled, :on_if_enabled
65
69
 
66
- # Not sure why this method is here, all test_result nodes should have been
67
- # converted to run_flag nodes by now
68
- def on_test_result(node)
69
- id, passed, *nodes = *node
70
- if (passed && !failed_test_ids.include?(id)) ||
71
- (!passed && failed_test_ids.include?(id))
70
+ def on_if_failed(node)
71
+ id, *nodes = *node
72
+ if failed_test_ids.include?(id)
73
+ process_all(nodes)
74
+ end
75
+ end
76
+
77
+ def on_if_passed(node)
78
+ id, *nodes = *node
79
+ unless failed_test_ids.include?(id)
72
80
  process_all(nodes)
73
81
  end
74
82
  end
@@ -77,7 +85,7 @@ module ATP
77
85
  if id = node.find(:id)
78
86
  id = id.to_a[0]
79
87
  if failed_test_ids.include?(id)
80
- node = node.add(n0(:failed))
88
+ node = node.add(node.updated(:failed, []))
81
89
  failed = true
82
90
  if n_on_fail = node.find(:on_fail)
83
91
  node = node.remove(n_on_fail)
@@ -155,16 +163,16 @@ module ATP
155
163
  end
156
164
  end
157
165
 
158
- def on_set_run_flag(node)
159
- run_flags << node.to_a[0]
166
+ def on_set_flag(node)
167
+ set_flags << node.to_a[0]
160
168
  end
161
169
 
162
- def on_enable_flow_flag(node)
163
- flow_flags << node.value unless flow_flags.include?(node.value)
170
+ def on_enable(node)
171
+ set_enables << node.value unless set_enables.include?(node.value)
164
172
  end
165
173
 
166
- def on_disable_flow_flag(node)
167
- flow_flags.delete(node.value)
174
+ def on_disable(node)
175
+ set_enables.delete(node.value)
168
176
  end
169
177
 
170
178
  def on_log(node)
@@ -172,9 +180,10 @@ module ATP
172
180
  end
173
181
  alias_method :on_render, :on_log
174
182
 
175
- def on_job(node)
176
- jobs, state, *nodes = *node
183
+ def on_if_job(node)
184
+ jobs, *nodes = *node
177
185
  jobs = clean_job(jobs)
186
+ state = node.type == :if_job
178
187
  unless job
179
188
  fail 'Flow contains JOB-based conditions and no current JOB has been given!'
180
189
  end
@@ -184,6 +193,7 @@ module ATP
184
193
  process_all(node) unless jobs.include?(job)
185
194
  end
186
195
  end
196
+ alias_method :on_unless_job, :on_if_job
187
197
 
188
198
  def clean_job(job)
189
199
  [job].flatten.map { |j| j.to_s.upcase }
@@ -197,13 +207,13 @@ module ATP
197
207
  @failed_test_ids ||= [@options[:failed_test_id] || @options[:failed_test_ids]].flatten.compact
198
208
  end
199
209
 
200
- def run_flags
201
- @run_flags ||= []
210
+ def set_flags
211
+ @set_flags ||= []
202
212
  end
203
213
 
204
214
  # Returns an array of enabled flow flags
205
- def flow_flags
206
- @flow_flags ||= [@options[:flow_flag] || @options[:flow_flags]].flatten.compact
215
+ def set_enables
216
+ @set_enables ||= [@options[:enable] || @options[:enables]].flatten.compact
207
217
  end
208
218
 
209
219
  def completed?
@@ -3,6 +3,14 @@ module ATP
3
3
  class Validator < Processor
4
4
  attr_reader :flow
5
5
 
6
+ def self.testing=(value)
7
+ @testing = value
8
+ end
9
+
10
+ def self.testing
11
+ @testing
12
+ end
13
+
6
14
  def initialize(flow)
7
15
  @flow = flow
8
16
  end
@@ -30,5 +38,16 @@ module ATP
30
38
 
31
39
  def setup
32
40
  end
41
+
42
+ def error(message)
43
+ # This is a hack to make the specs pass, for some reason RSpec
44
+ # seems to be swallowing the Origen log output after the first
45
+ # test that generates an error
46
+ if Validator.testing
47
+ puts message
48
+ else
49
+ Origen.log.error(message)
50
+ end
51
+ end
33
52
  end
34
53
  end
@@ -4,9 +4,9 @@ module ATP
4
4
  def on_completion
5
5
  if @duplicate_ids
6
6
  @duplicate_ids.each do |id, nodes|
7
- Origen.log.error "Test ID #{id} is defined more than once in flow #{flow.name}:"
7
+ error "Test ID #{id} is defined more than once in flow #{flow.name}:"
8
8
  nodes.each do |node|
9
- Origen.log.error " #{node.source}"
9
+ error " #{node.source}"
10
10
  end
11
11
  end
12
12
  true
@@ -9,23 +9,23 @@ module ATP
9
9
  def on_completion
10
10
  failed = false
11
11
  unless @conflicting.empty?
12
- Origen.log.error 'if_job and unless_job conditions cannot both be applied to the same tests'
13
- Origen.log.error "The following conflicts were found in flow #{flow.name}:"
12
+ error 'if_job and unless_job conditions cannot both be applied to the same tests'
13
+ error "The following conflicts were found in flow #{flow.name}:"
14
14
  @conflicting.each do |a, b|
15
15
  a_condition = a.to_a[1] ? 'if_job: ' : 'unless_job:'
16
16
  b_condition = b.to_a[1] ? 'if_job: ' : 'unless_job:'
17
- Origen.log.error " #{a_condition} #{a.source}"
18
- Origen.log.error " #{b_condition} #{b.source}"
19
- Origen.log.error ''
17
+ error " #{a_condition} #{a.source}"
18
+ error " #{b_condition} #{b.source}"
19
+ error ''
20
20
  end
21
21
  failed = true
22
22
  end
23
23
 
24
24
  unless @negative.empty?
25
- Origen.log.error 'Job names should not be negated, use unless_job if you want to specify !JOB'
26
- Origen.log.error "The following negative job names were found in flow #{flow.name}:"
25
+ error 'Job names should not be negated, use unless_job if you want to specify !JOB'
26
+ error "The following negative job names were found in flow #{flow.name}:"
27
27
  @negative.each do |node|
28
- Origen.log.error " #{node.to_a[0]} #{node.source}"
28
+ error " #{node.to_a[0]} #{node.source}"
29
29
  end
30
30
  failed = true
31
31
  end
@@ -33,9 +33,10 @@ module ATP
33
33
  failed
34
34
  end
35
35
 
36
- def on_job(node)
37
- jobs, state, *nodes = *node
36
+ def on_if_job(node)
37
+ jobs, *nodes = *node
38
38
  jobs = [jobs].flatten
39
+ state = node.type == :if_job
39
40
  if jobs.any? { |j| j.to_s =~ /^(!|~)/ }
40
41
  @negative << node
41
42
  end
@@ -48,6 +49,7 @@ module ATP
48
49
  @stack.pop
49
50
  end
50
51
  end
52
+ alias_method :on_unless_job, :on_if_job
51
53
  end
52
54
  end
53
55
  end