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,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