# frozen_string_literal: true require 'cucumber/messages' module Gherkin module Pickles class Compiler def initialize(id_generator) @id_generator = id_generator end def compile(gherkin_document, source) pickles = [] return pickles unless gherkin_document.feature feature = gherkin_document.feature language = feature.language tags = feature.tags compile_feature(pickles, language, tags, feature, source) pickles end private def compile_feature(pickles, language, tags, feature, source) feature_background_steps = [] feature.children.each do |child| if child.background feature_background_steps.concat(child.background.steps) elsif child.rule compile_rule(pickles, language, tags, feature_background_steps, child.rule, source) else scenario = child.scenario if scenario.examples.empty? compile_scenario(tags, feature_background_steps, scenario, language, pickles, source) else compile_scenario_outline(tags, feature_background_steps, scenario, language, pickles, source) end end end end def compile_rule(pickles, language, feature_tags, feature_background_steps, rule, source) tags = [].concat(feature_tags).concat(rule.tags) rule_background_steps = feature_background_steps.dup rule.children.each do |child| if child.background rule_background_steps.concat(child.background.steps) else scenario = child.scenario if scenario.examples.empty? compile_scenario(tags, rule_background_steps, scenario, language, pickles, source) else compile_scenario_outline(tags, rule_background_steps, scenario, language, pickles, source) end end end end def compile_scenario(inherited_tags, background_steps, scenario, language, pickles, source) tags = [].concat(inherited_tags).concat(scenario.tags) last_keyword_type = Cucumber::Messages::PickleStepType::UNKNOWN steps = [] unless scenario.steps.empty? [].concat(background_steps).concat(scenario.steps).each do |step| last_keyword_type = if step.keyword_type == Cucumber::Messages::StepKeywordType::CONJUNCTION last_keyword_type else step.keyword_type end steps.push(Cucumber::Messages::PickleStep.new(**pickle_step_props(step, [], nil, last_keyword_type))) end end pickle = Cucumber::Messages::Pickle.new( uri: source.uri, id: @id_generator.new_id, tags: pickle_tags(tags), name: scenario.name, language: language, ast_node_ids: [scenario.id], steps: steps ) pickles.push(pickle) end def compile_scenario_outline(inherited_tags, background_steps, scenario, language, pickles, source) scenario.examples.reject { |examples| examples.table_header.nil? }.each do |examples| variable_cells = examples.table_header.cells examples.table_body.each do |values_row| value_cells = values_row.cells tags = [].concat(inherited_tags).concat(scenario.tags).concat(examples.tags) last_keyword_type = nil steps = [] unless scenario.steps.empty? background_steps.each do |step| last_keyword_type = if step.keyword_type == Cucumber::Messages::StepKeywordType::CONJUNCTION last_keyword_type else step.keyword_type end step_props = pickle_step_props(step, [], nil, last_keyword_type) steps.push(Cucumber::Messages::PickleStep.new(**step_props)) end scenario.steps.each do |step| last_keyword_type = if step.keyword_type == Cucumber::Messages::StepKeywordType::CONJUNCTION last_keyword_type else step.keyword_type end step_props = pickle_step_props(step, variable_cells, values_row, last_keyword_type) steps.push(Cucumber::Messages::PickleStep.new(**step_props)) end end pickle = Cucumber::Messages::Pickle.new( uri: source.uri, id: @id_generator.new_id, name: interpolate(scenario.name, variable_cells, value_cells), language: language, steps: steps, tags: pickle_tags(tags), ast_node_ids: [ scenario.id, values_row.id ] ) pickles.push(pickle) end end end def interpolate(name, variable_cells, value_cells) variable_cells.each_with_index do |variable_cell, n| value_cell = value_cells[n] name = name.gsub('<' + variable_cell.value + '>', value_cell.value) end name end def pickle_step_props(step, variable_cells, values_row, keyword_type) value_cells = values_row ? values_row.cells : [] props = { id: @id_generator.new_id, ast_node_ids: [step.id], type: keyword_type, text: interpolate(step.text, variable_cells, value_cells), } props[:ast_node_ids].push(values_row.id) if values_row if step.data_table data_table = Cucumber::Messages::PickleStepArgument.new( data_table: pickle_data_table(step.data_table, variable_cells, value_cells) ) props[:argument] = data_table end if step.doc_string doc_string = Cucumber::Messages::PickleStepArgument.new( doc_string: pickle_doc_string(step.doc_string, variable_cells, value_cells) ) props[:argument] = doc_string end props end def pickle_data_table(data_table, variable_cells, value_cells) Cucumber::Messages::PickleTable.new( rows: data_table.rows.map do |row| Cucumber::Messages::PickleTableRow.new( cells: row.cells.map do |cell| Cucumber::Messages::PickleTableCell.new( value: interpolate(cell.value, variable_cells, value_cells) ) end ) end ) end def pickle_doc_string(doc_string, variable_cells, value_cells) props = { content: interpolate(doc_string.content, variable_cells, value_cells) } props[:media_type] = interpolate(doc_string.media_type, variable_cells, value_cells) if doc_string.media_type Cucumber::Messages::PickleDocString.new(**props) end def pickle_tags(tags) tags.map { |tag| pickle_tag(tag) } end def pickle_tag(tag) Cucumber::Messages::PickleTag.new( name: tag.name, ast_node_id: tag.id ) end end end end