origen_testers 0.4.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 +7 -0
- data/config/application.rb +140 -0
- data/config/commands.rb +73 -0
- data/config/development.rb +12 -0
- data/config/environment.rb +1 -0
- data/config/shared_commands.rb +47 -0
- data/config/users.rb +18 -0
- data/config/version.rb +8 -0
- data/lib/commands/build.rb +69 -0
- data/lib/origen_testers.rb +23 -0
- data/lib/origen_testers/api.rb +258 -0
- data/lib/origen_testers/basic_test_setups.rb +105 -0
- data/lib/origen_testers/callback_handlers.rb +58 -0
- data/lib/origen_testers/generator.rb +279 -0
- data/lib/origen_testers/generator/flow_control_api.rb +611 -0
- data/lib/origen_testers/generator/identity_map.rb +23 -0
- data/lib/origen_testers/generator/placeholder.rb +11 -0
- data/lib/origen_testers/generator/test_numberer.rb +23 -0
- data/lib/origen_testers/igxl_based_tester.rb +12 -0
- data/lib/origen_testers/igxl_based_tester/base.rb +641 -0
- data/lib/origen_testers/igxl_based_tester/base/flow.rb +171 -0
- data/lib/origen_testers/igxl_based_tester/base/flow_line.rb +322 -0
- data/lib/origen_testers/igxl_based_tester/base/generator.rb +217 -0
- data/lib/origen_testers/igxl_based_tester/base/patgroup.rb +109 -0
- data/lib/origen_testers/igxl_based_tester/base/patgroups.rb +38 -0
- data/lib/origen_testers/igxl_based_tester/base/patset.rb +68 -0
- data/lib/origen_testers/igxl_based_tester/base/patset_pattern.rb +56 -0
- data/lib/origen_testers/igxl_based_tester/base/patsets.rb +38 -0
- data/lib/origen_testers/igxl_based_tester/base/patsubr.rb +68 -0
- data/lib/origen_testers/igxl_based_tester/base/patsubr_pattern.rb +56 -0
- data/lib/origen_testers/igxl_based_tester/base/patsubrs.rb +38 -0
- data/lib/origen_testers/igxl_based_tester/base/test_instance.rb +326 -0
- data/lib/origen_testers/igxl_based_tester/base/test_instance_group.rb +58 -0
- data/lib/origen_testers/igxl_based_tester/base/test_instances.rb +179 -0
- data/lib/origen_testers/igxl_based_tester/files.rb +43 -0
- data/lib/origen_testers/igxl_based_tester/j750.rb +248 -0
- data/lib/origen_testers/igxl_based_tester/j750/flow.rb +10 -0
- data/lib/origen_testers/igxl_based_tester/j750/flow_line.rb +19 -0
- data/lib/origen_testers/igxl_based_tester/j750/generator.rb +19 -0
- data/lib/origen_testers/igxl_based_tester/j750/patgroup.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750/patgroups.rb +10 -0
- data/lib/origen_testers/igxl_based_tester/j750/patset.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750/patset_pattern.rb +18 -0
- data/lib/origen_testers/igxl_based_tester/j750/patsets.rb +10 -0
- data/lib/origen_testers/igxl_based_tester/j750/patsubr.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750/patsubr_pattern.rb +18 -0
- data/lib/origen_testers/igxl_based_tester/j750/patsubrs.rb +10 -0
- data/lib/origen_testers/igxl_based_tester/j750/templates/flow.txt.erb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750/templates/instances.txt.erb +16 -0
- data/lib/origen_testers/igxl_based_tester/j750/templates/patgroups.txt.erb +8 -0
- data/lib/origen_testers/igxl_based_tester/j750/templates/patsets.txt.erb +10 -0
- data/lib/origen_testers/igxl_based_tester/j750/templates/patsubrs.txt.erb +10 -0
- data/lib/origen_testers/igxl_based_tester/j750/test_instance.rb +547 -0
- data/lib/origen_testers/igxl_based_tester/j750/test_instance_group.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750/test_instances.rb +10 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt.rb +34 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/flow.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/flow_line.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/generator.rb +19 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patgroup.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patgroups.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patset.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patset_pattern.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patsets.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patsubr.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patsubr_pattern.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/patsubrs.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/test_instance.rb +515 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/test_instance_group.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/j750_hpt/test_instances.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/parser.rb +102 -0
- data/lib/origen_testers/igxl_based_tester/parser/ac_spec.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/parser/ac_specs.rb +0 -0
- data/lib/origen_testers/igxl_based_tester/parser/dc_spec.rb +33 -0
- data/lib/origen_testers/igxl_based_tester/parser/dc_specs.rb +48 -0
- data/lib/origen_testers/igxl_based_tester/parser/descriptions.rb +339 -0
- data/lib/origen_testers/igxl_based_tester/parser/flow.rb +109 -0
- data/lib/origen_testers/igxl_based_tester/parser/flow_line.rb +203 -0
- data/lib/origen_testers/igxl_based_tester/parser/flows.rb +21 -0
- data/lib/origen_testers/igxl_based_tester/parser/pattern_set.rb +92 -0
- data/lib/origen_testers/igxl_based_tester/parser/pattern_sets.rb +31 -0
- data/lib/origen_testers/igxl_based_tester/parser/test_instance.rb +341 -0
- data/lib/origen_testers/igxl_based_tester/parser/test_instances.rb +24 -0
- data/lib/origen_testers/igxl_based_tester/parser/timeset.rb +13 -0
- data/lib/origen_testers/igxl_based_tester/parser/timesets.rb +0 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex.rb +477 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/flow.rb +10 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/flow_line.rb +19 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/generator.rb +19 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/patgroup.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/patgroups.rb +10 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/patset.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/patset_pattern.rb +18 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/patsets.rb +10 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/patsubr.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/patsubr_pattern.rb +18 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/patsubrs.rb +10 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/flow.txt.erb +9 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/instances.txt.erb +16 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/patgroups.txt.erb +9 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/patsets.txt.erb +10 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/templates/patsubrs.txt.erb +10 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/test_instance.rb +270 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/test_instance_group.rb +9 -0
- data/lib/origen_testers/igxl_based_tester/ultraflex/test_instances.rb +10 -0
- data/lib/origen_testers/interface.rb +183 -0
- data/lib/origen_testers/parser.rb +22 -0
- data/lib/origen_testers/parser/description_lookup.rb +62 -0
- data/lib/origen_testers/parser/searchable_array.rb +30 -0
- data/lib/origen_testers/parser/searchable_hash.rb +30 -0
- data/lib/origen_testers/pattern_compilers.rb +116 -0
- data/lib/origen_testers/pattern_compilers/assembler.rb +88 -0
- data/lib/origen_testers/pattern_compilers/job.rb +96 -0
- data/lib/origen_testers/pattern_compilers/ultraflex_pattern_compiler.rb +599 -0
- data/lib/origen_testers/program_generators.rb +55 -0
- data/lib/origen_testers/smartest_based_tester.rb +8 -0
- data/lib/origen_testers/smartest_based_tester/base.rb +411 -0
- data/lib/origen_testers/smartest_based_tester/base/flow.rb +188 -0
- data/lib/origen_testers/smartest_based_tester/base/flow_node.rb +476 -0
- data/lib/origen_testers/smartest_based_tester/base/generator.rb +123 -0
- data/lib/origen_testers/smartest_based_tester/base/pattern_compiler.rb +23 -0
- data/lib/origen_testers/smartest_based_tester/base/pattern_master.rb +47 -0
- data/lib/origen_testers/smartest_based_tester/base/test_method.rb +143 -0
- data/lib/origen_testers/smartest_based_tester/base/test_methods.rb +73 -0
- data/lib/origen_testers/smartest_based_tester/base/test_methods/ac_tml.rb +33 -0
- data/lib/origen_testers/smartest_based_tester/base/test_methods/base_tml.rb +38 -0
- data/lib/origen_testers/smartest_based_tester/base/test_methods/custom_tml.rb +19 -0
- data/lib/origen_testers/smartest_based_tester/base/test_methods/dc_tml.rb +147 -0
- data/lib/origen_testers/smartest_based_tester/base/test_methods/limits.rb +43 -0
- data/lib/origen_testers/smartest_based_tester/base/test_suite.rb +166 -0
- data/lib/origen_testers/smartest_based_tester/base/test_suites.rb +58 -0
- data/lib/origen_testers/smartest_based_tester/v93k.rb +8 -0
- data/lib/origen_testers/smartest_based_tester/v93k/builder.rb +89 -0
- data/lib/origen_testers/smartest_based_tester/v93k/builder/flow.rb +169 -0
- data/lib/origen_testers/smartest_based_tester/v93k/builder/pattern_master.rb +54 -0
- data/lib/origen_testers/smartest_based_tester/v93k/flow.rb +10 -0
- data/lib/origen_testers/smartest_based_tester/v93k/flow_node.rb +9 -0
- data/lib/origen_testers/smartest_based_tester/v93k/generator.rb +19 -0
- data/lib/origen_testers/smartest_based_tester/v93k/pattern_compiler.rb +10 -0
- data/lib/origen_testers/smartest_based_tester/v93k/pattern_master.rb +10 -0
- data/lib/origen_testers/smartest_based_tester/v93k/templates/template.aiv.erb +17 -0
- data/lib/origen_testers/smartest_based_tester/v93k/templates/template.flow.erb +201 -0
- data/lib/origen_testers/smartest_based_tester/v93k/templates/template.pmfl.erb +13 -0
- data/lib/origen_testers/smartest_based_tester/v93k/test_method.rb +9 -0
- data/lib/origen_testers/smartest_based_tester/v93k/test_methods.rb +9 -0
- data/lib/origen_testers/smartest_based_tester/v93k/test_suite.rb +9 -0
- data/lib/origen_testers/smartest_based_tester/v93k/test_suites.rb +9 -0
- data/lib/origen_testers/test/basic_interface.rb +17 -0
- data/lib/origen_testers/test/block.rb +21 -0
- data/lib/origen_testers/test/dut.rb +184 -0
- data/lib/origen_testers/test/dut2.rb +76 -0
- data/lib/origen_testers/test/j750_base_interface.rb +119 -0
- data/lib/origen_testers/test/j750_hpt_interface.rb +8 -0
- data/lib/origen_testers/test/j750_interface.rb +8 -0
- data/lib/origen_testers/test/nvm.rb +94 -0
- data/lib/origen_testers/test/ultraflex_interface.rb +110 -0
- data/lib/origen_testers/test/v93k_interface.rb +115 -0
- data/lib/origen_testers/timing.rb +362 -0
- data/lib/origen_testers/vector.rb +203 -0
- data/lib/origen_testers/vector_based_tester.rb +42 -0
- data/lib/origen_testers/vector_generator.rb +623 -0
- data/lib/origen_testers/vector_pipeline.rb +288 -0
- data/pattern/dc_instr.rb +7 -0
- data/pattern/delay.rb +7 -0
- data/pattern/mem_test.rb +8 -0
- data/pattern/multi_vector.rb +117 -0
- data/pattern/multi_vector_plus1.rb +125 -0
- data/pattern/nvm/j750/add_late_pins.rb +3 -0
- data/pattern/nvm/j750/iterator_postfix_test_x_bx.rb +8 -0
- data/pattern/nvm/j750/iterator_test_x_bx.rb +8 -0
- data/pattern/nvm/j750/j750_halt.rb +159 -0
- data/pattern/nvm/j750/j750_workout.rb +202 -0
- data/pattern/nvm/j750/timing.rb +73 -0
- data/pattern/nvm/v93k/v93k_workout.rb +136 -0
- data/pattern/read_write_reg.rb +58 -0
- data/pattern/reset.rb +4 -0
- data/pattern/subroutines.rb +38 -0
- data/program/_additional_erase.rb +7 -0
- data/program/_efa_resources.rb +7 -0
- data/program/_erase.rb +25 -0
- data/program/_erase_vfy.rb +5 -0
- data/program/_iv_resources.rb +10 -0
- data/program/basic_interface.rb +5 -0
- data/program/components/_prb2_main.rb +6 -0
- data/program/flow_control.rb +164 -0
- data/program/prb1.rb +226 -0
- data/program/prb1_resources.rb +28 -0
- data/program/prb2.rb +40 -0
- data/program/test.rb +20 -0
- data/templates/example.txt.erb +53 -0
- data/templates/j750/_vt_flow.txt.erb +8 -0
- data/templates/j750/_vt_instances.txt.erb +4 -0
- data/templates/j750/program_sheet.txt.erb +9 -0
- data/templates/manifest/v93k.yaml.erb +22 -0
- data/templates/web/index.md.erb +51 -0
- data/templates/web/layouts/_basic.html.erb +15 -0
- data/templates/web/partials/_navbar.html.erb +22 -0
- data/templates/web/release_notes.md.erb +5 -0
- metadata +332 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
module OrigenTesters
|
|
2
|
+
# Including this module in a class will create a basic test program interface that
|
|
3
|
+
# can generate programs for all ATE platforms supported by the Testers plugin.
|
|
4
|
+
#
|
|
5
|
+
# It provides a number of methods that can be called from a test program flow file
|
|
6
|
+
# to do basic things like a functional test.
|
|
7
|
+
#
|
|
8
|
+
# @example How to setup and use
|
|
9
|
+
# # lib/myapp/program_interface.rb
|
|
10
|
+
# module MyApp
|
|
11
|
+
# class Interface
|
|
12
|
+
# include OrigenTesters::BasicTestSetups
|
|
13
|
+
# end
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# # program/prb1.rb
|
|
17
|
+
# Flow.create interface: 'MyApp::Interface' do
|
|
18
|
+
#
|
|
19
|
+
# functional :my_pattern_1, bin: 10
|
|
20
|
+
# functional :my_pattern_2, bin: 11
|
|
21
|
+
#
|
|
22
|
+
# end
|
|
23
|
+
module BasicTestSetups
|
|
24
|
+
include OrigenTesters::ProgramGenerators
|
|
25
|
+
|
|
26
|
+
# Execute a functional test
|
|
27
|
+
#
|
|
28
|
+
# @param [Symbol, String] name the name of the test.
|
|
29
|
+
# @param [Hash] options the options to customize the test.
|
|
30
|
+
# @option options [Integer] :bin The bin number
|
|
31
|
+
# @option options [Integer] :sbin The soft bin number
|
|
32
|
+
# @option options [String] :pattern The pattern name, if not specified the test
|
|
33
|
+
# name will be used
|
|
34
|
+
# @option options [String] :pin_levels ('Lvl') The name of the pin levels
|
|
35
|
+
# @option options [String] :time_set ('Tim') The name of the time set
|
|
36
|
+
#
|
|
37
|
+
# @see http://origen.freescale.net/origen/latest/guides/program/flowapi/ The options associated with the flow control API are fully supported
|
|
38
|
+
#
|
|
39
|
+
# @example Customizing a test from the flow
|
|
40
|
+
# functional :erase, pattern: 'erase_all_nosrc', sbin: 150
|
|
41
|
+
#
|
|
42
|
+
# @example Applying global customization from the interface
|
|
43
|
+
# include OrigenTesters::BasicTestSetups
|
|
44
|
+
#
|
|
45
|
+
# def functional(name, options = {})
|
|
46
|
+
# # Apply custom defaults before calling
|
|
47
|
+
# options = {
|
|
48
|
+
# bin: 3,
|
|
49
|
+
# levels: 'nvm',
|
|
50
|
+
# }.merge(options)
|
|
51
|
+
# # Now call the generator
|
|
52
|
+
# super
|
|
53
|
+
# end
|
|
54
|
+
#
|
|
55
|
+
# @return [Hash] all generated components of the test will be returned. The key
|
|
56
|
+
# naming will depend on what platform the test has been generated for, but for
|
|
57
|
+
# example this will contain :flow_line, :test_instance and :patset objects in
|
|
58
|
+
# the case of an IG-XL-based platform.
|
|
59
|
+
#
|
|
60
|
+
# @example Adding a custom interpose function for J750
|
|
61
|
+
# include OrigenTesters::BasicTestSetups
|
|
62
|
+
#
|
|
63
|
+
# # Override the default J750 test instance to add an interpose function
|
|
64
|
+
# def functional(name, options = {})
|
|
65
|
+
# components = super
|
|
66
|
+
# if tester.j750?
|
|
67
|
+
# components[:test_instance].post_test_func = 'delayedBinning'
|
|
68
|
+
# end
|
|
69
|
+
# end
|
|
70
|
+
def functional(name, options = {})
|
|
71
|
+
options = {
|
|
72
|
+
pin_levels: 'Lvl',
|
|
73
|
+
time_set: 'Tim'
|
|
74
|
+
}.merge(options)
|
|
75
|
+
pattern = extract_pattern(name, options)
|
|
76
|
+
if tester.j750? || tester.j750_hpt? || tester.ultraflex?
|
|
77
|
+
ins = test_instances.functional(name, options)
|
|
78
|
+
pname = "#{pattern}_pset"
|
|
79
|
+
pset = patsets.add(pname, [{ pattern: "#{pattern}.PAT" }])
|
|
80
|
+
ins.pattern = pname
|
|
81
|
+
line = flow.test(ins, options)
|
|
82
|
+
{ test_instance: ins, flow_line: line, patset: pset }
|
|
83
|
+
elsif tester.v93k?
|
|
84
|
+
tm = test_methods.ac_tml.ac_test.functional_test
|
|
85
|
+
ts = test_suites.run(name, options)
|
|
86
|
+
ts.test_method = tm
|
|
87
|
+
ts.pattern = pattern
|
|
88
|
+
node = flow.test(ts, options)
|
|
89
|
+
{ test_method: tm, test_suite: ts, node: node }
|
|
90
|
+
else
|
|
91
|
+
fail "Unsupported tester: #{tester.class}"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Extract the pattern name from the given options, falling back to the given
|
|
96
|
+
# test name if a :pattern option is not present.
|
|
97
|
+
#
|
|
98
|
+
# It will also strip any extension if one is present.
|
|
99
|
+
def extract_pattern(name, options = {})
|
|
100
|
+
p = options[:pattern] || name
|
|
101
|
+
p = p.to_s.sub(/\..*$/, '')
|
|
102
|
+
p
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module OrigenTesters
|
|
2
|
+
class CallbackHandlers
|
|
3
|
+
include Origen::PersistentCallbacks
|
|
4
|
+
|
|
5
|
+
# Snoop the pattern path that was just created and then compile it
|
|
6
|
+
# if the compiler was passed on the command line
|
|
7
|
+
def pattern_generated(path_to_generated_pattern)
|
|
8
|
+
current_compiler = select_compiler
|
|
9
|
+
run_compiler(current_compiler, path_to_generated_pattern)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Listen for a pattern with .atp or .atp.gz extension. If found then compile the fileand kill the 'origen g' command
|
|
13
|
+
def before_pattern_lookup(requested_pattern)
|
|
14
|
+
path = Pathname.new(requested_pattern)
|
|
15
|
+
patname = path.basename
|
|
16
|
+
dir = path.dirname
|
|
17
|
+
if patname.to_s.match(/.atp/)
|
|
18
|
+
if patname.extname == '.atp' || patname.extname == '.gz'
|
|
19
|
+
# Found a .atp or .atp.gz file so we should compile it
|
|
20
|
+
matches = Dir.glob("#{Origen.root}/**/#{patname}")
|
|
21
|
+
fail "Found multiple locations for #{patname}, exiting...\n\t#{matches}" if matches.size > 1
|
|
22
|
+
pattern = matches.first.to_s
|
|
23
|
+
current_compiler = select_compiler
|
|
24
|
+
run_compiler(current_compiler, pattern)
|
|
25
|
+
$compile = true
|
|
26
|
+
end
|
|
27
|
+
# Return false so the Origen generate command stops
|
|
28
|
+
return false
|
|
29
|
+
end
|
|
30
|
+
true
|
|
31
|
+
end
|
|
32
|
+
# Instantiate an instance of this class immediately when this file is required, this object will
|
|
33
|
+
# then listen for the remainder of the Origen thread
|
|
34
|
+
CallbackHandlers.new
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def select_compiler
|
|
39
|
+
current_compiler = nil
|
|
40
|
+
if $compiler == :use_app_default
|
|
41
|
+
current_compiler = $dut.compiler
|
|
42
|
+
fail "DUT compiler '#{current_compiler}' is not instantiated" if $dut.pattern_compilers[current_compiler].nil?
|
|
43
|
+
elsif $compiler.is_a? Symbol
|
|
44
|
+
current_compiler = $compiler
|
|
45
|
+
fail "Command line compiler '#{current_compiler}' is not instantiated" if $dut.pattern_compilers[current_compiler].nil?
|
|
46
|
+
end
|
|
47
|
+
current_compiler
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def run_compiler(current_compiler, pattern)
|
|
51
|
+
unless current_compiler.nil?
|
|
52
|
+
debug "Compiling pattern #{pattern} with compiler '#{current_compiler}'..."
|
|
53
|
+
$dut.pattern_compilers[current_compiler].find_jobs(pattern)
|
|
54
|
+
$dut.pattern_compilers[current_compiler].run
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
require 'active_support/concern'
|
|
2
|
+
require 'erb'
|
|
3
|
+
require 'yaml'
|
|
4
|
+
|
|
5
|
+
module OrigenTesters
|
|
6
|
+
# This module should be included in all test program component generators and provides the required
|
|
7
|
+
# integration with the Flow.create and Resources.create methods
|
|
8
|
+
module Generator
|
|
9
|
+
autoload :Placeholder, 'origen_testers/generator/placeholder'
|
|
10
|
+
autoload :IdentityMap, 'origen_testers/generator/identity_map'
|
|
11
|
+
autoload :FlowControlAPI, 'origen_testers/generator/flow_control_api'
|
|
12
|
+
|
|
13
|
+
extend ActiveSupport::Concern
|
|
14
|
+
|
|
15
|
+
included do
|
|
16
|
+
include Origen::Generator::Comparator
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# The program source files are executed by eval to allow the tester to filter the
|
|
20
|
+
# source contents before executing. For examples the doc tester replaces all comments
|
|
21
|
+
# with a method call containing each comment so that they can be captured.
|
|
22
|
+
def self.execute_source(file)
|
|
23
|
+
if Origen.interface.respond_to?(:filter_source)
|
|
24
|
+
File.open(file) do |f|
|
|
25
|
+
src = f.read
|
|
26
|
+
src = Origen.interface.filter_source(src)
|
|
27
|
+
eval(src, global_binding)
|
|
28
|
+
end
|
|
29
|
+
else
|
|
30
|
+
load file
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# When called on a generator no output files will be created from it
|
|
35
|
+
def inhibit_output
|
|
36
|
+
@inhibit_output = true
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Returns true if the output files from this generator will be inhibited
|
|
40
|
+
def output_inhibited?
|
|
41
|
+
@inhibit_output
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Expands and inserts all render statements that have been encountered
|
|
45
|
+
def close(options = {})
|
|
46
|
+
Origen.profile "closing #{filename}" do
|
|
47
|
+
base_collection = collection
|
|
48
|
+
base_collection.each_with_index do |item, i|
|
|
49
|
+
if item.is_a? Placeholder
|
|
50
|
+
if item.type == :render
|
|
51
|
+
txt = ''
|
|
52
|
+
Origen.file_handler.preserve_current_file do
|
|
53
|
+
Origen.file_handler.default_extension = file_extension
|
|
54
|
+
placeholder = compiler.render(item.file, item.options)
|
|
55
|
+
txt = compiler.insert(placeholder).chomp
|
|
56
|
+
end
|
|
57
|
+
base_collection[i] = txt
|
|
58
|
+
else
|
|
59
|
+
fail 'Unknown placeholder encountered!'
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
@collection = base_collection.flatten.compact
|
|
64
|
+
on_close(options)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def file_pipeline
|
|
69
|
+
@@file_pipeline ||= []
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Returns the directory of the current source file being generated
|
|
73
|
+
def current_dir
|
|
74
|
+
if file_pipeline.empty?
|
|
75
|
+
Origen.file_handler.base_directory
|
|
76
|
+
else
|
|
77
|
+
Pathname.new(file_pipeline.last).dirname
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Redefine this in the parent which includes this module if you want anything to
|
|
82
|
+
# occur after closing the generator (expanding all render/import statements) but
|
|
83
|
+
# before writing to a file.
|
|
84
|
+
def on_close(options = {})
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Redefine this in the parent which includes this module if you want anything to
|
|
88
|
+
# occur after all tests have been generated but before file writing starts.
|
|
89
|
+
def finalize(options = {})
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def compiler
|
|
93
|
+
Origen.generator.compiler
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def filename=(name)
|
|
97
|
+
@filename = name
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def filename(options = {})
|
|
101
|
+
options = {
|
|
102
|
+
include_extension: true
|
|
103
|
+
}.merge(options)
|
|
104
|
+
name = (@filename || Origen.file_handler.current_file.basename('.rb')).to_s
|
|
105
|
+
if Origen.config.program_prefix
|
|
106
|
+
unless name =~ /^#{Origen.config.program_prefix}/i
|
|
107
|
+
name = "#{Origen.config.program_prefix}_#{name}"
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
f = Pathname.new(name).basename
|
|
111
|
+
ext = f.extname.empty? ? file_extension : f.extname
|
|
112
|
+
body = f.basename(".#{ext}").to_s
|
|
113
|
+
body.gsub!('_resources', '')
|
|
114
|
+
if defined? self.class::OUTPUT_POSTFIX
|
|
115
|
+
# Unless the postfix is already in the name
|
|
116
|
+
unless body =~ /#{self.class::OUTPUT_POSTFIX}$/i
|
|
117
|
+
body = "#{body}_#{self.class::OUTPUT_POSTFIX}"
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
ext = ".#{ext}" unless ext =~ /^\./
|
|
121
|
+
if options[:include_extension]
|
|
122
|
+
"#{body}#{ext}"
|
|
123
|
+
else
|
|
124
|
+
"#{body}"
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def dont_diff=(val)
|
|
129
|
+
@dont_diff = val
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# All generators must implement a collection method that returns an
|
|
133
|
+
# array containing the generated items
|
|
134
|
+
def collection
|
|
135
|
+
@collection ||= []
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def collection=(array)
|
|
139
|
+
@collection = array
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def file_extension
|
|
143
|
+
if defined? self.class::OUTPUT_EXTENSION
|
|
144
|
+
self.class::OUTPUT_EXTENSION
|
|
145
|
+
elsif defined? self.class::TEMPLATE
|
|
146
|
+
p = Pathname.new(self.class::TEMPLATE)
|
|
147
|
+
ext = p.basename('.erb').extname
|
|
148
|
+
ext.empty? ? 'txt' : ext
|
|
149
|
+
else
|
|
150
|
+
'txt'
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def write_to_file(options = {})
|
|
155
|
+
c = caller[0]
|
|
156
|
+
unless output_inhibited?
|
|
157
|
+
if defined? self.class::TEMPLATE || Origen.tester.is_a?(Origen::Tester::Doc)
|
|
158
|
+
write_from_template(options)
|
|
159
|
+
else
|
|
160
|
+
fail "Don't know hot to write without a template!"
|
|
161
|
+
end
|
|
162
|
+
stats.completed_files += 1
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def write_from_template(options = {})
|
|
167
|
+
options = {
|
|
168
|
+
quiet: false,
|
|
169
|
+
skip_diff: false
|
|
170
|
+
}.merge(options)
|
|
171
|
+
unless output_inhibited?
|
|
172
|
+
# If this is not the first time we have written to the current output file
|
|
173
|
+
# then append to it, otherwise clear it and start from scratch.
|
|
174
|
+
# The use of a class variable to store the opened files means that it will be
|
|
175
|
+
# shared by all generators in this run.
|
|
176
|
+
@@opened_files ||= []
|
|
177
|
+
if @@opened_files.include?(output_file) && !Origen.tester.is_a?(Origen::Tester::Doc)
|
|
178
|
+
@append = true
|
|
179
|
+
Origen.file_handler.preserve_state do
|
|
180
|
+
File.open(output_file, 'a') do |out|
|
|
181
|
+
content = compiler.insert(ERB.new(File.read(self.class::TEMPLATE), 0, Origen.config.erb_trim_mode).result(binding))
|
|
182
|
+
out.puts content unless content.empty?
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
Origen.log.info "Appending... #{output_file.basename}" unless options[:quiet]
|
|
186
|
+
else
|
|
187
|
+
@append = false
|
|
188
|
+
Origen.file_handler.preserve_state do
|
|
189
|
+
if Origen.tester.is_a?(Origen::Tester::Doc)
|
|
190
|
+
if options[:return_model]
|
|
191
|
+
Origen::Tester::Doc.model.add_flow(filename(include_extension: false), to_yaml)
|
|
192
|
+
else
|
|
193
|
+
Origen.file_handler.open_for_write(output_file) do |f|
|
|
194
|
+
f.puts YAML.dump(to_yaml(include_descriptions: false))
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
else
|
|
198
|
+
File.open(output_file, 'w') do |out|
|
|
199
|
+
out.puts compiler.insert(ERB.new(File.read(self.class::TEMPLATE), 0, Origen.config.erb_trim_mode).result(binding))
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
@@opened_files << output_file
|
|
204
|
+
Origen.log.info "Writing... #{output_file.basename}" unless options[:quiet]
|
|
205
|
+
end
|
|
206
|
+
if !@dont_diff && !options[:skip_diff] && !options[:quiet]
|
|
207
|
+
check_for_changes(output_file, reference_file,
|
|
208
|
+
compile_job: true,
|
|
209
|
+
comment_char: Origen.app.tester.program_comment_char)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def output_file
|
|
215
|
+
if respond_to? :subdirectory
|
|
216
|
+
p = Pathname.new("#{Origen.file_handler.output_directory}/#{subdirectory}/#{filename}")
|
|
217
|
+
FileUtils.mkdir_p p.dirname.to_s unless p.dirname.exist?
|
|
218
|
+
p
|
|
219
|
+
else
|
|
220
|
+
Pathname.new("#{Origen.file_handler.output_directory}/#{filename}")
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def reference_file
|
|
225
|
+
Pathname.new("#{Origen.file_handler.reference_directory}/#{filename}")
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def import(file, options = {})
|
|
229
|
+
file = Pathname.new(file).absolute? ? file : "#{current_dir}/#{file}"
|
|
230
|
+
file = Origen.file_handler.clean_path_to_sub_program(file)
|
|
231
|
+
base_collection = collection
|
|
232
|
+
@collection = []
|
|
233
|
+
Origen.generator.option_pipeline << options
|
|
234
|
+
file_pipeline << file
|
|
235
|
+
::OrigenTesters::Generator.execute_source(file)
|
|
236
|
+
file_pipeline.pop
|
|
237
|
+
base_collection << @collection
|
|
238
|
+
@collection = base_collection.flatten
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
def render(file, options = {})
|
|
242
|
+
if options.delete(:_inline)
|
|
243
|
+
super Origen.file_handler.clean_path_to_sub_template(file), options
|
|
244
|
+
else
|
|
245
|
+
collection << Placeholder.new(:render, file, options)
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def stats
|
|
250
|
+
Origen.app.stats
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
def to_be_written?
|
|
254
|
+
true
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def set_flow_description(desc)
|
|
258
|
+
Origen.interface.descriptions.add_for_flow(output_file, desc)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def identity_map # :nodoc:
|
|
262
|
+
Origen.interface.identity_map
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def platform
|
|
266
|
+
Origen.interface.platform
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
module ClassMethods
|
|
270
|
+
def new(*args, &block) # :nodoc:
|
|
271
|
+
options = (args.last && args.last.is_a?(Hash)) ? args.last : {}
|
|
272
|
+
x = allocate
|
|
273
|
+
x.send(:initialize, *args, &block)
|
|
274
|
+
Origen.interface.sheet_generators << x unless options[:manually_register]
|
|
275
|
+
x
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
end
|
|
@@ -0,0 +1,611 @@
|
|
|
1
|
+
module OrigenTesters
|
|
2
|
+
module Generator
|
|
3
|
+
module FlowControlAPI
|
|
4
|
+
# Flow control methods related to flow context
|
|
5
|
+
FLOW_METHODS = [
|
|
6
|
+
# Methods in arrays are aliases, the primary name is the first one
|
|
7
|
+
[:if_enable, :if_enabled, :enable, :enabled],
|
|
8
|
+
[:unless_enable, :unless_enabled],
|
|
9
|
+
[:if_job, :if_jobs],
|
|
10
|
+
[:unless_job, :unless_jobs]
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
# Flow control methods related to a relationship with another test
|
|
14
|
+
RELATION_METHODS = [
|
|
15
|
+
# Methods in arrays are aliases, the primary name is the first one
|
|
16
|
+
:if_ran,
|
|
17
|
+
:unless_ran,
|
|
18
|
+
[:if_failed, :unless_passed],
|
|
19
|
+
[:if_passed, :unless_failed],
|
|
20
|
+
[:if_any_passed, :unless_all_failed],
|
|
21
|
+
[:if_all_passed, :unless_any_failed],
|
|
22
|
+
[:if_any_failed, :unless_all_passed],
|
|
23
|
+
[:if_all_failed, :unless_any_passed]
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
# Returns true if the test context generated from the supplied options + existing context
|
|
27
|
+
# wrappers is different from that which was applied to the previous test.
|
|
28
|
+
def context_changed?(options = {})
|
|
29
|
+
current_context[:hash_code] != summarize_context(options)[:hash_code]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @api private
|
|
33
|
+
def save_context(options = {})
|
|
34
|
+
# If the test has requested to use the current context...
|
|
35
|
+
if options[:context] == :current
|
|
36
|
+
replace_context_with_current(options)
|
|
37
|
+
else
|
|
38
|
+
@current_context = summarize_context(options)
|
|
39
|
+
options.merge(@current_context[:context])
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Returns a hash representing the current context, that is the context that was applied
|
|
44
|
+
# to the last test.
|
|
45
|
+
#
|
|
46
|
+
# The hash contains two items:
|
|
47
|
+
#
|
|
48
|
+
# * :context contains a hash that summarises the flow control options that have been
|
|
49
|
+
# used, for example it may contain something like: :if_enable => "data_collection"
|
|
50
|
+
# * :hash_code returns a hash-code for the values contained in the :context arrary. Any
|
|
51
|
+
# two equivalent contexts will have the same :hash_code, therefore this can be used
|
|
52
|
+
# to easily check the equivalence of any two contexts.
|
|
53
|
+
def current_context
|
|
54
|
+
@current_context ||= save_context
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# @api private
|
|
58
|
+
#
|
|
59
|
+
# Removes any context options from the given options hash and merges in the current
|
|
60
|
+
# context
|
|
61
|
+
def replace_context_with_current(options)
|
|
62
|
+
options = options.merge({})
|
|
63
|
+
[FLOW_METHODS, RELATION_METHODS].flatten.each do |m|
|
|
64
|
+
options.delete(m)
|
|
65
|
+
end
|
|
66
|
+
options.merge(current_context[:context])
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Returns a hash like that returned by current_context based on the given set of options +
|
|
70
|
+
# existing context wrappers.
|
|
71
|
+
def summarize_context(options = {})
|
|
72
|
+
code = []
|
|
73
|
+
context = {}
|
|
74
|
+
(FLOW_METHODS + RELATION_METHODS).each do |m|
|
|
75
|
+
primary = m.is_a?(Array) ? m.first : m
|
|
76
|
+
val = false
|
|
77
|
+
[m].flatten.each do |m|
|
|
78
|
+
if options[m]
|
|
79
|
+
val = options[m]
|
|
80
|
+
elsif instance_variable_get("@#{m}_block")
|
|
81
|
+
val = instance_variable_get("@#{m}_block")
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
if val
|
|
85
|
+
code << primary
|
|
86
|
+
code << val
|
|
87
|
+
context[primary] = val
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
{ hash_code: code.flatten.hash, context: context }
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# All tests generated within the given block will be assigned the given enable word.
|
|
94
|
+
#
|
|
95
|
+
# If a test encountered within the block already has another enable word assigned to it then
|
|
96
|
+
# an error will be raised.
|
|
97
|
+
def if_enable(word, options = {})
|
|
98
|
+
@if_enable_block = word
|
|
99
|
+
yield word
|
|
100
|
+
@if_enable_block = nil
|
|
101
|
+
end
|
|
102
|
+
alias_method :if_enabled, :if_enable
|
|
103
|
+
|
|
104
|
+
# All tests generated will not run unless the given enable word is asserted.
|
|
105
|
+
def unless_enable(word, options = {})
|
|
106
|
+
@unless_enable_block = word unless options[:or]
|
|
107
|
+
yield word
|
|
108
|
+
@unless_enable_block = nil
|
|
109
|
+
end
|
|
110
|
+
alias_method :unless_enabled, :unless_enable
|
|
111
|
+
|
|
112
|
+
# All tests generated within the given block will be enabled only for the given jobs.
|
|
113
|
+
def if_job(*jobs)
|
|
114
|
+
jobs = jobs.flatten
|
|
115
|
+
@if_job_block = @if_job_block ? @if_job_block + jobs : jobs
|
|
116
|
+
yield
|
|
117
|
+
@if_job_block = nil
|
|
118
|
+
end
|
|
119
|
+
alias_method :if_jobs, :if_job
|
|
120
|
+
|
|
121
|
+
# All tests generated within the given block will be enabled only for the given jobs.
|
|
122
|
+
def unless_job(*jobs)
|
|
123
|
+
jobs = jobs.flatten
|
|
124
|
+
@unless_job_block = @unless_job_block ? @unless_job_block + jobs : jobs
|
|
125
|
+
yield
|
|
126
|
+
@unless_job_block = nil
|
|
127
|
+
end
|
|
128
|
+
alias_method :unless_jobs, :unless_job
|
|
129
|
+
|
|
130
|
+
# All tests generated within the given block will only run if the given test id has also
|
|
131
|
+
# run earlier in the flow
|
|
132
|
+
def if_ran(test_id, options = {})
|
|
133
|
+
test_id = Origen.interface.filter_id(test_id, options)
|
|
134
|
+
return if options.key?(:if) && !options[:if]
|
|
135
|
+
return if options.key?(:unless) && options[:unless]
|
|
136
|
+
if @if_ran_block
|
|
137
|
+
fail 'Sorry but nesting of if_ran is not currently supported!'
|
|
138
|
+
end
|
|
139
|
+
@if_ran_block = test_id
|
|
140
|
+
yield
|
|
141
|
+
@if_ran_block = nil
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# All tests generated within the given block will only run if the given test id has not
|
|
145
|
+
# run earlier in the flow
|
|
146
|
+
def unless_ran(test_id, options = {})
|
|
147
|
+
test_id = Origen.interface.filter_id(test_id, options)
|
|
148
|
+
return if options.key?(:if) && !options[:if]
|
|
149
|
+
return if options.key?(:unless) && options[:unless]
|
|
150
|
+
if @unless_ran_block
|
|
151
|
+
fail 'Sorry but nesting of unless_ran is not currently supported!'
|
|
152
|
+
end
|
|
153
|
+
@unless_ran_block = test_id
|
|
154
|
+
yield
|
|
155
|
+
@unless_ran_block = nil
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# All tests generated within the given block will only run if the given test id has
|
|
159
|
+
# failed earlier in the flow
|
|
160
|
+
def if_failed(test_id, options = {})
|
|
161
|
+
test_id = Origen.interface.filter_id(test_id, options)
|
|
162
|
+
return if options.key?(:if) && !options[:if]
|
|
163
|
+
return if options.key?(:unless) && options[:unless]
|
|
164
|
+
if @if_failed_block
|
|
165
|
+
fail 'Sorry but nesting of if_failed is not currently supported!'
|
|
166
|
+
end
|
|
167
|
+
@if_failed_block = test_id
|
|
168
|
+
yield
|
|
169
|
+
@if_failed_block = nil
|
|
170
|
+
end
|
|
171
|
+
alias_method :unless_passed, :if_failed
|
|
172
|
+
|
|
173
|
+
# All tests generated within the given block will only run if the given test id has
|
|
174
|
+
# passed earlier in the flow
|
|
175
|
+
def if_passed(test_id, options = {})
|
|
176
|
+
test_id = Origen.interface.filter_id(test_id, options)
|
|
177
|
+
return if options.key?(:if) && !options[:if]
|
|
178
|
+
return if options.key?(:unless) && options[:unless]
|
|
179
|
+
if @if_passed_block
|
|
180
|
+
fail 'Sorry but nesting of if_passed is not currently supported!'
|
|
181
|
+
end
|
|
182
|
+
@if_passed_block = test_id
|
|
183
|
+
yield
|
|
184
|
+
@if_passed_block = nil
|
|
185
|
+
end
|
|
186
|
+
alias_method :unless_failed, :if_passed
|
|
187
|
+
|
|
188
|
+
# All tests generated within the given block will only run if the given test id has
|
|
189
|
+
# passed ON ANY SITE earlier in the flow
|
|
190
|
+
def if_any_passed(test_id, options = {})
|
|
191
|
+
test_id = Origen.interface.filter_id(test_id, options)
|
|
192
|
+
return if conditionally_deactivated?(options)
|
|
193
|
+
if @if_any_passed_block
|
|
194
|
+
fail 'Sorry but nesting of if_any_passed is not currently supported!'
|
|
195
|
+
end
|
|
196
|
+
@if_any_passed_block = test_id
|
|
197
|
+
yield
|
|
198
|
+
@if_any_passed_block = nil
|
|
199
|
+
end
|
|
200
|
+
alias_method :unless_all_failed, :if_any_passed
|
|
201
|
+
|
|
202
|
+
# All tests generated within the given block will only run if the given test id has
|
|
203
|
+
# passed ON ALL SITES earlier in the flow
|
|
204
|
+
def if_all_passed(test_id, options = {})
|
|
205
|
+
test_id = Origen.interface.filter_id(test_id, options)
|
|
206
|
+
return if conditionally_deactivated?(options)
|
|
207
|
+
if @if_all_passed_block
|
|
208
|
+
fail 'Sorry but nesting of if_all_passed is not currently supported!'
|
|
209
|
+
end
|
|
210
|
+
@if_all_passed_block = test_id
|
|
211
|
+
yield
|
|
212
|
+
@if_all_passed_block = nil
|
|
213
|
+
end
|
|
214
|
+
alias_method :unless_any_failed, :if_all_passed
|
|
215
|
+
|
|
216
|
+
# All tests generated within the given block will only run if the given test id has
|
|
217
|
+
# failed ON ANY SITE earlier in the flow
|
|
218
|
+
def if_any_failed(test_id, options = {})
|
|
219
|
+
test_id = Origen.interface.filter_id(test_id, options)
|
|
220
|
+
return if conditionally_deactivated?(options)
|
|
221
|
+
if @if_any_failed_block
|
|
222
|
+
fail 'Sorry but nesting of if_any_failed is not currently supported!'
|
|
223
|
+
end
|
|
224
|
+
@if_any_failed_block = test_id
|
|
225
|
+
yield
|
|
226
|
+
@if_any_failed_block = nil
|
|
227
|
+
end
|
|
228
|
+
alias_method :unless_all_passed, :if_any_failed
|
|
229
|
+
|
|
230
|
+
# All tests generated within the given block will only run if the given test id has
|
|
231
|
+
# failed ON ALL SITES earlier in the flow
|
|
232
|
+
def if_all_failed(test_id, options = {})
|
|
233
|
+
test_id = Origen.interface.filter_id(test_id, options)
|
|
234
|
+
return if conditionally_deactivated?(options)
|
|
235
|
+
if @if_all_failed_block
|
|
236
|
+
fail 'Sorry but nesting of if_all_failed is not currently supported!'
|
|
237
|
+
end
|
|
238
|
+
@if_all_failed_block = test_id
|
|
239
|
+
yield
|
|
240
|
+
@if_all_failed_block = nil
|
|
241
|
+
end
|
|
242
|
+
alias_method :unless_any_passed, :if_all_failed
|
|
243
|
+
|
|
244
|
+
def conditionally_deactivated?(options)
|
|
245
|
+
(options.key?(:if) && !options[:if]) ||
|
|
246
|
+
(options.key?(:unless) && options[:unless])
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def find_by_id(id, options = {}) # :nodoc:
|
|
250
|
+
options = {
|
|
251
|
+
search_other_flows: true
|
|
252
|
+
}.merge(options)
|
|
253
|
+
# Look within the current flow for a match first
|
|
254
|
+
t = identity_map[id.to_sym]
|
|
255
|
+
return t if t
|
|
256
|
+
# If no match then look across other flow modules for a match
|
|
257
|
+
# This currently returns the first match, should it raise an error on multiple?
|
|
258
|
+
if options[:search_other_flows]
|
|
259
|
+
Origen.interface.flow_generators.any? do |flow|
|
|
260
|
+
t = flow.find_by_id(id, search_other_flows: false)
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
t
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def identity_map # :nodoc:
|
|
267
|
+
@identity_map ||= {}
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
# If a class that includes this module has a finalize method it must
|
|
271
|
+
# call apply_relationships
|
|
272
|
+
def finalize(options = {}) # :nodoc:
|
|
273
|
+
apply_relationships
|
|
274
|
+
reset_globals
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def apply_relationships # :nodoc:
|
|
278
|
+
if @relationships
|
|
279
|
+
@relationships.each do |rel|
|
|
280
|
+
t = find_by_id(rel[:target_id])
|
|
281
|
+
fail "Test not found with ID: #{rel[:target_id]}, referenced in flow: #{filename}" unless t
|
|
282
|
+
t.id = rel[:target_id]
|
|
283
|
+
confirm_valid_context(t, rel[:dependent])
|
|
284
|
+
case rel[:type]
|
|
285
|
+
# The first cases here contain J750 logic, these should be replaced
|
|
286
|
+
# with the call method style used for the later cases when time permits.
|
|
287
|
+
when :failed
|
|
288
|
+
if rel[:dependent].respond_to?(:run_if_failed)
|
|
289
|
+
rel[:dependent].run_if_failed(rel[:target_id])
|
|
290
|
+
else
|
|
291
|
+
t.continue_on_fail
|
|
292
|
+
flag = t.set_flag_on_fail
|
|
293
|
+
rel[:dependent].flag_true = flag
|
|
294
|
+
end
|
|
295
|
+
when :passed
|
|
296
|
+
if rel[:dependent].respond_to?(:run_if_passed)
|
|
297
|
+
rel[:dependent].run_if_passed(rel[:target_id])
|
|
298
|
+
else
|
|
299
|
+
t.continue_on_fail
|
|
300
|
+
flag = t.set_flag_on_pass
|
|
301
|
+
rel[:dependent].flag_true = flag
|
|
302
|
+
end
|
|
303
|
+
when :if_ran, :unless_ran
|
|
304
|
+
if rel[:type] == :if_ran
|
|
305
|
+
if rel[:dependent].respond_to?(:run_if_ran)
|
|
306
|
+
rel[:dependent].run_if_ran(rel[:target_id])
|
|
307
|
+
else
|
|
308
|
+
# t.continue_on_fail
|
|
309
|
+
flag = t.set_flag_on_ran
|
|
310
|
+
rel[:dependent].flag_true = flag
|
|
311
|
+
end
|
|
312
|
+
else
|
|
313
|
+
if rel[:dependent].respond_to?(:run_unless_ran)
|
|
314
|
+
rel[:dependent].run_unless_ran(rel[:target_id])
|
|
315
|
+
else
|
|
316
|
+
# t.continue_on_fail
|
|
317
|
+
flag = t.set_flag_on_ran
|
|
318
|
+
rel[:dependent].flag_clear = flag
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
when :any_passed
|
|
322
|
+
rel[:dependent].run_if_any_passed(t)
|
|
323
|
+
when :all_passed
|
|
324
|
+
rel[:dependent].run_if_all_passed(t)
|
|
325
|
+
when :any_failed
|
|
326
|
+
rel[:dependent].run_if_any_failed(t)
|
|
327
|
+
when :all_failed
|
|
328
|
+
rel[:dependent].run_if_all_failed(t)
|
|
329
|
+
else
|
|
330
|
+
fail 'Unknown relationship type!'
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
@relationships = nil
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
def confirm_valid_context(test, dependent) # :nodoc:
|
|
338
|
+
# TODO: Add some validation checks here, for example make sure the dependent
|
|
339
|
+
# executes in the same job(s) as the test, otherwise the dependent will
|
|
340
|
+
# never be hit and will cause a validation error.
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
def record_id(test, options = {})
|
|
344
|
+
if options[:id]
|
|
345
|
+
@@existing_ids ||= []
|
|
346
|
+
if @@existing_ids.include?(options[:id].to_sym)
|
|
347
|
+
fail "The ID '#{test.id}' is not unique, it has already been assigned!"
|
|
348
|
+
else
|
|
349
|
+
@@existing_ids << options[:id].to_sym
|
|
350
|
+
end
|
|
351
|
+
identity_map[options[:id].to_sym] = test
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
# @api private
|
|
356
|
+
def at_run_start
|
|
357
|
+
@@existing_ids = nil
|
|
358
|
+
@@labels = nil
|
|
359
|
+
end
|
|
360
|
+
alias_method :reset_globals, :at_run_start
|
|
361
|
+
|
|
362
|
+
def replace_relationship_dependent(old_node, new_node)
|
|
363
|
+
@relationships.each do |rel|
|
|
364
|
+
rel[:dependent] = new_node if rel[:dependent] == old_node
|
|
365
|
+
end
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
# As generation of render and imports is not linear its possible that the test being
|
|
369
|
+
# referenced does not exist in the collection yet.
|
|
370
|
+
# Therefore the required relationship will be recorded for now and applied later upon
|
|
371
|
+
# closing the generator at which point the complete final collection will be available.
|
|
372
|
+
#
|
|
373
|
+
# Note - as of v2.0.1.dev64 the above is no longer true - imports are generated linearly.
|
|
374
|
+
# Therefore parent test should always already exist and it is possible that this relationship
|
|
375
|
+
# handling could be cleaned up considerably.
|
|
376
|
+
#
|
|
377
|
+
# However we should keep it around for now as it may come in useful when other tester
|
|
378
|
+
# platforms are supported in the future.
|
|
379
|
+
def track_relationships(test_options = {}) # :nodoc:
|
|
380
|
+
[:id, RELATION_METHODS].flatten.each do |id|
|
|
381
|
+
if test_options[id]
|
|
382
|
+
test_options[id] = Origen.interface.filter_id(test_options[id], test_options)
|
|
383
|
+
end
|
|
384
|
+
end
|
|
385
|
+
options = extract_relation_options!(test_options)
|
|
386
|
+
current_test = yield test_options
|
|
387
|
+
record_id(current_test, test_options)
|
|
388
|
+
@relationships ||= []
|
|
389
|
+
target_id = options[:if_failed] || options[:unless_passed] || @if_failed_block
|
|
390
|
+
if target_id
|
|
391
|
+
@relationships << {
|
|
392
|
+
type: :failed,
|
|
393
|
+
target_id: target_id,
|
|
394
|
+
dependent: current_test
|
|
395
|
+
}
|
|
396
|
+
end
|
|
397
|
+
target_id = options[:if_passed] || options[:unless_failed] || @if_passed_block
|
|
398
|
+
if target_id
|
|
399
|
+
@relationships << {
|
|
400
|
+
type: :passed,
|
|
401
|
+
target_id: target_id,
|
|
402
|
+
dependent: current_test
|
|
403
|
+
}
|
|
404
|
+
end
|
|
405
|
+
target_id = options.delete(:if_ran) || @if_ran_block
|
|
406
|
+
if target_id
|
|
407
|
+
@relationships << {
|
|
408
|
+
type: :if_ran,
|
|
409
|
+
target_id: target_id,
|
|
410
|
+
dependent: current_test
|
|
411
|
+
}
|
|
412
|
+
end
|
|
413
|
+
target_id = options.delete(:unless_ran) || @unless_ran_block
|
|
414
|
+
if target_id
|
|
415
|
+
@relationships << {
|
|
416
|
+
type: :unless_ran,
|
|
417
|
+
target_id: target_id,
|
|
418
|
+
dependent: current_test
|
|
419
|
+
}
|
|
420
|
+
end
|
|
421
|
+
target_id = options[:if_any_passed] || options[:unless_all_failed] || @if_any_passed_block
|
|
422
|
+
if target_id
|
|
423
|
+
@relationships << {
|
|
424
|
+
type: :any_passed,
|
|
425
|
+
target_id: target_id,
|
|
426
|
+
dependent: current_test
|
|
427
|
+
}
|
|
428
|
+
end
|
|
429
|
+
target_id = options[:if_all_passed] || options[:unless_any_failed] || @if_all_passed_block
|
|
430
|
+
if target_id
|
|
431
|
+
@relationships << {
|
|
432
|
+
type: :all_passed,
|
|
433
|
+
target_id: target_id,
|
|
434
|
+
dependent: current_test
|
|
435
|
+
}
|
|
436
|
+
end
|
|
437
|
+
target_id = options[:if_any_failed] || options[:unless_all_passed] || @if_any_failed_block
|
|
438
|
+
if target_id
|
|
439
|
+
@relationships << {
|
|
440
|
+
type: :any_failed,
|
|
441
|
+
target_id: target_id,
|
|
442
|
+
dependent: current_test
|
|
443
|
+
}
|
|
444
|
+
end
|
|
445
|
+
target_id = options[:if_all_failed] || options[:unless_any_passed] || @if_all_failed_block
|
|
446
|
+
if target_id
|
|
447
|
+
@relationships << {
|
|
448
|
+
type: :all_failed,
|
|
449
|
+
target_id: target_id,
|
|
450
|
+
dependent: current_test
|
|
451
|
+
}
|
|
452
|
+
end
|
|
453
|
+
if test_options[:context] == :current # Context has already been applied
|
|
454
|
+
current_test
|
|
455
|
+
else
|
|
456
|
+
apply_current_context!(current_test)
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
def apply_current_context!(line) # :nodoc:
|
|
461
|
+
if @if_enable_block
|
|
462
|
+
if line.enable && line.enable != @if_enable_block
|
|
463
|
+
fail "Cannot apply enable word '#{@if_enable_block}' to '#{line.parameter}', it already has '#{line.enable}'"
|
|
464
|
+
else
|
|
465
|
+
line.enable = @if_enable_block
|
|
466
|
+
end
|
|
467
|
+
end
|
|
468
|
+
if @unless_enable_block
|
|
469
|
+
line.unless_enable = @unless_enable_block
|
|
470
|
+
end
|
|
471
|
+
line.if_job = @if_job_block if @if_job_block
|
|
472
|
+
line.unless_job = @unless_job_block if @unless_job_block
|
|
473
|
+
line
|
|
474
|
+
end
|
|
475
|
+
|
|
476
|
+
# Removes any flow relationship options from given hash and returns them
|
|
477
|
+
# in a new hash
|
|
478
|
+
def extract_relation_options!(options) # :nodoc:
|
|
479
|
+
opts = {}
|
|
480
|
+
RELATION_METHODS.flatten.each do |o|
|
|
481
|
+
opts[o] = options.delete(o)
|
|
482
|
+
end
|
|
483
|
+
opts
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
def extract_flow_control_options!(options)
|
|
487
|
+
opts = {}
|
|
488
|
+
FLOW_METHODS.flatten.each do |o|
|
|
489
|
+
if options.key?(o)
|
|
490
|
+
opts[o] = options.delete(o)
|
|
491
|
+
end
|
|
492
|
+
end
|
|
493
|
+
opts
|
|
494
|
+
end
|
|
495
|
+
|
|
496
|
+
def generate_unique_label(id = nil)
|
|
497
|
+
id = 'label' if !id || id == ''
|
|
498
|
+
label = "#{Origen.interface.app_identifier}_#{id}"
|
|
499
|
+
label.gsub!(' ', '_')
|
|
500
|
+
label.upcase!
|
|
501
|
+
@@labels ||= {}
|
|
502
|
+
@@labels[Origen.tester.class] ||= {}
|
|
503
|
+
@@labels[Origen.tester.class][label] ||= 0
|
|
504
|
+
@@labels[Origen.tester.class][label] += 1
|
|
505
|
+
"#{label}_#{@@labels[Origen.tester.class][label]}"
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
module Interface
|
|
509
|
+
# Implement this method in your application interface if you want to
|
|
510
|
+
# sanitize all ID references used in the flow control API.
|
|
511
|
+
# For example you could use this to append a flow name prefix to every
|
|
512
|
+
# ID reference within a flow which can help with ID duplication problems
|
|
513
|
+
# when flow snippets are re-used.
|
|
514
|
+
def filter_id(id, options = {})
|
|
515
|
+
id
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
def extract_relation_options!(*args)
|
|
519
|
+
flow.extract_relation_options!(*args)
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
def extract_flow_control_options!(*args)
|
|
523
|
+
flow.extract_flow_control_options!(*args)
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
# Alias for flow#if_enable
|
|
527
|
+
def if_enable(*args, &block)
|
|
528
|
+
flow.if_enable(*args, &block)
|
|
529
|
+
end
|
|
530
|
+
alias_method :if_enabled, :if_enable
|
|
531
|
+
|
|
532
|
+
# Alias for flow#unless_enable
|
|
533
|
+
def unless_enable(*args, &block)
|
|
534
|
+
flow.unless_enable(*args, &block)
|
|
535
|
+
end
|
|
536
|
+
alias_method :unless_enabled, :unless_enable
|
|
537
|
+
|
|
538
|
+
# Alias for flow#if_job
|
|
539
|
+
def if_job(*args, &block)
|
|
540
|
+
flow.if_job(*args, &block)
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
# Alias for flow#unless_job
|
|
544
|
+
def unless_job(*args, &block)
|
|
545
|
+
flow.unless_job(*args, &block)
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
# Alias for flow#unless_ran
|
|
549
|
+
def unless_ran(*args, &block)
|
|
550
|
+
flow.unless_ran(*args, &block)
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
# Alias for flow#if_ran
|
|
554
|
+
def if_ran(*args, &block)
|
|
555
|
+
flow.if_ran(*args, &block)
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
# Alias for flow#if_failed
|
|
559
|
+
def if_failed(*args, &block)
|
|
560
|
+
flow.if_failed(*args, &block)
|
|
561
|
+
end
|
|
562
|
+
alias_method :unless_passed, :if_failed
|
|
563
|
+
|
|
564
|
+
# Alias for flow#if_passed
|
|
565
|
+
def if_passed(*args, &block)
|
|
566
|
+
flow.if_passed(*args, &block)
|
|
567
|
+
end
|
|
568
|
+
alias_method :unless_failed, :if_passed
|
|
569
|
+
|
|
570
|
+
# Alias for flow#if_any_passed
|
|
571
|
+
def if_any_passed(*args, &block)
|
|
572
|
+
flow.if_any_passed(*args, &block)
|
|
573
|
+
end
|
|
574
|
+
alias_method :unless_all_failed, :if_any_passed
|
|
575
|
+
|
|
576
|
+
# Alias for flow#if_all_passed
|
|
577
|
+
def if_all_passed(*args, &block)
|
|
578
|
+
flow.if_all_passed(*args, &block)
|
|
579
|
+
end
|
|
580
|
+
alias_method :unless_any_failed, :if_all_passed
|
|
581
|
+
|
|
582
|
+
# Alias for flow#if_any_failed
|
|
583
|
+
def if_any_failed(*args, &block)
|
|
584
|
+
flow.if_any_failed(*args, &block)
|
|
585
|
+
end
|
|
586
|
+
alias_method :unless_all_passed, :if_any_failed
|
|
587
|
+
|
|
588
|
+
# Alias for flow#if_all_failed
|
|
589
|
+
def if_all_failed(*args, &block)
|
|
590
|
+
flow.if_all_failed(*args, &block)
|
|
591
|
+
end
|
|
592
|
+
alias_method :unless_any_passed, :if_all_failed
|
|
593
|
+
|
|
594
|
+
# Alias for flow#skip
|
|
595
|
+
def skip(*args, &block)
|
|
596
|
+
flow.skip(*args, &block)
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
# Alias for flow#current_context
|
|
600
|
+
def current_context(*args, &block)
|
|
601
|
+
flow.current_context(*args, &block)
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
# Alias for flow#context_changed?
|
|
605
|
+
def context_changed?(*args, &block)
|
|
606
|
+
flow.context_changed?(*args, &block)
|
|
607
|
+
end
|
|
608
|
+
end
|
|
609
|
+
end
|
|
610
|
+
end
|
|
611
|
+
end
|