From e6352f54979a40919388a9c0ffe982b9adfbe33f Mon Sep 17 00:00:00 2001 From: Christopher Lam Date: Sat, 1 Apr 2023 13:51:14 +0800 Subject: [PATCH] [csv-export-helpers.cpp] helper function and full test suite --- gnucash/import-export/csv-exp/CMakeLists.txt | 5 + .../csv-exp/csv-export-helpers.cpp | 84 +++++++++++++++++ .../csv-exp/csv-export-helpers.hpp | 39 ++++++++ .../import-export/csv-exp/test/CMakeLists.txt | 25 +++++ .../csv-exp/test/test-csv-export-helpers.cpp | 92 +++++++++++++++++++ po/POTFILES.in | 1 + 6 files changed, 246 insertions(+) create mode 100644 gnucash/import-export/csv-exp/csv-export-helpers.cpp create mode 100644 gnucash/import-export/csv-exp/csv-export-helpers.hpp create mode 100644 gnucash/import-export/csv-exp/test/CMakeLists.txt create mode 100644 gnucash/import-export/csv-exp/test/test-csv-export-helpers.cpp diff --git a/gnucash/import-export/csv-exp/CMakeLists.txt b/gnucash/import-export/csv-exp/CMakeLists.txt index be95550015..61ae73e292 100644 --- a/gnucash/import-export/csv-exp/CMakeLists.txt +++ b/gnucash/import-export/csv-exp/CMakeLists.txt @@ -1,5 +1,9 @@ + +add_subdirectory(test) + set(csv_export_SOURCES gnc-plugin-csv-export.c + csv-export-helpers.cpp assistant-csv-export.c csv-tree-export.c csv-transactions-export.c @@ -11,6 +15,7 @@ set_source_files_properties (${csv_export_SOURCES} PROPERTIES OBJECT_DEPENDS ${C set(csv_export_noinst_HEADERS gnc-plugin-csv-export.h assistant-csv-export.h + csv-export-helpers.hpp csv-tree-export.h csv-transactions-export.h ) diff --git a/gnucash/import-export/csv-exp/csv-export-helpers.cpp b/gnucash/import-export/csv-exp/csv-export-helpers.cpp new file mode 100644 index 0000000000..f39953636b --- /dev/null +++ b/gnucash/import-export/csv-exp/csv-export-helpers.cpp @@ -0,0 +1,84 @@ +/*******************************************************************\ + * csv-export-helpers.c -- Functions to assist csv export * + * * + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * + * Boston, MA 02110-1301, USA gnu@gnu.org * +\********************************************************************/ +/** @file csv-export-helprs.cpp + @brief CSV Export helper functions + @author Christopher Lam +*/ +#include + +#include +#include +#include +#include + +#include "gnc-ui-util.h" +#include "csv-export-helpers.hpp" + +/* This static indicates the debugging module that this .o belongs to. */ +[[maybe_unused]] static QofLogModule log_module = GNC_MOD_ASSISTANT; + +/* CSV spec requires CRLF line endings. Tweak the end-of-line string so this + * true for each platform */ +#ifdef G_OS_WIN32 +# define EOLSTR "\n" +#else +# define EOLSTR "\r\n" +#endif + +#define QUOTE '"' + +bool +gnc_csv_add_line (std::ostream& ss, const StringVec& str_vec, + bool use_quotes, const char* sep) +{ + auto first{true}; + auto sep_view{std::string_view (sep ? sep : "")}; + for (const auto& str : str_vec) + { + auto need_quote = use_quotes + || (!sep_view.empty() && str.find (sep_view) != std::string::npos) + || str.find_first_of ("\"\n\r") != std::string::npos; + + if (first) + first = false; + else + ss << sep_view; + + if (need_quote) + ss << QUOTE; + + for (const char& p : str) + { + ss << p; + if (p == QUOTE) + ss << QUOTE; + } + + if (need_quote) + ss << QUOTE; + + if (ss.fail()) + return false; + } + ss << EOLSTR; + + return !ss.fail(); +} diff --git a/gnucash/import-export/csv-exp/csv-export-helpers.hpp b/gnucash/import-export/csv-exp/csv-export-helpers.hpp new file mode 100644 index 0000000000..be8fc24dc8 --- /dev/null +++ b/gnucash/import-export/csv-exp/csv-export-helpers.hpp @@ -0,0 +1,39 @@ +/*******************************************************************\ + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * + * Boston, MA 02110-1301, USA gnu@gnu.org * +\********************************************************************/ + +#ifndef CSV_EXPORT_HELPERS +#define CSV_EXPORT_HELPERS + +#include +#include +#include +#include + +using StringVec = std::vector; + +// add a csv-formatted line onto output stream. charsvec is the vector +// of std::strings, sep is the separator string. use_quotes to always +// "quote"; some strings may be quoted anyway if contains separator +// string, quote, \r or \n. This function returns a bool indicating +// success. +bool gnc_csv_add_line (std::ostream& ss, const StringVec& charsvec, + bool use_quotes, const char* sep); + +#endif + diff --git a/gnucash/import-export/csv-exp/test/CMakeLists.txt b/gnucash/import-export/csv-exp/test/CMakeLists.txt new file mode 100644 index 0000000000..6689091025 --- /dev/null +++ b/gnucash/import-export/csv-exp/test/CMakeLists.txt @@ -0,0 +1,25 @@ + +set (test-csv-export-helpers_SOURCES + test-csv-export-helpers.cpp +) + +set (test-csv-export-helpers_INCLUDE_DIRS + ${CMAKE_BINARY_DIR}/common + ${CMAKE_SOURCE_DIR}/libgnucash/engine +) + +set (test-csv-export-helpers_LIBS + gnc-csv-export + gtest +) + +gnc_add_test (test-csv-export-helpers + "${test-csv-export-helpers_SOURCES}" + test-csv-export-helpers_INCLUDE_DIRS + test-csv-export-helpers_LIBS +) + +set_dist_list (test-csv-export_DIST + CMakeLists.txt + ${test-csv-export-helpers_SOURCES} +) diff --git a/gnucash/import-export/csv-exp/test/test-csv-export-helpers.cpp b/gnucash/import-export/csv-exp/test/test-csv-export-helpers.cpp new file mode 100644 index 0000000000..1cafe5a8b3 --- /dev/null +++ b/gnucash/import-export/csv-exp/test/test-csv-export-helpers.cpp @@ -0,0 +1,92 @@ +/******************************************************************** + * This program is free software; you can redistribute it and/or * + * modify it under the terms of the GNU General Public License as * + * published by the Free Software Foundation; either version 2 of * + * the License, or (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License* + * along with this program; if not, you can retrieve it from * + * https://www.gnu.org/licenses/old-licenses/gpl-2.0.html * + * or contact: * + * * + * Free Software Foundation Voice: +1-617-542-5942 * + * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * + * Boston, MA 02110-1301, USA gnu@gnu.org * + ********************************************************************/ + +// #include "config.h" +#include "csv-export-helpers.hpp" +#include + +#include + +#ifdef G_OS_WIN32 +# define EOLSTR "\n" +#else +# define EOLSTR "\r\n" +#endif + +TEST (CsvHelperTest, EmptyTests) +{ + std::ostringstream ss; + gnc_csv_add_line (ss, {}, false, nullptr); + ASSERT_EQ (ss.str(), EOLSTR); + + std::ostringstream().swap(ss); + gnc_csv_add_line (ss, {}, true, ","); + ASSERT_EQ (ss.str(), EOLSTR); + + std::ostringstream().swap(ss); + gnc_csv_add_line (ss, {}, false, ","); + ASSERT_EQ (ss.str(), EOLSTR); + + std::ostringstream().swap(ss); + gnc_csv_add_line (ss, {}, true, nullptr); + ASSERT_EQ (ss.str(), EOLSTR); +} + +TEST (CsvHelperTest, BasicTests) +{ + std::ostringstream ss; + gnc_csv_add_line (ss, { "A","B","C","","D" }, false, ","); + ASSERT_EQ (ss.str(), "A,B,C,,D" EOLSTR); + + std::ostringstream().swap(ss); + gnc_csv_add_line (ss, { "A","B","C","","D" }, false, ""); + ASSERT_EQ (ss.str(), "ABCD" EOLSTR); + + std::ostringstream().swap(ss); + gnc_csv_add_line (ss, { "A","B","C","","D" }, false, nullptr); + ASSERT_EQ (ss.str(), "ABCD" EOLSTR); + + std::ostringstream().swap(ss); + gnc_csv_add_line (ss, { "A","B","C","","D" }, false, ";"); + ASSERT_EQ (ss.str(), "A;B;C;;D" EOLSTR); + + std::ostringstream().swap(ss); + gnc_csv_add_line (ss, { "A","B","C","","D" }, true, ","); + ASSERT_EQ (ss.str(), "\"A\",\"B\",\"C\",\"\",\"D\"" EOLSTR); + +} + + +TEST (CsvHelperTest, ForcedQuote) +{ + std::ostringstream ss; + gnc_csv_add_line (ss, { "A","B","C","\"","D" }, false, ","); + ASSERT_EQ (ss.str(), "A,B,C,\"\"\"\",D" EOLSTR); + + std::ostringstream().swap(ss); + gnc_csv_add_line (ss, { "A","B","C","",",D" }, false, ","); + ASSERT_EQ (ss.str(), "A,B,C,,\",D\"" EOLSTR); + + std::ostringstream().swap(ss); + gnc_csv_add_line (ss, { "A","B","C","\n","D\r" }, false, ";"); + ASSERT_EQ (ss.str(), "A;B;C;\"\n\";\"D\r\"" EOLSTR); + +} diff --git a/po/POTFILES.in b/po/POTFILES.in index 2e8342a4d6..cc95414f1f 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -326,6 +326,7 @@ gnucash/import-export/bi-import/dialog-bi-import-gui.c gnucash/import-export/bi-import/dialog-bi-import-helper.c gnucash/import-export/bi-import/gnc-plugin-bi-import.c gnucash/import-export/csv-exp/assistant-csv-export.c +gnucash/import-export/csv-exp/csv-export-helpers.cpp gnucash/import-export/csv-exp/csv-transactions-export.c gnucash/import-export/csv-exp/csv-tree-export.c gnucash/import-export/csv-exp/gnc-plugin-csv-export.c