test_ids 0.8.1 → 1.1.2

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
- SHA1:
3
- metadata.gz: 398ea9b7ec2c5bad27c399d18f0e94d55e505cdb
4
- data.tar.gz: 7474a3c2854ad487f8433316c74098dddcae3f92
2
+ SHA256:
3
+ metadata.gz: 2715a10e5e999b8e7cb1d8240803232fadf178139e64a2f44186d69b65602a15
4
+ data.tar.gz: 2b550ced04afc190362992970a7cfaeb76e7ba78d519894ebdeb04391cd3b721
5
5
  SHA512:
6
- metadata.gz: 901efb539a198fa3ba56c50b948dd75a70217e5d7b03fb2c8febfa34e06e5cb69a4c3784e18c11c62677eda9b051c3c4f67b2609dcc071b166d64719ede8888f
7
- data.tar.gz: 06cd20a662de6515f40674ef866ef5b6807e99658c9087b88dc3fa46b0943bc07f58bc5c6fdc66c0cb029a16a56fbfb89a68198fd1586068aa85f91eef1da738
6
+ metadata.gz: 4d62fc377c3bcbd5e840ed16c17e3749d7611f95e89eee17fe4bfa5ae7b572e6db8f12bf6016393f103e3dc2c59363205b5c90ad8ad999d43d87ba52017fd349
7
+ data.tar.gz: dfe969df5389777ea3545f506b78046b0d5596d49fc37890b7eab748329337ee955050ed6756c0977d22420408b6329c1dcaab1f400e0d8ef744c386bd197f13
@@ -33,6 +33,8 @@ when "examples", "test"
33
33
  # Program generator integration test
34
34
  ARGV = %w(program/prb1.rb -t default -e default -r approved)
35
35
  load "#{Origen.top}/lib/origen/commands/program.rb"
36
+ ARGV = %W(program/prb1.rb -t dut2 -o #{Origen.root}/output/dut2 -e default -r approved/dut2)
37
+ load "#{Origen.top}/lib/origen/commands/program.rb"
36
38
 
37
39
  if Origen.app.stats.changed_files == 0 &&
38
40
  Origen.app.stats.new_files == 0 &&
@@ -1,7 +1,7 @@
1
1
  module TestIds
2
- MAJOR = 0
3
- MINOR = 8
4
- BUGFIX = 1
2
+ MAJOR = 1
3
+ MINOR = 1
4
+ BUGFIX = 2
5
5
  DEV = nil
6
6
 
7
7
  VERSION = [MAJOR, MINOR, BUGFIX].join(".") + (DEV ? ".pre#{DEV}" : '')
@@ -24,12 +24,58 @@ module TestIds
24
24
  # returned will be the same as would be injected into flow.test.
25
25
  def allocate(instance, options = {})
26
26
  opts = options.dup
27
+ inject_flow_id(opts)
27
28
  current_configuration.allocator.allocate(instance, opts)
28
29
  { bin: opts[:bin], bin_size: opts[:bin_size], softbin: opts[:softbin], softbin_size: opts[:softbin_size],
29
30
  number: opts[:number], number_size: opts[:number_size]
30
31
  }
31
32
  end
32
33
 
34
+ # Similar to allocate, but allocates a test number only, i.e. no bin or softbin
35
+ def allocate_number(instance, options = {})
36
+ opts = options.dup
37
+ opts[:bin] = :none
38
+ opts[:softbin] = :none
39
+ inject_flow_id(opts)
40
+ current_configuration.allocator.allocate(instance, opts)
41
+ {
42
+ number: opts[:number], number_size: opts[:number_size]
43
+ }
44
+ end
45
+
46
+ # Similar to allocate, but allocates a softbin number only, i.e. no bin or test number
47
+ def allocate_softbin(instance, options = {})
48
+ opts = options.dup
49
+ opts[:bin] = :none
50
+ opts[:number] = :none
51
+ inject_flow_id(opts)
52
+ current_configuration.allocator.allocate(instance, opts)
53
+ {
54
+ softbin: opts[:softbin], softbin_size: opts[:softbin_size]
55
+ }
56
+ end
57
+ alias_method :allocate_soft_bin, :allocate_softbin
58
+
59
+ # Similar to allocate, but allocates a bin number only, i.e. no softbin or test number
60
+ def allocate_bin(instance, options = {})
61
+ opts = options.dup
62
+ opts[:softbin] = :none
63
+ opts[:number] = :none
64
+ inject_flow_id(opts)
65
+ current_configuration.allocator.allocate(instance, opts)
66
+ {
67
+ softbin: opts[:bin], softbin_size: opts[:bin_size]
68
+ }
69
+ end
70
+
71
+ # @api private
72
+ def inject_flow_id(options)
73
+ if Origen.interface_loaded?
74
+ flow = Origen.interface.flow
75
+ options[:test_ids_flow_id] = flow.try(:top_level).try(:id) || flow.id
76
+ end
77
+ end
78
+
33
79
  # Load an existing allocator, which will be loaded with a configuration based on what has
34
80
  # been serialized into the database if present, otherwise it will have an empty configuration.
35
81
  # Returns nil if the given database can not be found.
@@ -47,9 +93,11 @@ module TestIds
47
93
  configuration(@configuration_id)
48
94
  end
49
95
 
50
- def configuration(id)
96
+ def configuration(id, fail_on_missing = true)
51
97
  return @configuration[id] if @configuration && @configuration[id]
52
- fail('You have to create the configuration first before you can access it')
98
+ if fail_on_missing
99
+ fail('You have to create the configuration first before you can access it')
100
+ end
53
101
  end
54
102
  alias_method :config, :configuration
55
103
 
@@ -73,26 +121,51 @@ module TestIds
73
121
  initialize_git
74
122
  end
75
123
 
76
- ## Can be called in place of TestIDs.configure to change the configuration from
77
- ## the one that was originally supplied.
78
- ## It is expected that this is mainly useful for testing purposes only.
79
- # def reconfigure(id = nil, options = {}, &block)
80
- # id, options = nil, id if id.is_a?(Hash)
124
+ # Switch the current configuration to the given ID
125
+ def config=(id)
126
+ unless @configuration[id]
127
+ fail "The TestIds configuration '#{id}' has not been defined yet!"
128
+ end
129
+ @configuration_id = id
130
+ end
81
131
 
82
- # @configuration_id = id || options[:id] || :not_specified
132
+ # Return an Array of configuration IDs
133
+ def configs
134
+ @configuration.ids
135
+ end
83
136
 
84
- # @configuration ||= {}
137
+ def bin_config=(id)
138
+ @bin_config = id
139
+ end
85
140
 
86
- # old = @configuration[@configuration_id]
87
- # new = Configuration.new(@configuration_id)
88
- # new.instance_variable_set('@allocator', old.allocator)
89
- # new.allocator.instance_variable_set('@config', new)
90
- # @configuration[@configuration_id] = new
141
+ def bin_config
142
+ @bin_config ? configuration(@bin_config, false) : current_configuration
143
+ end
91
144
 
92
- # yield new
145
+ def softbin_config=(id)
146
+ @softbin_config = id
147
+ end
93
148
 
94
- # new.validate!
95
- # end
149
+ def softbin_config
150
+ @softbin_config ? configuration(@softbin_config, false) : current_configuration
151
+ end
152
+
153
+ def number_config=(id)
154
+ @number_config = id
155
+ end
156
+
157
+ def number_config
158
+ @number_config ? configuration(@number_config, false) : current_configuration
159
+ end
160
+
161
+ # Temporarily switches the current configuration to the given ID for the
162
+ # duration of the given block, then switches it back to what it was
163
+ def with_config(id)
164
+ orig = @configuration_id
165
+ @configuration_id = id
166
+ yield
167
+ @configuration_id = orig
168
+ end
96
169
 
97
170
  def configured?
98
171
  !!@configuration_id
@@ -205,6 +278,9 @@ module TestIds
205
278
 
206
279
  def clear_configuration_id
207
280
  @configuration_id = nil
281
+ @bin_config = nil
282
+ @softbin_config = nil
283
+ @number_config = nil
208
284
  end
209
285
 
210
286
  def testing=(val)
@@ -8,12 +8,20 @@ module TestIds
8
8
  class Allocator
9
9
  STORE_FORMAT_REVISION = 2
10
10
 
11
- attr_reader :config
12
-
13
11
  def initialize(configuration)
14
12
  @config = configuration
15
13
  end
16
14
 
15
+ def config(type = nil)
16
+ if type
17
+ type = type.to_s
18
+ type.chop! if type[-1] == 's'
19
+ TestIds.send("#{type}_config") || @config
20
+ else
21
+ @config
22
+ end
23
+ end
24
+
17
25
  # Allocates a softbin number from the range specified in the test flow
18
26
  # It also keeps a track of the last softbin assigned out from a particular range
19
27
  # and uses that to increment the pointers accordingly.
@@ -25,9 +33,15 @@ module TestIds
25
33
  end
26
34
 
27
35
  def range_item(range, options)
36
+ # This is the actual fix, it should now not be dependent on the json file being read in, instead the store pointers
37
+ # will be utilized to get the correct number assigned from the range.
38
+ if store['pointers']['ranges'].nil?
39
+ rangehash = {}
40
+ else
41
+ rangehash = store['pointers']['ranges']
42
+ rangehash = Hash[rangehash.map { |k, v| [k.to_sym, v] }]
43
+ end
28
44
  orig_options = options.dup
29
- # Create an alias for the databse that stores the pointers per range
30
- rangehash = store['pointers']['ranges'] ||= {}
31
45
  # Check the database to see if the passed in range has already been included in the database hash
32
46
  if rangehash.key?(:"#{range}")
33
47
  # Read out the database hash to see what the last_softbin given out was for that range.
@@ -47,152 +61,114 @@ module TestIds
47
61
  assigned_value = range.to_a[@pointer]
48
62
  end
49
63
  # Now update the database pointers to point to the lastest assigned softbin for a given range.
50
- rangehash.merge!("#{range}": "#{range.to_a[@pointer]}")
64
+ rangehash.merge!(:"#{range}" => "#{range.to_a[@pointer]}")
51
65
  else
52
66
  # This is the case for a brand new range that has not been passed before
53
67
  # We start from the first value as the assigned softbin and update the database to reflect.
54
68
  @pointer = 0
55
- rangehash.merge!("#{range}": "#{range.to_a[@pointer]}")
69
+ rangehash.merge!(:"#{range}" => "#{range.to_a[@pointer]}")
56
70
  assigned_value = range.to_a[@pointer]
57
71
  end
58
72
  unless !assigned_value.nil? && assigned_value.between?(range.min, range.max)
59
73
  Origen.log.error 'Assigned value not in range'
60
74
  fail
61
75
  end
76
+ # Since the assigned value for this test has now changed, update store to contain the newly assigned value
77
+ # so that when the json file is written, it contains the latest assigned value name.
78
+ store['pointers']['ranges'] = rangehash
62
79
  assigned_value
63
80
  end
64
81
 
65
- # Main method to inject generated bin and test numbers, the given
66
- # options instance is modified accordingly
67
- def allocate(instance, options)
68
- orig_options = options.dup
69
- clean(options)
70
- @callbacks = []
71
- name = extract_test_name(instance, options)
72
- name = "#{name}_#{options[:index]}" if options[:index]
73
-
74
- # First work out the test ID to be used for each of the numbers, and how many numbers
75
- # should be reserved
76
- if (options[:bin].is_a?(Symbol) || options[:bin].is_a?(String)) && options[:bin] != :none
77
- bin_id = options[:bin].to_s
82
+ # Returns an array containing :bin, :softbin, :number in the order that they should be calculated in order to fulfil
83
+ # the requirements of the current configuration and the given options.
84
+ # If an item is not required (e.g. if set to :none in the options), then it will not be present in the array.
85
+ def allocation_order(options)
86
+ items = []
87
+ items_required = 0
88
+ if allocation_required?(:bin, options) ||
89
+ (allocation_required?(:softbin, options) && config(:softbin).softbins.needs?(:bin)) ||
90
+ (allocation_required?(:number, options) && config(:number).numbers.needs?(:bin))
91
+ items_required += 1
78
92
  else
79
- bin_id = name
93
+ bin_done = true
80
94
  end
81
- if (options[:softbin].is_a?(Symbol) || options[:softbin].is_a?(String)) && options[:softbin] != :none
82
- softbin_id = options[:softbin].to_s
95
+ if allocation_required?(:softbin, options) ||
96
+ (allocation_required?(:bin, options) && config(:bin).bins.needs?(:softbin)) ||
97
+ (allocation_required?(:number, options) && config(:number).numbers.needs?(:softbin))
98
+ items_required += 1
83
99
  else
84
- softbin_id = name
100
+ softbin_done = true
85
101
  end
86
- if (options[:number].is_a?(Symbol) || options[:number].is_a?(String)) && options[:number] != :none
87
- number_id = options[:number].to_s
102
+ if allocation_required?(:number, options) ||
103
+ (allocation_required?(:bin, options) && config(:bin).bins.needs?(:number)) ||
104
+ (allocation_required?(:softbin, options) && config(:softbin).softbins.needs?(:number))
105
+ items_required += 1
88
106
  else
89
- number_id = name
90
- end
91
-
92
- bin_size = options[:bin_size] || config.bins.size
93
- softbin_size = options[:softbin_size] || config.softbins.size
94
- number_size = options[:number_size] || config.numbers.size
95
-
96
- bin = store['assigned']['bins'][bin_id] ||= {}
97
- softbin = store['assigned']['softbins'][softbin_id] ||= {}
98
- number = store['assigned']['numbers'][number_id] ||= {}
99
-
100
- # If the user has supplied any of these, that number should be used
101
- # and reserved so that it is not automatically generated later
102
- if options[:bin] && options[:bin].is_a?(Numeric)
103
- bin['number'] = options[:bin]
104
- bin['size'] = bin_size
105
- store['manually_assigned']['bins'][options[:bin].to_s] = true
106
- # Regenerate the bin if the original allocation has since been applied
107
- # manually elsewhere
108
- elsif store['manually_assigned']['bins'][bin['number'].to_s]
109
- bin['number'] = nil
110
- bin['size'] = nil
111
- # Also regenerate these as they could be a function of the bin
112
- if config.softbins.function?
113
- softbin['number'] = nil
114
- softbin['size'] = nil
115
- end
116
- if config.numbers.function?
117
- number['number'] = nil
118
- number['size'] = nil
119
- end
120
- end
121
- if options[:softbin] && options[:softbin].is_a?(Numeric)
122
- softbin['number'] = options[:softbin]
123
- softbin['size'] = softbin_size
124
- store['manually_assigned']['softbins'][options[:softbin].to_s] = true
125
- elsif store['manually_assigned']['softbins'][softbin['number'].to_s]
126
- softbin['number'] = nil
127
- softbin['size'] = nil
128
- # Also regenerate the number as it could be a function of the softbin
129
- if config.numbers.function?
130
- number['number'] = nil
131
- number['size'] = nil
132
- end
133
- end
134
- if options[:number] && options[:number].is_a?(Numeric)
135
- number['number'] = options[:number]
136
- number['size'] = number_size
137
- store['manually_assigned']['numbers'][options[:number].to_s] = true
138
- elsif store['manually_assigned']['numbers'][number['number'].to_s]
139
- number['number'] = nil
140
- number['size'] = nil
141
- # Also regenerate the softbin as it could be a function of the number
142
- if config.softbins.function?
143
- softbin['number'] = nil
144
- softbin['size'] = nil
107
+ number_done = true
108
+ end
109
+ items_required.times do |i|
110
+ if !bin_done && (!config(:bin).bins.needs?(:softbin) || softbin_done) && (!config(:bin).bins.needs?(:number) || number_done)
111
+ items << :bin
112
+ bin_done = true
113
+ elsif !softbin_done && (!config(:softbin).softbins.needs?(:bin) || bin_done) && (!config(:softbin).softbins.needs?(:number) || number_done)
114
+ items << :softbin
115
+ softbin_done = true
116
+ elsif !number_done && (!config(:number).numbers.needs?(:bin) || bin_done) && (!config(:number).numbers.needs?(:softbin) || softbin_done)
117
+ items << :number
118
+ number_done = true
119
+ else
120
+ fail "Couldn't work out whether to generate next on iteration #{i} of #{items_required}, already picked: #{items}"
145
121
  end
146
122
  end
123
+ items
124
+ end
147
125
 
148
- # Otherwise generate the missing ones
149
- bin['number'] ||= allocate_bin(options.merge(size: bin_size))
150
- bin['size'] ||= bin_size
151
- # If the softbin is based on the test number, then need to calculate the
152
- # test number first.
153
- # Also do the number first if the softbin is a callback and the number is not.
154
- if (config.softbins.algorithm && config.softbins.algorithm.to_s =~ /n/) ||
155
- (config.softbins.callback && !config.numbers.function?)
156
- number['number'] ||= allocate_number(options.merge(bin: bin['number'], size: number_size))
157
- number['size'] ||= number_size
158
- softbin['number'] ||= allocate_softbin(options.merge(bin: bin['number'], number: number['number'], size: softbin_size))
159
- softbin['size'] ||= softbin_size
160
- else
161
- softbin['number'] ||= allocate_softbin(options.merge(bin: bin['number'], size: softbin_size))
162
- softbin['size'] ||= softbin_size
163
- number['number'] ||= allocate_number(options.merge(bin: bin['number'], softbin: softbin['number'], size: number_size))
164
- number['size'] ||= number_size
165
- end
126
+ # Main method to inject generated bin and test numbers, the given
127
+ # options instance is modified accordingly
128
+ def allocate(instance, options)
129
+ orig_options = options.dup
130
+ clean(options)
131
+ name = extract_test_name(instance, options)
166
132
 
167
- # Record that there has been a reference to the final numbers
168
- time = Time.now.to_f
169
- bin_size.times do |i|
170
- store['references']['bins'][(bin['number'] + i).to_s] = time if bin['number'] && options[:bin] != :none
171
- end
172
- softbin_size.times do |i|
173
- store['references']['softbins'][(softbin['number'] + i).to_s] = time if softbin['number'] && options[:softbin] != :none
174
- end
175
- number_size.times do |i|
176
- store['references']['numbers'][(number['number'] + i).to_s] = time if number['number'] && options[:number] != :none
177
- end
133
+ nones = []
178
134
 
179
- # Update the supplied options hash that will be forwarded to the program generator
180
- unless options.delete(:bin) == :none
181
- options[:bin] = bin['number']
182
- options[:bin_size] = bin['size']
135
+ # Record any :nones that are present for later
136
+ [:bin, :softbin, :number].each do |type|
137
+ nones << type if options[type] == :none
138
+ config(type).allocator.instance_variable_set('@needs_regenerated', {})
183
139
  end
184
- unless options.delete(:softbin) == :none
185
- options[:softbin] = softbin['number']
186
- options[:softbin_size] = softbin['size']
140
+
141
+ allocation_order(options).each do |type|
142
+ config(type).allocator.send(:_allocate, type, name, options)
187
143
  end
188
- unless options.delete(:number) == :none
189
- options[:number] = number['number']
190
- options[:number_size] = number['size']
144
+
145
+ # Turn any :nones into nils in the returned options
146
+ nones.each do |type|
147
+ options[type] = nil
148
+ options["#{type}_size"] = nil
191
149
  end
192
150
 
193
151
  options
194
152
  end
195
153
 
154
+ # Merge the given other store into the current one, it is assumed that both are formatted
155
+ # from the same (latest) revision
156
+ def merge_store(other_store)
157
+ store['pointers'] = store['pointers'].merge(other_store['pointers'])
158
+ @last_bin = store['pointers']['bins']
159
+ @last_softbin = store['pointers']['softbins']
160
+ @last_number = store['pointers']['numbers']
161
+ store['assigned']['bins'] = store['assigned']['bins'].merge(other_store['assigned']['bins'])
162
+ store['assigned']['softbins'] = store['assigned']['softbins'].merge(other_store['assigned']['softbins'])
163
+ store['assigned']['numbers'] = store['assigned']['numbers'].merge(other_store['assigned']['numbers'])
164
+ store['manually_assigned']['bins'] = store['manually_assigned']['bins'].merge(other_store['manually_assigned']['bins'])
165
+ store['manually_assigned']['softbins'] = store['manually_assigned']['softbins'].merge(other_store['manually_assigned']['softbins'])
166
+ store['manually_assigned']['numbers'] = store['manually_assigned']['numbers'].merge(other_store['manually_assigned']['numbers'])
167
+ store['references']['bins'] = store['references']['bins'].merge(other_store['references']['bins'])
168
+ store['references']['softbins'] = store['references']['softbins'].merge(other_store['references']['softbins'])
169
+ store['references']['numbers'] = store['references']['numbers'].merge(other_store['references']['numbers'])
170
+ end
171
+
196
172
  def store
197
173
  @store ||= begin
198
174
  if file && File.exist?(file)
@@ -256,7 +232,7 @@ module TestIds
256
232
  { 'bins' => 'bins', 'softbins' => 'softbins', 'numbers' => 'test_numbers' }.each do |type, name|
257
233
  if !config.send(type).function? && store['pointers'][type] == 'done'
258
234
  Origen.log.info "Checking for missing #{name}..."
259
- recovered = add_missing_references(config.send(type), store['references'][type])
235
+ recovered = add_missing_references(config.send, store['references'][type])
260
236
  if recovered == 0
261
237
  Origen.log.info " All #{name} are already available."
262
238
  else
@@ -385,6 +361,72 @@ module TestIds
385
361
 
386
362
  private
387
363
 
364
+ def _allocate(type, name, options)
365
+ type_plural = "#{type}s"
366
+ conf = config.send(type_plural)
367
+
368
+ # First work out the test ID to be used for each of the numbers, and how many numbers
369
+ # should be reserved
370
+ if (options[type].is_a?(Symbol) || options[type].is_a?(String)) && options[type] != :none
371
+ id = options[type].to_s
372
+ else
373
+ id = name
374
+ end
375
+ id = "#{id}_#{options[:index]}" if options[:index]
376
+ id = "#{id}_#{options[:test_ids_flow_id]}" if config.unique_by_flow?
377
+
378
+ val = store['assigned'][type_plural][id] ||= {}
379
+
380
+ if options[type].is_a?(Integer)
381
+ unless val['number'] == options[type]
382
+ store['manually_assigned']["#{type}s"][options[type].to_s] = true
383
+ val['number'] = options[type]
384
+ end
385
+ else
386
+ # Will be set if an upstream dependent type has been marked for regeneration by the code below
387
+ if @needs_regenerated[type]
388
+ val['number'] = nil
389
+ val['size'] = nil
390
+ # Regenerate the number if the original allocation has since been applied manually elsewhere
391
+ elsif store['manually_assigned'][type_plural][val['number'].to_s]
392
+ val['number'] = nil
393
+ val['size'] = nil
394
+ # Also regenerate these as they could be a function of the number we just invalidated
395
+ ([:bin, :softbin, :number] - [type]).each do |t|
396
+ if config.send("#{t}s").needs?(type)
397
+ @needs_regenerated[t] = true
398
+ end
399
+ end
400
+ end
401
+ end
402
+
403
+ if size = options["#{type}_size".to_sym]
404
+ val['size'] = size
405
+ end
406
+
407
+ # Generate the missing ones
408
+ val['size'] ||= conf.size
409
+ val['number'] ||= allocate_item(type, options.merge(size: val['size']))
410
+
411
+ # Record that there has been a reference to the final numbers
412
+ time = Time.now.to_f
413
+ val['size'].times do |i|
414
+ store['references'][type_plural][(val['number'] + i).to_s] = time if val['number'] && options[type] != :none
415
+ end
416
+
417
+ # Update the supplied options hash that will be forwarded to the program generator
418
+ options[type] = val['number']
419
+ options["#{type}_size".to_sym] = val['size']
420
+ end
421
+
422
+ def allocation_required?(type, options)
423
+ if options[type] == :none
424
+ false
425
+ else
426
+ !config(type).send("#{type}s").empty?
427
+ end
428
+ end
429
+
388
430
  def remove_invalid_references(config_item, references, manually_assigned)
389
431
  removed = 0
390
432
  references.each do |num, time|
@@ -424,161 +466,34 @@ module TestIds
424
466
  recovered
425
467
  end
426
468
 
427
- # Returns the next available bin in the pool, if they have all been given out
428
- # the one that hasn't been used for the longest time will be given out
429
- def allocate_bin(options)
430
- # Not sure if this is the right way. IMO the following are true:
431
- # 1. config.bins will have a callback only when ranges are specified.
432
- # 2. If config.bins is empty but config.bins is not a callback, return nil to maintain functionality as before.
433
- return nil if config.bins.empty? && !config.bins.callback
434
- if store['pointers']['bins'] == 'done'
435
- reclaim_bin(options)
436
- elsif callback = config.bins.callback
437
- callback.call(options)
438
- else
439
- b = config.bins.include.next(after: @last_bin, size: options[:size])
440
- @last_bin = nil
441
- while b && (store['manually_assigned']['bins'][b.to_s] || config.bins.exclude.include?(b))
442
- b = config.bins.include.next(size: options[:size])
443
- end
444
- # When no bin is returned it means we have used them all, all future generation
445
- # now switches to reclaim mode
446
- if b
447
- store['pointers']['bins'] = b
448
- else
449
- store['pointers']['bins'] = 'done'
450
- reclaim_bin(options)
451
- end
452
- end
453
- end
454
-
455
- def reclaim_bin(options)
456
- store['references']['bins'] = store['references']['bins'].sort_by { |k, v| v }.to_h
457
- if options[:size] == 1
458
- store['references']['bins'].first[0].to_i
459
- else
460
- reclaim(store['references']['bins'], options)
461
- end
462
- end
463
-
464
- def allocate_softbin(options)
465
- bin = options[:bin]
466
- num = options[:number]
467
- return nil if config.softbins.empty?
468
- if config.softbins.algorithm
469
- algo = config.softbins.algorithm.to_s.downcase
470
- if algo.to_s =~ /^[b\dxn]+$/
469
+ def allocate_item(type, options)
470
+ type_plural = "#{type}s"
471
+ conf = config.send(type_plural)
472
+ if conf.algorithm
473
+ algo = conf.algorithm.to_s.downcase
474
+ if algo.to_s =~ /^[bsn\dx]+$/
471
475
  number = algo.to_s
472
- bin = bin.to_s
473
- if number =~ /(b+)/
474
- max_bin_size = Regexp.last_match(1).size
475
- if bin.size > max_bin_size
476
- fail "Bin number (#{bin}) overflows the softbin number algorithm (#{algo})"
477
- end
478
- number = number.sub(/b+/, bin.rjust(max_bin_size, '0'))
479
- end
480
- if number =~ /(n+)/
481
- num = num.to_s
482
- max_num_size = Regexp.last_match(1).size
483
- if num.size > max_num_size
484
- fail "Test number (#{num}) overflows the softbin number algorithm (#{algo})"
485
- end
486
- number = number.sub(/n+/, num.rjust(max_num_size, '0'))
487
- end
488
- if number =~ /(x+)/
489
- max_counter_size = Regexp.last_match(1).size
490
- refs = store['references']['softbins']
491
- i = 0
492
- possible = []
493
- proposal = number.sub(/x+/, i.to_s.rjust(max_counter_size, '0'))
494
- possible << proposal
495
- while refs[proposal] && i.to_s.size <= max_counter_size
496
- i += 1
497
- proposal = number.sub(/x+/, i.to_s.rjust(max_counter_size, '0'))
498
- possible << proposal
499
- end
500
- # Overflowed, need to go search for the oldest duplicate now
501
- if i.to_s.size > max_counter_size
502
- i = 0
503
- # Not the most efficient search algorithm, but this should be hit very rarely
504
- # and even then only to generate the bin the first time around
505
- p = refs.sort_by { |bin, last_used| last_used }.find do |bin, last_used|
506
- possible.include?(bin)
476
+ ([:bin, :softbin, :number] - [type]).each do |t|
477
+ if number =~ /(#{t.to_s[0]}+)/
478
+ max_size = Regexp.last_match(1).size
479
+ num = options[t].to_s
480
+ if num.size > max_size
481
+ fail "The allocated number, #{num}, overflows the #{t} field in the #{type} algorithm - #{algo}"
507
482
  end
508
- proposal = p[0]
483
+ number = number.sub(/#{t.to_s[0]}+/, num.rjust(max_size, '0'))
509
484
  end
510
- number = proposal
511
- end
512
- else
513
- fail "Unknown softbin algorithm: #{algo}"
514
- end
515
- number.to_i
516
- elsif callback = config.softbins.callback
517
- callback.call(bin, options)
518
- else
519
- if store['pointers']['softbins'] == 'done'
520
- reclaim_softbin(options)
521
- else
522
- b = config.softbins.include.next(after: @last_softbin, size: options[:size])
523
- @last_softbin = nil
524
- while b && (store['manually_assigned']['softbins'][b.to_s] || config.softbins.exclude.include?(b))
525
- b = config.softbins.include.next(size: options[:size])
526
- end
527
- # When no softbin is returned it means we have used them all, all future generation
528
- # now switches to reclaim mode
529
- if b
530
- store['pointers']['softbins'] = b
531
- else
532
- store['pointers']['softbins'] = 'done'
533
- reclaim_softbin(options)
534
485
  end
535
- end
536
- end
537
- end
538
-
539
- def reclaim_softbin(options)
540
- store['references']['softbins'] = store['references']['softbins'].sort_by { |k, v| v }.to_h
541
- if options[:size] == 1
542
- store['references']['softbins'].first[0].to_i
543
- else
544
- reclaim(store['references']['softbins'], options)
545
- end
546
- end
547
486
 
548
- def allocate_number(options)
549
- bin = options[:bin]
550
- softbin = options[:softbin]
551
- return nil if config.numbers.empty?
552
- if config.numbers.algorithm
553
- algo = config.numbers.algorithm.to_s.downcase
554
- if algo.to_s =~ /^[bs\dx]+$/
555
- number = algo.to_s
556
- bin = bin.to_s
557
- if number =~ /(b+)/
558
- max_bin_size = Regexp.last_match(1).size
559
- if bin.size > max_bin_size
560
- fail "Bin number (#{bin}) overflows the test number algorithm (#{algo})"
561
- end
562
- number = number.sub(/b+/, bin.rjust(max_bin_size, '0'))
563
- end
564
- softbin = softbin.to_s
565
- if number =~ /(s+)/
566
- max_softbin_size = Regexp.last_match(1).size
567
- if softbin.size > max_softbin_size
568
- fail "Softbin number (#{softbin}) overflows the test number algorithm (#{algo})"
569
- end
570
- number = number.sub(/s+/, softbin.rjust(max_softbin_size, '0'))
571
- end
572
487
  if number =~ /(x+)/
573
488
  max_counter_size = Regexp.last_match(1).size
574
- refs = store['references']['numbers']
489
+ refs = store['references'][type_plural]
575
490
  i = 0
576
491
  possible = []
577
- proposal = number.sub(/x+/, i.to_s.rjust(max_counter_size, '0'))
492
+ proposal = number.sub(/x+/, i.to_s.rjust(max_counter_size, '0')).to_i.to_s
578
493
  possible << proposal
579
494
  while refs[proposal] && i.to_s.size <= max_counter_size
580
495
  i += 1
581
- proposal = number.sub(/x+/, i.to_s.rjust(max_counter_size, '0'))
496
+ proposal = number.sub(/x+/, i.to_s.rjust(max_counter_size, '0')).to_i.to_s
582
497
  possible << proposal
583
498
  end
584
499
  # Overflowed, need to go search for the oldest duplicate now
@@ -593,39 +508,42 @@ module TestIds
593
508
  end
594
509
  number = proposal
595
510
  end
596
- number.to_i
597
511
  else
598
- fail "Unknown test number algorithm: #{algo}"
512
+ fail "Illegal algorithm: #{algo}"
599
513
  end
600
- elsif callback = config.numbers.callback
601
- callback.call(bin, softbin, options)
514
+ number.to_i
515
+ elsif callback = conf.callback
516
+ callback.call(options)
602
517
  else
603
- if store['pointers']['numbers'] == 'done'
604
- reclaim_number(options)
518
+ if store['pointers'][type_plural] == 'done'
519
+ reclaim_item(type, options)
605
520
  else
606
- b = config.numbers.include.next(after: @last_number, size: options[:size])
607
- @last_number = nil
608
- while b && (store['manually_assigned']['numbers'][b.to_s] || config.numbers.exclude.include?(b))
609
- b = config.numbers.include.next(size: options[:size])
521
+ b = conf.include.next(after: instance_variable_get("@last_#{type}"), size: options[:size])
522
+ instance_variable_set("@last_#{type}", nil)
523
+ while b && (store['manually_assigned'][type_plural][b.to_s] || conf.exclude.include?(b))
524
+ b = conf.include.next(size: options[:size])
610
525
  end
611
526
  # When no number is returned it means we have used them all, all future generation
612
527
  # now switches to reclaim mode
613
528
  if b
614
- store['pointers']['numbers'] = b
529
+ store['pointers'][type_plural] = b + (options[:size] || 1) - 1
530
+ b
615
531
  else
616
- store['pointers']['numbers'] = 'done'
617
- reclaim_number(options)
532
+ store['pointers'][type_plural] = 'done'
533
+ reclaim_item(type, options)
618
534
  end
619
535
  end
620
536
  end
621
537
  end
622
538
 
623
- def reclaim_number(options)
624
- store['references']['numbers'] = store['references']['numbers'].sort_by { |k, v| v }.to_h
539
+ def reclaim_item(type, options)
540
+ type_plural = "#{type}s"
541
+ store['references'][type_plural] = store['references'][type_plural].sort_by { |k, v| v }.to_h
625
542
  if options[:size] == 1
626
- store['references']['numbers'].first[0].to_i
543
+ v = store['references'][type_plural].first
544
+ v[0].to_i if v
627
545
  else
628
- reclaim(store['references']['numbers'], options)
546
+ reclaim(store['references'][type_plural], options)
629
547
  end
630
548
  end
631
549
 
@@ -1,22 +1,29 @@
1
1
  module TestIds
2
2
  class Configuration
3
3
  class Item
4
- attr_accessor :include, :exclude, :algorithm, :size
4
+ attr_accessor :include, :exclude, :algorithm, :size, :needs
5
5
 
6
6
  def initialize
7
7
  @include = BinArray.new
8
8
  @exclude = BinArray.new
9
+ @needs = []
9
10
  @size = 1
10
11
  end
11
12
 
12
- def callback(&block)
13
+ def callback(options = {}, &block)
13
14
  if block_given?
15
+ @needs += Array(options[:needs])
14
16
  @callback = block
15
17
  else
16
18
  @callback
17
19
  end
18
20
  end
19
21
 
22
+ def needs?(type)
23
+ !!(!empty? && function? && (needs.include?(type) ||
24
+ (algorithm && (algorithm.to_s =~ /#{type.to_s[0]}/i))))
25
+ end
26
+
20
27
  def empty?
21
28
  include.empty? && exclude.empty? && !algorithm && !callback
22
29
  end
@@ -36,6 +43,7 @@ module TestIds
36
43
  def freeze
37
44
  @include.freeze
38
45
  @exclude.freeze
46
+ @needs.freeze
39
47
  super
40
48
  end
41
49
 
@@ -88,18 +96,23 @@ module TestIds
88
96
  @id
89
97
  end
90
98
 
91
- def bins(&block)
99
+ def bins(options = {}, &block)
92
100
  @bins ||= Item.new
93
101
  if block_given?
94
- @bins.callback(&block)
102
+ @bins.callback(options, &block)
95
103
  end
96
104
  @bins
97
105
  end
98
106
 
99
- def softbins(&block)
107
+ # An alias for config.bins.algorithm=
108
+ def bins=(val)
109
+ bins.algorithm = val
110
+ end
111
+
112
+ def softbins(options = {}, &block)
100
113
  @softbins ||= Item.new
101
114
  if block_given?
102
- @softbins.callback(&block)
115
+ @softbins.callback(options, &block)
103
116
  end
104
117
  @softbins
105
118
  end
@@ -109,10 +122,10 @@ module TestIds
109
122
  softbins.algorithm = val
110
123
  end
111
124
 
112
- def numbers(&block)
125
+ def numbers(options = {}, &block)
113
126
  @numbers ||= Item.new
114
127
  if block_given?
115
- @numbers.callback(&block)
128
+ @numbers.callback(options, &block)
116
129
  end
117
130
  @numbers
118
131
  end
@@ -123,18 +136,23 @@ module TestIds
123
136
  end
124
137
 
125
138
  def send_to_ate=(val)
126
- @send_to_ate = val
139
+ @send_to_ate = !!val
127
140
  end
128
141
 
129
- def send_to_ate
130
- @send_to_ate
142
+ def send_to_ate?
143
+ defined?(@send_to_ate) ? @send_to_ate : true
144
+ end
145
+
146
+ def unique_by_flow=(val)
147
+ @unique_by_flow = !!val
148
+ end
149
+
150
+ def unique_by_flow?
151
+ @unique_by_flow || false
131
152
  end
132
153
 
133
154
  def validate!
134
155
  unless validated?
135
- if bins.algorithm
136
- fail 'The TestIds bins configuration cannot be set to an algorithm, only a range set by bins.include and bins.exclude is permitted'
137
- end
138
156
  @validated = true
139
157
  freeze
140
158
  end
@@ -7,13 +7,16 @@ module OrigenTesters
7
7
  # test numbers
8
8
  alias_method :_orig_test, :test
9
9
  def test(instance, options = {})
10
- if TestIds.configured? && options[:test_ids] != :notrack
11
- TestIds.current_configuration.allocator.allocate(instance, options)
12
- end
13
10
  if TestIds.configured?
14
- if TestIds.current_configuration.send_to_ate == false
15
- BIN_OPTS.each do |opt|
16
- options.delete(opt)
11
+ unless options[:test_ids] == :notrack
12
+ options[:test_ids_flow_id] = try(:top_level).try(:id) || id
13
+
14
+ TestIds.current_configuration.allocator.allocate(instance, options)
15
+
16
+ unless TestIds.current_configuration.send_to_ate?
17
+ BIN_OPTS.each do |opt|
18
+ options.delete(opt)
19
+ end
17
20
  end
18
21
  end
19
22
  end
@@ -5,17 +5,23 @@ module TestIdsDev
5
5
  def initialize(options = {})
6
6
  case dut.test_ids
7
7
  when 1
8
- TestIds.configure do |config|
8
+ TestIds.configure id: :cfg1 do |config|
9
9
  # Example of testing remote repo
10
10
  # config.repo = 'ssh://git@sw-stash.freescale.net/~r49409/test_ids_repo.git'
11
11
  config.bins.include << 3
12
12
  config.bins.include << (10..20)
13
13
  config.bins.exclude << 15
14
14
  config.softbins = :bbbxx
15
- config.numbers do |bin, softbin|
16
- softbin * 100
15
+ config.numbers needs: :softbin do |options|
16
+ options[:softbin] * 100
17
17
  end
18
18
  end
19
+
20
+ when 2
21
+ TestIds.configure id: :cfg2 do |config|
22
+ config.bins.include << (5..16)
23
+ config.softbins = :bbxxx
24
+ end
19
25
  end
20
26
  end
21
27
 
@@ -1,7 +1,14 @@
1
1
  Flow.create do
2
-
3
- func :t1
4
- func :t2
5
- func :t3
6
- func :t3, bin: :none, sbin: :none
2
+ if dut.test_ids == 2
3
+ func :t1, bin: 11
4
+ func :t2, bin: 11
5
+ func :t3, bin: 11
6
+ func :t4, bin: 11
7
+ func :t5, bin: 11
8
+ else
9
+ func :t1
10
+ func :t2
11
+ func :t3
12
+ func :t3, bin: :none, sbin: :none
13
+ end
7
14
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: test_ids
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen McGinty
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-15 00:00:00.000000000 Z
11
+ date: 2020-07-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: origen
@@ -100,8 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
100
  - !ruby/object:Gem::Version
101
101
  version: 1.8.11
102
102
  requirements: []
103
- rubyforge_project:
104
- rubygems_version: 2.6.7
103
+ rubygems_version: 3.0.3
105
104
  signing_key:
106
105
  specification_version: 4
107
106
  summary: Origen plugin to assign and track test program bins and test numbers