r-cochran/cuke_sniffer

View on GitHub
lib/cuke_sniffer/cuke_sniffer_helper.rb

Summary

Maintainability
A
1 hr
Test Coverage
module CukeSniffer
  # Author::    Robert Cochran  (mailto:cochrarj@miamioh.edu)
  # Copyright:: Copyright (C) 2014 Robert Cochran
  # License::   Distributes under the MIT License
  # Static class used for aiding cuke_sniffer in various tasks
  class CukeSnifferHelper

    # Iterates over the passed features list and returns all steps found in scenarios and backgrounds.
    def self.extract_steps_from_features(features)
      steps = {}
      features.each do |feature|
        steps.merge! extract_scenario_steps(feature.background) unless feature.background.nil?
        feature.scenarios.each do |scenario|
          if scenario.type == "Scenario Outline"
            steps.merge! extract_scenario_outline_steps(scenario)
          else
            steps.merge! extract_scenario_steps(scenario)
          end
        end
      end
      steps
    end

    # Iterates over the passed features list and returns all scenarios and backgrounds found.
    def self.get_all_scenarios(features)
      scenarios = []
      features.each do |feature|
        scenarios << feature.background unless feature.background.nil?
        scenarios << feature.scenarios
      end
      scenarios.flatten
    end

    # Grabs the values from an example without the bars
    def self.extract_variables_from_example(example)
      example = example[example.index('|')..example.length]
      example.split(/\s*\|\s*/) - [""]
    end

    # Creates a step call from the details of an example table
    def self.build_updated_step_from_example(step, variable_list, row_variables)
      new_step = step.dup
      variable_list.each do |variable|
        if step.include? variable
          table_variable_to_insert = row_variables[variable_list.index(variable)]
          table_variable_to_insert ||= ""
          new_step.gsub!("<#{variable}>", table_variable_to_insert)
        end
      end
      new_step
    end

    # Creates a hash of steps with the build up example step calls.
    def self.extract_scenario_outline_steps(scenario)
      steps = {}
      examples = scenario.examples_table
      return {} if examples.empty?
      variable_list = extract_variables_from_example(examples.first)
      (1...examples.size).each do |example_counter|
        #TODO Abstraction needed for this regex matcher (constants?)
        next if examples[example_counter] =~ /^\#.*$/
        row_variables = extract_variables_from_example(examples[example_counter])
        step_counter = 1
        scenario.steps.each do |step|
          step_line = scenario.start_line + step_counter
          location = "#{scenario.location.gsub(/\d+$/, step_line.to_s)}(Example #{example_counter})"
          steps[location] = build_updated_step_from_example(step, variable_list, row_variables)
          step_counter += 1
        end
      end
      steps
    end

    # Returns all steps found in a scenario
    def self.extract_scenario_steps(scenario)
      steps_hash = {}
      counter = 1
      scenario.steps.each do |step|
        location = scenario.location.gsub(/:\d*$/, ":#{scenario.start_line + counter}")
        steps_hash[location] = step
        counter += 1
      end
      steps_hash
    end

    # Builds a list of rule objects out of a hash. See CukeSniffer::RulesConfig for hash example.
    def self.build_rules(rules)
      return [] if rules.nil?
      rules.collect do |symbol, value|
        CukeSniffer::CukeSnifferHelper.build_rule(symbol, value)
      end
    end

    # Builds rule object out of a hash. See CukeSniffer::RulesConfig for hash example.
    def self.build_rule(symbol, rule_hash)
      rule = CukeSniffer::Rule.new
      rule.symbol = symbol
      rule.phrase = rule_hash[:phrase]
      rule.score = rule_hash[:score]
      rule.enabled = rule_hash[:enabled]
      conditional_keys = rule_hash.keys - [:phrase, :score, :enabled, :targets, :reason]
      conditions = {}
      conditional_keys.each do |key|
        conditions[key] = (rule_hash[key].kind_of? Array) ? Array.new(rule_hash[key]) : rule_hash[key]
      end
      rule.conditions = conditions
      rule.reason = rule_hash[:reason]
      rule.targets = rule_hash[:targets]
      rule
    end

    # Returns a list of all nested step calls found in a step definition.
    def self.extract_steps_from_step_definitions(step_definitions)
      steps = {}
      step_definitions.each do |definition|
        definition.nested_steps.each do |location, step|
          steps[location] = step
        end
      end
      steps
    end

    # Returns a fuzzy match for a step definition for cataloging steps.
    def self.convert_steps_with_expressions(steps_with_expressions)
      step_regex_hash = {}
      steps_with_expressions.each do |step_location, step_value|
        modified_step = step_value.gsub(/\#{[^}]*}/, '.*')
        next if modified_step == '.*'
        step_regex_hash[step_location] = Regexp.new('^' + modified_step + '$')
      end
      step_regex_hash
    end

    # Extracts all possible step calls from the passed features and step definitions.
    def self.get_all_steps(features, step_definitions)
      feature_steps = CukeSniffer::CukeSnifferHelper.extract_steps_from_features(features)
      step_definition_steps = CukeSniffer::CukeSnifferHelper.extract_steps_from_step_definitions(step_definitions)
      feature_steps.merge step_definition_steps
    end

    # Applies all possible fuzzy calls to a step definition.
    def self.catalog_possible_dead_steps(step_definitions, steps_with_expressions)
      step_definitions.each do |step_definition|
        next unless step_definition.calls.empty?
        regex_as_string = step_definition.regex.to_s.gsub(/\(\?-mix:\^?/, "").gsub(/\$\)$/, "")
        steps_with_expressions.each do |step_location, step_value|
          if regex_as_string =~ step_value
            step_definition.add_call(step_location, step_value)
          end
        end
      end
      step_definitions
    end

    # Returns a list of all step definitions with a capture group
    def self.get_steps_with_expressions(steps)
      steps_with_expressions = {}
      steps.each do |step_location, step_value|
        if step_value =~ /\#{.*}/
          steps_with_expressions[step_location] = step_value
        end
      end
      steps_with_expressions
    end

  end
end