enkessler/cuke_linter

View on GitHub
lib/cuke_linter/linters/test_should_use_background_linter.rb

Summary

Maintainability
A
1 hr
Test Coverage
# TODO: Make a new class that it is from the POV of a Feature model instead

module CukeLinter

  # A linter that detects scenarios and outlines within a feature that all share common beginning steps
  class TestShouldUseBackgroundLinter < Linter

    # The rule used to determine if a model has a problem
    def rule(model)
      return false unless model.is_a?(CukeModeler::Scenario) || model.is_a?(CukeModeler::Outline)

      model_steps          = model.steps || []
      parent_feature_model = model.get_ancestor(:feature)

      return false unless parent_feature_model.tests.count > 1

      matching_steps     = all_first_steps_match?(parent_feature_model, model_steps)
      none_parameterized = no_parameterized_steps?(parent_feature_model)

      matching_steps && none_parameterized
    end

    # The message used to describe the problem that has been found
    def message
      'Test shares steps with all other tests in feature. Use a background.'
    end


    private


    def all_first_steps_match?(feature_model, model_steps)
      feature_model.tests.all? do |test|
        test_steps = test.steps || []
        test_steps.first == model_steps.first
      end
    end

    def no_parameterized_steps?(feature_model)
      feature_model.tests.none? do |test|
        next false if test.is_a?(CukeModeler::Scenario)

        test_steps          = test.steps || []
        params_used_by_test = test.examples.map(&:parameters).flatten.uniq

        next false unless test_steps.any?

        parameterized_step?(test_steps.first, parameters: params_used_by_test)
      end
    end

    def parameterized_step?(step_model, parameters:)
      parameters.any? do |parameter|
        parameter_string = "<#{parameter}>"

        parameterized_text?(step_model, parameter_string) ||
          parameterized_doc_string?(step_model, parameter_string) ||
          parameterized_table?(step_model, parameter_string)
      end
    end

    def parameterized_text?(step_model, parameter)
      step_model.text.include?(parameter)
    end

    def parameterized_doc_string?(step_model, parameter)
      return false unless step_model.block.is_a?(CukeModeler::DocString)

      step_model.block.content.include?(parameter)
    end

    def parameterized_table?(step_model, parameter)
      return false unless step_model.block.is_a?(CukeModeler::Table)

      step_model.block.rows.map(&:cells).flatten.map(&:value).any? { |cell_text| cell_text.include?(parameter) }
    end

  end

end