origen_testers 0.51.1 → 0.51.3

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
  SHA256:
3
- metadata.gz: d6f96fa1f3c65b7ab6cd0fb2c25abb378ef0cd0d9489a05cc7c94eb05becf628
4
- data.tar.gz: 0d465b02299aceb26467727fd021736b78c959d46ece03fddd0c581495291e3d
3
+ metadata.gz: 3762e544f419c1c77e9f1d670c7203cd44e9ad6fef0246463f62c77e8592be92
4
+ data.tar.gz: 3c2e4679fae95dbb6f9976be317bbcf6c9fe3f8eff113d40fbdafe68cea06973
5
5
  SHA512:
6
- metadata.gz: d08fd272bc3331a87ac33011d22386e535981d376c0c995c4d3605794e6a7c3be7d755f69b0d851e22bf398692e98b516ce19999860e4b46fbba7af3ee1123e2
7
- data.tar.gz: b754e33f7577da5f100e93cb7b020ad8abf014e8e7b102d17e07bace411ff5e20df0c47e5e033f74fab814ccda0bc6b89fc1b2e5e768b8cb13b9e2e03ae4a32e
6
+ metadata.gz: 563af43372ac16a7159e4f1ca6d8aa8aed2fc630dc9224f477cb427332f76ec9ada304428caa15695cf48e7923fa3243154de71bc12b737e170d5370946a44f3
7
+ data.tar.gz: 2674ab9dda1e9b8e6a7816d5cab6add7eb9dc44b037ac2b12ef46a5d2473324632034faf88cf34998d501140eda7545a7ac19a8e0710ffb062c5523f93bdff49
data/config/commands.rb CHANGED
@@ -175,7 +175,7 @@ when "tags"
175
175
  # Run the unit tests
176
176
  when "specs"
177
177
  require "rspec"
178
- exit RSpec::Core::Runner.run(['spec'])
178
+ exit RSpec::Core::Runner.run($ARGV.empty? ? ['spec'] : $ARGV)
179
179
 
180
180
  # Run the example-based (diff) tests
181
181
  when "examples", "test"
data/config/version.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module OrigenTesters
2
2
  MAJOR = 0
3
3
  MINOR = 51
4
- BUGFIX = 1
4
+ BUGFIX = 3
5
5
  DEV = nil
6
6
  VERSION = [MAJOR, MINOR, BUGFIX].join(".") + (DEV ? ".pre#{DEV}" : '')
7
7
  end
@@ -19,7 +19,7 @@ module OrigenTesters
19
19
  # @return [Array] list of charz routines to be called under this profile
20
20
  # @!attribute charz_only
21
21
  # @return [Boolean] indicates if the point tests should or shouldn't be added to the flow
22
- attr_accessor :id, :name, :placement, :on_result, :enables, :flags, :routines, :charz_only
22
+ attr_accessor :id, :name, :placement, :on_result, :enables, :flags, :routines, :charz_only, :force_keep_parent, :and_enables, :and_flags
23
23
 
24
24
  def initialize(id, options, &block)
25
25
  @id = id
@@ -30,6 +30,7 @@ module OrigenTesters
30
30
  @placement ||= :inline
31
31
  @defined_routines = options.delete(:defined_routines)
32
32
  attrs_ok?
33
+ massage_gates
33
34
  end
34
35
 
35
36
  def attrs_ok?
@@ -74,8 +75,34 @@ module OrigenTesters
74
75
  end
75
76
 
76
77
  unless @gate_checks == false
77
- gate_check(@enables, :enables) if @enables
78
- gate_check(@flags, :flags) if @flags
78
+ if @and_enables && @and_flags
79
+ Origen.log.error "@and_enables and @and_flags are both set to true. Please only 'and' one gate type"
80
+ fail
81
+ end
82
+ if @and_enables
83
+ gate_check(@flags, :flags) if @flags
84
+ gate_check_and(@enables, :enables, @flags) if @enables
85
+ elsif @and_flags
86
+ gate_check(@enables, :enables) if @enables
87
+ gate_check_and(@flags, :flags, @enables) if @flags
88
+ else
89
+ gate_check(@enables, :enable) if @enables
90
+ gate_check(@flags, :flags) if @flags
91
+ end
92
+ end
93
+ end
94
+
95
+ # convert hash gates to set convert their routines to type array if not already
96
+ def massage_gates
97
+ if @enables.is_a?(Hash)
98
+ @enables = {}.tap do |new_h|
99
+ @enables.each { |gates, routines| new_h[gates] = [routines].flatten }
100
+ end
101
+ end
102
+ if @flags.is_a?(Hash)
103
+ @flags = {}.tap do |new_h|
104
+ @flags.each { |gates, routines| new_h[gates] = [routines].flatten }
105
+ end
79
106
  end
80
107
  end
81
108
 
@@ -112,6 +139,46 @@ module OrigenTesters
112
139
  end
113
140
  end
114
141
 
142
+ def gate_check_and(gates, gate_type, other_gate)
143
+ if other_gate.is_a? Hash
144
+ Origen.log.error "Profile #{id}: #{other_gate} When using &&-ing feature, the non-anded gate can not be of type hash."
145
+ fail
146
+ end
147
+ case gates
148
+ when Symbol, String
149
+ return
150
+ when Array
151
+ unknown_gates = gates.reject { |gate| [String, Symbol].include? gate.class }
152
+ if unknown_gates.empty?
153
+ return
154
+ else
155
+ Origen.log.error "Profile #{id}: Unknown #{gate_type} type(s) in #{gate_type} array."
156
+ Origen.log.error "Arrays must contain Strings and/or Symbols, but #{unknown_gates.map(&:class).uniq } were found in #{gates}"
157
+ fail
158
+ end
159
+ when Hash
160
+ gates.each do |gated_routine, gates|
161
+ if gated_routine.is_a? Hash
162
+ Origen.log.error "Profile #{id}: #{gate_type} Hash keys cannot be of type Hash, but only Symbol, String, or Array"
163
+ fail
164
+ end
165
+ unless @defined_routines.include?(gated_routine)
166
+ Origen.log.error "Profile #{id}: #{gated_routine} Hash keys for &&-ed gates must be defined routines."
167
+ fail
168
+ end
169
+ gates = [gates] unless gates.is_a? Array
170
+ unknown_gates = gates.reject { |gate| [String, Symbol].include? gate.class }
171
+ unless unknown_gates.empty?
172
+ Origen.log.error "Gate array must contain Strings and/or Symbols, but #{unknown_gates.map(&:class).uniq } were found in #{gates}"
173
+ fail
174
+ end
175
+ end
176
+ else
177
+ Origen.log.error "Profile #{id}: Unknown #{gate_type} type: #{gates.class}. #{gate_type} must be of type Symbol, String, Array, or Hash"
178
+ fail
179
+ end
180
+ end
181
+
115
182
  def method_missing(m, *args, &block)
116
183
  ivar = "@#{m.to_s.gsub('=', '')}"
117
184
  ivar_sym = ":#{ivar}"
@@ -1,29 +1,59 @@
1
1
  module OrigenTesters
2
2
  module Charz
3
3
  # A charz session
4
- # contains the final combination of charz object (routines/profiles) and user options to determine how and what charz tests should be created
4
+ # contains a collection of the final combinations of charz object (routines/profiles) and user options to determine how and what charz tests should be created
5
5
  # the session should be checked in your interface to determine the current status and can be queried to make charz generation decisions
6
- class Session < Profile
6
+ class Session
7
+ # @!attribute id
8
+ # @return [Symbol] current session ID. Will be a concatenation of the instances' ids
9
+ # @!attribute instances
10
+ # @return [Array] list of active instances (which are essentially Profiles)
11
+ # @!attribute current_instance
12
+ # @return [Profile] Set when looping over instances via #loop_instances. The interface can query the charz_instance for more detailed info
13
+ # @!attribute valid
14
+ # @return [Boolean] whether or not the current session setup is valid, if not then charz wont be created
7
15
  # @!attribute defaults
8
16
  # @return [Hash] list of values to instantiate the inherited attributes from Profile with if not altered by the session update
9
- attr_accessor :defaults
17
+ # @!attribute stored_instance
18
+ # @return [Profile] This is to store the instance that the interface is storing. Its to support a legacy usecase of querying the session for instance level info during EOF
19
+ attr_accessor :id, :instances, :current_instance, :valid, :defaults, :stored_instance
10
20
 
11
21
  def initialize(options = {})
12
- @id = :current_charz_session
22
+ @id = :empty_session
23
+ @instances = []
24
+ @current_instance = nil
25
+ @stored_instance = nil
13
26
  @active = false
14
27
  @valid = false
15
- if options[:defaults]
16
- @defaults = options[:defaults]
17
- else
18
- @defaults = {
19
- placement: :inline,
20
- on_result: nil,
21
- enables: nil,
22
- flags: nil,
23
- name: 'charz',
24
- charz_only: false
25
- }
26
- end
28
+ @defaults = {
29
+ placement: :inline,
30
+ routines: [],
31
+ on_result: nil,
32
+ enables: nil,
33
+ flags: nil,
34
+ enables_and: false,
35
+ and_enables: false,
36
+ flags_and: false,
37
+ and_flags: false,
38
+ name: 'charz',
39
+ charz_only: false,
40
+ force_keep_parent: false
41
+ }.merge((options[:defaults] || {}))
42
+ end
43
+
44
+ def on_result?
45
+ instances.any? { |charz_instance| !charz_instance.on_result.nil? }
46
+ end
47
+
48
+ def charz_only?
49
+ any_only = instances.any?(&:charz_only)
50
+ any_force = instances.any?(&:force_keep_parent)
51
+ !any_force && any_only && !on_result?
52
+ end
53
+
54
+ def charz_only
55
+ Origen.log.deprecate '#charz_only has been deprecated in favor of #charz_only? It is no longer an attribute, instead a runtime calculation.'
56
+ charz_only?
27
57
  end
28
58
 
29
59
  # Pauses the current session's activity while maintaining everthing else about the sessions state
@@ -31,6 +61,11 @@ module OrigenTesters
31
61
  @active = false
32
62
  end
33
63
 
64
+ def active?
65
+ !!@active
66
+ end
67
+ alias_method :active, :active?
68
+
34
69
  # Resume activity, if the session is valid
35
70
  def resume
36
71
  if @valid
@@ -38,61 +73,103 @@ module OrigenTesters
38
73
  end
39
74
  end
40
75
 
41
- # Takes a Routine or Profile, and queries it to setup the session's attributes
76
+ def current_instance
77
+ instance = @current_instance || instances.first
78
+ if instance.nil? && @stored_instance
79
+ Origen.log.deprecate '@current_instance had to source @stored_instance. This likely means charz_session.<some_attr> is being queried when the newer charz_instance.<some_attr> should be instead'
80
+ instance = @stored_instance
81
+ end
82
+ instance
83
+ end
84
+
85
+ def loop_instances
86
+ instances.each do |charz_instance|
87
+ @current_instance = charz_instance
88
+ yield
89
+ @current_instance = nil
90
+ end
91
+ end
92
+
93
+ # Takes a CharzTuple and queries it to setup an instance's attributes
42
94
  # the attributes values can be set from 3 different sources, in order of priority (first is most important):
43
95
  # - options
44
- # - charz object
96
+ # - charz object (Profile or Routine)
45
97
  # - defaults
46
98
  #
47
99
  # If the resulting session is invalid, @valid will turn false. Otherwise, the session becomes active
48
- def update(charz_obj, options)
100
+ def update(charz_tuples)
101
+ @instances = []
49
102
  @valid = false
50
- if charz_obj.nil?
103
+ if charz_tuples.nil? || charz_tuples.empty?
51
104
  @active = false
52
105
  @valid = false
106
+ @current_instance = nil
53
107
  return @valid
54
108
  end
55
- @defined_routines = options.delete(:defined_routines)
56
- assign_by_priority(:placement, charz_obj, options)
57
- assign_by_priority(:on_result, charz_obj, options)
58
- assign_by_priority(:enables, charz_obj, options)
59
- assign_by_priority(:flags, charz_obj, options)
60
- assign_by_priority(:routines, charz_obj, options)
61
- assign_by_priority(:name, charz_obj, options)
62
- assign_by_priority(:charz_only, charz_obj, options)
63
- attrs_ok?
64
- massage_gates
109
+ @defined_routines = charz_tuples.map(&:defined_routines).flatten.uniq.compact
110
+
111
+ charz_tuples.each do |charz_tuple|
112
+ profile_options = assign_by_priority(charz_tuple)
113
+ @instances << Profile.new(charz_tuple.obj.id, profile_options.merge(defined_routines: @defined_routines))
114
+ end
115
+ @id = instances.map(&:id).join('_').to_sym
65
116
  @active = true
66
117
  @valid = true
67
118
  end
68
119
 
69
120
  private
70
121
 
71
- # convert hash gates to set convert their routines to type array if not already
72
- def massage_gates
73
- if @enables.is_a?(Hash)
74
- @enables = {}.tap do |new_h|
75
- @enables.each { |gates, routines| new_h[gates] = [routines].flatten }
76
- end
77
- end
78
- if @flags.is_a?(Hash)
79
- @flags = {}.tap do |new_h|
80
- @flags.each { |gates, routines| new_h[gates] = [routines].flatten }
122
+ def assign_by_priority(charz_tuple)
123
+ options = charz_tuple.options
124
+ charz_obj = charz_tuple.obj
125
+ instance_options = {}
126
+ get_instance_setting_keys(charz_obj).each do |ivar|
127
+ if options.keys.include?(ivar)
128
+ instance_options[ivar] = options[ivar]
129
+ elsif charz_obj.send(ivar)
130
+ instance_options[ivar] = charz_obj.send(ivar)
131
+ elsif @defaults.keys.include?(ivar)
132
+ instance_options[ivar] = @defaults[ivar]
133
+ else
134
+ Origen.log.error "Charz Session: No value could be determined for #{ivar}"
135
+ fail
81
136
  end
82
137
  end
138
+ instance_options
83
139
  end
84
140
 
85
- # see initialize
86
- def assign_by_priority(ivar, charz_obj, options)
87
- if options.keys.include?(ivar)
88
- instance_variable_set("@#{ivar}", options[ivar])
89
- elsif charz_obj.send(ivar)
90
- instance_variable_set("@#{ivar}", charz_obj.send(ivar))
91
- elsif @defaults.keys.include?(ivar)
92
- instance_variable_set("@#{ivar}", @defaults[ivar])
141
+ def get_instance_setting_keys(charz_obj)
142
+ keys = charz_obj.instance_variables | @defaults.keys
143
+ keys.map! { |k| k.to_s.sub('@', '').to_sym }
144
+ keys -= [:id]
145
+ keys
146
+ end
147
+
148
+ def method_missing(method, *args, &block)
149
+ deprecated_methods = [
150
+ :name,
151
+ :placement,
152
+ :on_result,
153
+ :enables,
154
+ :flags,
155
+ :routines,
156
+ :and_enables,
157
+ :enables_and,
158
+ :and_flags,
159
+ :flags_and,
160
+ :charz_only,
161
+ :force_keep_parent
162
+ ]
163
+ if deprecated_methods.include?(method.to_sym) || deprecated_methods.include?(method.to_s[0..-2].to_sym)
164
+ Origen.log.deprecate "charz_session.#{method} has been deprecated. Please query charz_instance.#{method} instead."
165
+ if current_instance.nil? && !valid
166
+ Origen.log.error "blocked call of 'charz_session.#{method}'!"
167
+ Origen.log.warn 'The charz instance attributes are no longer accessible when the session is invalid!'
168
+ else
169
+ current_instance.send(method, *args, &block)
170
+ end
93
171
  else
94
- Origen.log.error "Charz Session: No value could be determined for #{ivar}"
95
- fail
172
+ super
96
173
  end
97
174
  end
98
175
  end
@@ -3,6 +3,7 @@ Dir.glob("#{File.dirname(__FILE__)}/charz/**/*.rb").sort.each do |file|
3
3
  end
4
4
  module OrigenTesters
5
5
  module Charz
6
+ CharzTuple = Struct.new(:obj, :options, :defined_routines, keyword_init: true)
6
7
  # @!attribute charz_stack
7
8
  # @return [Array] FILO queue of charz session defining data
8
9
  # @!attribute charz_routines
@@ -11,13 +12,15 @@ module OrigenTesters
11
12
  # @return [Hash] user defined charz profiles
12
13
  # @!attribute charz_session
13
14
  # @return [Session] current charz session, based on data in the top of the charz_stack
15
+ # @!attribute charz_instance
16
+ # @return [Session] current charz instance of the session. If there is not a current instance, will return the first instance of the session instance stack
14
17
  # @!attribute eof_charz_tests
15
18
  # @return [Array] charz tests to be added at the end of the flow
16
19
  # @!attribute skip_group_eof_charz_tests
17
20
  # @return [Boolean] whether or not to wrap eof charz tests in a group
18
21
  # @!attribute eof_charz_tests_group_name
19
22
  # @return [String, Symbol] group name to be used to for eof charz tests
20
- attr_accessor :charz_stack, :charz_routines, :charz_profiles, :charz_session, :eof_charz_tests, :skip_group_eof_charz_tests, :eof_charz_tests_group_name
23
+ attr_accessor :charz_stack, :charz_routines, :charz_profiles, :charz_session, :charz_instance, :eof_charz_tests, :skip_group_eof_charz_tests, :eof_charz_tests_group_name
21
24
 
22
25
  def charz_stack
23
26
  @charz_stack ||= []
@@ -35,6 +38,21 @@ module OrigenTesters
35
38
  @charz_session ||= Session.new
36
39
  end
37
40
 
41
+ # If there is a current instance present, that should always be used. However when running EOF charz,
42
+ # the instance to be used is no longer set, so instead of referencing the session, use the one that we've
43
+ # stored already
44
+ def charz_instance
45
+ unless charz_session.current_instance.nil?
46
+ set_charz_instance(charz_session.current_instance)
47
+ end
48
+ @charz_instance
49
+ end
50
+
51
+ def set_charz_instance(instance)
52
+ @charz_instance = instance
53
+ charz_session.stored_instance = instance
54
+ end
55
+
38
56
  def eof_charz_tests
39
57
  @eof_charz_tests ||= []
40
58
  end
@@ -106,12 +124,12 @@ module OrigenTesters
106
124
 
107
125
  # Queries the current charz session to see if its active, indicating point tests should be generating charz tests
108
126
  def charz_active?
109
- charz_session.active
127
+ charz_session.active?
110
128
  end
111
129
 
112
130
  # Queries the current charz session to see if point tests should skip generation, only adding the resulting charz test
113
131
  def charz_only?
114
- charz_active? && charz_session.charz_only
132
+ charz_active? && charz_session.charz_only?
115
133
  end
116
134
 
117
135
  # Pauses the current charz session, preventing point tests from generating charz tests even if the session is valid
@@ -129,10 +147,12 @@ module OrigenTesters
129
147
  # if not, the session will become inactive
130
148
  def charz_off
131
149
  charz_stack.pop
150
+ unless charz_session.update(charz_stack.last) || charz_stack.empty?
151
+ Origen.log.error 'charz_on failed to create a valid charz session'
152
+ fail
153
+ end
132
154
  if charz_stack.empty?
133
- update_charz_session(nil)
134
- else
135
- update_charz_session(*charz_stack.last)
155
+ set_charz_instance(nil)
136
156
  end
137
157
  end
138
158
 
@@ -145,36 +165,61 @@ module OrigenTesters
145
165
  # @param [Hash] options charz_on options
146
166
  # @option options [Symbol] :type (:profile) whether the charz_id refers to a charz profile or routine
147
167
  def charz_on(charz_id, options = {})
148
- options = {
149
- type: :profile
150
- }.merge(options)
151
- case options[:type]
152
- when :profile
153
- charz_obj = charz_profiles[charz_id]
154
- when :routine
155
- if charz_id.is_a?(Array)
156
- charz_obj = charz_routines[charz_id.first]
157
- options[:routines] = charz_id
158
- else
159
- charz_obj = charz_routines[charz_id]
160
- options[:routines] = [charz_id]
161
- end
162
- else
163
- Origen.log.error "Unknown charz object type #{options[:type]}, valid types: :profile, :routine"
168
+ charz_stack.push([get_charz_tuple(charz_id, options)])
169
+ unless charz_session.update(charz_stack.last)
170
+ Origen.log.error 'charz_on failed to create a valid charz session'
164
171
  fail
165
172
  end
166
- if charz_obj.nil?
167
- Origen.log.error "No #{options[:type]} found for charz_id: #{charz_id}"
168
- fail
173
+ if block_given?
174
+ yield
175
+ charz_off
169
176
  end
170
- charz_stack.push([charz_obj, options])
171
- unless update_charz_session(*charz_stack.last)
177
+ end
178
+
179
+ # Pushes a charz object (either a profile or a routine) onto the current sessions instance stack, along with any optional updates to modify that instance.
180
+ # This will result in subsequent charzable point tests in being processed against each of the current instances. In other words, this new push will not
181
+ # take priority over the current stack head, but instead append to it.
182
+ # Once pushed, the charz_session will attempt to update itself with the new data, failing if the resulting session is invalid
183
+ #
184
+ # If a block is passed, yield the block of tests to enable charz for those tests, then disable charz with a charz_off_truncate call
185
+ #
186
+ # @param [Symbol] charz_id either a routine or profile id. Method fails if the id can't be found in @charz_routines or @charz_profiles
187
+ # @param [Hash] options charz_on options
188
+ # @option options [Symbol] :type (:profile) whether the charz_id refers to a charz profile or routine
189
+ def charz_on_append(charz_id, options = {})
190
+ charz_tuple = get_charz_tuple(charz_id, options)
191
+
192
+ # take the current session and append to its instance stack
193
+ session = charz_stack.pop || []
194
+ session.push(charz_tuple)
195
+ charz_stack.push(session)
196
+
197
+ unless charz_session.update(charz_stack.last)
172
198
  Origen.log.error 'charz_on failed to create a valid charz session'
173
199
  fail
174
200
  end
175
201
  if block_given?
176
202
  yield
177
- charz_off
203
+ charz_off_truncate
204
+ end
205
+ end
206
+
207
+ # Removes the current sessions last instance. If the session only had one instance, this is functionally the same as charz_off
208
+ # If charz data is still on the stack afterward, the session will update to reflect the new data
209
+ # if not, the session will become inactive
210
+ def charz_off_truncate
211
+ session = charz_stack.pop || []
212
+ session.pop
213
+ unless session.empty?
214
+ charz_stack.push(session)
215
+ end
216
+
217
+ unless charz_session.update(charz_stack.last) || charz_stack.empty?
218
+ Origen.log.error 'charz_on failed to create a valid charz session'
219
+ fail
220
+ end
221
+ if charz_stack.empty?
222
+ set_charz_instance(nil)
178
223
  end
179
224
  end
180
225
 
@@ -196,8 +241,12 @@ module OrigenTesters
196
241
  end
197
242
  unless options[:id]
198
243
  if charz_active?
199
- if charz_session.on_result
200
- options[:id] = "#{parent_test_name}_charz_#{charz_session.name}".to_sym
244
+ if charz_session.on_result?
245
+ md5_id = Digest::MD5.new
246
+ md5_id << parent_test_name.to_s
247
+ md5_id << options.to_s
248
+ md5_id << charz_session.id.to_s
249
+ options[:id] = "auto_charz_id_#{md5_id}".to_sym
201
250
  end
202
251
  end
203
252
  end
@@ -206,7 +255,7 @@ module OrigenTesters
206
255
  # Called after the relevant point test has been inserted into the flow
207
256
  # Takes the options used to build the previous point test as well as insert_charz_test specific options to then
208
257
  # drill down to the point of the flow where the charz test would go, at which point control is handed back to the user's
209
- # interface to handle creating and inserting the test
258
+ # interface to handle creating and inserting the test. This will occur for each instance in the current session's instance stack
210
259
  #
211
260
  # By default, this method will handle:
212
261
  # - the placement of the test (inline aka right after the point test, end of flow, or other)
@@ -224,25 +273,27 @@ module OrigenTesters
224
273
  current_id = options.delete(:id)
225
274
  options[:last_test_id] ||= current_id
226
275
  end
227
- case charz_session.placement
228
- when :inline
229
- create_charz_group(options, &block)
230
- when :eof
231
- # collect the current session and options into a proc, stored in eof_charz_tests to be called later
232
- current_session = charz_session.clone
233
- eof_charz_tests << proc do
234
- @charz_session = current_session
276
+ charz_session.loop_instances do
277
+ case charz_instance.placement
278
+ when :inline
235
279
  create_charz_group(options, &block)
236
- end
237
- else
238
- # inline is the default behavior, and eof (end of flow) has built in support.
239
- if respond_to?(:"create_#{charz_session.placement}_charz_tests")
240
- send(:"create_#{charz_session.placement}_charz_tests", options, &block)
241
- elsif respond_to?(:"insert_#{charz_session.placement}_charz_tests")
242
- send(:"insert_#{charz_session.placement}_charz_tests", options, &block)
280
+ when :eof
281
+ # collect the current instance and options into a proc, stored in eof_charz_tests to be called later
282
+ current_instance = charz_instance.clone
283
+ eof_charz_tests << proc do
284
+ set_charz_instance(current_instance)
285
+ create_charz_group(options, &block)
286
+ end
243
287
  else
244
- Origen.log.error "No handling specified for #{charz_session.placement} placement charz tests"
245
- fail
288
+ # inline is the default behavior, and eof (end of flow) has built in support.
289
+ if respond_to?(:"create_#{charz_instance.placement}_charz_tests")
290
+ send(:"create_#{charz_instance.placement}_charz_tests", options, &block)
291
+ elsif respond_to?(:"insert_#{charz_instance.placement}_charz_tests")
292
+ send(:"insert_#{charz_instance.placement}_charz_tests", options, &block)
293
+ else
294
+ Origen.log.error "No handling specified for #{charz_instance.placement} placement charz tests"
295
+ fail
296
+ end
246
297
  end
247
298
  end
248
299
  end
@@ -265,9 +316,29 @@ module OrigenTesters
265
316
 
266
317
  private
267
318
 
268
- # called by charz_on, updates the current session, and passes the available routines in for validity checks
269
- def update_charz_session(charz_obj, options = {})
270
- charz_session.update(charz_obj, options.merge(defined_routines: charz_routines.ids))
319
+ # helper method for charz_on and charz_on_append
320
+ def get_charz_tuple(charz_id, options)
321
+ options[:type] ||= :profile
322
+ case options[:type]
323
+ when :profile
324
+ charz_obj = charz_profiles[charz_id]
325
+ when :routine
326
+ if charz_id.is_a?(Array)
327
+ charz_obj = charz_routines[charz_id.first]
328
+ options[:routines] = charz_id
329
+ else
330
+ charz_obj = charz_routines[charz_id]
331
+ options[:routines] = [charz_id]
332
+ end
333
+ else
334
+ Origen.log.error "Unknown charz object type #{options[:type]}, valid types: :profile, :routine"
335
+ fail
336
+ end
337
+ if charz_obj.nil?
338
+ Origen.log.error "No #{options[:type]} found for charz_id: #{charz_id}"
339
+ fail
340
+ end
341
+ CharzTuple.new(obj: charz_obj, options: options, defined_routines: charz_routines.ids)
271
342
  end
272
343
 
273
344
  # called by insert_charz_tests
@@ -280,7 +351,7 @@ module OrigenTesters
280
351
  if options[:skip_group]
281
352
  process_on_result(options, &block)
282
353
  else
283
- group_name = options[:group_name] || "#{options[:parent_test_name]} charz #{charz_session.name}"
354
+ group_name = options[:group_name] || "#{options[:parent_test_name]} charz #{charz_instance.name}"
284
355
  group group_name.to_sym do
285
356
  process_on_result(options, &block)
286
357
  end
@@ -298,8 +369,8 @@ module OrigenTesters
298
369
  #
299
370
  # @see set_conditional_charz_id
300
371
  def process_on_result(options, &block)
301
- if charz_session.on_result
302
- case charz_session.on_result
372
+ if charz_instance.on_result
373
+ case charz_instance.on_result
303
374
  when :on_fail, :fail, :failed
304
375
  last_test_id = options[:last_test_id] || @last_test_id
305
376
  if_failed last_test_id do
@@ -311,10 +382,10 @@ module OrigenTesters
311
382
  process_gates(options, &block)
312
383
  end
313
384
  else
314
- if respond_to?(:"process_#{charz_session.placement}_charz_tests")
315
- send(:"process_#{charz_session.on_result}_charz_tests", options, &block)
385
+ if respond_to?(:"process_#{charz_instance.placement}_charz_tests")
386
+ send(:"process_#{charz_instance.on_result}_charz_tests", options, &block)
316
387
  else
317
- Origen.log.error "No handling specified for result #{charz_session.on_result} charz tests"
388
+ Origen.log.error "No handling specified for result #{charz_instance.on_result} charz tests"
318
389
  fail
319
390
  end
320
391
  end
@@ -334,34 +405,123 @@ module OrigenTesters
334
405
  #
335
406
  # This is the final method of handling the insert_charz_test usecases, where the block thats been passed around is finally called
336
407
  # the user's provided block is passed the current routine (one at a time) to then take its info to generate a charz test
408
+
409
+ # Pass an "and_if_true" variable for enables and flags? And use that to to decide what to do? Then we don't need 4.
410
+ # But the hash has to be structured a different way for the enable_and (routine is key, enables is value.)
337
411
  def process_gates(options, &block)
338
- if options[:skip_gates] || !(charz_session.enables || charz_session.flags)
339
- charz_session.routines.each do |routine|
412
+ if options[:skip_gates] || !(charz_instance.enables || charz_instance.flags)
413
+ charz_instance.routines.each do |routine|
340
414
  block.call(options.merge(current_routine: routine))
341
415
  end
342
416
  else
343
- if charz_session.enables && charz_session.flags
344
- if charz_session.enables.is_a?(Hash) && !charz_session.flags.is_a?(Hash)
417
+ if charz_instance.and_enables
418
+ if charz_instance.flags
419
+ # Wrap all tests in flag, wrap some tests in anded enables.
420
+ ungated_routines = charz_instance.routines - charz_instance.enables.keys
421
+ ungated_routines.each do |routine|
422
+ if_flag charz_instance.flags do
423
+ block.call(options.merge(current_routine: routine))
424
+ end
425
+ end
426
+ gated_routines = charz_instance.routines - ungated_routines
427
+ # Build the proc which contains the nested if statements for each routine so they are anded.
428
+ gated_routines.each do |routine|
429
+ my_proc = -> do
430
+ if_flag charz_instance.flags do
431
+ block.call(options.merge(current_routine: routine))
432
+ end
433
+ end
434
+ charz_instance.enables[routine].inject(my_proc) do |my_block, enable|
435
+ lambda do
436
+ if_enable :"#{enable}" do
437
+ my_block.call
438
+ end
439
+ end
440
+ end.call
441
+ end
442
+ else
443
+ ungated_routines = charz_instance.routines - charz_instance.enables.keys
444
+ ungated_routines.each do |routine|
445
+ block.call(options.merge(current_routine: routine))
446
+ end
447
+ # Build the proc which contains the nested if statements for each routine so they are anded.
448
+ gated_routines = charz_instance.routines - ungated_routines
449
+ gated_routines.each do |routine|
450
+ my_proc = -> { block.call(options.merge(current_routine: routine)) }
451
+ charz_instance.enables[routine].inject(my_proc) do |my_block, enable|
452
+ lambda do
453
+ if_enable :"#{enable}" do
454
+ my_block.call
455
+ end
456
+ end
457
+ end.call
458
+ end
459
+ end
460
+ elsif charz_instance.and_flags
461
+ if charz_instance.enables
462
+ # Wrap all tests in enable, some tests in anded flags.
463
+ ungated_routines = charz_instance.routines - charz_instance.flags.keys
464
+ ungated_routines.each do |routine|
465
+ if_enable charz_instance.enables do
466
+ block.call(options.merge(current_routine: routine))
467
+ end
468
+ end
469
+ # Build the proc which contains the nested if statemements for each routine so they are anded.
470
+ gated_routines = charz_instance.routines - ungated_routines
471
+ gated_routines.each do |routine|
472
+ my_proc = -> do
473
+ if_enable charz_instance.enables do
474
+ block.call(options.merge(current_routine: routine))
475
+ end
476
+ end
477
+ charz_instance.flags[routine].inject(my_proc) do |my_block, flag|
478
+ lambda do
479
+ if_flag :"#{flag}" do
480
+ my_block.call
481
+ end
482
+ end
483
+ end.call
484
+ end
485
+ else
486
+ ungated_routines = charz_instance.routines - charz_instance.flags.keys
487
+ ungated_routines.each do |routine|
488
+ block.call(options.merge(current_routine: routine))
489
+ end
490
+ # Build the proc which contains the nested if statemements for each routine so they are anded.
491
+ gated_routines = charz_instance.routines - ungated_routines
492
+ gated_routines.each do |routine|
493
+ my_proc = -> { block.call(options.merge(current_routine: routine)) }
494
+ charz_instance.flags[routine].inject(my_proc) do |my_block, flag|
495
+ lambda do
496
+ if_flag :"#{flag}" do
497
+ my_block.call
498
+ end
499
+ end
500
+ end.call
501
+ end
502
+ end
503
+ elsif charz_instance.enables && charz_instance.flags
504
+ if charz_instance.enables.is_a?(Hash) && !charz_instance.flags.is_a?(Hash)
345
505
  # wrap all tests in flags, wrap specific tests in enables
346
- if_flag charz_session.flags do
347
- insert_hash_gates(options, charz_session.enables, :if_enable, &block)
506
+ if_flag charz_instance.flags do
507
+ insert_hash_gates(options, charz_instance.enables, :if_enable, &block)
348
508
  end
349
- elsif !charz_session.enables.is_a?(Hash) && charz_session.flags.is_a?(Hash)
509
+ elsif !charz_instance.enables.is_a?(Hash) && charz_instance.flags.is_a?(Hash)
350
510
  # wrap all tests in enables, wrap specific tests in flags
351
- if_enable charz_session.enables do
352
- insert_hash_gates(options, charz_session.flags, :if_flag, &block)
511
+ if_enable charz_instance.enables do
512
+ insert_hash_gates(options, charz_instance.flags, :if_flag, &block)
353
513
  end
354
- elsif charz_session.enables.is_a?(Hash) && charz_session.flags.is_a?(Hash)
514
+ elsif charz_instance.enables.is_a?(Hash) && charz_instance.flags.is_a?(Hash)
355
515
  # first insert the tests that are not tied to an enable or flag gate
356
- ungated_routines = charz_session.routines - (charz_session.enables.values.flatten | charz_session.flags.values.flatten)
516
+ ungated_routines = charz_instance.routines - (charz_instance.enables.values.flatten | charz_instance.flags.values.flatten)
357
517
  ungated_routines.each do |routine|
358
518
  block.call(options.merge(current_routine: routine))
359
519
  end
360
520
  # wrap tests in an enable gate, flag gate, or both
361
- gated_routines = charz_session.routines - ungated_routines
521
+ gated_routines = charz_instance.routines - ungated_routines
362
522
  gated_routines.each do |routine|
363
- enable = charz_session.enables.find { |gates, routines| routines.include?(routine) }&.first
364
- flag = charz_session.flags.find { |gates, routines| routines.include?(routine) }&.first
523
+ enable = charz_instance.enables.find { |gates, routines| routines.include?(routine) }&.first
524
+ flag = charz_instance.flags.find { |gates, routines| routines.include?(routine) }&.first
365
525
  if enable && flag
366
526
  if_enable enable do
367
527
  if_flag flag do
@@ -383,9 +543,9 @@ module OrigenTesters
383
543
  end
384
544
  else
385
545
  # both enable and flag is set, and both apply to all routines in session
386
- if_enable charz_session.enables do
387
- if_flag charz_session.flags do
388
- charz_session.routines.each do |routine|
546
+ if_enable charz_instance.enables do
547
+ if_flag charz_instance.flags do
548
+ charz_instance.routines.each do |routine|
389
549
  block.call(options.merge(current_routine: routine))
390
550
  end
391
551
  end
@@ -393,11 +553,11 @@ module OrigenTesters
393
553
  end
394
554
  else
395
555
  # only enables or flags is set, not both
396
- if charz_session.enables
397
- gates = charz_session.enables
556
+ if charz_instance.enables
557
+ gates = charz_instance.enables
398
558
  gate_method = :if_enable
399
- elsif charz_session.flags
400
- gates = charz_session.flags
559
+ elsif charz_instance.flags
560
+ gates = charz_instance.flags
401
561
  gate_method = :if_flag
402
562
  end
403
563
  if gates.is_a?(Hash)
@@ -406,7 +566,7 @@ module OrigenTesters
406
566
  else
407
567
  # wrap all tests in the indicated gates
408
568
  send(gate_method, gates) do
409
- charz_session.routines.each do |routine|
569
+ charz_instance.routines.each do |routine|
410
570
  block.call(options.merge(current_routine: routine))
411
571
  end
412
572
  end
@@ -418,7 +578,7 @@ module OrigenTesters
418
578
  # helper method for the process gates method above
419
579
  # handles wrapping routines in specific gates, and passing ungated routines back to the user
420
580
  def insert_hash_gates(options, gate_hash, gate_method, &block)
421
- ungated_routines = charz_session.routines - gate_hash.values.flatten
581
+ ungated_routines = charz_instance.routines - gate_hash.values.flatten
422
582
  ungated_routines.each do |routine|
423
583
  block.call(options.merge(current_routine: routine))
424
584
  end
@@ -50,6 +50,28 @@ module OrigenTesters
50
50
  profile.enables = { ['$MyEnable1'] => [:routine1], ['$MyEnable2'] => [:routine2, :routine3], '$MyEnable3' => :routine5 }
51
51
  profile.routines = [:routine1, :routine2, :routine3, :routine4, :routine5, :routine6]
52
52
  end
53
+
54
+ add_charz_profile :simple_anded_flags do |profile|
55
+ profile.and_flags = true
56
+ profile.routines = [:routine1]
57
+ end
58
+
59
+ add_charz_profile :simple_anded_enables do |profile|
60
+ profile.and_enables = true
61
+ profile.routines = [:routine1]
62
+ end
63
+
64
+ add_charz_profile :complex_anded_flags do |profile|
65
+ profile.and_flags = true
66
+ profile.enables = :my_enable
67
+ profile.routines = [:routine1]
68
+ end
69
+
70
+ add_charz_profile :complex_anded_enables do |profile|
71
+ profile.and_enables = true
72
+ profile.flags = :my_flag
73
+ profile.routines = [:routine1]
74
+ end
53
75
  end
54
76
 
55
77
  # Test that the block form of flow control methods like this can
data/program/charz.rb CHANGED
@@ -7,11 +7,11 @@ Flow.create interface: 'OrigenTesters::Test::Interface' do
7
7
 
8
8
  if tester.v93k? && tester.smt7?
9
9
  charz_on :complex_gates, { on_result: :fail }
10
- func_with_charz :func_complex_gates_on_fail
10
+ func_with_charz :func_complex_gates_on_fail
11
11
  charz_off
12
12
 
13
13
  charz_on :complex_gates, { enables: :my_enable }
14
- func_with_charz :func_complex_flag_simple_enable
14
+ func_with_charz :func_complex_flag_simple_enable
15
15
  charz_off
16
16
 
17
17
  charz_on :complex_gates, { flags: :my_flag } do
@@ -19,17 +19,17 @@ Flow.create interface: 'OrigenTesters::Test::Interface' do
19
19
  end
20
20
 
21
21
  charz_on :cz_only, { placement: :eof }
22
- func_with_charz :func_charz_only
22
+ func_with_charz :func_charz_only
23
23
  charz_off
24
24
 
25
25
  func_with_charz :func_test_level_routine, charz: [:routine1, { type: :routine }]
26
26
 
27
27
  charz_on :cz
28
- func_with_charz :func_skip_group, skip_group: true
29
- charz_pause
30
- func_with_charz :func_pause_charz
31
- charz_resume
32
- func_with_charz :func_resume_charz
28
+ func_with_charz :func_skip_group, skip_group: true
29
+ charz_pause
30
+ func_with_charz :func_pause_charz
31
+ charz_resume
32
+ func_with_charz :func_resume_charz
33
33
  charz_off
34
34
 
35
35
  charz_on :simple_gates, { on_result: :pass } do
@@ -43,6 +43,27 @@ Flow.create interface: 'OrigenTesters::Test::Interface' do
43
43
  charz_on :simple_gates, { flags: nil }
44
44
  func_with_charz :func_simple_enables
45
45
  charz_off
46
- end
47
46
 
47
+ charz_on :simple_anded_flags, { flags: { routine1: [:my_flag1, :my_flag2]}}
48
+ func_with_charz :func_simple_anded_flags
49
+ charz_off
50
+
51
+ charz_on :simple_anded_enables, {enables: { routine1: [:my_enable1, :my_enable2]}}
52
+ func_with_charz :func_simple_anded_enables
53
+ charz_off
54
+
55
+ charz_on :complex_anded_flags, {flags: { routine1: [:my_flag1, :my_flag2]}}
56
+ func_with_charz :func_complex_anded_flags
57
+ charz_on_append :routine2, { type: :routine }
58
+ func_with_charz :func_complex_anded_flags_add_simple_rt2
59
+ charz_off_truncate
60
+ charz_off
61
+
62
+ charz_on :complex_anded_enables, {enables: { routine1: [:my_enable1, :my_enable2]}}
63
+ func_with_charz :func_complex_anded_enables
64
+ charz_off
65
+
66
+
67
+
68
+ end
48
69
  end
@@ -48,7 +48,7 @@ end
48
48
  Charz profiles contain a collection of routines, as well as test creation meta data related to test placement, production test result dependence, and conditional execution.
49
49
 
50
50
  The interface adds charz profiles by calling the `add_charz_profile` method. To create a profile that contains previously defined vmin and vmax search routines, whose resulting searches
51
- only run if the production test failed, and sets the vmax search routine to only run if the 'VmaxEnable' variable is set:
51
+ only run if the production test failed, and sets the vmax search routine to only run if the 'VmaxEnable' variable is set.
52
52
 
53
53
  ~~~ruby
54
54
  add_charz_profile :fail_searches do |profile|
@@ -59,6 +59,83 @@ add_charz_profile :fail_searches do |profile|
59
59
  end
60
60
  ~~~
61
61
 
62
+ The default behavior for gates is to "OR" them if multiple are defined. The below will result in each routine being nested inside 'my_enable1 or my_enable2'.
63
+ ~~~ruby
64
+ add_charz_profile :enables do |profile|
65
+ profile.name = 'enables'
66
+ profile.routines = [:vmin, :vmax]
67
+ profile.enables = [:my_enable1, :my_enable2]
68
+ end
69
+ ~~~
70
+
71
+ The profile can be updated to "AND" together multiple enables or flags. To set up this functionality
72
+ create a hash which maps a routine name to multiple flags and set the corresponding "and_" profile attribute to true.
73
+ ~~~ruby
74
+ add_charz_profile :anded_enables do |profile|
75
+ profile.name = 'anded_enables'
76
+ profile.routines = [:vmin, :vmax]
77
+ profile.and_enables = true
78
+ profile.enables = { vmin: [:overall_enable, :vmin_enable], vmax: [:overall_enable, :vmax_enable]}
79
+ end
80
+ ~~~
81
+
82
+ ### Flow API
83
+
84
+ Once your profiles and routines are initialized, the primary way of using the Charz API are through charz on/off calls as well as their append/truncate counterparts:
85
+
86
+ #### charz_on / charz_off
87
+
88
+ Pushes/pops a charz object (either a profile or a routine) onto the stack, along with any optional updates to modify the current session.
89
+ Once pushed, the charz_session will attempt to update itself with the new data, failing if the resulting session is invalid. The updates will be stored as an "instance" which
90
+ is essentially a dummy Profile, and placed inside the sessions instance stack, effectively making the charz_stack a 2D array.
91
+
92
+ Once an instance is pushed onto the stack, the session becomes active and valid, allowing your apps hooks to query that state to know if a charz test needs to be inserted.
93
+
94
+ Basic Usage:
95
+
96
+ ~~~ruby
97
+ # pushes the profile :my_profile onto the charz stack
98
+ charz_on :my_profile
99
+ # after you've updated your app to insert charz tests,
100
+ # this line will make two tests: point test and charz variant
101
+ func :my_test
102
+ # pops :my_profile off the charz stack
103
+ charz_off
104
+
105
+ # alternate block form, functionally identical
106
+ charz_on :my_profile do
107
+ func :my_test
108
+ end
109
+ ~~~
110
+
111
+ #### charz_on_append / charz_off_truncate
112
+
113
+ Very similar to the previous charz_on/off, the append/truncate instead operates in the 2nd dimension of the 2D array that is the charz stack.
114
+ Pushes/pops a charz object (either a profile or a routine) onto the current sessions instance stack, along with any optional updates to modify that instance.
115
+ This will result in subsequent charzable point tests in being processed against each of the current instances. In other words, this new push will not take
116
+ priority over the current stack head, but instead append to it.
117
+
118
+ Basic Usage:
119
+
120
+ ~~~ruby
121
+ # pushes the profile :my_profile onto the charz stack
122
+ charz_on :my_profile
123
+ # after you've updated your app to insert charz tests, this line will make two tests:
124
+ # point test and charz variant
125
+ func :my_test
126
+ # instead of pushing onto the charz stack itself,
127
+ # this will push :my_other_profile onto the instance stack of the current session,
128
+ # which is the at the head of the charz stack
129
+ charz_on_append :my_other_profile
130
+ # this line now makes 3 tests: the point test, a charz variant
131
+ # per :my_profile, and another per :my_other_profile
132
+ func :my_other_test
133
+ # pops the session of the stack, meaning both :my_profile and :my_other_profile
134
+ # are gone since they were in the same session alternately run charz_off_truncate
135
+ # to only remove :my_other_profile
136
+ charz_off
137
+ ~~~
138
+
62
139
  ### Charz Session
63
140
 
64
141
  The charz session (stored in your interfaces `@charz_session` attribute) monitors the current state of characterization at a given point in flow generation.
@@ -190,7 +267,10 @@ Where insert_current_charz_test is a method defined in the company charz flow me
190
267
 
191
268
  ### Flow Usage Examples
192
269
 
193
- Now that the interface has charz routines and profiles, lets look at how to use the API within the flow itself:
270
+ Now that the interface has charz routines and profiles, lets look at how to use the API within the flow itself. Basic usage is to make charz_on/off calls, which will set the
271
+ session to contain the called profile as the current instance to generate against.
272
+
273
+ Additionally if you would like to add additional profiles to the current session, you can use the `charz_on_append` (and its counter part: `charz_off_truncate`) to do so.
194
274
 
195
275
  ~~~ruby
196
276
  Flow.create(interface: 'MyApp:Interface') do
@@ -215,6 +295,19 @@ Flow.create(interface: 'MyApp:Interface') do
215
295
  func :my_test4
216
296
  end
217
297
 
298
+ # create profileA charz test variants of my_test5, as well as profileA and profileB charz variants of my_test6
299
+ # this would produce the following tests in order:
300
+ # my_test5
301
+ # my_test5_routineA
302
+ # my_test6
303
+ # my_test6_routineA
304
+ # my_test6_routineB
305
+ charz_on :profileA do
306
+ func :my_test5
307
+ charz_on_append :profileB
308
+ func :my_test6
309
+ end
310
+
218
311
  end
219
312
  ~~~
220
313
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: origen_testers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.51.1
4
+ version: 0.51.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen McGinty
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-06 00:00:00.000000000 Z
11
+ date: 2023-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: origen
@@ -601,7 +601,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
601
601
  - !ruby/object:Gem::Version
602
602
  version: '0'
603
603
  requirements: []
604
- rubygems_version: 3.2.31
604
+ rubygems_version: 3.2.3
605
605
  signing_key:
606
606
  specification_version: 4
607
607
  summary: This plugin provides Origen tester models to drive ATE type testers like