
require File.dirname(__FILE__) + '/spec_helper'

module Terminal
  describe Table do
    before :each do
      @table = Table.new
    end
    
    it "should select columns" do
      @table << ['foo', 'bar']
      @table << ['big foo', 'big foo bar']
      @table.column(1).should == ['bar', 'big foo bar']
    end

    it "should select the column with headings at an index" do
      @table << [1,2,3]
      @table << [4,5,6]
      @table.column_with_headings(2).should == [3,6]
    end

    #it "should select the columns with colspans > 1 in the index" do
    #  @table << [1,{:value => 2, :colspan => 2}]
    #  @table << [{:value => 3, :colspan => 2}, 4]
    #end

    it "should account for the colspan when selecting columns" do
      @table << [1,2,3]
      @table << [{:value => "4,5", :colspan => 2}, 6]
      @table.column_with_headings(0).should == [1,"4,5"]
      @table.column_with_headings(1).should == [2,"4,5"]
      @table.column_with_headings(2).should == [3,6]
    end

    it "should render tables with colspan properly" do
      @table << [1,2,3]
      @table << [4,5,6]
      @table << [{:value => "7", :colspan => 2}, 88]
      @table.render.should == <<-EOF.deindent
        +---+---+----+
        | 1 | 2 | 3  |
        | 4 | 5 | 6  |
        | 7     | 88 |
        +---+---+----+
      EOF
    end

    it "should count columns" do
      @table << [1, 2, 3]
      @table.number_of_columns.should == 3
    end

    it "should iterate columns" do
      @table << [1, 2, 3]
      @table << [4, 5, 6]
      @table.columns.should == [[1, 4], [2, 5], [3, 6]]
    end

    it "should select columns" do
      @table.headings = ['one', 'two']
      @table << ['foo', 'bar']
      @table << ['big foo', 'big foo bar']
      @table.column(1).should == ['bar', 'big foo bar']
    end

    it "should select columns when using hashes" do
      @table.headings = ['one', 'two']
      @table.rows = [[{ :value => 'a', :align => :left }, 1], ['b', 2], ['c', 3]]
      @table.column(0).should == ['a', 'b', 'c']
    end

    it "should find column length" do
      @table << ['foo', 'bar', 'a']
      @table << ['big foo', 'big foo bar']
      @table.column_width(1).should == 11
    end

    it "should find column length with headings" do
      @table.headings = ['one', 'super long heading']
      @table << ['foo', 'bar', 'a']
      @table << ['big foo', 'big foo bar']
      @table.column_width(1).should == 18
    end

    it "should render separators" do
      @table.headings = ['Char', 'Num']
      @table << ['a', 1]
      separator = Terminal::Table::Separator.new(@table)
      separator.render.should == '+------+-----+'
    end

    it "should add separator" do
      @table << ['a', 1]
      @table.add_separator
      @table << ['b', 2]
      @table.rows.size.should == 2
    end

    it "should render an empty table properly" do
      @table.render.should == <<-EOF.deindent
        ++
        ++
      EOF
    end

    it "should render properly" do
      @table.headings = ['Char', 'Num']
      @table << ['a', 1]
      @table << ['b', 2]
      @table << ['c', 3]
      @table.render.should == <<-EOF.deindent
        +------+-----+
        | Char | Num |
        +------+-----+
        | a    | 1   |
        | b    | 2   |
        | c    | 3   |
        +------+-----+
      EOF
    end

    it "should render styles properly" do
      @table.headings = ['Char', 'Num']
      @table.style = {:border_x => "=", :border_y => ":", :border_i => "x", :padding_left => 0, :padding_right => 2}
      @table << ['a', 1]
      @table << ['b', 2]
      @table << ['c', 3]
      @table.style.padding_right.should == 2
      @table.render.should == <<-EOF.deindent
        x======x=====x
        :Char  :Num  :
        x======x=====x
        :a     :1    :
        :b     :2    :
        :c     :3    :
        x======x=====x
      EOF
    end


    it "should render default alignment properly" do
      @table.headings = ['Char', 'Num']
      @table << ['a', 1]
      @table << ['b', 2]
      @table << ['c', 3]
      @table.style.width = 21
      @table.style.alignment = :right
      @table.render.should == <<-EOF.deindent
        +---------+---------+
        |    Char |     Num |
        +---------+---------+
        |       a |       1 |
        |       b |       2 |
        |       c |       3 |
        +---------+---------+
      EOF
    end

    it "should render width properly" do
      @table.headings = ['Char', 'Num']
      @table << ['a', 1]
      @table << ['b', 2]
      @table << ['c', 3]
      @table.style.width = 21
      @table.render.should == <<-EOF.deindent
        +---------+---------+
        | Char    | Num     |
        +---------+---------+
        | a       | 1       |
        | b       | 2       |
        | c       | 3       |
        +---------+---------+
      EOF
    end

    it "should render title properly" do
      @table.title = "Title"
      @table.headings = ['Char', 'Num']
      @table << ['a', 1]
      @table << ['b', 2]
      @table << ['c', 3]
      @table.render.should == <<-EOF.deindent
        +------+-----+
        |   Title    |
        +------+-----+
        | Char | Num |
        +------+-----+
        | a    | 1   |
        | b    | 2   |
        | c    | 3   |
        +------+-----+
      EOF
    end

    it "should render properly without headings" do
      @table << ['a', 1]
      @table << ['b', 2]
      @table << ['c', 3]
      @table.render.should == <<-EOF.deindent
        +---+---+
        | a | 1 |
        | b | 2 |
        | c | 3 |
        +---+---+
      EOF
    end

    it "should render separators" do
      @table.headings = ['Char', 'Num']
      @table << ['a', 1]
      @table << ['b', 2]
      @table.add_separator
      @table << ['c', 3]
      @table.render.should == <<-EOF.deindent
        +------+-----+
        | Char | Num |
        +------+-----+
        | a    | 1   |
        | b    | 2   |
        +------+-----+
        | c    | 3   |
        +------+-----+
      EOF
    end

    it "should align columns with separators" do
      @table.headings = ['Char', 'Num']
      @table << ['a', 1]
      @table << ['b', 2]
      @table.add_separator
      @table << ['c', 3]
      @table.align_column 1, :right
      @table.render.should == <<-EOF.deindent
        +------+-----+
        | Char | Num |
        +------+-----+
        | a    |   1 |
        | b    |   2 |
        +------+-----+
        | c    |   3 |
        +------+-----+
      EOF
    end


    it "should render properly using block syntax" do
      table = Terminal::Table.new do |t|
        t << ['a', 1]
        t << ['b', 2]
        t << ['c', 3]
      end
      table.render.should == <<-EOF.deindent
        +---+---+
        | a | 1 |
        | b | 2 |
        | c | 3 |
        +---+---+
      EOF
    end

    it "should render properly using instance_eval block syntax" do
      table = Terminal::Table.new do
        add_row ['a', 1]
        add_row ['b', 2]
        add_row ['c', 3]
      end
      table.render.should == <<-EOF.deindent
        +---+---+
        | a | 1 |
        | b | 2 |
        | c | 3 |
        +---+---+
      EOF
    end

    it "should allows a hash of options for creation" do
      headings = ['Char', 'Num']
      rows = [['a', 1], ['b', 2], ['c', 3]]
      Terminal::Table.new(:rows => rows, :headings => headings).render.should == <<-EOF.deindent
        +------+-----+
        | Char | Num |
        +------+-----+
        | a    | 1   |
        | b    | 2   |
        | c    | 3   |
        +------+-----+
      EOF
    end

    it "should flex for large cells" do
      @table.headings = ['Just some characters', 'Num']
      @table.rows = [['a', 1], ['b', 2], ['c', 3]]
      @table.render.should == <<-EOF.deindent
        +----------------------+-----+
        | Just some characters | Num |
        +----------------------+-----+
        | a                    | 1   |
        | b                    | 2   |
        | c                    | 3   |
        +----------------------+-----+
      EOF
    end

    it "should allow alignment of headings and cells" do
      @table.headings = ['Characters', {:value => 'Nums', :alignment => :right} ]
      @table << [{:value => 'a', :alignment => :center}, 1]
      @table << ['b', 222222222222222]
      @table << ['c', 3]
      @table.render.should == <<-EOF.deindent
        +------------+-----------------+
        | Characters |            Nums |
        +------------+-----------------+
        |     a      | 1               |
        | b          | 222222222222222 |
        | c          | 3               |
        +------------+-----------------+
      EOF

    end

    it "should align columns, but allow specifics to remain" do
      @table.headings = ['Just some characters', 'Num']
      @table.rows = [[{:value => 'a', :alignment => :left}, 1], ['b', 2], ['c', 3]]
      @table.align_column 0, :center
      @table.align_column 1, :right
      @table.render.should == <<-EOF.deindent
        +----------------------+-----+
        | Just some characters | Num |
        +----------------------+-----+
        | a                    |   1 |
        |          b           |   2 |
        |          c           |   3 |
        +----------------------+-----+
      EOF
    end

    describe "#==" do
      it "should be equal to itself" do
        t = Table.new
        t.should == t
      end

     # it "should be equal with two empty tables" do
     #   table_one = Table.new
     #   table_two = Table.new
     # 
     #   table_one.should == table_two
     #   table_two.should == table_one
     # end

      it "should not be equal with different headings" do
        table_one = Table.new
        table_two = Table.new

        table_one.headings << "a"

        table_one.should_not == table_two
        table_two.should_not == table_one
      end

      it "should not be equal with different rows" do
        table_one = Table.new
        table_two = Table.new

        table_one.should_not == table_two
        table_two.should_not == table_one
      end

      it "should not be equal if the other object does not respond_to? :headings" do
        table_one = Table.new
        table_two = Object.new
        table_two.stub!(:rows).and_return([])
        table_one.should_not == table_two
      end

      it "should not be equal if the other object does not respond_to? :rows" do
        table_one = Table.new
        table_two = Object.new
        table_two.stub!(:rows).and_return([])
        table_one.should_not == table_two
      end
    end

    it "should handle colspan inside heading" do
      @table.headings = ['one', { :value => 'two', :alignment => :center, :colspan => 2}]
      @table.rows = [['a', 1, 2], ['b', 3, 4], ['c', 3, 4]]
      @table.render.should == <<-EOF.deindent
        +-----+---+---+
        | one |  two  |
        +-----+---+---+
        | a   | 1 | 2 |
        | b   | 3 | 4 |
        | c   | 3 | 4 |
        +-----+---+---+
      EOF
    end

    it "should handle colspan inside cells" do
      @table.headings = ['one', 'two', 'three']
      @table.rows = [['a', 1, 2], ['b', 3, 4], [{:value => "joined", :colspan => 2,:alignment => :center}, 'c']]
      @table.render.should == <<-EOF.deindent
        +-----+-----+-------+
        | one | two | three |
        +-----+-----+-------+
        | a   | 1   | 2     |
        | b   | 3   | 4     |
        |  joined   | c     |
        +-----+-----+-------+
      EOF
    end

    it "should handle colspan inside cells regardless of colspan position" do
      @table.headings = ['one', 'two', 'three']
      @table.rows = [['a', 1, 2], ['b', 3, 4], ['c', {:value => "joined", :colspan => 2,:alignment => :center}]]
      @table.render.should == <<-EOF.deindent
        +-----+-----+-------+
        | one | two | three |
        +-----+-----+-------+
        | a   | 1   | 2     |
        | b   | 3   | 4     |
        | c   |   joined    |
        +-----+-----+-------+
      EOF
    end

    it "should handle overflowing colspans" do
      @table.headings = ['one', 'two', 'three']
      @table.rows = [['a', 1, 2], ['b', 3, 4], ['c', {:value => "joined that is very very long", :colspan => 2,:alignment => :center}]]
      @table.render.should == <<-EOF.deindent
        +-----+---------------+---------------+
        | one | two           | three         |
        +-----+---------------+---------------+
        | a   | 1             | 2             |
        | b   | 3             | 4             |
        | c   | joined that is very very long |
        +-----+---------------+---------------+
      EOF
    end

    it "should only increase column size for multi-column if it is unavoidable" do
      @table << [12345,2,3]
      @table << [{:value => 123456789, :colspan => 2}, 4]
      @table.render.should == <<-EOF.deindent
        +-------+---+---+
        | 12345 | 2 | 3 |
        | 123456789 | 4 |
        +-------+---+---+
      EOF
    end


    it "should handle colspan 1" do
      @table.headings = ['name', { :value => 'values', :colspan => 1}]
      @table.rows = [['a', 1], ['b', 4], ['c', 7]]
      @table.render.should == <<-EOF.deindent
        +------+--------+
        | name | values |
        +------+--------+
        | a    | 1      |
        | b    | 4      |
        | c    | 7      |
        +------+--------+
      EOF
    end

    it "should handle big colspan" do
      @table.headings = ['name', { :value => 'values', :alignment => :right, :colspan => 3}]
      @table.headings = ['name', { :value => 'values', :colspan => 3}]
      @table.rows = [['a', 1, 2, 3], ['b', 4, 5, 6], ['c', 7, 8, 9]]
      
      @table.render.should == <<-EOF.deindent
        +------+---+---+---+
        | name | values    |
        +------+---+---+---+
        | a    | 1 | 2 | 3 |
        | b    | 4 | 5 | 6 |
        | c    | 7 | 8 | 9 |
        +------+---+---+---+
      EOF
    end
    
    it "should handle multiple colspan" do
      @table.headings = [
        'name',
        { :value => 'Values', :alignment => :right, :colspan => 2},
        { :value => 'Other values', :alignment => :right, :colspan => 2},
        { :value => 'Column 3', :alignment => :right, :colspan => 2}
      ]

      3.times do |row_index|
        row = ["row ##{row_index+1}"]
        6.times do |i|
          row << row_index*6 + i
        end
        @table.add_row(row)
      end

      @table.render.should == <<-EOF.deindent
        +--------+----+----+-------+-------+-----+-----+
        | name   |  Values |  Other values |  Column 3 |
        +--------+----+----+-------+-------+-----+-----+
        | row #1 | 0  | 1  | 2     | 3     | 4   | 5   |
        | row #2 | 6  | 7  | 8     | 9     | 10  | 11  |
        | row #3 | 12 | 13 | 14    | 15    | 16  | 17  |
        +--------+----+----+-------+-------+-----+-----+
      EOF
    end
    
    it "should render a table with only X cell borders" do
      @table.style = {:border_x => "-", :border_y => "", :border_i => ""}

      @table.headings = ['name', { :value => 'values', :alignment => :right, :colspan => 3}]
      @table.headings = ['name', { :value => 'values', :colspan => 3}]
      @table.rows = [['a', 1, 2, 3], ['b', 4, 5, 6], ['c', 7, 8, 9]]

      @table.render.should == <<-EOF.strip
---------------
 name  values  
---------------
 a     1  2  3 
 b     4  5  6 
 c     7  8  9 
---------------
      EOF
    end
    
    it "should render a table without cell borders" do
      @table.style = {:border_x => "", :border_y => "", :border_i => ""}

      @table.headings = ['name', { :value => 'values', :alignment => :right, :colspan => 3}]
      @table.headings = ['name', { :value => 'values', :colspan => 3}]
      @table.rows = [['a', 1, 2, 3], ['b', 4, 5, 6], ['c', 7, 8, 9]]

      @table.render.should == <<-EOF

 name  values  

 a     1  2  3 
 b     4  5  6 
 c     7  8  9 
      EOF
    end
  end
end
