[glom: 3/4] Refactoring Dialog_Import_CSV: created testcase for the CsvParser's signal emission



commit b0415320a7e53790f46ffeab28168137a35d03aa
Author: Michael Hasselmann <michaelh openismus com>
Date:   Thu Sep 17 18:35:57 2009 +0200

    Refactoring Dialog_Import_CSV: created testcase for the CsvParser's signal emission
    
    * Makefile_tests.am: all tests now run within valgrind by default since mem
    leaks in testcases are potential mem leaks in the application. Parameters might
    need tweaking.
    
    * glom/import_csv.cc (CsvParser::on_idle_parse): Fixed a missing negation in a
    conditional, which was wrongfully leading to signal emissions. Found by the
    import signals testcase.
    
    * test/import/test_parsing.cc: Fixed a null byte issue when setting the raw
    contents of the parser.
    
    * test/import/test_signals.cc: This testcase checks the CsvParser's signal
    emission on varying input. The basic idea was to have on testcase for each
    code path that leads to a signal emission in glom/import_csv.cc, even if that
    leads to overlapping code coverage tests with the parser testcase.

 Makefile_tests.am            |   11 +++-
 glom/import_csv.cc           |    6 +-
 tests/import/test_parsing.cc |    4 +-
 tests/import/test_signals.cc |  165 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 180 insertions(+), 6 deletions(-)
---
diff --git a/Makefile_tests.am b/Makefile_tests.am
index f5760a2..bce76b8 100644
--- a/Makefile_tests.am
+++ b/Makefile_tests.am
@@ -25,14 +25,18 @@ check_PROGRAMS =						\
 	tests/test_parsing_time			\
 	tests/test_signal_reemit			\
 	tests/test_load_python_library\
-	tests/import/test_parsing
+	tests/import/test_parsing\
+	tests/import/test_signals
 
 TESTS =	tests/test_parsing_time	\
 	tests/test_signal_reemit	\
 	tests/test_load_python_library\
 	tests/import/test_parsing\
+	tests/import/test_signals\
 	tests/import.sh
 
+TESTS_ENVIRONMENT=which valgrind && valgrind --tool=memcheck --leak-check=full --leak-resolution=high --trace-children=yes --num-callers=30
+
 tests_ldadd = glom/libglom/libglom-$(GLOM_ABI_VERSION).la $(LIBGLOM_LIBS)
 
 glom_libglom_test_connectionpool_SOURCES = glom/libglom/test_connectionpool.cc
@@ -46,6 +50,10 @@ tests_import_test_parsing_SOURCES =	\
 	glom/import_csv.cc	\
 	glom/import_csv.h	\
 	tests/import/test_parsing.cc
+tests_import_test_signals_SOURCES =	\
+	glom/import_csv.cc	\
+	glom/import_csv.h	\
+	tests/import/test_signals.cc
 
 glom_libglom_test_connectionpool_LDADD = $(tests_ldadd)
 glom_libglom_test_document_LDADD = $(tests_ldadd)
@@ -71,3 +79,4 @@ tests_test_parsing_time_LDADD = $(tests_ldadd)
 tests_test_signal_reemit_LDADD = $(LIBGLOM_LIBS)
 tests_test_load_python_library_LDADD = $(LIBGLOM_LIBS)
 tests_import_test_parsing_LDADD = $(LIBGLOM_LIBS)
+tests_import_test_signals_LDADD = $(LIBGLOM_LIBS)
diff --git a/glom/import_csv.cc b/glom/import_csv.cc
index 8844500..b0363c5 100644
--- a/glom/import_csv.cc
+++ b/glom/import_csv.cc
@@ -265,7 +265,7 @@ bool CsvParser::on_idle_parse()
 
       // Found a newline (outside of quotes) that marks the end of the line:
       m_current_line.append(prev_line_end, pos - prev_line_end);
-      ++(m_line_number);
+      ++m_line_number;
 
       if(!m_current_line.empty())
       {
@@ -295,10 +295,10 @@ bool CsvParser::on_idle_parse()
   m_current_line.append(prev, outbuf - prev);
   if(!m_stream && m_raw.size() == m_input_position)
   {
-    ++(m_line_number);
+    ++m_line_number;
 
     // Handle last line, if nonempty
-    if(m_current_line.empty())
+    if(!m_current_line.empty())
     {
       signal_line_scanned().emit(m_current_line, m_line_number);
     }
diff --git a/tests/import/test_parsing.cc b/tests/import/test_parsing.cc
index 7e784c3..49779fd 100644
--- a/tests/import/test_parsing.cc
+++ b/tests/import/test_parsing.cc
@@ -43,8 +43,8 @@ bool check_tokens(Glib::RefPtr<Glib::Regex> check)
 
 void set_parser_contents(Glom::CsvParser& parser, const char* input, guint size)
 {
-
-  parser.m_raw = std::vector<char>(input, input + size);
+  // Do not read terminating null byte.
+  parser.m_raw = std::vector<char>(input, input + size -1);
 }
 
 void on_line_scanned(const Glib::ustring& line, guint /*line_number*/)
diff --git a/tests/import/test_signals.cc b/tests/import/test_signals.cc
new file mode 100644
index 0000000..61eaf86
--- /dev/null
+++ b/tests/import/test_signals.cc
@@ -0,0 +1,165 @@
+#include <glom/import_csv.h>
+#include <glibmm/regex.h>
+#include <iostream>
+#include <stdexcept>
+#include <cstdlib>
+
+namespace {
+
+typedef std::vector<std::string> Encodings;
+
+void set_parser_contents(Glom::CsvParser& parser, const char* input, guint size)
+{
+  // Do not read terminating null byte.
+  parser.m_raw = std::vector<char>(input, input + size -1);
+}
+
+guint& get_line_scanned_count_instance()
+{
+  static guint line_scanned_count = 0;
+  return line_scanned_count;
+}
+
+guint& get_encoding_error_count_instance()
+{
+  static guint encoding_error_count = 0;
+  return encoding_error_count;
+}
+
+void on_line_scanned()
+{
+  ++(get_line_scanned_count_instance());
+}
+
+void on_encoding_error()
+{
+  ++(get_encoding_error_count_instance());
+}
+
+void reset_signal_counts()
+{
+  get_line_scanned_count_instance() = 0;
+  get_encoding_error_count_instance() = 0;
+}
+
+void print_signal_counts()
+{
+  std::cout << "lines scanned: " << get_line_scanned_count_instance() << std::endl;
+  std::cout << "encoding errors: " << get_encoding_error_count_instance() << std::endl;
+}
+
+} // namespace
+
+// Testcases
+int main()
+{
+  Glom::CsvParser parser("UTF-8");
+  parser.signal_line_scanned().connect(sigc::hide(sigc::hide(&on_line_scanned)));
+  parser.signal_encoding_error().connect(sigc::ptr_fun(&on_encoding_error));
+
+  bool test_ignore_quoted_newlines = false;
+  bool test_ignore_empty_lines = false;
+  bool test_wrong_encoding = false;
+  bool test_incomplete_chars = false;
+
+  std::stringstream results;
+
+  // test_ignore_quoted_newlines
+  {
+    // 2 CSV lines, first one contains newlines inside quotes
+    const char raw[] = "\"some\n quoted\r\n newlines\n\", \"token2\"\n\"token3\"\n";
+    set_parser_contents(parser, raw, sizeof(raw));
+
+    while(parser.on_idle_parse())
+    {}
+
+    results << "test_ignore_quoted_newlines: "
+            << (test_ignore_quoted_newlines = (2 == get_line_scanned_count_instance()))
+            << std::endl;
+
+    reset_signal_counts();
+    parser.clear();
+  }
+
+  // test_ignore_empty_lines
+  {
+    // 5 CSV lines, but only 2 contain data
+    const char raw[] = "token1\n\n\n\ntoken2, token3\n";
+    set_parser_contents(parser, raw, sizeof(raw));
+
+    while(parser.on_idle_parse())
+    {}
+
+    results << "test_ignore_empty_lines: "
+            << (test_ignore_empty_lines = (2 == get_line_scanned_count_instance() &&
+                                           0 == get_encoding_error_count_instance()))
+            << std::endl;
+
+    reset_signal_counts();
+    parser.clear();
+  }
+
+  // test_wrong_encoding
+  {
+    const char* const encoding_arr[] = {"UTF-8", "UCS-2"};
+    Encodings encodings(encoding_arr, encoding_arr + G_N_ELEMENTS(encoding_arr));
+
+    // An invalid Unicode sequence.
+    const char raw[] = "\0xc0\0x00\n";
+    set_parser_contents(parser, raw, sizeof(raw));
+
+    for (Encodings::const_iterator iter = encodings.begin();
+         iter != encodings.end();
+         ++iter)
+    {
+      try
+      {
+        while(parser.on_idle_parse())
+        {}
+
+        parser.clear();
+      }
+      catch (Glib::ConvertError& exception)
+      {
+        std::cout << exception.what() << std::endl;
+      }
+
+      parser.set_encoding((*iter).c_str());
+    }
+
+    results << "test_wrong_encoding: "
+            << (test_wrong_encoding = (2 == get_encoding_error_count_instance() &&
+                                       0 == get_line_scanned_count_instance()))
+            << std::endl;
+
+    reset_signal_counts();
+    parser.clear();
+  }
+
+  // test_incomplete_chars
+  {
+    // An incomplete Unicode sequence.
+    const char raw[] = "\0xc0\n";
+    set_parser_contents(parser, raw, sizeof(raw));
+
+    while(parser.on_idle_parse())
+    {}
+
+    parser.clear();
+
+    results << "test_incomplete_chars: "
+            << (test_incomplete_chars = (1 == get_encoding_error_count_instance() &&
+                                         0 == get_line_scanned_count_instance()))
+            << std::endl;
+
+    reset_signal_counts();
+    parser.clear();
+  }
+
+  std::cout << results.rdbuf();
+  return (test_ignore_quoted_newlines &&
+          test_ignore_empty_lines &&
+          test_wrong_encoding &&
+          test_incomplete_chars
+         ) ? EXIT_SUCCESS : EXIT_FAILURE;
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]