require "spec"
require "csv"

describe CSV do
  describe "parse" do
    it "parses empty string" do
      CSV.parse("").should eq([] of String)
    end

    it "parses one simple row" do
      CSV.parse("hello,world").should eq([["hello", "world"]])
    end

    it "parses one row with spaces" do
      CSV.parse("   hello   ,   world  ").should eq([["   hello   ", "   world  "]])
    end

    it "parses two rows" do
      CSV.parse("hello,world\ngood,bye").should eq([
        ["hello", "world"],
        ["good", "bye"],
      ])
    end

    it "parses two rows with the last one having a newline" do
      CSV.parse("hello,world\ngood,bye\n").should eq([
        ["hello", "world"],
        ["good", "bye"],
      ])
    end

    it "parses with quote" do
      CSV.parse(%("hello","world")).should eq([["hello", "world"]])
    end

    it "parses with quote and newline" do
      CSV.parse(%("hello","world"\nfoo)).should eq([["hello", "world"], ["foo"]])
    end

    it "parses with double quote" do
      CSV.parse(%("hel""lo","wor""ld")).should eq([[%(hel"lo), %(wor"ld)]])
    end

    it "parses some commas" do
      CSV.parse(%(,,)).should eq([["", "", ""]])
    end

    it "parses empty quoted string" do
      CSV.parse(%("","")).should eq([["", ""]])
    end

    it "raises if single quote in the middle" do
      expect_raises CSV::MalformedCSVError, "Unexpected quote at line 1, column 4" do
        CSV.parse(%(hel"lo))
      end
    end

    it "raises if command, newline or end doesn't follow quote" do
      expect_raises CSV::MalformedCSVError, "Expecting comma, newline or end, not 'a' at line 2, column 6" do
        CSV.parse(%(foo\n"hel"a))
      end
    end

    it "raises if command, newline or end doesn't follow quote (2)" do
      expect_raises CSV::MalformedCSVError, "Expecting comma, newline or end, not 'a' at line 2, column 6" do
        CSV.parse(%(\n"hel"a))
      end
    end

    it "parses from IO" do
      CSV.parse(IO::Memory.new(%("hel""lo",world))).should eq([[%(hel"lo), %(world)]])
    end

    it "takes an optional separator argument" do
      CSV.parse("foo;bar", separator: ';').should eq([["foo", "bar"]])
    end

    it "takes an optional quote char argument" do
      CSV.parse("'foo,bar'", quote_char: '\'').should eq([["foo,bar"]])
    end
  end

  it "parses row by row" do
    parser = CSV::Parser.new("hello,world\ngood,bye\n")
    parser.next_row.should eq(%w(hello world))
    parser.next_row.should eq(%w(good bye))
    parser.next_row.should be_nil
  end

  it "does CSV.each_row" do
    sum = 0
    CSV.each_row("1,2\n3,4\n") do |row|
      sum += row.sum(&.to_i)
    end.should be_nil
    sum.should eq(10)
  end

  it "does CSV.each_row with separator and quotes" do
    sum = 0
    CSV.each_row("1\t'2'\n3\t4\n", '\t', '\'') do |row|
      sum += row.sum(&.to_i)
    end.should be_nil
    sum.should eq(10)
  end

  it "gets row iterator" do
    iter = CSV.each_row("1,2\n3,4\n")
    iter.next.should eq(["1", "2"])
    iter.next.should eq(["3", "4"])
    iter.next.should be_a(Iterator::Stop)
  end
end
