atp 1.0.0 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 898bb2e160b6d893026e211eba9cf858387c33b5
4
- data.tar.gz: f6e78515801ad71eed4358f3c5373df08a32e115
3
+ metadata.gz: 0a0d850eca7f69b2f9c49af6e1192fc97d248cb8
4
+ data.tar.gz: fcf7c3fa24bcca9d19eb3d590d68f6acef66ac83
5
5
  SHA512:
6
- metadata.gz: ef51a2e7bdcd532882e9266db0f5be8537e9079dd6f6c370b4ccff34e989737539f7fa7123cdbadf7d388540f29570946a49bde56d4b3f63b5bb740753acf92e
7
- data.tar.gz: c35f0f652e10edf1634b8ed839c4d77efbbfed048b80529d73c61ff08b7987ce35355e10f73ab4e9fa5b18abca593ad4ee89b1fcbca715019e0a648e743969c9
6
+ metadata.gz: 7b2cf5e3e8b7252884cdb9f45ef8cd57374b1eda91e1559f19f5303c10ccfb6c16b35fdf38a2fd5d7ca58a124034b6551964e59937227398ec67710125c9ab8d
7
+ data.tar.gz: 88d0018049a88372325e2acbbec0fd729f872c70500ae15208001321da2504404814d5401886e8752d5ed8f3dc2cb50d6fb97bf63293697b9df986325cf3241f
@@ -1,6 +1,6 @@
1
1
  module ATP
2
2
  MAJOR = 1
3
- MINOR = 0
3
+ MINOR = 1
4
4
  BUGFIX = 0
5
5
  DEV = nil
6
6
 
data/lib/atp.rb CHANGED
@@ -79,6 +79,7 @@ module ATP
79
79
  autoload :MissingIDs, 'atp/validators/missing_ids'
80
80
  autoload :Condition, 'atp/validators/condition'
81
81
  autoload :Jobs, 'atp/validators/jobs'
82
+ autoload :Flags, 'atp/validators/flags'
82
83
  end
83
84
 
84
85
  # Formatters are run on the processed AST to display the flow or to render
@@ -86,6 +86,13 @@ module ATP
86
86
  def set_flags
87
87
  Processors::ExtractSetFlags.new.run(self)
88
88
  end
89
+
90
+ # Returns true if the node contains any nodes of the given type(s) or if any
91
+ # of its children do.
92
+ # To consider only direct children of this node use: node.find_all(*types).empty?
93
+ def contains?(*types)
94
+ !Extractor.new.process(self, types).empty?
95
+ end
89
96
  end
90
97
  end
91
98
  end
@@ -98,17 +98,21 @@ module ATP
98
98
  # used to build and represent the given test flow
99
99
  def ast(options = {})
100
100
  options = {
101
- apply_relationships: true,
101
+ apply_relationships: true,
102
102
  # Supply a unique ID to append to all IDs
103
- unique_id: nil,
103
+ unique_id: nil,
104
104
  # Set to :smt, or :igxl
105
- optimization: :runner,
105
+ optimization: :runner,
106
+ # When true, will remove set_result nodes in an on_fail branch which contains a continue
107
+ implement_continue: true,
108
+ # When false, this will not optimize the use of a flag by nesting a dependent test within
109
+ # the parent test's on_fail branch if the on_fail contains a continue
110
+ optimize_flags_when_continue: true,
106
111
  # These options are not intended for application use, but provide the ability to
107
112
  # turn off certain processors during test cases
108
- add_ids: true,
109
- optimize_flags: true,
110
- one_flag_per_test: true,
111
- implement_continue: true
113
+ add_ids: true,
114
+ optimize_flags: true,
115
+ one_flag_per_test: true
112
116
  }.merge(options)
113
117
  ###############################################################################
114
118
  ## Common pre-processing and validation
@@ -117,6 +121,7 @@ module ATP
117
121
  Validators::DuplicateIDs.new(self).run(ast)
118
122
  Validators::MissingIDs.new(self).run(ast)
119
123
  Validators::Jobs.new(self).run(ast)
124
+ Validators::Flags.new(self).run(ast)
120
125
  # Ensure everything has an ID, this helps later if condition nodes need to be generated
121
126
  ast = Processors::AddIDs.new.run(ast) if options[:add_ids]
122
127
  ast = Processors::FlowID.new.run(ast, options[:unique_id]) if options[:unique_id]
@@ -132,7 +137,9 @@ module ATP
132
137
  unless options[:optimization] == :runner
133
138
  ast = Processors::ContinueImplementer.new.run(ast) if options[:implement_continue]
134
139
  end
135
- ast = Processors::FlagOptimizer.new.run(ast) if options[:optimize_flags]
140
+ if options[:optimize_flags]
141
+ ast = Processors::FlagOptimizer.new.run(ast, optimize_when_continue: options[:optimize_flags_when_continue])
142
+ end
136
143
  ast = Processors::AdjacentIfCombiner.new.run(ast)
137
144
 
138
145
  ###############################################################################
@@ -187,6 +194,17 @@ module ATP
187
194
  @pipeline[0] = add_volatile_flags(@pipeline[0], flags)
188
195
  end
189
196
 
197
+ # Record a description for a bin number
198
+ def describe_bin(number, description, options = {})
199
+ @pipeline[0] = add_bin_description(@pipeline[0], number, description, type: :hard)
200
+ end
201
+
202
+ # Record a description for a softbin number
203
+ def describe_soft_bin(number, description, options = {})
204
+ @pipeline[0] = add_bin_description(@pipeline[0], number, description, type: :soft)
205
+ end
206
+ alias_method :describe_softbin, :describe_soft_bin
207
+
190
208
  # Group all tests generated within the given block
191
209
  #
192
210
  # @example
@@ -240,6 +258,10 @@ module ATP
240
258
  options[:on_fail] ||= {}
241
259
  options[:on_fail][:continue] = true
242
260
  end
261
+ if options.key?(:delayed)
262
+ options[:on_fail] ||= {}
263
+ options[:on_fail][:delayed] = options.delete(:delayed)
264
+ end
243
265
  if f = options.delete(:flag_pass)
244
266
  options[:on_pass] ||= {}
245
267
  options[:on_pass][:set_flag] = f
@@ -276,11 +298,22 @@ module ATP
276
298
  end
277
299
  end
278
300
 
279
- if lims = options[:limit] || options[:limits]
280
- lims = [lims] unless lims.is_a?(Array)
281
- lims.each do |l|
282
- if l.is_a?(Hash)
283
- children << limit(l[:value], l[:rule], l[:unit] || l[:units])
301
+ lims = options[:limit] || options[:limits]
302
+ if lims || options[:lo] || options[:low] || options[:hi] || options[:high]
303
+ if lims == :none || lims == 'none'
304
+ children << n0(:nolimits)
305
+ else
306
+ lims = Array(lims) unless lims.is_a?(Array)
307
+ if lo = options[:lo] || options[:low]
308
+ lims << { value: lo, rule: :gte }
309
+ end
310
+ if hi = options[:hi] || options[:high]
311
+ lims << { value: hi, rule: :lte }
312
+ end
313
+ lims.each do |l|
314
+ if l.is_a?(Hash)
315
+ children << n(:limit, [l[:value], l[:rule], l[:unit] || l[:units], l[:selector]])
316
+ end
284
317
  end
285
318
  end
286
319
  end
@@ -450,6 +483,10 @@ module ATP
450
483
  "<ATP::Flow:#{object_id} #{name}>"
451
484
  end
452
485
 
486
+ def ids(options = {})
487
+ ATP::AST::Extractor.new.process(raw, [:id]).map { |node| node.to_a[0] }
488
+ end
489
+
453
490
  private
454
491
 
455
492
  def flow_control_method(name, flag, options = {}, &block)
@@ -617,6 +654,7 @@ module ATP
617
654
  children << set_flag_node(options[:set_run_flag] || options[:set_flag])
618
655
  end
619
656
  children << n0(:continue) if options[:continue]
657
+ children << n1(:delayed, !!options[:delayed]) if options.key?(:delayed)
620
658
  children << n1(:render, options[:render]) if options[:render]
621
659
  n(:on_fail, children)
622
660
  end
@@ -663,14 +701,6 @@ module ATP
663
701
  end
664
702
  end
665
703
 
666
- def limit(value, rule, units = nil)
667
- if units
668
- n(:limit, [value, rule, units])
669
- else
670
- n2(:limit, value, rule)
671
- end
672
- end
673
-
674
704
  def pin(name)
675
705
  n1(:pin, name)
676
706
  end
@@ -717,6 +747,27 @@ module ATP
717
747
  node.updated(nil, [name, v] + nodes)
718
748
  end
719
749
 
750
+ # Ensures the flow ast has a bin descriptions node, then adds the
751
+ # given description to it
752
+ def add_bin_description(node, number, description, options)
753
+ @existing_bin_descriptions ||= { soft: {}, hard: {} }
754
+ return node if @existing_bin_descriptions[options[:type]][number]
755
+ @existing_bin_descriptions[options[:type]][number] = true
756
+ name, *nodes = *node
757
+ if nodes[0] && nodes[0].type == :volatile
758
+ v = nodes.shift
759
+ else
760
+ v = nil
761
+ end
762
+ if nodes[0] && nodes[0].type == :bin_descriptions
763
+ d = nodes.shift
764
+ else
765
+ d = n0(:bin_descriptions)
766
+ end
767
+ d = d.updated(nil, d.children + [n2(options[:type], number, description)])
768
+ node.updated(nil, [name, v, d].compact + nodes)
769
+ end
770
+
720
771
  def n(type, children, options = {})
721
772
  options[:file] ||= options.delete(:source_file) || source_file
722
773
  options[:line_number] ||= options.delete(:source_line_number) || source_line_number
@@ -9,7 +9,7 @@ module ATP
9
9
  end
10
10
 
11
11
  ([:test, :bin, :pass, :continue, :cz, :log, :sub_test, :volatile, :set_flag, :enable, :disable, :render,
12
- :context_changed?] +
12
+ :context_changed?, :ids, :describe_bin, :describe_softbin, :describe_soft_bin] +
13
13
  ATP::Flow::CONDITION_KEYS.keys).each do |method|
14
14
  define_method method do |*args, &block|
15
15
  options = args.pop if args.last.is_a?(Hash)
@@ -22,5 +22,35 @@ module ATP
22
22
  end
23
23
 
24
24
  alias_method :logprint, :log
25
+
26
+ def lo_limit(value, options)
27
+ {
28
+ value: value,
29
+ rule: options[:rule] || :gte,
30
+ units: options[:units],
31
+ selector: options[:selector] || options[:test_mode]
32
+ }
33
+ end
34
+
35
+ def hi_limit(value, options)
36
+ {
37
+ value: value,
38
+ rule: options[:rule] || :lte,
39
+ units: options[:units],
40
+ selector: options[:selector] || options[:test_mode]
41
+ }
42
+ end
43
+
44
+ def limit(value, options)
45
+ unless options[:rule]
46
+ fail 'You must supply option :rule (e.g. rule: :gt) when calling the limit helper'
47
+ end
48
+ {
49
+ value: value,
50
+ rule: options[:rule] || :lt,
51
+ units: options[:units],
52
+ selector: options[:selector] || options[:test_mode]
53
+ }
54
+ end
25
55
  end
26
56
  end
@@ -90,7 +90,8 @@ module ATP
90
90
  def safe_to_combine?(node1, node2)
91
91
  # Nodes won't be collapsed if node1 touches the shared run flag, i.e. if there is any chance
92
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])
93
+ (!volatile?(node1.to_a[0]) || (volatile?(node1.to_a[0]) && !node1.contains?(:test))) &&
94
+ !SetRunFlagFinder.new.contains?(node1, node1.to_a[0])
94
95
  end
95
96
  end
96
97
  end
@@ -25,7 +25,7 @@ module ATP
25
25
  # s(:name, "test2")))))
26
26
  #
27
27
  class FlagOptimizer < Processor
28
- attr_reader :run_flag_table
28
+ attr_reader :run_flag_table, :optimize_when_continue
29
29
 
30
30
  class ExtractRunFlagTable < Processor
31
31
  # Hash table of run_flag name with number of times used
@@ -53,7 +53,11 @@ module ATP
53
53
  alias_method :on_unless_flag, :on_if_flag
54
54
  end
55
55
 
56
- def run(node)
56
+ def run(node, options = {})
57
+ options = {
58
+ optimize_when_continue: true
59
+ }.merge(options)
60
+ @optimize_when_continue = options[:optimize_when_continue]
57
61
  # Pre-process the AST for # of occurrences of each run-flag used
58
62
  t = ExtractRunFlagTable.new
59
63
  t.process(node)
@@ -70,11 +74,16 @@ module ATP
70
74
  alias_method :on_group, :on_named_collection
71
75
  alias_method :on_unless_flag, :on_named_collection
72
76
 
77
+ def on_unnamed_collection(node)
78
+ node.updated(nil, optimize(process_all(node.children)))
79
+ end
80
+ alias_method :on_else, :on_unnamed_collection
81
+
73
82
  def on_if_flag(node)
74
83
  name, *nodes = *node
75
84
  # Remove this node and return its children if required
76
85
  if if_run_flag_to_remove.last == node.to_a[0]
77
- node.updated(:inline, node.to_a[1..-1])
86
+ node.updated(:inline, optimize(process_all(node.to_a[1..-1])))
78
87
  else
79
88
  node.updated(nil, [name] + optimize(process_all(nodes)))
80
89
  end
@@ -124,7 +133,10 @@ module ATP
124
133
  end
125
134
 
126
135
  def can_be_combined?(node1, node2)
127
- if node1.type == :test && (node2.type == :if_flag || node2.type == :unless_flag)
136
+ if node1.type == :test && (node2.type == :if_flag || node2.type == :unless_flag) &&
137
+ # Don't optimize tests which are marked as continue if told not to
138
+ !(node1.find(:on_fail) && node1.find(:on_fail).find(:continue) && !optimize_when_continue)
139
+
128
140
  if node1.find_all(:on_fail, :on_pass).any? do |node|
129
141
  if n = node.find(:set_flag)
130
142
  # Inline instead of setting a flag if...
@@ -141,7 +153,7 @@ module ATP
141
153
  end
142
154
 
143
155
  def combine(node1, node2)
144
- nodes_to_inline_on_pass_or_fail << node2
156
+ nodes_to_inline_on_pass_or_fail << node2 # .updated(nil, process_all(node2.children))
145
157
  node1 = node1.updated(nil, process_all(node1.children))
146
158
  nodes_to_inline_on_pass_or_fail.pop
147
159
  node1
@@ -66,7 +66,12 @@ module ATP
66
66
  if n.type == :on_pass
67
67
  n = n.add node.updated(:set_flag, ["#{id}_PASSED", :auto_generated])
68
68
  elsif n.type == :on_fail
69
- n.ensure_node_present(:continue)
69
+ delayed = n.find(:delayed)
70
+ if delayed && delayed.to_a[0]
71
+ n
72
+ else
73
+ n.ensure_node_present(:continue)
74
+ end
70
75
  else
71
76
  n
72
77
  end
@@ -78,7 +83,12 @@ module ATP
78
83
  node.updated(nil, node.children.map do |n|
79
84
  if n.type == :on_fail
80
85
  n = n.add node.updated(:set_flag, ["#{id}_FAILED", :auto_generated])
81
- n.ensure_node_present(:continue)
86
+ delayed = n.find(:delayed)
87
+ if delayed && delayed.to_a[0]
88
+ n
89
+ else
90
+ n.ensure_node_present(:continue)
91
+ end
82
92
  else
83
93
  n
84
94
  end
@@ -111,6 +121,7 @@ module ATP
111
121
  # Set flags depending on the result on tests which have dependents later
112
122
  # in the flow
113
123
  def on_test(node)
124
+ node = node.updated(nil, process_all(node.children))
114
125
  nid = id(node)
115
126
  # If this test has a dependent
116
127
  if test_results[nid]
@@ -118,11 +129,7 @@ module ATP
118
129
  node = add_fail_flag(nid, node) if test_results[nid][:failed]
119
130
  node = add_ran_flags(nid, node) if test_results[nid][:ran]
120
131
  end
121
- if node.type == :group
122
- node.updated(nil, process_all(node))
123
- else
124
- node
125
- end
132
+ node
126
133
  end
127
134
  alias_method :on_group, :on_test
128
135
 
@@ -0,0 +1,59 @@
1
+ module ATP
2
+ module Validators
3
+ class Flags < Validator
4
+ def setup
5
+ @open_if_nodes = []
6
+ @open_unless_nodes = []
7
+ @conflicting = []
8
+ end
9
+
10
+ def on_completion
11
+ failed = false
12
+ unless @conflicting.empty?
13
+ error 'if_flag and unless_flag conditions cannot be nested and refer to the same flag unless it is declared as volatile'
14
+ error "The following conflicts were found in flow #{flow.name}:"
15
+ @conflicting.each do |a, b|
16
+ a_condition = a.to_a[1] ? 'if_job: ' : 'unless_job:'
17
+ b_condition = b.to_a[1] ? 'if_job: ' : 'unless_job:'
18
+ error " #{a.type}(#{a.to_a[0]}) #{a.source}"
19
+ error " #{b.type}(#{b.to_a[0]}) #{b.source}"
20
+ error ''
21
+ end
22
+ failed = true
23
+ end
24
+ failed
25
+ end
26
+
27
+ def on_flow(node)
28
+ extract_volatiles(node)
29
+ process_all(node.children)
30
+ end
31
+
32
+ def on_if_flag(node)
33
+ if volatile?(node.to_a[0])
34
+ process_all(node.children)
35
+ else
36
+ if n = @open_unless_nodes.find { |n| n.to_a[0] == node.to_a[0] }
37
+ @conflicting << [n, node]
38
+ end
39
+ @open_if_nodes << node
40
+ process_all(node.children)
41
+ @open_if_nodes.pop
42
+ end
43
+ end
44
+
45
+ def on_unless_flag(node)
46
+ if volatile?(node.to_a[0])
47
+ process_all(node.children)
48
+ else
49
+ if n = @open_if_nodes.find { |n| n.to_a[0] == node.to_a[0] }
50
+ @conflicting << [n, node]
51
+ end
52
+ @open_unless_nodes << node
53
+ process_all(node.children)
54
+ @open_unless_nodes.pop
55
+ end
56
+ end
57
+ end
58
+ end
59
+ 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: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen McGinty
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-20 00:00:00.000000000 Z
11
+ date: 2018-01-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: origen
@@ -97,6 +97,7 @@ files:
97
97
  - lib/atp/validator.rb
98
98
  - lib/atp/validators/condition.rb
99
99
  - lib/atp/validators/duplicate_ids.rb
100
+ - lib/atp/validators/flags.rb
100
101
  - lib/atp/validators/jobs.rb
101
102
  - lib/atp/validators/missing_ids.rb
102
103
  - lib/tasks/atp.rake
@@ -125,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
125
126
  version: 1.8.11
126
127
  requirements: []
127
128
  rubyforge_project:
128
- rubygems_version: 2.5.2
129
+ rubygems_version: 2.6.8
129
130
  signing_key:
130
131
  specification_version: 4
131
132
  summary: An abstract test program model for Origen