require "#{File.dirname(__FILE__)}/../spec_helper"


describe 'Cell, Integration' do

  let(:clazz) { CukeModeler::Cell }


  describe 'common behavior' do

    it_should_behave_like 'a model, integration'

  end


  describe 'unique behavior' do

    it 'can be instantiated with the minimum viable Gherkin' do
      source = ''

      expect { clazz.new(source) }.to_not raise_error
    end

    it 'provides a descriptive filename when being parsed from stand alone text' do
      source = "not a \n cell"

      expect { clazz.new(source) }.to raise_error(/'cuke_modeler_stand_alone_cell\.feature'/)
    end

    it 'stores the original data generated by the parsing adapter', :gherkin4 => true do
      cell = clazz.new('a cell')
      data = cell.parsing_data

      expect(data.keys).to match_array([:type, :location, :value])
      expect(data[:type]).to eq(:TableCell)
    end

    it 'stores the original data generated by the parsing adapter', :gherkin3 => true do
      cell = clazz.new("a cell")
      data = cell.parsing_data

      expect(data.keys).to match_array([:type, :location, :value])
      expect(data[:type]).to eq('TableCell')
    end

    it 'stores the original data generated by the parsing adapter', :gherkin2 => true do
      cell = clazz.new("a cell")
      data = cell.parsing_data

      # Cells did not exist as full fledged objects in the Gherkin2 parser
      expect(data).to eq('a cell')
    end


    describe 'getting ancestors' do

      before(:each) do
        source = ['Feature: Test feature',
                  '',
                  '  Scenario: Test test',
                  '    * a step',
                  '      | a value |']
        source = source.join("\n")

        file_path = "#{@default_file_directory}/cell_test_file.feature"
        File.open(file_path, 'w') { |file| file.write(source) }
      end

      let(:directory) { CukeModeler::Directory.new(@default_file_directory) }
      let(:cell) { directory.feature_files.first.feature.tests.first.steps.first.block.rows.first.cells.first }


      it 'can get its directory' do
        ancestor = cell.get_ancestor(:directory)

        expect(ancestor).to equal(directory)
      end

      it 'can get its feature file' do
        ancestor = cell.get_ancestor(:feature_file)

        expect(ancestor).to equal(directory.feature_files.first)
      end

      it 'can get its feature' do
        ancestor = cell.get_ancestor(:feature)

        expect(ancestor).to equal(directory.feature_files.first.feature)
      end

      context 'a cell that is part of an outline' do

        before(:each) do
          source = 'Feature: Test feature
                      
                      Scenario Outline: Test outline
                        * a step
                      Examples:
                        | param |
                        | value |'

          file_path = "#{@default_file_directory}/cell_test_file.feature"
          File.open(file_path, 'w') { |file| file.write(source) }
        end

        let(:directory) { CukeModeler::Directory.new(@default_file_directory) }
        let(:cell) { directory.feature_files.first.feature.tests.first.examples.first.rows.first.cells.first }


        it 'can get its outline' do
          ancestor = cell.get_ancestor(:outline)

          expect(ancestor).to equal(directory.feature_files.first.feature.tests.first)
        end

        it 'can get its example' do
          ancestor = cell.get_ancestor(:example)

          expect(ancestor).to equal(directory.feature_files.first.feature.tests.first.examples.first)
        end

        it 'can get its row' do
          ancestor = cell.get_ancestor(:row)

          expect(ancestor).to equal(directory.feature_files.first.feature.tests.first.examples.first.rows.first)
        end

      end


      context 'a cell that is part of a scenario' do

        before(:each) do
          source = 'Feature: Test feature

                      Scenario: Test test
                        * a step:
                          | a | table |'

          file_path = "#{@default_file_directory}/cell_test_file.feature"
          File.open(file_path, 'w') { |file| file.write(source) }
        end

        let(:directory) { CukeModeler::Directory.new(@default_file_directory) }
        let(:cell) { directory.feature_files.first.feature.tests.first.steps.first.block.rows.first.cells.first }


        it 'can get its scenario' do
          ancestor = cell.get_ancestor(:scenario)

          expect(ancestor).to equal(directory.feature_files.first.feature.tests.first)
        end

      end

      context 'a cell that is part of a background' do

        before(:each) do
          source = 'Feature: Test feature

                      Background: Test background
                        * a step:
                          | a | table |'

          file_path = "#{@default_file_directory}/cell_test_file.feature"
          File.open(file_path, 'w') { |file| file.write(source) }
        end

        let(:directory) { CukeModeler::Directory.new(@default_file_directory) }
        let(:cell) { directory.feature_files.first.feature.background.steps.first.block.rows.first.cells.first }


        it 'can get its background' do
          ancestor = cell.get_ancestor(:background)

          expect(ancestor).to equal(directory.feature_files.first.feature.background)
        end

      end

      context 'a cell that is part of a step' do

        before(:each) do
          source = 'Feature: Test feature

                      Scenario: Test test
                        * a step:
                          | a | table |'

          file_path = "#{@default_file_directory}/cell_test_file.feature"
          File.open(file_path, 'w') { |file| file.write(source) }
        end

        let(:directory) { CukeModeler::Directory.new(@default_file_directory) }
        let(:cell) { directory.feature_files.first.feature.tests.first.steps.first.block.rows.first.cells.first }


        it 'can get its step' do
          ancestor = cell.get_ancestor(:step)

          expect(ancestor).to equal(directory.feature_files.first.feature.tests.first.steps.first)
        end

        it 'can get its table' do
          ancestor = cell.get_ancestor(:table)

          expect(ancestor).to equal(directory.feature_files.first.feature.tests.first.steps.first.block)
        end

        it 'can get its row' do
          ancestor = cell.get_ancestor(:row)

          expect(ancestor).to equal(directory.feature_files.first.feature.tests.first.steps.first.block.rows.first)
        end

      end

      it 'returns nil if it does not have the requested type of ancestor' do
        ancestor = cell.get_ancestor(:example)

        expect(ancestor).to be_nil
      end

    end


    describe 'model population' do

      context 'from source text' do

        let(:source_text) { 'a cell' }
        let(:cell) { clazz.new(source_text) }


        it "models the cell's value" do
          expect(cell.value).to eq('a cell')
        end

        it "models the cell's source line" do
          source_text = 'Feature:

                           Scenario:
                             * a step
                               | value |'
          cell = CukeModeler::Feature.new(source_text).tests.first.steps.first.block.rows.first.cells.first

          expect(cell.source_line).to eq(5)
        end

      end

    end


    describe 'cell output' do

      it 'can be remade from its own output' do
        source = 'a \\\\ complex \| cell'
        cell = clazz.new(source)

        cell_output = cell.to_s
        remade_cell_output = clazz.new(cell_output).to_s

        expect(remade_cell_output).to eq(cell_output)
      end


      context 'from source text' do

        it 'can output a cell' do
          source = 'a cell'
          cell = clazz.new(source)

          expect(cell.to_s).to eq('a cell')
        end

        #  Because vertical bars mark the beginning and end of a cell, any vertical bars inside
        #  of the cell (which would have had to have been escaped to get inside of the cell in
        #  the first place) will be escaped when outputted so as to retain the quality of being
        #  able to use the output directly as Gherkin.

        it 'can output a cell that has vertical bars in it' do
          source = 'cell with a \| in it'
          cell = clazz.new(source)

          cell_output = cell.to_s

          expect(cell_output).to eq('cell with a \| in it')
        end

        #  Because backslashes are used to escape special characters, any backslashes inside
        #  of the cell (which would have had to have been escaped to get inside of the cell in
        #  the first place) will be escaped when outputted so as to retain the quality of being
        #  able to use the output directly as Gherkin.

        it 'can output a cell that has backslashes in it' do
          source = 'cell with a \\\\ in it'
          cell = clazz.new(source)

          cell_output = cell.to_s

          expect(cell_output).to eq('cell with a \\\\ in it')
        end

        # Depending on the order in which special characters are escaped, extra backslashes might occur.
        it 'can output a cell that has several kinds of special characters in it' do
          source = 'cell with a \\\\ and \| in it'
          cell = clazz.new(source)

          cell_output = cell.to_s

          expect(cell_output).to eq('cell with a \\\\ and \| in it')
        end

      end

    end

  end

end