#include #include #include #include "csv.h" using namespace std; using namespace testing; TEST(TestEmptyObject, StandardInitialization) { csv_t csv{}; ASSERT_THAT(csv_nfields(&csv), Eq(0)); } TEST(TestEmptyObject, ExplicitInitialization) { csv_t csv; csv_init(&csv); ASSERT_THAT(csv_nfields(&csv), Eq(0)); } class TestLineEndingsBase : public Test { using file_ptr = unique_ptr; public: explicit TestLineEndingsBase(string_view data) : data_{ data } , file_{ fmemopen(data_.data(), data_.size(), "r"), &fclose } { csv_init(&csv_); } TestLineEndingsBase(string_view data, csv_options_t &csv_options) : data_{ data } , file_{ fmemopen(data_.data(), data_.size(), "r"), &fclose } { csv_init_opt(&csv_, &csv_options); } ~TestLineEndingsBase() override { csv_cleanup(&csv_); } TestLineEndingsBase(const TestLineEndingsBase &) = delete; TestLineEndingsBase(TestLineEndingsBase &&) = delete; void operator=(const TestLineEndingsBase &) = delete; void operator=(TestLineEndingsBase &&) = delete; csv_t csv_{}; string data_; file_ptr file_; }; class TestLineEndings : public TestLineEndingsBase { protected: TestLineEndings() : TestLineEndingsBase("A,B,C\r\nD,E,F\n") { } }; TEST_F(TestLineEndings, Part1) { EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(3)); EXPECT_THAT(csv_nfields(&csv_), Eq(3)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); EXPECT_STREQ(csv_field(&csv_, 1), "B"); EXPECT_STREQ(csv_field(&csv_, 2), "C"); EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(3)); EXPECT_THAT(csv_nfields(&csv_), Eq(3)); EXPECT_STREQ(csv_field(&csv_, 0), "D"); EXPECT_STREQ(csv_field(&csv_, 1), "E"); EXPECT_STREQ(csv_field(&csv_, 2), "F"); EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(0)); } class TestEmptyLinesWithDifferentLineEndings : public TestLineEndingsBase { protected: TestEmptyLinesWithDifferentLineEndings() : TestLineEndingsBase("\r\n\n") { } }; TEST_F(TestEmptyLinesWithDifferentLineEndings, Part1) { EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(1)); EXPECT_THAT(csv_nfields(&csv_), Eq(1)); EXPECT_STREQ(csv_field(&csv_, 0), ""); EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(1)); EXPECT_THAT(csv_nfields(&csv_), Eq(1)); EXPECT_STREQ(csv_field(&csv_, 0), ""); EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(0)); } class TestEmptyFieldsWithDifferentLineEndings : public TestLineEndingsBase { // NOLINTBEGIN constexpr static const char *data = "\n" // L1 "\r" // L2 "\r\n" // L3 "\"\"\n" // L4 "\"\"\r" // L5 "\"\"\r\n" // L6 ",\n" // L7 ",\r" // L8 ",\r\n" // L9 "\"\",\"\"\n" // L10 "\"\",\"\"\r" // L11 "\"\",\"\"\r\n" // L12 ",,\n" // L13 ",,\r" // L14 ",,\r\n" // L15 "\"\",\"\",\n" // L16 "\"\",\"\",\r" // L17 "\"\",\"\",\r\n" // L18 ",,"; // L19 // NOLINTEND protected: TestEmptyFieldsWithDifferentLineEndings() : TestLineEndingsBase(data) { } }; TEST_F(TestEmptyFieldsWithDifferentLineEndings, Part1) { // Line 1 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(1)); EXPECT_THAT(csv_nfields(&csv_), Eq(1)); EXPECT_STREQ(csv_field(&csv_, 0), ""); // Line 2 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(1)); EXPECT_THAT(csv_nfields(&csv_), Eq(1)); EXPECT_STREQ(csv_field(&csv_, 0), ""); // Line 3 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(1)); EXPECT_THAT(csv_nfields(&csv_), Eq(1)); EXPECT_STREQ(csv_field(&csv_, 0), ""); // Line 4 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(1)); EXPECT_THAT(csv_nfields(&csv_), Eq(1)); EXPECT_STREQ(csv_field(&csv_, 0), ""); // Line 5 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(1)); EXPECT_THAT(csv_nfields(&csv_), Eq(1)); EXPECT_STREQ(csv_field(&csv_, 0), ""); // Line 6 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(1)); EXPECT_THAT(csv_nfields(&csv_), Eq(1)); EXPECT_STREQ(csv_field(&csv_, 0), ""); // Line 7 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(2)); EXPECT_THAT(csv_nfields(&csv_), Eq(2)); EXPECT_STREQ(csv_field(&csv_, 0), ""); EXPECT_STREQ(csv_field(&csv_, 1), ""); // Line 8 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(2)); EXPECT_THAT(csv_nfields(&csv_), Eq(2)); EXPECT_STREQ(csv_field(&csv_, 0), ""); EXPECT_STREQ(csv_field(&csv_, 1), ""); // Line 9 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(2)); EXPECT_THAT(csv_nfields(&csv_), Eq(2)); EXPECT_STREQ(csv_field(&csv_, 0), ""); EXPECT_STREQ(csv_field(&csv_, 1), ""); // Line 10 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(2)); EXPECT_THAT(csv_nfields(&csv_), Eq(2)); EXPECT_STREQ(csv_field(&csv_, 0), ""); EXPECT_STREQ(csv_field(&csv_, 1), ""); // Line 11 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(2)); EXPECT_THAT(csv_nfields(&csv_), Eq(2)); EXPECT_STREQ(csv_field(&csv_, 0), ""); EXPECT_STREQ(csv_field(&csv_, 1), ""); // Line 12 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(2)); EXPECT_THAT(csv_nfields(&csv_), Eq(2)); EXPECT_STREQ(csv_field(&csv_, 0), ""); EXPECT_STREQ(csv_field(&csv_, 1), ""); // Line 13 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(3)); EXPECT_THAT(csv_nfields(&csv_), Eq(3)); EXPECT_STREQ(csv_field(&csv_, 0), ""); EXPECT_STREQ(csv_field(&csv_, 1), ""); EXPECT_STREQ(csv_field(&csv_, 2), ""); // Line 14 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(3)); EXPECT_THAT(csv_nfields(&csv_), Eq(3)); EXPECT_STREQ(csv_field(&csv_, 0), ""); EXPECT_STREQ(csv_field(&csv_, 1), ""); EXPECT_STREQ(csv_field(&csv_, 2), ""); // Line 15 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(3)); EXPECT_THAT(csv_nfields(&csv_), Eq(3)); EXPECT_STREQ(csv_field(&csv_, 0), ""); EXPECT_STREQ(csv_field(&csv_, 1), ""); EXPECT_STREQ(csv_field(&csv_, 2), ""); // Line 16 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(3)); EXPECT_THAT(csv_nfields(&csv_), Eq(3)); EXPECT_STREQ(csv_field(&csv_, 0), ""); EXPECT_STREQ(csv_field(&csv_, 1), ""); EXPECT_STREQ(csv_field(&csv_, 2), ""); // Line 17 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(3)); EXPECT_THAT(csv_nfields(&csv_), Eq(3)); EXPECT_STREQ(csv_field(&csv_, 0), ""); EXPECT_STREQ(csv_field(&csv_, 1), ""); EXPECT_STREQ(csv_field(&csv_, 2), ""); // Line 18 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(3)); EXPECT_THAT(csv_nfields(&csv_), Eq(3)); EXPECT_STREQ(csv_field(&csv_, 0), ""); EXPECT_STREQ(csv_field(&csv_, 1), ""); EXPECT_STREQ(csv_field(&csv_, 2), ""); // Line 19 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(3)); EXPECT_THAT(csv_nfields(&csv_), Eq(3)); EXPECT_STREQ(csv_field(&csv_, 0), ""); EXPECT_STREQ(csv_field(&csv_, 1), ""); EXPECT_STREQ(csv_field(&csv_, 2), ""); // EOF EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(0)); EXPECT_THAT(csv_nfields(&csv_), Eq(0)); } class TestFieldsWithDifferentLineEndings : public TestLineEndingsBase { // NOLINTBEGIN static constexpr const char *data = "A\n" // L1 "A\r" // L2 "A\r\n" // L3 "\"A\"\n" // L4 "\"A\"\r" // L5 "\"A\"\r\n" // L6 "A,B\n" // L7 "A,B\r" // L8 "A,B\r\n" // L9 "\"A\",\"B\"\n" // L10 "\"A\",\"B\"\r" // L11 "\"A\",\"B\"\r\n" // L12 "A,B,C\n" // L13 "A,B,C\r" // L14 "A,B,C\r\n" // L15 "\"A\",\"B\",C\n" // L16 "\"A\",\"B\",C\r" // L17 "\"A\",\"B\",C\r\n" // L18 "A,B,C"; // L19 // NOLINTEND protected: TestFieldsWithDifferentLineEndings() : TestLineEndingsBase(data) { } }; TEST_F(TestFieldsWithDifferentLineEndings, Part1) { // Line 1 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(1)); EXPECT_THAT(csv_nfields(&csv_), Eq(1)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); // Line 2 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(1)); EXPECT_THAT(csv_nfields(&csv_), Eq(1)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); // Line 3 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(1)); EXPECT_THAT(csv_nfields(&csv_), Eq(1)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); // Line 4 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(1)); EXPECT_THAT(csv_nfields(&csv_), Eq(1)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); // Line 5 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(1)); EXPECT_THAT(csv_nfields(&csv_), Eq(1)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); // Line 6 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(1)); EXPECT_THAT(csv_nfields(&csv_), Eq(1)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); // Line 7 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(2)); EXPECT_THAT(csv_nfields(&csv_), Eq(2)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); EXPECT_STREQ(csv_field(&csv_, 1), "B"); // Line 8 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(2)); EXPECT_THAT(csv_nfields(&csv_), Eq(2)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); EXPECT_STREQ(csv_field(&csv_, 1), "B"); // Line 9 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(2)); EXPECT_THAT(csv_nfields(&csv_), Eq(2)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); EXPECT_STREQ(csv_field(&csv_, 1), "B"); // Line 10 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(2)); EXPECT_THAT(csv_nfields(&csv_), Eq(2)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); EXPECT_STREQ(csv_field(&csv_, 1), "B"); // Line 11 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(2)); EXPECT_THAT(csv_nfields(&csv_), Eq(2)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); EXPECT_STREQ(csv_field(&csv_, 1), "B"); // Line 12 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(2)); EXPECT_THAT(csv_nfields(&csv_), Eq(2)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); EXPECT_STREQ(csv_field(&csv_, 1), "B"); // Line 13 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(3)); EXPECT_THAT(csv_nfields(&csv_), Eq(3)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); EXPECT_STREQ(csv_field(&csv_, 1), "B"); EXPECT_STREQ(csv_field(&csv_, 2), "C"); // Line 14 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(3)); EXPECT_THAT(csv_nfields(&csv_), Eq(3)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); EXPECT_STREQ(csv_field(&csv_, 1), "B"); EXPECT_STREQ(csv_field(&csv_, 2), "C"); // Line 15 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(3)); EXPECT_THAT(csv_nfields(&csv_), Eq(3)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); EXPECT_STREQ(csv_field(&csv_, 1), "B"); EXPECT_STREQ(csv_field(&csv_, 2), "C"); // Line 16 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(3)); EXPECT_THAT(csv_nfields(&csv_), Eq(3)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); EXPECT_STREQ(csv_field(&csv_, 1), "B"); EXPECT_STREQ(csv_field(&csv_, 2), "C"); // Line 17 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(3)); EXPECT_THAT(csv_nfields(&csv_), Eq(3)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); EXPECT_STREQ(csv_field(&csv_, 1), "B"); EXPECT_STREQ(csv_field(&csv_, 2), "C"); // Line 18 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(3)); EXPECT_THAT(csv_nfields(&csv_), Eq(3)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); EXPECT_STREQ(csv_field(&csv_, 1), "B"); EXPECT_STREQ(csv_field(&csv_, 2), "C"); // Line 19 EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(3)); EXPECT_THAT(csv_nfields(&csv_), Eq(3)); EXPECT_STREQ(csv_field(&csv_, 0), "A"); EXPECT_STREQ(csv_field(&csv_, 1), "B"); EXPECT_STREQ(csv_field(&csv_, 2), "C"); // EOF EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(0)); EXPECT_THAT(csv_nfields(&csv_), Eq(0)); } class TestQuotedFields : public TestLineEndingsBase { // NOLINTBEGIN static constexpr const char *data = "foo \"baz\" bar,foo \"\"baz\"\" bar,\"foo \"\"baz\"\" bar\",\"foo \"baz\" bar\",\"foo \"\"baz\"\", bar\""; // NOLINTEND protected: TestQuotedFields() : TestLineEndingsBase(data) { } }; TEST_F(TestQuotedFields, Part1) { EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(5)); EXPECT_THAT(csv_nfields(&csv_), Eq(5)); EXPECT_STREQ(csv_field(&csv_, 0), "foo \"baz\" bar"); EXPECT_STREQ(csv_field(&csv_, 1), "foo \"\"baz\"\" bar"); EXPECT_STREQ(csv_field(&csv_, 2), "foo \"baz\" bar"); EXPECT_STREQ(csv_field(&csv_, 3), "foo \"baz\" bar"); EXPECT_STREQ(csv_field(&csv_, 4), "foo \"baz\", bar"); EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(0)); EXPECT_THAT(csv_nfields(&csv_), Eq(0)); } class TestWrongQuotedFields : public TestLineEndingsBase { protected: TestWrongQuotedFields() : TestLineEndingsBase("\"foo") { } }; TEST_F(TestWrongQuotedFields, Part1) { EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(1)); EXPECT_THAT(csv_nfields(&csv_), Eq(1)); EXPECT_STREQ(csv_field(&csv_, 0), "foo"); EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(0)); EXPECT_THAT(csv_nfields(&csv_), Eq(0)); } class TestOutOfRangeError : public TestLineEndingsBase { protected: TestOutOfRangeError() : TestLineEndingsBase(",") { csv_options.cb_error = &cb_error; csv_init_opt(&csv_, &csv_options); } static void cb_error(csv_err_t /*unused*/, void * /*unused*/) { throw out_of_range("out of range"); } csv_options_t csv_options{ csv_default_options }; }; TEST_F(TestOutOfRangeError, Part1) { EXPECT_THAT(csv_read(&csv_, file_.get()), Eq(2)); EXPECT_THAT(csv_nfields(&csv_), Eq(2)); EXPECT_THROW({ csv_field(&csv_, 2); }, out_of_range); }