require "spec" require "csv" class CSV::Lexer def expect_cell(value, file = __FILE__, line = __LINE__) token = next_token token.kind.should eq(CSV::Token::Kind::Cell), file: file, line: line token.value.should eq(value), file: file, line: line end def expect_eof(file = __FILE__, line = __LINE__) next_token.kind.should eq(CSV::Token::Kind::Eof), file: file, line: line end def expect_newline(file = __FILE__, line = __LINE__) next_token.kind.should eq(CSV::Token::Kind::Newline), file: file, line: line end end describe CSV do describe "lex" do it "lexes two columns" do lexer = CSV::Lexer.new("hello,world") lexer.expect_cell "hello" lexer.expect_cell "world" lexer.expect_eof end it "lexes two columns with two rows" do lexer = CSV::Lexer.new("hello,world\nfoo,bar") lexer.expect_cell "hello" lexer.expect_cell "world" lexer.expect_newline lexer.expect_cell "foo" lexer.expect_cell "bar" lexer.expect_eof end it "lexes two columns with two rows with \r\n" do lexer = CSV::Lexer.new("hello,world\r\nfoo,bar") lexer.expect_cell "hello" lexer.expect_cell "world" lexer.expect_newline lexer.expect_cell "foo" lexer.expect_cell "bar" lexer.expect_eof end it "lexes two empty columns" do lexer = CSV::Lexer.new(",") lexer.expect_cell "" lexer.expect_cell "" lexer.expect_eof end it "lexes last empty column" do lexer = CSV::Lexer.new("foo,") lexer.expect_cell "foo" lexer.expect_cell "" lexer.expect_eof end it "lexes with empty columns" do lexer = CSV::Lexer.new("foo,,bar") lexer.expect_cell "foo" lexer.expect_cell "" lexer.expect_cell "bar" lexer.expect_eof end it "lexes with whitespace" do lexer = CSV::Lexer.new(" foo , bar ") lexer.expect_cell " foo " lexer.expect_cell " bar " lexer.expect_eof end it "lexes two with quotes" do lexer = CSV::Lexer.new(%("hello","world")) lexer.expect_cell "hello" lexer.expect_cell "world" lexer.expect_eof end it "lexes two with inner quotes" do lexer = CSV::Lexer.new(%("hel""lo","wor""ld")) lexer.expect_cell %(hel"lo) lexer.expect_cell %(wor"ld) lexer.expect_eof end it "lexes with comma inside quote" do lexer = CSV::Lexer.new(%("foo,bar")) lexer.expect_cell "foo,bar" lexer.expect_eof end it "lexes with newline inside quote" do lexer = CSV::Lexer.new(%("foo\nbar")) lexer.expect_cell "foo\nbar" lexer.expect_eof end it "lexes newline followed by eof" do lexer = CSV::Lexer.new("hello,world\n") lexer.expect_cell "hello" lexer.expect_cell "world" lexer.expect_newline lexer.expect_eof end it "lexes with a given separator" do lexer = CSV::Lexer.new("hello;world\n", separator: ';') lexer.expect_cell "hello" lexer.expect_cell "world" lexer.expect_newline lexer.expect_eof end it "lexes with a given quote char" do lexer = CSV::Lexer.new("'hello,world'\n", quote_char: '\'') lexer.expect_cell "hello,world" lexer.expect_newline lexer.expect_eof end it "raises if single quote in the middle" do expect_raises CSV::MalformedCSVError, "Unexpected quote at line 1, column 4" do lexer = CSV::Lexer.new %(hel"lo) lexer.next_token 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 1, column 6" do lexer = CSV::Lexer.new %("hel"a) lexer.next_token end end it "raises on unclosed quote" do expect_raises CSV::MalformedCSVError, "Unclosed quote at line 1, column 5" do lexer = CSV::Lexer.new %("foo) lexer.next_token end end it "doesn't consume char after \\n (#11172)" do io = IO::Memory.new("a\nx") lexer = CSV::Lexer.new(io) lexer.expect_cell "a" lexer.expect_newline io.pos.should eq(2) end it "doesn't consume char after \\r (#11172)" do io = IO::Memory.new("a\r\nx") lexer = CSV::Lexer.new(io) lexer.expect_cell "a" io.pos.should eq(2) lexer.expect_newline lexer.expect_cell "x" lexer.expect_eof end end end