Fix string-convert tests for Windows and hopefully macOS/OS X
authorTim Mayberry <mojofunk@gmail.com>
Mon, 17 Apr 2017 03:16:12 +0000 (13:16 +1000)
committerTim Mayberry <mojofunk@gmail.com>
Mon, 17 Apr 2017 03:21:02 +0000 (13:21 +1000)
Tests requires a locale installed on the host that uses a comma as the decimal
mark/point.

libs/pbd/test/string_convert_test.cc
libs/pbd/test/string_convert_test.h

index f383aed8a2dc84d20c9f8f8e7c65e6a9a3042445..2f06ad9c52868894a730ddf50f2a1d3a31112d17 100644 (file)
@@ -17,10 +17,53 @@ using namespace std;
 
 CPPUNIT_TEST_SUITE_REGISTRATION (StringConvertTest);
 
-static std::vector<std::string> get_test_locales ()
+namespace {
+
+class LocaleGuard {
+public:
+       // RAII class that sets the global C locale and then resets it to its
+       // previous setting when going out of scope
+       LocaleGuard (const std::string& locale)
+       {
+               m_previous_locale = setlocale (LC_ALL, NULL);
+
+               CPPUNIT_ASSERT (m_previous_locale != NULL);
+
+               const char* new_locale = setlocale (LC_ALL, locale.c_str ());
+
+               if (new_locale == NULL) {
+                       std::cerr << "Failed to set locale to : " << locale << std::endl;
+               }
+
+               CPPUNIT_ASSERT (new_locale != NULL);
+       }
+
+       ~LocaleGuard ()
+       {
+               CPPUNIT_ASSERT (setlocale (LC_ALL, m_previous_locale) != NULL);
+       }
+
+private:
+       const char* m_previous_locale;
+};
+
+static
+bool
+check_decimal_mark_is_comma ()
+{
+       char buf[32];
+       double const dnum = 12345.67890;
+       snprintf (buf, sizeof(buf), "%.12g", dnum);
+       bool found = (strchr (buf, ',') != NULL);
+       return found;
+}
+
+static std::vector<std::string> get_locale_list ()
 {
        std::vector<std::string> locales;
 
+       locales.push_back(""); // User preferred locale
+
 #ifdef PLATFORM_WINDOWS
        locales.push_back("French_France.1252"); // must be first
        locales.push_back("Dutch_Netherlands.1252");
@@ -29,8 +72,12 @@ static std::vector<std::string> get_test_locales ()
        locales.push_back("Chinese_China.936");
        locales.push_back("Czech_Czech Republic.1250");
 #else
-       locales.push_back("fr_FR"); // French France // must be first
+       locales.push_back("fr_FR"); // French France
+       locales.push_back("fr_FR.UTF-8");
+       locales.push_back("de_DE"); // German Germany
+       locales.push_back("de_DE.UTF-8");
        locales.push_back("nl_NL"); // Dutch - Netherlands
+       locales.push_back("nl_NL.UTF-8");
        locales.push_back("it_IT"); // Italian
        locales.push_back("fa_IR"); // Farsi Iran
        locales.push_back("zh_CN"); // Chinese
@@ -39,37 +86,78 @@ static std::vector<std::string> get_test_locales ()
        return locales;
 }
 
+static std::vector<std::string> get_supported_locales ()
+{
+       std::vector<std::string> locales = get_locale_list ();
+       std::vector<std::string> supported_locales;
 
-namespace {
+       const char * m_orig_locale = setlocale (LC_ALL, NULL);
 
-class LocaleGuard {
-public:
-       // RAII class that sets the global C locale and then resets it to its
-       // previous setting when going out of scope
-       LocaleGuard (const std::string& locale)
-       {
-               m_previous_locale = setlocale (LC_ALL, NULL);
+       CPPUNIT_ASSERT (m_orig_locale != NULL);
 
-               CPPUNIT_ASSERT (m_previous_locale != NULL);
+       std::cerr << std::endl << "Original locale: " << m_orig_locale << std::endl;
 
-               const char* new_locale = setlocale (LC_ALL, locale.c_str ());
+       for (std::vector<std::string>::const_iterator it = locales.begin(); it != locales.end(); ++it) {
 
-               CPPUNIT_ASSERT (new_locale != NULL);
+               const char* locale = it->c_str();
+               const char* new_locale = setlocale (LC_ALL, locale);
+
+               if (new_locale == NULL) {
+                       std::cerr << "Unable to set locale : " << locale << ", may not be installed." << std::endl;
+                       continue;
+               }
+
+               if (*it != new_locale) {
+                       // Setting the locale may be successful but locale has a different
+                       // (or longer) name.
+                       if (it->empty()) {
+                               std::cerr << "User preferred locale is : " << new_locale << std::endl;
+                       } else {
+                               std::cerr << "locale : " << locale << ", has name : " << new_locale << std::endl;
+                       }
+               }
 
-               CPPUNIT_ASSERT (locale == new_locale);
+               std::cerr << "Adding locale : " << new_locale << " to test locales" << std::endl;
+
+               supported_locales.push_back (*it);
        }
 
-       ~LocaleGuard ()
-       {
-               CPPUNIT_ASSERT (setlocale (LC_ALL, m_previous_locale) != NULL);
+       if (setlocale (LC_ALL, m_orig_locale) == NULL) {
+               std::cerr << "ERROR: Unable to restore original locale " << m_orig_locale
+                         << ", further tests may be invalid." << std::endl;
        }
 
-private:
-       const char* m_previous_locale;
-};
+       return supported_locales;
+}
+
+static std::vector<std::string> get_test_locales ()
+{
+       static std::vector<std::string> locales = get_supported_locales ();
+       return locales;
+}
+
+static bool get_locale_with_comma_decimal_mark (std::string& locale_str) {
+       std::vector<std::string> locales = get_test_locales ();
+
+       for (std::vector<std::string>::const_iterator it = locales.begin(); it != locales.end(); ++it) {
+               LocaleGuard guard (*it);
+               if (check_decimal_mark_is_comma ()) {
+                       locale_str = *it;
+                       return true;
+               }
+       }
+       return false;
+}
 
 } // anon namespace
 
+void
+StringConvertTest::test_required_locales ()
+{
+       std::string locale_str;
+       CPPUNIT_ASSERT(get_locale_with_comma_decimal_mark(locale_str));
+}
+
 static const std::string MAX_INT16_STR ("32767");
 static const std::string MIN_INT16_STR ("-32768");
 
@@ -558,7 +646,7 @@ check_double_convert ()
        return (num == string_to<double>(to_string<double> (num)));
 }
 
-static const int s_iter_count = 500000;
+static const int s_iter_count = 1000000;
 
 void*
 check_int_convert_thread(void*)
@@ -589,20 +677,11 @@ check_double_convert_thread(void*)
 
 static const double s_test_double = 31459.265359;
 
-bool
-check_fr_printf ()
-{
-       char buf[32];
-       snprintf (buf, sizeof(buf), "%.12g", s_test_double);
-       bool found = (strchr (buf, ',') != NULL);
-       return found;
-}
-
 void*
-check_fr_printf_thread (void*)
+check_decimal_mark_is_comma_thread (void*)
 {
        for (int n = 0; n < s_iter_count; n++) {
-               assert (check_fr_printf ());
+               assert (check_decimal_mark_is_comma ());
        }
 
        return NULL;
@@ -617,12 +696,16 @@ check_fr_printf_thread (void*)
 void
 StringConvertTest::test_convert_thread_safety ()
 {
-       LocaleGuard guard (get_test_locales().front());
+       std::string locale_str;
+
+       CPPUNIT_ASSERT(get_locale_with_comma_decimal_mark(locale_str));
+
+       LocaleGuard guard (locale_str);
 
        CPPUNIT_ASSERT (check_int_convert ());
        CPPUNIT_ASSERT (check_float_convert ());
        CPPUNIT_ASSERT (check_double_convert ());
-       CPPUNIT_ASSERT (check_fr_printf ());
+       CPPUNIT_ASSERT (check_decimal_mark_is_comma ());
 
        pthread_t convert_int_thread;
        pthread_t convert_float_thread;
@@ -639,7 +722,7 @@ StringConvertTest::test_convert_thread_safety ()
            pthread_create (
                &convert_double_thread, NULL, check_double_convert_thread, NULL) == 0);
        CPPUNIT_ASSERT (
-           pthread_create (&fr_printf_thread, NULL, check_fr_printf_thread, NULL) ==
+           pthread_create (&fr_printf_thread, NULL, check_decimal_mark_is_comma_thread, NULL) ==
            0);
 
        void* return_value;
index 82ccb26af312ea3fa733ff9d66aa57a5ecf4d01e..d9a7e1f4de0b401a4b2f0e98f2ddd46b7e7654c7 100644 (file)
@@ -4,6 +4,7 @@
 class StringConvertTest : public CppUnit::TestFixture
 {
        CPPUNIT_TEST_SUITE (StringConvertTest);
+       CPPUNIT_TEST (test_required_locales);
        CPPUNIT_TEST (test_int16_conversion);
        CPPUNIT_TEST (test_uint16_conversion);
        CPPUNIT_TEST (test_int32_conversion);
@@ -17,6 +18,7 @@ class StringConvertTest : public CppUnit::TestFixture
        CPPUNIT_TEST_SUITE_END ();
 
 public:
+       void test_required_locales ();
        void test_int16_conversion ();
        void test_uint16_conversion ();
        void test_int32_conversion ();