Module: Origen::Tester::Generator::FlowControlAPI

Included in:
Doc::Generator::Flow, J750::Generator::Flow, Ultraflex::Generator::Flow
Defined in:
lib/origen/tester/generator/flow_control_api.rb

Defined Under Namespace

Modules: Interface

Constant Summary

FLOW_METHODS =

Flow control methods related to flow context

[
  # Methods in arrays are aliases, the primary name is the first one
  [:if_enable, :if_enabled, :enable, :enabled],
  [:unless_enable, :unless_enabled],
  [:if_job, :if_jobs],
  [:unless_job, :unless_jobs]
]
RELATION_METHODS =

Flow control methods related to a relationship with another test

[
  # Methods in arrays are aliases, the primary name is the first one
  :if_ran,
  :unless_ran,
  [:if_failed, :unless_passed],
  [:if_passed, :unless_failed],
  [:if_any_passed, :unless_all_failed],
  [:if_all_passed, :unless_any_failed],
  [:if_any_failed, :unless_all_passed],
  [:if_all_failed, :unless_any_passed]
]

Instance Method Summary (collapse)

Instance Method Details

- (Object) apply_current_context!(line)

:nodoc:



454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
# File 'lib/origen/tester/generator/flow_control_api.rb', line 454

def apply_current_context!(line) # :nodoc:
  if @if_enable_block
    if line.enable && line.enable != @if_enable_block
      fail "Cannot apply enable word '#{@if_enable_block}' to '#{line.parameter}', it already has '#{line.enable}'"
    else
      line.enable = @if_enable_block
    end
  end
  if @unless_enable_block
    line.unless_enable = @unless_enable_block
  end
  line.if_job = @if_job_block if @if_job_block
  line.unless_job = @unless_job_block if @unless_job_block
  line
end

- (Object) apply_relationships

:nodoc:



277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'lib/origen/tester/generator/flow_control_api.rb', line 277

def apply_relationships # :nodoc:
  if @relationships
    @relationships.each do |rel|
      t = find_by_id(rel[:target_id])
      fail "Test not found with ID: #{rel[:target_id]}, referenced in flow: #{filename}" unless t
      t.id = rel[:target_id]
      confirm_valid_context(t, rel[:dependent])
      case rel[:type]
      # The first cases here contain J750 logic, these should be replaced
      # with the call method style used for the later cases when time permits.
      when :failed
        if rel[:dependent].respond_to?(:run_if_failed)
          rel[:dependent].run_if_failed(rel[:target_id])
        else
          t.continue_on_fail
          flag = t.set_flag_on_fail
          rel[:dependent].flag_true = flag
        end
      when :passed
        if rel[:dependent].respond_to?(:run_if_passed)
          rel[:dependent].run_if_passed(rel[:target_id])
        else
          t.continue_on_fail
          flag = t.set_flag_on_pass
          rel[:dependent].flag_true = flag
        end
      when :if_ran, :unless_ran
        if rel[:type] == :if_ran
          if rel[:dependent].respond_to?(:run_if_ran)
            rel[:dependent].run_if_ran(rel[:target_id])
          else
            # t.continue_on_fail
            flag = t.set_flag_on_ran
            rel[:dependent].flag_true = flag
          end
        else
          if rel[:dependent].respond_to?(:run_unless_ran)
            rel[:dependent].run_unless_ran(rel[:target_id])
          else
            # t.continue_on_fail
            flag = t.set_flag_on_ran
            rel[:dependent].flag_clear = flag
          end
        end
      when :any_passed
        rel[:dependent].run_if_any_passed(t)
      when :all_passed
        rel[:dependent].run_if_all_passed(t)
      when :any_failed
        rel[:dependent].run_if_any_failed(t)
      when :all_failed
        rel[:dependent].run_if_all_failed(t)
      else
        fail 'Unknown relationship type!'
      end
    end
    @relationships = nil
  end
end

- (Object) at_run_start Also known as: reset_globals

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



356
357
358
359
# File 'lib/origen/tester/generator/flow_control_api.rb', line 356

def at_run_start
  @@existing_ids = nil
  @@labels = nil
end

- (Boolean) conditionally_deactivated?(options)

Returns:

  • (Boolean)


245
246
247
248
# File 'lib/origen/tester/generator/flow_control_api.rb', line 245

def conditionally_deactivated?(options)
  (options.key?(:if) && !options[:if]) ||
    (options.key?(:unless) && options[:unless])
end

- (Object) confirm_valid_context(_test, _dependent)

:nodoc:



337
338
339
340
341
# File 'lib/origen/tester/generator/flow_control_api.rb', line 337

def confirm_valid_context(_test, _dependent) # :nodoc:
  # TODO:  Add some validation checks here, for example make sure the dependent
  #        executes in the same job(s) as the test, otherwise the dependent will
  #        never be hit and will cause a validation error.
end

- (Boolean) context_changed?(options = {})

Returns true if the test context generated from the supplied options + existing context wrappers is different from that which was applied to the previous test.

Returns:

  • (Boolean)


29
30
31
# File 'lib/origen/tester/generator/flow_control_api.rb', line 29

def context_changed?(options = {})
  current_context[:hash_code] != summarize_context(options)[:hash_code]
end

- (Object) current_context

Returns a hash representing the current context, that is the context that was applied to the last test.

The hash contains two items:

  • :context contains a hash that summarises the flow control options that have been used, for example it may contain something like: :if_enable => “data_collection”

  • :hash_code returns a hash-code for the values contained in the :context arrary. Any two equivalent contexts will have the same :hash_code, therefore this can be used to easily check the equivalence of any two contexts.



54
55
56
# File 'lib/origen/tester/generator/flow_control_api.rb', line 54

def current_context
  @current_context ||= save_context
end

- (Object) extract_flow_control_options!(options)



480
481
482
483
484
485
486
487
488
# File 'lib/origen/tester/generator/flow_control_api.rb', line 480

def extract_flow_control_options!(options)
  opts = {}
  FLOW_METHODS.flatten.each do |o|
    if options.key?(o)
      opts[o] = options.delete(o)
    end
  end
  opts
end

- (Object) extract_relation_options!(options)

Removes any flow relationship options from given hash and returns them in a new hash



472
473
474
475
476
477
478
# File 'lib/origen/tester/generator/flow_control_api.rb', line 472

def extract_relation_options!(options) # :nodoc:
  opts = {}
  RELATION_METHODS.flatten.each do |o|
    opts[o] = options.delete(o)
  end
  opts
end

- (Object) finalize(_options = {})

If a class that includes this module has a finalize method it must call apply_relationships



273
274
275
# File 'lib/origen/tester/generator/flow_control_api.rb', line 273

def finalize(_options = {}) # :nodoc:
  apply_relationships
end

- (Object) find_by_id(id, options = {})

:nodoc:



250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# File 'lib/origen/tester/generator/flow_control_api.rb', line 250

def find_by_id(id, options = {}) # :nodoc:
  options = {
    search_other_flows: true
  }.merge(options)
  # Look within the current flow for a match first
  t = identity_map[id.to_sym]
  return t if t
  # If no match then look across other flow modules for a match
  # This currently returns the first match, should it raise an error on multiple?
  if options[:search_other_flows]
    Origen.interface.flow_generators.any? do |flow|
      t = flow.find_by_id(id, search_other_flows: false)
    end
  end
  t
end

- (Object) generate_unique_label(id = nil)



490
491
492
493
494
495
496
497
498
499
500
# File 'lib/origen/tester/generator/flow_control_api.rb', line 490

def generate_unique_label(id = nil)
  id = 'label' if !id || id == ''
  label = "#{Origen.interface.app_identifier}_#{id}"
  label.gsub!(' ', '_')
  label.upcase!
  @@labels ||= {}
  @@labels[Origen.tester.class] ||= {}
  @@labels[Origen.tester.class][label] ||= 0
  @@labels[Origen.tester.class][label] += 1
  "#{label}_#{@@labels[Origen.tester.class][label]}"
end

- (Object) identity_map

:nodoc:



267
268
269
# File 'lib/origen/tester/generator/flow_control_api.rb', line 267

def identity_map # :nodoc:
  @identity_map ||= {}
end

- (Object) if_all_failed(test_id, options = {}) Also known as: unless_any_passed

All tests generated within the given block will only run if the given test id has failed ON ALL SITES earlier in the flow



233
234
235
236
237
238
239
240
241
242
# File 'lib/origen/tester/generator/flow_control_api.rb', line 233

def if_all_failed(test_id, options = {})
  test_id = Origen.interface.filter_id(test_id, options)
  return if conditionally_deactivated?(options)
  if @if_all_failed_block
    fail 'Sorry but nesting of if_all_failed is not currently supported!'
  end
  @if_all_failed_block = test_id
  yield
  @if_all_failed_block = nil
end

- (Object) if_all_passed(test_id, options = {}) Also known as: unless_any_failed

All tests generated within the given block will only run if the given test id has passed ON ALL SITES earlier in the flow



205
206
207
208
209
210
211
212
213
214
# File 'lib/origen/tester/generator/flow_control_api.rb', line 205

def if_all_passed(test_id, options = {})
  test_id = Origen.interface.filter_id(test_id, options)
  return if conditionally_deactivated?(options)
  if @if_all_passed_block
    fail 'Sorry but nesting of if_all_passed is not currently supported!'
  end
  @if_all_passed_block = test_id
  yield
  @if_all_passed_block = nil
end

- (Object) if_any_failed(test_id, options = {}) Also known as: unless_all_passed

All tests generated within the given block will only run if the given test id has failed ON ANY SITE earlier in the flow



219
220
221
222
223
224
225
226
227
228
# File 'lib/origen/tester/generator/flow_control_api.rb', line 219

def if_any_failed(test_id, options = {})
  test_id = Origen.interface.filter_id(test_id, options)
  return if conditionally_deactivated?(options)
  if @if_any_failed_block
    fail 'Sorry but nesting of if_any_failed is not currently supported!'
  end
  @if_any_failed_block = test_id
  yield
  @if_any_failed_block = nil
end

- (Object) if_any_passed(test_id, options = {}) Also known as: unless_all_failed

All tests generated within the given block will only run if the given test id has passed ON ANY SITE earlier in the flow



191
192
193
194
195
196
197
198
199
200
# File 'lib/origen/tester/generator/flow_control_api.rb', line 191

def if_any_passed(test_id, options = {})
  test_id = Origen.interface.filter_id(test_id, options)
  return if conditionally_deactivated?(options)
  if @if_any_passed_block
    fail 'Sorry but nesting of if_any_passed is not currently supported!'
  end
  @if_any_passed_block = test_id
  yield
  @if_any_passed_block = nil
end

- (Object) if_enable(word, _options = {}) {|word| ... } Also known as: if_enabled

All tests generated within the given block will be assigned the given enable word.

If a test encountered within the block already has another enable word assigned to it then an error will be raised.

Yields:

  • (word)


98
99
100
101
102
# File 'lib/origen/tester/generator/flow_control_api.rb', line 98

def if_enable(word, _options = {})
  @if_enable_block = word
  yield word
  @if_enable_block = nil
end

- (Object) if_failed(test_id, options = {}) Also known as: unless_passed

All tests generated within the given block will only run if the given test id has failed earlier in the flow



161
162
163
164
165
166
167
168
169
170
171
# File 'lib/origen/tester/generator/flow_control_api.rb', line 161

def if_failed(test_id, options = {})
  test_id = Origen.interface.filter_id(test_id, options)
  return if options.key?(:if) && !options[:if]
  return if options.key?(:unless) && options[:unless]
  if @if_failed_block
    fail 'Sorry but nesting of if_failed is not currently supported!'
  end
  @if_failed_block = test_id
  yield
  @if_failed_block = nil
end

- (Object) if_job(*jobs) Also known as: if_jobs

All tests generated within the given block will be enabled only for the given jobs.



114
115
116
117
118
119
# File 'lib/origen/tester/generator/flow_control_api.rb', line 114

def if_job(*jobs)
  jobs = jobs.flatten
  @if_job_block = @if_job_block ? @if_job_block + jobs : jobs
  yield
  @if_job_block = nil
end

- (Object) if_passed(test_id, options = {}) Also known as: unless_failed

All tests generated within the given block will only run if the given test id has passed earlier in the flow



176
177
178
179
180
181
182
183
184
185
186
# File 'lib/origen/tester/generator/flow_control_api.rb', line 176

def if_passed(test_id, options = {})
  test_id = Origen.interface.filter_id(test_id, options)
  return if options.key?(:if) && !options[:if]
  return if options.key?(:unless) && options[:unless]
  if @if_passed_block
    fail 'Sorry but nesting of if_passed is not currently supported!'
  end
  @if_passed_block = test_id
  yield
  @if_passed_block = nil
end

- (Object) if_ran(test_id, options = {})

All tests generated within the given block will only run if the given test id has also run earlier in the flow



133
134
135
136
137
138
139
140
141
142
143
# File 'lib/origen/tester/generator/flow_control_api.rb', line 133

def if_ran(test_id, options = {})
  test_id = Origen.interface.filter_id(test_id, options)
  return if options.key?(:if) && !options[:if]
  return if options.key?(:unless) && options[:unless]
  if @if_ran_block
    fail 'Sorry but nesting of if_ran is not currently supported!'
  end
  @if_ran_block = test_id
  yield
  @if_ran_block = nil
end

- (Object) record_id(test, options = {})



343
344
345
346
347
348
349
350
351
352
353
# File 'lib/origen/tester/generator/flow_control_api.rb', line 343

def record_id(test, options = {})
  if options[:id]
    @@existing_ids ||= []
    if @@existing_ids.include?(options[:id].to_sym)
      fail "The ID '#{test.id}' is not unique, it has already been assigned!"
    else
      @@existing_ids << options[:id].to_sym
    end
    identity_map[options[:id].to_sym] = test
  end
end

- (Object) replace_context_with_current(options)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Removes any context options from the given options hash and merges in the current context



62
63
64
65
66
67
68
# File 'lib/origen/tester/generator/flow_control_api.rb', line 62

def replace_context_with_current(options)
  options = options.merge({})
  [FLOW_METHODS, RELATION_METHODS].flatten.each do |m|
    options.delete(m)
  end
  options.merge(current_context[:context])
end

- (Object) save_context(options = {})

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



34
35
36
37
38
39
40
41
42
# File 'lib/origen/tester/generator/flow_control_api.rb', line 34

def save_context(options = {})
  # If the test has requested to use the current context...
  if options[:context] == :current
    replace_context_with_current(options)
  else
    @current_context = summarize_context(options)
    options.merge(@current_context[:context])
  end
end

- (Object) summarize_context(options = {})

Returns a hash like that returned by current_context based on the given set of options + existing context wrappers.



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/origen/tester/generator/flow_control_api.rb', line 72

def summarize_context(options = {})
  code = []
  context = {}
  (FLOW_METHODS + RELATION_METHODS).each do |m|
    primary = m.is_a?(Array) ? m.first : m
    val = false
    [m].flatten.each do |m|
      if options[m]
        val = options[m]
      elsif instance_variable_get("@#{m}_block")
        val = instance_variable_get("@#{m}_block")
      end
    end
    if val
      code << primary
      code << val
      context[primary] = val
    end
  end
  { hash_code: code.flatten.hash, context: context }
end

- (Object) track_relationships(test_options = {})

As generation of render and imports is not linear its possible that the test being referenced does not exist in the collection yet. Therefore the required relationship will be recorded for now and applied later upon closing the generator at which point the complete final collection will be available.

Note - as of v2.0.1.dev64 the above is no longer true - imports are generated linearly. Therefore parent test should always already exist and it is possible that this relationship handling could be cleaned up considerably.

However we should keep it around for now as it may come in useful when other tester platforms are supported in the future.



373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
# File 'lib/origen/tester/generator/flow_control_api.rb', line 373

def track_relationships(test_options = {}) # :nodoc:
  [:id, RELATION_METHODS].flatten.each do |id|
    if test_options[id]
      test_options[id] = Origen.interface.filter_id(test_options[id], test_options)
    end
  end
  options = extract_relation_options!(test_options)
  current_test = yield test_options
  record_id(current_test, test_options)
  @relationships ||= []
  target_id = options[:if_failed] || options[:unless_passed] || @if_failed_block
  if target_id
    @relationships << {
      type:      :failed,
      target_id: target_id,
      dependent: current_test
    }
  end
  target_id = options[:if_passed] || options[:unless_failed] || @if_passed_block
  if target_id
    @relationships << {
      type:      :passed,
      target_id: target_id,
      dependent: current_test
    }
  end
  target_id = options.delete(:if_ran) || @if_ran_block
  if target_id
    @relationships << {
      type:      :if_ran,
      target_id: target_id,
      dependent: current_test
    }
  end
  target_id = options.delete(:unless_ran) || @unless_ran_block
  if target_id
    @relationships << {
      type:      :unless_ran,
      target_id: target_id,
      dependent: current_test
    }
  end
  target_id = options[:if_any_passed] || options[:unless_all_failed] || @if_any_passed_block
  if target_id
    @relationships << {
      type:      :any_passed,
      target_id: target_id,
      dependent: current_test
    }
  end
  target_id = options[:if_all_passed] || options[:unless_any_failed] || @if_all_passed_block
  if target_id
    @relationships << {
      type:      :all_passed,
      target_id: target_id,
      dependent: current_test
    }
  end
  target_id = options[:if_any_failed] || options[:unless_all_passed] || @if_any_failed_block
  if target_id
    @relationships << {
      type:      :any_failed,
      target_id: target_id,
      dependent: current_test
    }
  end
  target_id = options[:if_all_failed] || options[:unless_any_passed] || @if_all_failed_block
  if target_id
    @relationships << {
      type:      :all_failed,
      target_id: target_id,
      dependent: current_test
    }
  end
  if test_options[:context] == :current  # Context has already been applied
    current_test
  else
    apply_current_context!(current_test)
  end
end

- (Object) unless_enable(word, options = {}) {|word| ... } Also known as: unless_enabled

All tests generated will not run unless the given enable word is asserted.

Yields:

  • (word)


106
107
108
109
110
# File 'lib/origen/tester/generator/flow_control_api.rb', line 106

def unless_enable(word, options = {})
  @unless_enable_block = word unless options[:or]
  yield word
  @unless_enable_block = nil
end

- (Object) unless_job(*jobs) Also known as: unless_jobs

All tests generated within the given block will be enabled only for the given jobs.



123
124
125
126
127
128
# File 'lib/origen/tester/generator/flow_control_api.rb', line 123

def unless_job(*jobs)
  jobs = jobs.flatten
  @unless_job_block = @unless_job_block ? @unless_job_block + jobs : jobs
  yield
  @unless_job_block = nil
end

- (Object) unless_ran(test_id, options = {})

All tests generated within the given block will only run if the given test id has not run earlier in the flow



147
148
149
150
151
152
153
154
155
156
157
# File 'lib/origen/tester/generator/flow_control_api.rb', line 147

def unless_ran(test_id, options = {})
  test_id = Origen.interface.filter_id(test_id, options)
  return if options.key?(:if) && !options[:if]
  return if options.key?(:unless) && options[:unless]
  if @unless_ran_block
    fail 'Sorry but nesting of unless_ran is not currently supported!'
  end
  @unless_ran_block = test_id
  yield
  @unless_ran_block = nil
end