lib/atp/flow.rb in atp-1.0.0 vs lib/atp/flow.rb in atp-1.1.0

- old
+ new

@@ -96,29 +96,34 @@ # Returns a processed/optimized AST, this is the one that should be # used to build and represent the given test flow def ast(options = {}) options = { - apply_relationships: true, + apply_relationships: true, # Supply a unique ID to append to all IDs - unique_id: nil, + unique_id: nil, # Set to :smt, or :igxl - optimization: :runner, + optimization: :runner, + # When true, will remove set_result nodes in an on_fail branch which contains a continue + implement_continue: true, + # When false, this will not optimize the use of a flag by nesting a dependent test within + # the parent test's on_fail branch if the on_fail contains a continue + optimize_flags_when_continue: true, # These options are not intended for application use, but provide the ability to # turn off certain processors during test cases - add_ids: true, - optimize_flags: true, - one_flag_per_test: true, - implement_continue: true + add_ids: true, + optimize_flags: true, + one_flag_per_test: true }.merge(options) ############################################################################### ## Common pre-processing and validation ############################################################################### ast = Processors::PreCleaner.new.run(raw) Validators::DuplicateIDs.new(self).run(ast) Validators::MissingIDs.new(self).run(ast) Validators::Jobs.new(self).run(ast) + Validators::Flags.new(self).run(ast) # Ensure everything has an ID, this helps later if condition nodes need to be generated ast = Processors::AddIDs.new.run(ast) if options[:add_ids] ast = Processors::FlowID.new.run(ast, options[:unique_id]) if options[:unique_id] ############################################################################### @@ -130,11 +135,13 @@ ast = Processors::Relationship.new.run(ast) if options[:apply_relationships] ast = Processors::Condition.new.run(ast) unless options[:optimization] == :runner ast = Processors::ContinueImplementer.new.run(ast) if options[:implement_continue] end - ast = Processors::FlagOptimizer.new.run(ast) if options[:optimize_flags] + if options[:optimize_flags] + ast = Processors::FlagOptimizer.new.run(ast, optimize_when_continue: options[:optimize_flags_when_continue]) + end ast = Processors::AdjacentIfCombiner.new.run(ast) ############################################################################### ## Optimization for a row-based target, e.g. UltraFLEX ############################################################################### @@ -185,10 +192,21 @@ options = flags.pop if flags.last.is_a?(Hash) flags = flags.flatten @pipeline[0] = add_volatile_flags(@pipeline[0], flags) end + # Record a description for a bin number + def describe_bin(number, description, options = {}) + @pipeline[0] = add_bin_description(@pipeline[0], number, description, type: :hard) + end + + # Record a description for a softbin number + def describe_soft_bin(number, description, options = {}) + @pipeline[0] = add_bin_description(@pipeline[0], number, description, type: :soft) + end + alias_method :describe_softbin, :describe_soft_bin + # Group all tests generated within the given block # # @example # flow.group "RAM Tests" do # flow.test ... @@ -238,10 +256,14 @@ end if options.delete(:continue) options[:on_fail] ||= {} options[:on_fail][:continue] = true end + if options.key?(:delayed) + options[:on_fail] ||= {} + options[:on_fail][:delayed] = options.delete(:delayed) + end if f = options.delete(:flag_pass) options[:on_pass] ||= {} options[:on_pass][:set_flag] = f end if f = options.delete(:flag_fail) @@ -274,16 +296,27 @@ levels.each do |l| children << level(l[:name], l[:value], l[:unit] || l[:units]) end end - if lims = options[:limit] || options[:limits] - lims = [lims] unless lims.is_a?(Array) - lims.each do |l| - if l.is_a?(Hash) - children << limit(l[:value], l[:rule], l[:unit] || l[:units]) + lims = options[:limit] || options[:limits] + if lims || options[:lo] || options[:low] || options[:hi] || options[:high] + if lims == :none || lims == 'none' + children << n0(:nolimits) + else + lims = Array(lims) unless lims.is_a?(Array) + if lo = options[:lo] || options[:low] + lims << { value: lo, rule: :gte } end + if hi = options[:hi] || options[:high] + lims << { value: hi, rule: :lte } + end + lims.each do |l| + if l.is_a?(Hash) + children << n(:limit, [l[:value], l[:rule], l[:unit] || l[:units], l[:selector]]) + end + end end end if pins = options[:pin] || options[:pins] pins = [pins] unless pins.is_a?(Array) @@ -448,10 +481,14 @@ def inspect "<ATP::Flow:#{object_id} #{name}>" end + def ids(options = {}) + ATP::AST::Extractor.new.process(raw, [:id]).map { |node| node.to_a[0] } + end + private def flow_control_method(name, flag, options = {}, &block) extract_meta!(options) if flag.is_a?(Array) @@ -615,10 +652,11 @@ end if options[:set_run_flag] || options[:set_flag] children << set_flag_node(options[:set_run_flag] || options[:set_flag]) end children << n0(:continue) if options[:continue] + children << n1(:delayed, !!options[:delayed]) if options.key?(:delayed) children << n1(:render, options[:render]) if options[:render] n(:on_fail, children) end end @@ -661,18 +699,10 @@ else n2(:level, name, value) end end - def limit(value, rule, units = nil) - if units - n(:limit, [value, rule, units]) - else - n2(:limit, value, rule) - end - end - def pin(name) n1(:pin, name) end def set_result(type, options = {}) @@ -713,9 +743,30 @@ flags.each do |flag| new << n1(:flag, flag) unless existing.include?(flag) end v = v.updated(nil, v.children + new) node.updated(nil, [name, v] + nodes) + end + + # Ensures the flow ast has a bin descriptions node, then adds the + # given description to it + def add_bin_description(node, number, description, options) + @existing_bin_descriptions ||= { soft: {}, hard: {} } + return node if @existing_bin_descriptions[options[:type]][number] + @existing_bin_descriptions[options[:type]][number] = true + name, *nodes = *node + if nodes[0] && nodes[0].type == :volatile + v = nodes.shift + else + v = nil + end + if nodes[0] && nodes[0].type == :bin_descriptions + d = nodes.shift + else + d = n0(:bin_descriptions) + end + d = d.updated(nil, d.children + [n2(options[:type], number, description)]) + node.updated(nil, [name, v, d].compact + nodes) end def n(type, children, options = {}) options[:file] ||= options.delete(:source_file) || source_file options[:line_number] ||= options.delete(:source_line_number) || source_line_number