atp 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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