atp 0.2.0 → 0.2.1
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.
- 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
|