test_ids 0.8.2 → 1.0.0

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