atp 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/config/version.rb +1 -1
- data/lib/atp.rb +5 -0
- data/lib/atp/ast/builder.rb +40 -5
- data/lib/atp/ast/factories.rb +6 -3
- data/lib/atp/ast/node.rb +10 -0
- data/lib/atp/flow.rb +80 -32
- data/lib/atp/processor.rb +4 -0
- data/lib/atp/processors/condition.rb +53 -3
- data/lib/atp/processors/condition_extractor.rb +46 -0
- data/lib/atp/processors/pre_cleaner.rb +19 -3
- data/lib/atp/program.rb +1 -1
- data/lib/atp/validator.rb +24 -0
- data/lib/atp/validators/duplicate_ids.rb +32 -0
- data/lib/atp/validators/missing_ids.rb +55 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0318ad5ca67b39da3b87b038434eaa85b1ee2a1d
|
4
|
+
data.tar.gz: 63bdc11c210bba2219097d14b3c5aa55678a8c8f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ae4da77cd22cc197e3ecf80af390de270b71c6a00cfcae3c49345156b9840c5f6429520707c29c36dffb89d54ec50b8af710257c93f23b872d44b5a10fb8aad6
|
7
|
+
data.tar.gz: 6ee881a43ee9cf5015860b50719d6d07c461f545180d967319d8ada891a36cd47adf8ac48a5ef277c79494bfbc0a54dfdddb77d1bbaac77a70dc8a6d67b63f24
|
data/config/version.rb
CHANGED
data/lib/atp.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'origen'
|
2
2
|
require_relative '../config/application.rb'
|
3
|
+
|
3
4
|
module ATP
|
4
5
|
autoload :Program, 'atp/program'
|
5
6
|
autoload :Flow, 'atp/flow'
|
6
7
|
autoload :Processor, 'atp/processor'
|
8
|
+
autoload :Validator, 'atp/validator'
|
7
9
|
autoload :Runner, 'atp/runner'
|
8
10
|
autoload :Formatter, 'atp/formatter'
|
9
11
|
autoload :Parser, 'atp/parser'
|
@@ -22,6 +24,7 @@ module ATP
|
|
22
24
|
# and to implement the flow control API
|
23
25
|
module Processors
|
24
26
|
autoload :Condition, 'atp/processors/condition'
|
27
|
+
autoload :ConditionExtractor, 'atp/processors/condition_extractor'
|
25
28
|
autoload :Relationship, 'atp/processors/relationship'
|
26
29
|
autoload :PreCleaner, 'atp/processors/pre_cleaner'
|
27
30
|
autoload :PostCleaner, 'atp/processors/post_cleaner'
|
@@ -34,6 +37,8 @@ module ATP
|
|
34
37
|
# Validators are run on the processed AST to check it for common errors or
|
35
38
|
# logical issues that will prevent it being rendered to a test program format
|
36
39
|
module Validators
|
40
|
+
autoload :DuplicateIDs, 'atp/validators/duplicate_ids'
|
41
|
+
autoload :MissingIDs, 'atp/validators/missing_ids'
|
37
42
|
autoload :Condition, 'atp/validators/condition'
|
38
43
|
end
|
39
44
|
|
data/lib/atp/ast/builder.rb
CHANGED
@@ -4,6 +4,7 @@ module ATP
|
|
4
4
|
include Factories
|
5
5
|
|
6
6
|
attr_reader :context
|
7
|
+
attr_accessor :source_file, :source_line_number
|
7
8
|
|
8
9
|
def flow
|
9
10
|
n0(:flow)
|
@@ -13,8 +14,13 @@ module ATP
|
|
13
14
|
n(:name, str.to_s)
|
14
15
|
end
|
15
16
|
|
16
|
-
def log(str)
|
17
|
-
n(:log, str.to_s)
|
17
|
+
def log(str, options = {})
|
18
|
+
test = n(:log, str.to_s)
|
19
|
+
if options[:conditions]
|
20
|
+
apply_conditions(test, options[:conditions])
|
21
|
+
else
|
22
|
+
test
|
23
|
+
end
|
18
24
|
end
|
19
25
|
|
20
26
|
def render(str)
|
@@ -41,6 +47,24 @@ module ATP
|
|
41
47
|
n(:test_executed, id, executed, node)
|
42
48
|
end
|
43
49
|
|
50
|
+
def enable_flow_flag(var, options = {})
|
51
|
+
test = n(:enable_flow_flag, var)
|
52
|
+
if options[:conditions]
|
53
|
+
apply_conditions(test, options[:conditions])
|
54
|
+
else
|
55
|
+
test
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def disable_flow_flag(var, options = {})
|
60
|
+
test = n(:disable_flow_flag, var)
|
61
|
+
if options[:conditions]
|
62
|
+
apply_conditions(test, options[:conditions])
|
63
|
+
else
|
64
|
+
test
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
44
68
|
def group(group_name, nodes, options = {})
|
45
69
|
children = [name(group_name)]
|
46
70
|
|
@@ -59,8 +83,13 @@ module ATP
|
|
59
83
|
end
|
60
84
|
end
|
61
85
|
|
62
|
-
def cz(setup, node)
|
63
|
-
n(:cz, setup, node)
|
86
|
+
def cz(setup, node, options = {})
|
87
|
+
test = n(:cz, setup, node)
|
88
|
+
if options[:conditions]
|
89
|
+
apply_conditions(test, options[:conditions])
|
90
|
+
else
|
91
|
+
test
|
92
|
+
end
|
64
93
|
end
|
65
94
|
|
66
95
|
def new_context
|
@@ -199,7 +228,13 @@ module ATP
|
|
199
228
|
children << n(:bin, options[:bin]) if options[:bin]
|
200
229
|
children << n(:softbin, options[:softbin]) if options[:softbin]
|
201
230
|
children << n(:description, options[:description]) if options[:description]
|
202
|
-
n(:set_result, *children)
|
231
|
+
result = n(:set_result, *children)
|
232
|
+
|
233
|
+
if options[:conditions]
|
234
|
+
apply_conditions(result, options[:conditions])
|
235
|
+
else
|
236
|
+
result
|
237
|
+
end
|
203
238
|
end
|
204
239
|
|
205
240
|
def number(val)
|
data/lib/atp/ast/factories.rb
CHANGED
@@ -2,11 +2,14 @@ module ATP
|
|
2
2
|
module AST
|
3
3
|
module Factories
|
4
4
|
def n(type, *children)
|
5
|
-
|
5
|
+
options = children.last.is_a?(Hash) ? children.pop : {}
|
6
|
+
options[:file] ||= options.delete(:source_file) || try(:source_file)
|
7
|
+
options[:line_number] ||= options.delete(:source_line_number) || try(:source_line_number)
|
8
|
+
ATP::AST::Node.new(type, children, options)
|
6
9
|
end
|
7
10
|
|
8
|
-
def n0(type)
|
9
|
-
|
11
|
+
def n0(type, options = {})
|
12
|
+
n(type, options)
|
10
13
|
end
|
11
14
|
end
|
12
15
|
end
|
data/lib/atp/ast/node.rb
CHANGED
@@ -4,6 +4,8 @@ module ATP
|
|
4
4
|
class Node < ::AST::Node
|
5
5
|
include Factories
|
6
6
|
|
7
|
+
attr_reader :file, :line_number
|
8
|
+
|
7
9
|
def initialize(type, children = [], properties = {})
|
8
10
|
# Always use strings instead of symbols in the AST, makes serializing
|
9
11
|
# back and forward to a string easier
|
@@ -11,6 +13,14 @@ module ATP
|
|
11
13
|
super type, children, properties
|
12
14
|
end
|
13
15
|
|
16
|
+
def source
|
17
|
+
if file
|
18
|
+
"#{file}:#{line_number}"
|
19
|
+
else
|
20
|
+
'<Sorry, lost the source file info, please include an example if you report as a bug>'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
14
24
|
# Create a new node from the given S-expression (a string)
|
15
25
|
def self.from_sexp(sexp)
|
16
26
|
@parser ||= Parser.new
|
data/lib/atp/flow.rb
CHANGED
@@ -2,12 +2,13 @@ module ATP
|
|
2
2
|
# Implements the main user API for building and interacting
|
3
3
|
# with an abstract test program
|
4
4
|
class Flow
|
5
|
-
attr_reader :program
|
5
|
+
attr_reader :program, :name
|
6
6
|
# Returns the raw AST
|
7
7
|
attr_reader :raw
|
8
8
|
|
9
|
-
def initialize(program)
|
9
|
+
def initialize(program, name = nil)
|
10
10
|
@program = program
|
11
|
+
@name = name
|
11
12
|
@builder = AST::Builder.new
|
12
13
|
@raw = builder.flow
|
13
14
|
end
|
@@ -16,6 +17,8 @@ module ATP
|
|
16
17
|
# used to build and represent the given test flow
|
17
18
|
def ast
|
18
19
|
ast = Processors::PreCleaner.new.process(raw)
|
20
|
+
Validators::DuplicateIDs.new(self).process(ast)
|
21
|
+
Validators::MissingIDs.new(self).process(ast)
|
19
22
|
ast = Processors::Condition.new.process(ast)
|
20
23
|
ast = Processors::Relationship.new.process(ast)
|
21
24
|
ast = Processors::PostCleaner.new.process(ast)
|
@@ -44,60 +47,86 @@ module ATP
|
|
44
47
|
# @option options [Hash] :on_pass What action to take if the test passes
|
45
48
|
# @option options [Hash] :conditions What conditions must be met to execute the test
|
46
49
|
def test(instance, options = {})
|
50
|
+
extract_meta!(options)
|
47
51
|
r = options.delete(:return)
|
48
|
-
|
49
|
-
options
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
options
|
56
|
-
|
57
|
-
|
58
|
-
options[:on_fail] ||= {}
|
59
|
-
options[:on_fail][:softbin] = b
|
60
|
-
end
|
61
|
-
if options.delete(:continue)
|
62
|
-
options[:on_fail] ||= {}
|
63
|
-
options[:on_fail][:continue] = true
|
64
|
-
end
|
65
|
-
builder.new_context
|
66
|
-
|
67
|
-
t = builder.test(instance, options)
|
68
|
-
unless options[:context] == :current
|
69
|
-
open_conditions.each do |conditions|
|
70
|
-
t = builder.apply_conditions(t, conditions)
|
52
|
+
t = apply_open_conditions(options) do |options|
|
53
|
+
# Allows any continue, bin, or soft bin argument passed in at the options top-level to be assumed
|
54
|
+
# to be the action to take if the test fails
|
55
|
+
if b = options.delete(:bin)
|
56
|
+
options[:on_fail] ||= {}
|
57
|
+
options[:on_fail][:bin] = b
|
58
|
+
end
|
59
|
+
if b = options.delete(:softbin) || b = options.delete(:sbin) || b = options.delete(:soft_bin)
|
60
|
+
options[:on_fail] ||= {}
|
61
|
+
options[:on_fail][:softbin] = b
|
71
62
|
end
|
63
|
+
if options.delete(:continue)
|
64
|
+
options[:on_fail] ||= {}
|
65
|
+
options[:on_fail][:continue] = true
|
66
|
+
end
|
67
|
+
builder.test(instance, options)
|
72
68
|
end
|
73
69
|
append(t) unless r
|
74
70
|
t
|
75
71
|
end
|
76
72
|
|
77
73
|
def bin(number, options = {})
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
74
|
+
extract_meta!(options)
|
75
|
+
t = apply_open_conditions(options) do |options|
|
76
|
+
fail 'A :type option set to :pass or :fail is required when calling bin' unless options[:type]
|
77
|
+
options[:bin] = number
|
78
|
+
options[:softbin] ||= options[:soft_bin] || options[:sbin]
|
79
|
+
builder.set_result(options[:type], options)
|
80
|
+
end
|
81
|
+
append(t)
|
82
82
|
end
|
83
83
|
|
84
84
|
def cz(instance, cz_setup, options = {})
|
85
|
-
options
|
86
|
-
|
85
|
+
extract_meta!(options)
|
86
|
+
t = apply_open_conditions(options) do |options|
|
87
|
+
conditions = options.delete(:conditions)
|
88
|
+
options[:return] = true
|
89
|
+
builder.cz(cz_setup, test(instance, options), conditions: conditions)
|
90
|
+
end
|
91
|
+
append(t)
|
87
92
|
end
|
88
93
|
alias_method :characterize, :cz
|
89
94
|
|
90
95
|
# Append a log message line to the flow
|
91
96
|
def log(message, options = {})
|
92
|
-
|
97
|
+
extract_meta!(options)
|
98
|
+
t = apply_open_conditions(options) do |options|
|
99
|
+
builder.log(message, options)
|
100
|
+
end
|
101
|
+
append(t)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Enable a flow control variable
|
105
|
+
def enable(var, options = {})
|
106
|
+
extract_meta!(options)
|
107
|
+
t = apply_open_conditions(options) do |options|
|
108
|
+
builder.enable_flow_flag(var, options)
|
109
|
+
end
|
110
|
+
append(t)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Disable a flow control variable
|
114
|
+
def disable(var, options = {})
|
115
|
+
extract_meta!(options)
|
116
|
+
t = apply_open_conditions(options) do |options|
|
117
|
+
builder.disable_flow_flag(var, options)
|
118
|
+
end
|
119
|
+
append(t)
|
93
120
|
end
|
94
121
|
|
95
122
|
# Insert explicitly rendered content in to the flow
|
96
123
|
def render(str, options = {})
|
124
|
+
extract_meta!(options)
|
97
125
|
append builder.render(str)
|
98
126
|
end
|
99
127
|
|
100
128
|
def with_condition(options)
|
129
|
+
extract_meta!(options)
|
101
130
|
open_conditions.push(options)
|
102
131
|
yield
|
103
132
|
open_conditions.pop
|
@@ -112,6 +141,25 @@ module ATP
|
|
112
141
|
|
113
142
|
private
|
114
143
|
|
144
|
+
def apply_open_conditions(options)
|
145
|
+
if options[:context] == :current
|
146
|
+
options[:conditions] = builder.context[:conditions]
|
147
|
+
end
|
148
|
+
builder.new_context
|
149
|
+
t = yield(options)
|
150
|
+
unless options[:context] == :current
|
151
|
+
open_conditions.each do |conditions|
|
152
|
+
t = builder.apply_conditions(t, conditions)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
t
|
156
|
+
end
|
157
|
+
|
158
|
+
def extract_meta!(options)
|
159
|
+
builder.source_file = options.delete(:source_file) if options[:source_file]
|
160
|
+
builder.source_line_number = options.delete(:source_line_number) if options[:source_line_number]
|
161
|
+
end
|
162
|
+
|
115
163
|
# For testing
|
116
164
|
def raw=(ast)
|
117
165
|
@raw = ast
|
data/lib/atp/processor.rb
CHANGED
@@ -65,7 +65,9 @@ module ATP
|
|
65
65
|
children = node.children.dup
|
66
66
|
name = children.shift
|
67
67
|
state = children.shift
|
68
|
+
remove_condition << node
|
68
69
|
children = optimize_siblings(n(:temp, children))
|
70
|
+
remove_condition.pop
|
69
71
|
if condition_to_be_removed?(node)
|
70
72
|
process_all(children)
|
71
73
|
else
|
@@ -79,7 +81,9 @@ module ATP
|
|
79
81
|
def on_condition(node)
|
80
82
|
children = node.children.dup
|
81
83
|
name = children.shift
|
84
|
+
remove_condition << node
|
82
85
|
children = optimize_siblings(n(:temp, children))
|
86
|
+
remove_condition.pop
|
83
87
|
if condition_to_be_removed?(node)
|
84
88
|
process_all(children)
|
85
89
|
else
|
@@ -100,7 +104,7 @@ module ATP
|
|
100
104
|
end
|
101
105
|
|
102
106
|
def condition_to_be_removed?(node)
|
103
|
-
remove_condition.
|
107
|
+
remove_condition.any? { |c| equal_conditions?(c, node) }
|
104
108
|
end
|
105
109
|
|
106
110
|
def equal_conditions?(node1, node2)
|
@@ -118,11 +122,17 @@ module ATP
|
|
118
122
|
end
|
119
123
|
|
120
124
|
def on_flow(node)
|
121
|
-
|
125
|
+
# The extract_common_embedded_conditions method can probably do the whole job,
|
126
|
+
# but it might get a little complicated with regards to optimizing adjacent groups,
|
127
|
+
# so have left the original logic to have the first crack and deal with the groups
|
128
|
+
# for now.
|
129
|
+
nodes = optimize_siblings(node)
|
130
|
+
nodes = extract_common_embedded_conditions(nodes)
|
131
|
+
node.updated(nil, nodes)
|
122
132
|
end
|
123
133
|
|
124
134
|
def on_members(node)
|
125
|
-
node.updated(nil, optimize_siblings(node))
|
135
|
+
node.updated(nil, extract_common_embedded_conditions(optimize_siblings(node)))
|
126
136
|
end
|
127
137
|
|
128
138
|
def optimize_siblings(top_node)
|
@@ -166,6 +176,46 @@ module ATP
|
|
166
176
|
children.flatten
|
167
177
|
end
|
168
178
|
|
179
|
+
def extract_common_embedded_conditions(nodes)
|
180
|
+
nodes = [nodes] unless nodes.is_a?(Array)
|
181
|
+
result = []
|
182
|
+
cond_a = nil
|
183
|
+
test_a = nil
|
184
|
+
ConditionExtractor.new.run(nodes).each do |cond_b, test_b|
|
185
|
+
if cond_a
|
186
|
+
common = cond_a & cond_b
|
187
|
+
if common.empty?
|
188
|
+
result << combine(cond_a, extract_common_embedded_conditions(test_a))
|
189
|
+
cond_a = cond_b
|
190
|
+
test_a = test_b
|
191
|
+
else
|
192
|
+
a = combine(cond_a - common, test_a)
|
193
|
+
b = combine(cond_b - common, test_b)
|
194
|
+
cond_a = common
|
195
|
+
test_a = [a, b].flatten
|
196
|
+
end
|
197
|
+
else
|
198
|
+
cond_a = cond_b
|
199
|
+
test_a = test_b
|
200
|
+
end
|
201
|
+
end
|
202
|
+
if nodes == [test_a]
|
203
|
+
nodes
|
204
|
+
else
|
205
|
+
result << combine(cond_a, extract_common_embedded_conditions(test_a))
|
206
|
+
result.flatten
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def combine(conditions, node)
|
211
|
+
if conditions && !conditions.empty?
|
212
|
+
conditions.reverse_each do |n|
|
213
|
+
node = n.updated(nil, n.children + (node.is_a?(Array) ? node : [node]))
|
214
|
+
end
|
215
|
+
end
|
216
|
+
node
|
217
|
+
end
|
218
|
+
|
169
219
|
def remove_condition
|
170
220
|
@remove_condition ||= []
|
171
221
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module ATP
|
2
|
+
module Processors
|
3
|
+
class ConditionExtractor < Processor
|
4
|
+
attr_reader :results, :conditions
|
5
|
+
|
6
|
+
def run(nodes)
|
7
|
+
@results = []
|
8
|
+
@conditions = []
|
9
|
+
process_all(nodes)
|
10
|
+
@results
|
11
|
+
end
|
12
|
+
|
13
|
+
def on_boolean_condition(node)
|
14
|
+
children = node.children.dup
|
15
|
+
name = children.shift
|
16
|
+
state = children.shift
|
17
|
+
conditions << node.updated(nil, [name, state])
|
18
|
+
process_all(children)
|
19
|
+
conditions.pop
|
20
|
+
end
|
21
|
+
alias_method :on_flow_flag, :on_boolean_condition
|
22
|
+
alias_method :on_test_result, :on_boolean_condition
|
23
|
+
alias_method :on_test_executed, :on_boolean_condition
|
24
|
+
|
25
|
+
def on_condition(node)
|
26
|
+
children = node.children.dup
|
27
|
+
name = children.shift
|
28
|
+
conditions << node.updated(nil, [name])
|
29
|
+
process_all(children)
|
30
|
+
conditions.pop
|
31
|
+
end
|
32
|
+
alias_method :on_job, :on_condition
|
33
|
+
|
34
|
+
def on_test(node)
|
35
|
+
results << [conditions.uniq, node]
|
36
|
+
end
|
37
|
+
alias_method :on_group, :on_test
|
38
|
+
alias_method :on_log, :on_test
|
39
|
+
alias_method :on_enable_flow_flag, :on_test
|
40
|
+
alias_method :on_disable_flow_flag, :on_test
|
41
|
+
alias_method :on_cz, :on_test
|
42
|
+
alias_method :on_set_result, :on_test
|
43
|
+
alias_method :on_render, :on_test
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -8,12 +8,20 @@ module ATP
|
|
8
8
|
@group_ids = []
|
9
9
|
end
|
10
10
|
|
11
|
+
# Make all IDs lower cased symbols
|
11
12
|
def on_id(node)
|
12
|
-
id = node.to_a
|
13
|
-
|
14
|
-
node.updated(nil, [id])
|
13
|
+
id = node.to_a[0]
|
14
|
+
node.updated(nil, [clean(id)])
|
15
15
|
end
|
16
16
|
|
17
|
+
# Make all ID references use the lower case symbols
|
18
|
+
def on_test_executed(node)
|
19
|
+
children = node.children.dup
|
20
|
+
children[0] = clean(children[0])
|
21
|
+
node.updated(nil, process_all(children))
|
22
|
+
end
|
23
|
+
alias_method :on_test_result, :on_test_executed
|
24
|
+
|
17
25
|
def on_group(node)
|
18
26
|
if id = node.children.find { |n| n.type == :id }
|
19
27
|
@group_ids << process(id).value
|
@@ -38,6 +46,14 @@ module ATP
|
|
38
46
|
end
|
39
47
|
node.updated(nil, process_all(children))
|
40
48
|
end
|
49
|
+
|
50
|
+
def clean(id)
|
51
|
+
if id.is_a?(Array)
|
52
|
+
id.map { |i| clean(i) }
|
53
|
+
else
|
54
|
+
id.to_s.downcase.to_sym
|
55
|
+
end
|
56
|
+
end
|
41
57
|
end
|
42
58
|
end
|
43
59
|
end
|
data/lib/atp/program.rb
CHANGED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'ast'
|
2
|
+
module ATP
|
3
|
+
class Validator < Processor
|
4
|
+
attr_reader :flow
|
5
|
+
|
6
|
+
def initialize(flow)
|
7
|
+
@flow = flow
|
8
|
+
end
|
9
|
+
|
10
|
+
def process(node)
|
11
|
+
if @top_level_called
|
12
|
+
super
|
13
|
+
else
|
14
|
+
@top_level_called = true
|
15
|
+
setup
|
16
|
+
super(node)
|
17
|
+
exit 1 if on_completion
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def setup
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ATP
|
2
|
+
module Validators
|
3
|
+
class DuplicateIDs < Validator
|
4
|
+
def on_completion
|
5
|
+
if @duplicate_ids
|
6
|
+
@duplicate_ids.each do |id, nodes|
|
7
|
+
Origen.log.error "Test ID #{id} is defined more than once in flow #{flow.name}:"
|
8
|
+
nodes.each do |node|
|
9
|
+
Origen.log.error " #{node.source}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def on_id(node)
|
17
|
+
@existing_ids ||= {}
|
18
|
+
id = node.value
|
19
|
+
if @existing_ids[id]
|
20
|
+
@duplicate_ids ||= {}
|
21
|
+
if @duplicate_ids[id]
|
22
|
+
@duplicate_ids[id] << node
|
23
|
+
else
|
24
|
+
@duplicate_ids[id] = [@existing_ids[id], node]
|
25
|
+
end
|
26
|
+
else
|
27
|
+
@existing_ids[id] = node
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module ATP
|
2
|
+
module Validators
|
3
|
+
class MissingIDs < Validator
|
4
|
+
def setup
|
5
|
+
@referenced_ids = {}
|
6
|
+
@present_ids ||= {}.with_indifferent_access
|
7
|
+
@referenced_early = {}.with_indifferent_access
|
8
|
+
end
|
9
|
+
|
10
|
+
def on_completion
|
11
|
+
failed = false
|
12
|
+
@referenced_ids.each do |id, nodes|
|
13
|
+
unless @present_ids[id]
|
14
|
+
Origen.log.error "Test ID #{id} is referenced in flow #{flow.name} in the following lines, but it is never defined:"
|
15
|
+
nodes.each do |node|
|
16
|
+
Origen.log.error " #{node.source}"
|
17
|
+
end
|
18
|
+
failed = true
|
19
|
+
@referenced_early.delete(id)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
@referenced_early.each do |id, nodes|
|
23
|
+
Origen.log.error "Test ID #{id} is referenced in flow #{flow.name} in the following line(s):"
|
24
|
+
nodes.each do |node|
|
25
|
+
Origen.log.error " #{node.source}"
|
26
|
+
end
|
27
|
+
Origen.log.error 'but it was not defined until later:'
|
28
|
+
Origen.log.error " #{@present_ids[id].first.source}"
|
29
|
+
failed = true
|
30
|
+
end
|
31
|
+
failed
|
32
|
+
end
|
33
|
+
|
34
|
+
def on_id(node)
|
35
|
+
id = node.value
|
36
|
+
@present_ids[id] ||= []
|
37
|
+
@present_ids[id] << node
|
38
|
+
end
|
39
|
+
|
40
|
+
def on_test_executed(node)
|
41
|
+
ids = node.to_a[0]
|
42
|
+
[ids].flatten.each do |id|
|
43
|
+
@referenced_ids[id] ||= []
|
44
|
+
@referenced_ids[id] << node
|
45
|
+
unless @present_ids[id]
|
46
|
+
@referenced_early[id] ||= []
|
47
|
+
@referenced_early[id] << node
|
48
|
+
end
|
49
|
+
end
|
50
|
+
process_all(node)
|
51
|
+
end
|
52
|
+
alias_method :on_test_result, :on_test_executed
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: atp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen McGinty
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-01-
|
11
|
+
date: 2016-01-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: origen
|
@@ -78,12 +78,16 @@ files:
|
|
78
78
|
- lib/atp/parser.rb
|
79
79
|
- lib/atp/processor.rb
|
80
80
|
- lib/atp/processors/condition.rb
|
81
|
+
- lib/atp/processors/condition_extractor.rb
|
81
82
|
- lib/atp/processors/post_cleaner.rb
|
82
83
|
- lib/atp/processors/pre_cleaner.rb
|
83
84
|
- lib/atp/processors/relationship.rb
|
84
85
|
- lib/atp/program.rb
|
85
86
|
- lib/atp/runner.rb
|
87
|
+
- lib/atp/validator.rb
|
86
88
|
- lib/atp/validators/condition.rb
|
89
|
+
- lib/atp/validators/duplicate_ids.rb
|
90
|
+
- lib/atp/validators/missing_ids.rb
|
87
91
|
- lib/tasks/atp.rake
|
88
92
|
- templates/web/archive.md.erb
|
89
93
|
- templates/web/contact.md.erb
|