test_ids 0.8.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 131ee6beb6b36186d39111f96c2ba0c06d9a71fd
4
- data.tar.gz: 5d4fc2e812a336213246939bf1f23b61739a35c8
3
+ metadata.gz: 5ed0f63265007afb642078d96f8acd7362495c85
4
+ data.tar.gz: 748add426abaf38bdc4c8e3577736d28d97d09b0
5
5
  SHA512:
6
- metadata.gz: 91110e14f7c4ff5f63fdb3011abca0e3ecaf774423a1002a6a5db73ce3bdf0fd33bc31cdde8e6d3887cf4c1e5dd37c5dd8fc0112fc7ca1c096320e9bcae50530
7
- data.tar.gz: fed24675c4d9754fce08d539b43039a7bda4c838c5cd5daa378d94fbcff05151a314b70a20185c514b4a15012371e5aab9fe5d9b3b0324acefe20bddbf89d37e
6
+ metadata.gz: 9e5823734dc64272dd90f73196100e21434b3c9a5d05519929d90a2262712d99108a9cbf9efc378813307e1a8450f50ef4efdfb237ca07486de7d12b30738eb0
7
+ data.tar.gz: 73ffa02f9b035e7f94ba1ccd0eb91fef83cc115c8489884bac20221ff538137d84926d40d5c331eb01fb8684b399b3641468fa7f03147eab61c59939bbdf3344
data/config/commands.rb CHANGED
@@ -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 &&
data/config/version.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module TestIds
2
- MAJOR = 0
3
- MINOR = 8
4
- BUGFIX = 2
2
+ MAJOR = 1
3
+ MINOR = 0
4
+ BUGFIX = 0
5
5
  DEV = nil
6
6
 
7
7
  VERSION = [MAJOR, MINOR, BUGFIX].join(".") + (DEV ? ".pre#{DEV}" : '')
data/lib/test_ids.rb CHANGED
@@ -24,12 +24,57 @@ 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
+ options[:test_ids_flow_id] = Origen.interface.flow.id
75
+ end
76
+ end
77
+
33
78
  # Load an existing allocator, which will be loaded with a configuration based on what has
34
79
  # been serialized into the database if present, otherwise it will have an empty configuration.
35
80
  # Returns nil if the given database can not be found.
@@ -47,9 +92,11 @@ module TestIds
47
92
  configuration(@configuration_id)
48
93
  end
49
94
 
50
- def configuration(id)
95
+ def configuration(id, fail_on_missing = true)
51
96
  return @configuration[id] if @configuration && @configuration[id]
52
- fail('You have to create the configuration first before you can access it')
97
+ if fail_on_missing
98
+ fail('You have to create the configuration first before you can access it')
99
+ end
53
100
  end
54
101
  alias_method :config, :configuration
55
102
 
@@ -73,26 +120,46 @@ module TestIds
73
120
  initialize_git
74
121
  end
75
122
 
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)
123
+ # Switch the current configuration to the given ID
124
+ def config=(id)
125
+ unless @configuration[id]
126
+ fail "The TestIds configuration '#{id}' has not been defined yet!"
127
+ end
128
+ @configuration_id = id
129
+ end
130
+
131
+ def bin_config=(id)
132
+ @bin_config = id
133
+ end
134
+
135
+ def bin_config
136
+ @bin_config ? configuration(@bin_config, false) : current_configuration
137
+ end
81
138
 
82
- # @configuration_id = id || options[:id] || :not_specified
139
+ def softbin_config=(id)
140
+ @softbin_config = id
141
+ end
83
142
 
84
- # @configuration ||= {}
143
+ def softbin_config
144
+ @softbin_config ? configuration(@softbin_config, false) : current_configuration
145
+ end
85
146
 
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
147
+ def number_config=(id)
148
+ @number_config = id
149
+ end
91
150
 
92
- # yield new
151
+ def number_config
152
+ @number_config ? configuration(@number_config, false) : current_configuration
153
+ end
93
154
 
94
- # new.validate!
95
- # end
155
+ # Temporarily switches the current configuration to the given ID for the
156
+ # duration of the given block, then switches it back to what it was
157
+ def with_config(id)
158
+ orig = @configuration_id
159
+ @configuration_id = id
160
+ yield
161
+ @configuration_id = orig
162
+ end
96
163
 
97
164
  def configured?
98
165
  !!@configuration_id
@@ -205,6 +272,9 @@ module TestIds
205
272
 
206
273
  def clear_configuration_id
207
274
  @configuration_id = nil
275
+ @bin_config = nil
276
+ @softbin_config = nil
277
+ @number_config = nil
208
278
  end
209
279
 
210
280
  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.
@@ -73,137 +81,96 @@ module TestIds
73
81
  assigned_value
74
82
  end
75
83
 
76
- # Main method to inject generated bin and test numbers, the given
77
- # options instance is modified accordingly
78
- def allocate(instance, options)
79
- orig_options = options.dup
80
- clean(options)
81
- @callbacks = []
82
- name = extract_test_name(instance, options)
83
- name = "#{name}_#{options[:index]}" if options[:index]
84
-
85
- # First work out the test ID to be used for each of the numbers, and how many numbers
86
- # should be reserved
87
- if (options[:bin].is_a?(Symbol) || options[:bin].is_a?(String)) && options[:bin] != :none
88
- bin_id = options[:bin].to_s
84
+ # Returns an array containing :bin, :softbin, :number in the order that they should be calculated in order to fulfil
85
+ # the requirements of the current configuration and the given options.
86
+ # If an item is not required (e.g. if set to :none in the options), then it will not be present in the array.
87
+ def allocation_order(options)
88
+ items = []
89
+ items_required = 0
90
+ if allocation_required?(:bin, options) ||
91
+ (allocation_required?(:softbin, options) && config(:softbin).softbins.needs?(:bin)) ||
92
+ (allocation_required?(:number, options) && config(:number).numbers.needs?(:bin))
93
+ items_required += 1
89
94
  else
90
- bin_id = name
95
+ bin_done = true
91
96
  end
92
- if (options[:softbin].is_a?(Symbol) || options[:softbin].is_a?(String)) && options[:softbin] != :none
93
- softbin_id = options[:softbin].to_s
97
+ if allocation_required?(:softbin, options) ||
98
+ (allocation_required?(:bin, options) && config(:bin).bins.needs?(:softbin)) ||
99
+ (allocation_required?(:number, options) && config(:number).numbers.needs?(:softbin))
100
+ items_required += 1
94
101
  else
95
- softbin_id = name
102
+ softbin_done = true
96
103
  end
97
- if (options[:number].is_a?(Symbol) || options[:number].is_a?(String)) && options[:number] != :none
98
- number_id = options[:number].to_s
104
+ if allocation_required?(:number, options) ||
105
+ (allocation_required?(:bin, options) && config(:bin).bins.needs?(:number)) ||
106
+ (allocation_required?(:softbin, options) && config(:softbin).softbins.needs?(:number))
107
+ items_required += 1
99
108
  else
100
- number_id = name
101
- end
102
-
103
- bin_size = options[:bin_size] || config.bins.size
104
- softbin_size = options[:softbin_size] || config.softbins.size
105
- number_size = options[:number_size] || config.numbers.size
106
-
107
- bin = store['assigned']['bins'][bin_id] ||= {}
108
- softbin = store['assigned']['softbins'][softbin_id] ||= {}
109
- number = store['assigned']['numbers'][number_id] ||= {}
110
-
111
- # If the user has supplied any of these, that number should be used
112
- # and reserved so that it is not automatically generated later
113
- if options[:bin] && options[:bin].is_a?(Numeric)
114
- bin['number'] = options[:bin]
115
- bin['size'] = bin_size
116
- store['manually_assigned']['bins'][options[:bin].to_s] = true
117
- # Regenerate the bin if the original allocation has since been applied
118
- # manually elsewhere
119
- elsif store['manually_assigned']['bins'][bin['number'].to_s]
120
- bin['number'] = nil
121
- bin['size'] = nil
122
- # Also regenerate these as they could be a function of the bin
123
- if config.softbins.function?
124
- softbin['number'] = nil
125
- softbin['size'] = nil
126
- end
127
- if config.numbers.function?
128
- number['number'] = nil
129
- number['size'] = nil
130
- end
131
- end
132
- if options[:softbin] && options[:softbin].is_a?(Numeric)
133
- softbin['number'] = options[:softbin]
134
- softbin['size'] = softbin_size
135
- store['manually_assigned']['softbins'][options[:softbin].to_s] = true
136
- elsif store['manually_assigned']['softbins'][softbin['number'].to_s]
137
- softbin['number'] = nil
138
- softbin['size'] = nil
139
- # Also regenerate the number as it could be a function of the softbin
140
- if config.numbers.function?
141
- number['number'] = nil
142
- number['size'] = nil
143
- end
144
- end
145
- if options[:number] && options[:number].is_a?(Numeric)
146
- number['number'] = options[:number]
147
- number['size'] = number_size
148
- store['manually_assigned']['numbers'][options[:number].to_s] = true
149
- elsif store['manually_assigned']['numbers'][number['number'].to_s]
150
- number['number'] = nil
151
- number['size'] = nil
152
- # Also regenerate the softbin as it could be a function of the number
153
- if config.softbins.function?
154
- softbin['number'] = nil
155
- softbin['size'] = nil
109
+ number_done = true
110
+ end
111
+ items_required.times do |i|
112
+ if !bin_done && (!config(:bin).bins.needs?(:softbin) || softbin_done) && (!config(:bin).bins.needs?(:number) || number_done)
113
+ items << :bin
114
+ bin_done = true
115
+ elsif !softbin_done && (!config(:softbin).softbins.needs?(:bin) || bin_done) && (!config(:softbin).softbins.needs?(:number) || number_done)
116
+ items << :softbin
117
+ softbin_done = true
118
+ elsif !number_done && (!config(:number).numbers.needs?(:bin) || bin_done) && (!config(:number).numbers.needs?(:softbin) || softbin_done)
119
+ items << :number
120
+ number_done = true
121
+ else
122
+ fail "Couldn't work out whether to generate next on iteration #{i} of #{items_required}, already picked: #{items}"
156
123
  end
157
124
  end
125
+ items
126
+ end
158
127
 
159
- # Otherwise generate the missing ones
160
- bin['number'] ||= allocate_bin(options.merge(size: bin_size))
161
- bin['size'] ||= bin_size
162
- # If the softbin is based on the test number, then need to calculate the
163
- # test number first.
164
- # Also do the number first if the softbin is a callback and the number is not.
165
- if (config.softbins.algorithm && config.softbins.algorithm.to_s =~ /n/) ||
166
- (config.softbins.callback && !config.numbers.function?)
167
- number['number'] ||= allocate_number(options.merge(bin: bin['number'], size: number_size))
168
- number['size'] ||= number_size
169
- softbin['number'] ||= allocate_softbin(options.merge(bin: bin['number'], number: number['number'], size: softbin_size))
170
- softbin['size'] ||= softbin_size
171
- else
172
- softbin['number'] ||= allocate_softbin(options.merge(bin: bin['number'], size: softbin_size))
173
- softbin['size'] ||= softbin_size
174
- number['number'] ||= allocate_number(options.merge(bin: bin['number'], softbin: softbin['number'], size: number_size))
175
- number['size'] ||= number_size
176
- end
128
+ # Main method to inject generated bin and test numbers, the given
129
+ # options instance is modified accordingly
130
+ def allocate(instance, options)
131
+ orig_options = options.dup
132
+ clean(options)
133
+ name = extract_test_name(instance, options)
177
134
 
178
- # Record that there has been a reference to the final numbers
179
- time = Time.now.to_f
180
- bin_size.times do |i|
181
- store['references']['bins'][(bin['number'] + i).to_s] = time if bin['number'] && options[:bin] != :none
182
- end
183
- softbin_size.times do |i|
184
- store['references']['softbins'][(softbin['number'] + i).to_s] = time if softbin['number'] && options[:softbin] != :none
185
- end
186
- number_size.times do |i|
187
- store['references']['numbers'][(number['number'] + i).to_s] = time if number['number'] && options[:number] != :none
188
- end
135
+ nones = []
189
136
 
190
- # Update the supplied options hash that will be forwarded to the program generator
191
- unless options.delete(:bin) == :none
192
- options[:bin] = bin['number']
193
- options[:bin_size] = bin['size']
137
+ # Record any :nones that are present for later
138
+ [:bin, :softbin, :number].each do |type|
139
+ nones << type if options[type] == :none
140
+ config(type).allocator.instance_variable_set('@needs_regenerated', {})
194
141
  end
195
- unless options.delete(:softbin) == :none
196
- options[:softbin] = softbin['number']
197
- options[:softbin_size] = softbin['size']
142
+
143
+ allocation_order(options).each do |type|
144
+ config(type).allocator.send(:_allocate, type, name, options)
198
145
  end
199
- unless options.delete(:number) == :none
200
- options[:number] = number['number']
201
- options[:number_size] = number['size']
146
+
147
+ # Turn any :nones into nils in the returned options
148
+ nones.each do |type|
149
+ options[type] = nil
150
+ options["#{type}_size"] = nil
202
151
  end
203
152
 
204
153
  options
205
154
  end
206
155
 
156
+ # Merge the given other store into the current one, it is assumed that both are formatted
157
+ # from the same (latest) revision
158
+ def merge_store(other_store)
159
+ store['pointers'] = store['pointers'].merge(other_store['pointers'])
160
+ @last_bin = store['pointers']['bins']
161
+ @last_softbin = store['pointers']['softbins']
162
+ @last_number = store['pointers']['numbers']
163
+ store['assigned']['bins'] = store['assigned']['bins'].merge(other_store['assigned']['bins'])
164
+ store['assigned']['softbins'] = store['assigned']['softbins'].merge(other_store['assigned']['softbins'])
165
+ store['assigned']['numbers'] = store['assigned']['numbers'].merge(other_store['assigned']['numbers'])
166
+ store['manually_assigned']['bins'] = store['manually_assigned']['bins'].merge(other_store['manually_assigned']['bins'])
167
+ store['manually_assigned']['softbins'] = store['manually_assigned']['softbins'].merge(other_store['manually_assigned']['softbins'])
168
+ store['manually_assigned']['numbers'] = store['manually_assigned']['numbers'].merge(other_store['manually_assigned']['numbers'])
169
+ store['references']['bins'] = store['references']['bins'].merge(other_store['references']['bins'])
170
+ store['references']['softbins'] = store['references']['softbins'].merge(other_store['references']['softbins'])
171
+ store['references']['numbers'] = store['references']['numbers'].merge(other_store['references']['numbers'])
172
+ end
173
+
207
174
  def store
208
175
  @store ||= begin
209
176
  if file && File.exist?(file)
@@ -267,7 +234,7 @@ module TestIds
267
234
  { 'bins' => 'bins', 'softbins' => 'softbins', 'numbers' => 'test_numbers' }.each do |type, name|
268
235
  if !config.send(type).function? && store['pointers'][type] == 'done'
269
236
  Origen.log.info "Checking for missing #{name}..."
270
- recovered = add_missing_references(config.send(type), store['references'][type])
237
+ recovered = add_missing_references(config.send, store['references'][type])
271
238
  if recovered == 0
272
239
  Origen.log.info " All #{name} are already available."
273
240
  else
@@ -396,6 +363,72 @@ module TestIds
396
363
 
397
364
  private
398
365
 
366
+ def _allocate(type, name, options)
367
+ type_plural = "#{type}s"
368
+ conf = config.send(type_plural)
369
+
370
+ # First work out the test ID to be used for each of the numbers, and how many numbers
371
+ # should be reserved
372
+ if (options[type].is_a?(Symbol) || options[type].is_a?(String)) && options[type] != :none
373
+ id = options[type].to_s
374
+ else
375
+ id = name
376
+ end
377
+ id = "#{id}_#{options[:index]}" if options[:index]
378
+ id = "#{id}_#{options[:test_ids_flow_id]}" if config.unique_by_flow?
379
+
380
+ val = store['assigned'][type_plural][id] ||= {}
381
+
382
+ if options[type].is_a?(Integer)
383
+ unless val['number'] == options[type]
384
+ store['manually_assigned']["#{type}s"][options[type].to_s] = true
385
+ val['number'] = options[type]
386
+ end
387
+ else
388
+ # Will be set if an upstream dependent type has been marked for regeneration by the code below
389
+ if @needs_regenerated[type]
390
+ val['number'] = nil
391
+ val['size'] = nil
392
+ # Regenerate the number if the original allocation has since been applied manually elsewhere
393
+ elsif store['manually_assigned'][type_plural][val['number'].to_s]
394
+ val['number'] = nil
395
+ val['size'] = nil
396
+ # Also regenerate these as they could be a function of the number we just invalidated
397
+ ([:bin, :softbin, :number] - [type]).each do |t|
398
+ if config.send("#{t}s").needs?(type)
399
+ @needs_regenerated[t] = true
400
+ end
401
+ end
402
+ end
403
+ end
404
+
405
+ if size = options["#{type}_size".to_sym]
406
+ val['size'] = size
407
+ end
408
+
409
+ # Generate the missing ones
410
+ val['size'] ||= conf.size
411
+ val['number'] ||= allocate_item(type, options.merge(size: val['size']))
412
+
413
+ # Record that there has been a reference to the final numbers
414
+ time = Time.now.to_f
415
+ val['size'].times do |i|
416
+ store['references'][type_plural][(val['number'] + i).to_s] = time if val['number'] && options[type] != :none
417
+ end
418
+
419
+ # Update the supplied options hash that will be forwarded to the program generator
420
+ options[type] = val['number']
421
+ options["#{type}_size".to_sym] = val['size']
422
+ end
423
+
424
+ def allocation_required?(type, options)
425
+ if options[type] == :none
426
+ false
427
+ else
428
+ !config(type).send("#{type}s").empty?
429
+ end
430
+ end
431
+
399
432
  def remove_invalid_references(config_item, references, manually_assigned)
400
433
  removed = 0
401
434
  references.each do |num, time|
@@ -435,161 +468,34 @@ module TestIds
435
468
  recovered
436
469
  end
437
470
 
438
- # Returns the next available bin in the pool, if they have all been given out
439
- # the one that hasn't been used for the longest time will be given out
440
- def allocate_bin(options)
441
- # Not sure if this is the right way. IMO the following are true:
442
- # 1. config.bins will have a callback only when ranges are specified.
443
- # 2. If config.bins is empty but config.bins is not a callback, return nil to maintain functionality as before.
444
- return nil if config.bins.empty? && !config.bins.callback
445
- if store['pointers']['bins'] == 'done'
446
- reclaim_bin(options)
447
- elsif callback = config.bins.callback
448
- callback.call(options)
449
- else
450
- b = config.bins.include.next(after: @last_bin, size: options[:size])
451
- @last_bin = nil
452
- while b && (store['manually_assigned']['bins'][b.to_s] || config.bins.exclude.include?(b))
453
- b = config.bins.include.next(size: options[:size])
454
- end
455
- # When no bin is returned it means we have used them all, all future generation
456
- # now switches to reclaim mode
457
- if b
458
- store['pointers']['bins'] = b
459
- else
460
- store['pointers']['bins'] = 'done'
461
- reclaim_bin(options)
462
- end
463
- end
464
- end
465
-
466
- def reclaim_bin(options)
467
- store['references']['bins'] = store['references']['bins'].sort_by { |k, v| v }.to_h
468
- if options[:size] == 1
469
- store['references']['bins'].first[0].to_i
470
- else
471
- reclaim(store['references']['bins'], options)
472
- end
473
- end
474
-
475
- def allocate_softbin(options)
476
- bin = options[:bin]
477
- num = options[:number]
478
- return nil if config.softbins.empty?
479
- if config.softbins.algorithm
480
- algo = config.softbins.algorithm.to_s.downcase
481
- if algo.to_s =~ /^[b\dxn]+$/
471
+ def allocate_item(type, options)
472
+ type_plural = "#{type}s"
473
+ conf = config.send(type_plural)
474
+ if conf.algorithm
475
+ algo = conf.algorithm.to_s.downcase
476
+ if algo.to_s =~ /^[bsn\dx]+$/
482
477
  number = algo.to_s
483
- bin = bin.to_s
484
- if number =~ /(b+)/
485
- max_bin_size = Regexp.last_match(1).size
486
- if bin.size > max_bin_size
487
- fail "Bin number (#{bin}) overflows the softbin number algorithm (#{algo})"
488
- end
489
- number = number.sub(/b+/, bin.rjust(max_bin_size, '0'))
490
- end
491
- if number =~ /(n+)/
492
- num = num.to_s
493
- max_num_size = Regexp.last_match(1).size
494
- if num.size > max_num_size
495
- fail "Test number (#{num}) overflows the softbin number algorithm (#{algo})"
496
- end
497
- number = number.sub(/n+/, num.rjust(max_num_size, '0'))
498
- end
499
- if number =~ /(x+)/
500
- max_counter_size = Regexp.last_match(1).size
501
- refs = store['references']['softbins']
502
- i = 0
503
- possible = []
504
- proposal = number.sub(/x+/, i.to_s.rjust(max_counter_size, '0'))
505
- possible << proposal
506
- while refs[proposal] && i.to_s.size <= max_counter_size
507
- i += 1
508
- proposal = number.sub(/x+/, i.to_s.rjust(max_counter_size, '0'))
509
- possible << proposal
510
- end
511
- # Overflowed, need to go search for the oldest duplicate now
512
- if i.to_s.size > max_counter_size
513
- i = 0
514
- # Not the most efficient search algorithm, but this should be hit very rarely
515
- # and even then only to generate the bin the first time around
516
- p = refs.sort_by { |bin, last_used| last_used }.find do |bin, last_used|
517
- possible.include?(bin)
478
+ ([:bin, :softbin, :number] - [type]).each do |t|
479
+ if number =~ /(#{t.to_s[0]}+)/
480
+ max_size = Regexp.last_match(1).size
481
+ num = options[t].to_s
482
+ if num.size > max_size
483
+ fail "The allocated number, #{num}, overflows the #{t} field in the #{type} algorithm - #{algo}"
518
484
  end
519
- proposal = p[0]
485
+ number = number.sub(/#{t.to_s[0]}+/, num.rjust(max_size, '0'))
520
486
  end
521
- number = proposal
522
- end
523
- else
524
- fail "Unknown softbin algorithm: #{algo}"
525
- end
526
- number.to_i
527
- elsif callback = config.softbins.callback
528
- callback.call(bin, options)
529
- else
530
- if store['pointers']['softbins'] == 'done'
531
- reclaim_softbin(options)
532
- else
533
- b = config.softbins.include.next(after: @last_softbin, size: options[:size])
534
- @last_softbin = nil
535
- while b && (store['manually_assigned']['softbins'][b.to_s] || config.softbins.exclude.include?(b))
536
- b = config.softbins.include.next(size: options[:size])
537
- end
538
- # When no softbin is returned it means we have used them all, all future generation
539
- # now switches to reclaim mode
540
- if b
541
- store['pointers']['softbins'] = b
542
- else
543
- store['pointers']['softbins'] = 'done'
544
- reclaim_softbin(options)
545
487
  end
546
- end
547
- end
548
- end
549
-
550
- def reclaim_softbin(options)
551
- store['references']['softbins'] = store['references']['softbins'].sort_by { |k, v| v }.to_h
552
- if options[:size] == 1
553
- store['references']['softbins'].first[0].to_i
554
- else
555
- reclaim(store['references']['softbins'], options)
556
- end
557
- end
558
488
 
559
- def allocate_number(options)
560
- bin = options[:bin]
561
- softbin = options[:softbin]
562
- return nil if config.numbers.empty?
563
- if config.numbers.algorithm
564
- algo = config.numbers.algorithm.to_s.downcase
565
- if algo.to_s =~ /^[bs\dx]+$/
566
- number = algo.to_s
567
- bin = bin.to_s
568
- if number =~ /(b+)/
569
- max_bin_size = Regexp.last_match(1).size
570
- if bin.size > max_bin_size
571
- fail "Bin number (#{bin}) overflows the test number algorithm (#{algo})"
572
- end
573
- number = number.sub(/b+/, bin.rjust(max_bin_size, '0'))
574
- end
575
- softbin = softbin.to_s
576
- if number =~ /(s+)/
577
- max_softbin_size = Regexp.last_match(1).size
578
- if softbin.size > max_softbin_size
579
- fail "Softbin number (#{softbin}) overflows the test number algorithm (#{algo})"
580
- end
581
- number = number.sub(/s+/, softbin.rjust(max_softbin_size, '0'))
582
- end
583
489
  if number =~ /(x+)/
584
490
  max_counter_size = Regexp.last_match(1).size
585
- refs = store['references']['numbers']
491
+ refs = store['references'][type_plural]
586
492
  i = 0
587
493
  possible = []
588
- proposal = number.sub(/x+/, i.to_s.rjust(max_counter_size, '0'))
494
+ proposal = number.sub(/x+/, i.to_s.rjust(max_counter_size, '0')).to_i.to_s
589
495
  possible << proposal
590
496
  while refs[proposal] && i.to_s.size <= max_counter_size
591
497
  i += 1
592
- proposal = number.sub(/x+/, i.to_s.rjust(max_counter_size, '0'))
498
+ proposal = number.sub(/x+/, i.to_s.rjust(max_counter_size, '0')).to_i.to_s
593
499
  possible << proposal
594
500
  end
595
501
  # Overflowed, need to go search for the oldest duplicate now
@@ -604,39 +510,42 @@ module TestIds
604
510
  end
605
511
  number = proposal
606
512
  end
607
- number.to_i
608
513
  else
609
- fail "Unknown test number algorithm: #{algo}"
514
+ fail "Illegal algorithm: #{algo}"
610
515
  end
611
- elsif callback = config.numbers.callback
612
- callback.call(bin, softbin, options)
516
+ number.to_i
517
+ elsif callback = conf.callback
518
+ callback.call(options)
613
519
  else
614
- if store['pointers']['numbers'] == 'done'
615
- reclaim_number(options)
520
+ if store['pointers'][type_plural] == 'done'
521
+ reclaim_item(type, options)
616
522
  else
617
- b = config.numbers.include.next(after: @last_number, size: options[:size])
618
- @last_number = nil
619
- while b && (store['manually_assigned']['numbers'][b.to_s] || config.numbers.exclude.include?(b))
620
- b = config.numbers.include.next(size: options[:size])
523
+ b = conf.include.next(after: instance_variable_get("@last_#{type}"), size: options[:size])
524
+ instance_variable_set("@last_#{type}", nil)
525
+ while b && (store['manually_assigned'][type_plural][b.to_s] || conf.exclude.include?(b))
526
+ b = conf.include.next(size: options[:size])
621
527
  end
622
528
  # When no number is returned it means we have used them all, all future generation
623
529
  # now switches to reclaim mode
624
530
  if b
625
- store['pointers']['numbers'] = b
531
+ store['pointers'][type_plural] = b + (options[:size] || 1) - 1
532
+ b
626
533
  else
627
- store['pointers']['numbers'] = 'done'
628
- reclaim_number(options)
534
+ store['pointers'][type_plural] = 'done'
535
+ reclaim_item(type, options)
629
536
  end
630
537
  end
631
538
  end
632
539
  end
633
540
 
634
- def reclaim_number(options)
635
- store['references']['numbers'] = store['references']['numbers'].sort_by { |k, v| v }.to_h
541
+ def reclaim_item(type, options)
542
+ type_plural = "#{type}s"
543
+ store['references'][type_plural] = store['references'][type_plural].sort_by { |k, v| v }.to_h
636
544
  if options[:size] == 1
637
- store['references']['numbers'].first[0].to_i
545
+ v = store['references'][type_plural].first
546
+ v[0].to_i if v
638
547
  else
639
- reclaim(store['references']['numbers'], options)
548
+ reclaim(store['references'][type_plural], options)
640
549
  end
641
550
  end
642
551
 
@@ -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] = 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
 
data/program/prb1.rb CHANGED
@@ -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.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen McGinty
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-16 00:00:00.000000000 Z
11
+ date: 2018-06-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: origen
@@ -101,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
101
101
  version: 1.8.11
102
102
  requirements: []
103
103
  rubyforge_project:
104
- rubygems_version: 2.6.7
104
+ rubygems_version: 2.6.14.1
105
105
  signing_key:
106
106
  specification_version: 4
107
107
  summary: Origen plugin to assign and track test program bins and test numbers