test_ids 0.8.1 → 1.1.2

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
- 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