1 #include "string_convert_test.h"
13 #include "pbd/string_convert.h"
18 CPPUNIT_TEST_SUITE_REGISTRATION (StringConvertTest);
24 // RAII class that sets the global C locale and then resets it to its
25 // previous setting when going out of scope
26 LocaleGuard (const std::string& locale)
28 m_previous_locale = setlocale (LC_ALL, NULL);
30 CPPUNIT_ASSERT (m_previous_locale != NULL);
32 const char* new_locale = setlocale (LC_ALL, locale.c_str ());
34 if (new_locale == NULL) {
35 std::cerr << "Failed to set locale to : " << locale << std::endl;
38 CPPUNIT_ASSERT (new_locale != NULL);
43 CPPUNIT_ASSERT (setlocale (LC_ALL, m_previous_locale) != NULL);
47 const char* m_previous_locale;
52 check_decimal_mark_is_comma ()
55 double const dnum = 12345.67890;
56 snprintf (buf, sizeof(buf), "%.12g", dnum);
57 bool found = (strchr (buf, ',') != NULL);
61 static std::vector<std::string> get_locale_list ()
63 std::vector<std::string> locales;
65 locales.push_back(""); // User preferred locale
67 #ifdef PLATFORM_WINDOWS
68 locales.push_back("French_France.1252"); // must be first
69 locales.push_back("Dutch_Netherlands.1252");
70 locales.push_back("Italian_Italy.1252");
71 locales.push_back("Farsi_Iran.1256");
72 locales.push_back("Chinese_China.936");
73 locales.push_back("Czech_Czech Republic.1250");
75 locales.push_back("fr_FR"); // French France
76 locales.push_back("fr_FR.UTF-8");
77 locales.push_back("de_DE"); // German Germany
78 locales.push_back("de_DE.UTF-8");
79 locales.push_back("nl_NL"); // Dutch - Netherlands
80 locales.push_back("nl_NL.UTF-8");
81 locales.push_back("it_IT"); // Italian
82 locales.push_back("fa_IR"); // Farsi Iran
83 locales.push_back("zh_CN"); // Chinese
84 locales.push_back("cs_CZ"); // Czech
89 static std::vector<std::string> get_supported_locales ()
91 std::vector<std::string> locales = get_locale_list ();
92 std::vector<std::string> supported_locales;
94 const char * m_orig_locale = setlocale (LC_ALL, NULL);
96 CPPUNIT_ASSERT (m_orig_locale != NULL);
98 std::cerr << std::endl << "Original locale: " << m_orig_locale << std::endl;
100 for (std::vector<std::string>::const_iterator it = locales.begin(); it != locales.end(); ++it) {
102 const char* locale = it->c_str();
103 const char* new_locale = setlocale (LC_ALL, locale);
105 if (new_locale == NULL) {
106 std::cerr << "Unable to set locale : " << locale << ", may not be installed." << std::endl;
110 if (*it != new_locale) {
111 // Setting the locale may be successful but locale has a different
114 std::cerr << "User preferred locale is : " << new_locale << std::endl;
116 std::cerr << "locale : " << locale << ", has name : " << new_locale << std::endl;
120 std::cerr << "Adding locale : " << new_locale << " to test locales" << std::endl;
122 supported_locales.push_back (*it);
125 if (setlocale (LC_ALL, m_orig_locale) == NULL) {
126 std::cerr << "ERROR: Unable to restore original locale " << m_orig_locale
127 << ", further tests may be invalid." << std::endl;
130 return supported_locales;
133 static std::vector<std::string> get_test_locales ()
135 static std::vector<std::string> locales = get_supported_locales ();
139 static bool get_locale_with_comma_decimal_mark (std::string& locale_str) {
140 std::vector<std::string> locales = get_test_locales ();
142 for (std::vector<std::string>::const_iterator it = locales.begin(); it != locales.end(); ++it) {
143 LocaleGuard guard (*it);
144 if (check_decimal_mark_is_comma ()) {
155 StringConvertTest::test_required_locales ()
157 std::string locale_str;
158 CPPUNIT_ASSERT(get_locale_with_comma_decimal_mark(locale_str));
161 static const std::string MAX_INT16_STR ("32767");
162 static const std::string MIN_INT16_STR ("-32768");
164 typedef void (*TestFunctionType)(void);
167 test_function_for_locales (TestFunctionType test_func)
169 const std::vector<std::string> locales = get_test_locales();
171 for (std::vector<std::string>::const_iterator ci = locales.begin ();
172 ci != locales.end ();
174 LocaleGuard guard (*ci);
180 _test_int16_conversion ()
183 CPPUNIT_ASSERT (int16_to_string (numeric_limits<int16_t>::max (), str));
184 CPPUNIT_ASSERT_EQUAL (MAX_INT16_STR, str);
187 CPPUNIT_ASSERT (string_to_int16 (str, val));
188 CPPUNIT_ASSERT_EQUAL (numeric_limits<int16_t>::max (), val);
190 CPPUNIT_ASSERT (int16_to_string (numeric_limits<int16_t>::min (), str));
191 CPPUNIT_ASSERT_EQUAL (MIN_INT16_STR, str);
193 CPPUNIT_ASSERT (string_to_int16 (str, val));
194 CPPUNIT_ASSERT_EQUAL (numeric_limits<int16_t>::min (), val);
196 // test the string_to/to_string templates
197 int16_t max = numeric_limits<int16_t>::max ();
198 CPPUNIT_ASSERT_EQUAL (max, string_to<int16_t>(to_string (max)));
200 int16_t min = numeric_limits<int16_t>::min ();
201 CPPUNIT_ASSERT_EQUAL (min, string_to<int16_t>(to_string (min)));
205 StringConvertTest::test_int16_conversion ()
207 test_function_for_locales(&_test_int16_conversion);
210 static const std::string MAX_UINT16_STR("65535");
211 static const std::string MIN_UINT16_STR("0");
214 _test_uint16_conversion ()
217 CPPUNIT_ASSERT (uint16_to_string (numeric_limits<uint16_t>::max (), str));
218 CPPUNIT_ASSERT_EQUAL (MAX_UINT16_STR, str);
221 CPPUNIT_ASSERT (string_to_uint16 (str, val));
222 CPPUNIT_ASSERT_EQUAL (numeric_limits<uint16_t>::max (), val);
224 CPPUNIT_ASSERT (uint16_to_string (numeric_limits<uint16_t>::min (), str));
225 CPPUNIT_ASSERT_EQUAL (MIN_UINT16_STR, str);
227 CPPUNIT_ASSERT (string_to_uint16 (str, val));
228 CPPUNIT_ASSERT_EQUAL (numeric_limits<uint16_t>::min (), val);
230 // test the string_to/to_string templates
231 uint16_t max = numeric_limits<uint16_t>::max ();
232 CPPUNIT_ASSERT_EQUAL (max, string_to<uint16_t>(to_string (max)));
234 uint16_t min = numeric_limits<uint16_t>::min ();
235 CPPUNIT_ASSERT_EQUAL (min, string_to<uint16_t>(to_string (min)));
239 StringConvertTest::test_uint16_conversion ()
241 test_function_for_locales(&_test_uint16_conversion);
244 static const std::string MAX_INT32_STR ("2147483647");
245 static const std::string MIN_INT32_STR ("-2147483648");
248 _test_int32_conversion ()
251 CPPUNIT_ASSERT (int32_to_string (numeric_limits<int32_t>::max (), str));
252 CPPUNIT_ASSERT_EQUAL (MAX_INT32_STR, str);
255 CPPUNIT_ASSERT (string_to_int32 (str, val));
256 CPPUNIT_ASSERT_EQUAL (numeric_limits<int32_t>::max (), val);
258 CPPUNIT_ASSERT (int32_to_string (numeric_limits<int32_t>::min (), str));
259 CPPUNIT_ASSERT_EQUAL (MIN_INT32_STR, str);
261 CPPUNIT_ASSERT (string_to_int32 (str, val));
262 CPPUNIT_ASSERT_EQUAL (numeric_limits<int32_t>::min (), val);
264 // test the string_to/to_string templates
265 int32_t max = numeric_limits<int32_t>::max ();
266 CPPUNIT_ASSERT_EQUAL (max, string_to<int32_t>(to_string (max)));
268 int32_t min = numeric_limits<int32_t>::min ();
269 CPPUNIT_ASSERT_EQUAL (min, string_to<int32_t>(to_string (min)));
273 StringConvertTest::test_int32_conversion ()
275 test_function_for_locales(&_test_int32_conversion);
278 static const std::string MAX_UINT32_STR("4294967295");
279 static const std::string MIN_UINT32_STR("0");
282 _test_uint32_conversion ()
285 CPPUNIT_ASSERT (uint32_to_string (numeric_limits<uint32_t>::max (), str));
286 CPPUNIT_ASSERT_EQUAL (MAX_UINT32_STR, str);
289 CPPUNIT_ASSERT (string_to_uint32 (str, val));
290 CPPUNIT_ASSERT_EQUAL (numeric_limits<uint32_t>::max (), val);
292 CPPUNIT_ASSERT (uint32_to_string (numeric_limits<uint32_t>::min (), str));
293 CPPUNIT_ASSERT_EQUAL (MIN_UINT32_STR, str);
295 CPPUNIT_ASSERT (string_to_uint32 (str, val));
296 CPPUNIT_ASSERT_EQUAL (numeric_limits<uint32_t>::min (), val);
298 // test the string_to/to_string templates
299 uint32_t max = numeric_limits<uint32_t>::max ();
300 CPPUNIT_ASSERT_EQUAL (max, string_to<uint32_t>(to_string (max)));
302 uint32_t min = numeric_limits<uint32_t>::min ();
303 CPPUNIT_ASSERT_EQUAL (min, string_to<uint32_t>(to_string (min)));
307 StringConvertTest::test_uint32_conversion ()
309 test_function_for_locales(&_test_uint32_conversion);
312 static const std::string MAX_INT64_STR ("9223372036854775807");
313 static const std::string MIN_INT64_STR ("-9223372036854775808");
316 _test_int64_conversion ()
319 CPPUNIT_ASSERT (int64_to_string (numeric_limits<int64_t>::max (), str));
320 CPPUNIT_ASSERT_EQUAL (MAX_INT64_STR, str);
323 CPPUNIT_ASSERT (string_to_int64 (str, val));
324 CPPUNIT_ASSERT_EQUAL (numeric_limits<int64_t>::max (), val);
326 CPPUNIT_ASSERT (int64_to_string (numeric_limits<int64_t>::min (), str));
327 CPPUNIT_ASSERT_EQUAL (MIN_INT64_STR, str);
329 CPPUNIT_ASSERT (string_to_int64 (str, val));
330 CPPUNIT_ASSERT_EQUAL (numeric_limits<int64_t>::min (), val);
332 // test the string_to/to_string templates
333 int64_t max = numeric_limits<int64_t>::max ();
334 CPPUNIT_ASSERT_EQUAL (max, string_to<int64_t>(to_string (max)));
336 int64_t min = numeric_limits<int64_t>::min ();
337 CPPUNIT_ASSERT_EQUAL (min, string_to<int64_t>(to_string (min)));
341 StringConvertTest::test_int64_conversion ()
343 test_function_for_locales(&_test_int64_conversion);
346 static const std::string MAX_UINT64_STR ("18446744073709551615");
347 static const std::string MIN_UINT64_STR ("0");
350 _test_uint64_conversion ()
353 CPPUNIT_ASSERT (uint64_to_string (numeric_limits<uint64_t>::max (), str));
354 CPPUNIT_ASSERT_EQUAL (MAX_UINT64_STR, str);
357 CPPUNIT_ASSERT (string_to_uint64 (str, val));
358 CPPUNIT_ASSERT_EQUAL (numeric_limits<uint64_t>::max (), val);
360 CPPUNIT_ASSERT (uint64_to_string (numeric_limits<uint64_t>::min (), str));
361 CPPUNIT_ASSERT_EQUAL (MIN_UINT64_STR, str);
363 CPPUNIT_ASSERT (string_to_uint64 (str, val));
364 CPPUNIT_ASSERT_EQUAL (numeric_limits<uint64_t>::min (), val);
366 // test the string_to/to_string templates
367 uint64_t max = numeric_limits<uint64_t>::max ();
368 CPPUNIT_ASSERT_EQUAL (max, string_to<uint64_t>(to_string (max)));
370 uint64_t min = numeric_limits<uint64_t>::min ();
371 CPPUNIT_ASSERT_EQUAL (min, string_to<uint64_t>(to_string (min)));
375 StringConvertTest::test_uint64_conversion ()
377 test_function_for_locales(&_test_uint64_conversion);
380 static const std::string POS_INFINITY_STR ("infinity");
381 static const std::string NEG_INFINITY_STR ("-infinity");
382 static const std::string POS_INFINITY_CAPS_STR ("INFINITY");
383 static const std::string NEG_INFINITY_CAPS_STR ("-INFINITY");
384 static const std::string POS_INF_STR ("inf");
385 static const std::string NEG_INF_STR ("-inf");
386 static const std::string POS_INF_CAPS_STR ("INF");
387 static const std::string NEG_INF_CAPS_STR ("-INF");
390 std::vector<std::string>
391 _pos_infinity_strings ()
393 std::vector<std::string> vec;
394 vec.push_back (POS_INFINITY_STR);
395 vec.push_back (POS_INFINITY_CAPS_STR);
396 vec.push_back (POS_INF_STR);
397 vec.push_back (POS_INF_CAPS_STR);
402 std::vector<std::string>
403 _neg_infinity_strings ()
405 std::vector<std::string> vec;
406 vec.push_back (NEG_INFINITY_STR);
407 vec.push_back (NEG_INFINITY_CAPS_STR);
408 vec.push_back (NEG_INF_STR);
409 vec.push_back (NEG_INF_CAPS_STR);
413 template <class FloatType>
415 _test_infinity_conversion ()
417 const FloatType pos_infinity = numeric_limits<FloatType>::infinity ();
418 const FloatType neg_infinity = -numeric_limits<FloatType>::infinity ();
420 // Check float -> string
422 CPPUNIT_ASSERT (to_string<FloatType> (pos_infinity, str));
423 CPPUNIT_ASSERT_EQUAL (POS_INF_STR, str);
425 CPPUNIT_ASSERT (to_string<FloatType> (neg_infinity, str));
426 CPPUNIT_ASSERT_EQUAL (NEG_INF_STR, str);
428 // Check string -> float for all supported string representations of "INFINITY"
429 std::vector<std::string> pos_inf_strings = _pos_infinity_strings ();
431 for (std::vector<std::string>::const_iterator i = pos_inf_strings.begin ();
432 i != pos_inf_strings.end (); ++i) {
433 FloatType pos_infinity_arg;
434 CPPUNIT_ASSERT (string_to<FloatType> (*i, pos_infinity_arg));
435 CPPUNIT_ASSERT_EQUAL (pos_infinity_arg, pos_infinity);
438 // Check string -> float for all supported string representations of "-INFINITY"
439 std::vector<std::string> neg_inf_strings = _neg_infinity_strings ();
441 for (std::vector<std::string>::const_iterator i = neg_inf_strings.begin ();
442 i != neg_inf_strings.end (); ++i) {
443 FloatType neg_infinity_arg;
444 CPPUNIT_ASSERT (string_to<FloatType> (*i, neg_infinity_arg));
445 CPPUNIT_ASSERT_EQUAL (neg_infinity_arg, neg_infinity);
448 // Check round-trip equality
449 CPPUNIT_ASSERT_EQUAL (pos_infinity, string_to<FloatType> (to_string<FloatType> (pos_infinity)));
450 CPPUNIT_ASSERT_EQUAL (neg_infinity, string_to<FloatType> (to_string<FloatType> (neg_infinity)));
453 static const std::string MAX_FLOAT_WIN ("3.4028234663852886e+038");
454 static const std::string MIN_FLOAT_WIN ("1.1754943508222875e-038");
455 static const std::string MAX_FLOAT_STR ("3.4028234663852886e+38");
456 static const std::string MIN_FLOAT_STR ("1.1754943508222875e-38");
459 _test_float_conversion ()
461 // check float to string and back again for min and max float values
463 CPPUNIT_ASSERT (float_to_string (numeric_limits<float>::max (), str));
464 #ifdef PLATFORM_WINDOWS
465 CPPUNIT_ASSERT_EQUAL (MAX_FLOAT_WIN, str);
467 CPPUNIT_ASSERT_EQUAL (MAX_FLOAT_STR, str);
471 CPPUNIT_ASSERT (string_to_float (str, val));
472 CPPUNIT_ASSERT_DOUBLES_EQUAL (
473 numeric_limits<float>::max (), val, numeric_limits<float>::epsilon ());
475 CPPUNIT_ASSERT (float_to_string (numeric_limits<float>::min (), str));
476 #ifdef PLATFORM_WINDOWS
477 CPPUNIT_ASSERT_EQUAL (MIN_FLOAT_WIN, str);
479 CPPUNIT_ASSERT_EQUAL (MIN_FLOAT_STR, str);
482 CPPUNIT_ASSERT (string_to_float (str, val));
483 CPPUNIT_ASSERT_DOUBLES_EQUAL (
484 numeric_limits<float>::min (), val, numeric_limits<float>::epsilon ());
486 // test the string_to/to_string templates
487 float max = numeric_limits<float>::max ();
488 CPPUNIT_ASSERT_EQUAL (max, string_to<float>(to_string<float> (max)));
490 float min = numeric_limits<float>::min ();
491 CPPUNIT_ASSERT_EQUAL (min, string_to<float>(to_string<float> (min)));
493 // check that parsing the windows float string representation with the
494 // difference in the exponent part parses correctly on other platforms
496 #ifdef PLATFORM_WINDOWS
497 CPPUNIT_ASSERT (string_to_float (MAX_FLOAT_STR, val));
498 CPPUNIT_ASSERT_DOUBLES_EQUAL (
499 numeric_limits<float>::max (), val, numeric_limits<float>::epsilon ());
501 CPPUNIT_ASSERT (string_to_float (MIN_FLOAT_STR, val));
502 CPPUNIT_ASSERT_DOUBLES_EQUAL (
503 numeric_limits<float>::min (), val, numeric_limits<float>::epsilon ());
505 CPPUNIT_ASSERT (string_to_float (MAX_FLOAT_WIN, val));
506 CPPUNIT_ASSERT_DOUBLES_EQUAL (
507 numeric_limits<float>::max (), val, numeric_limits<float>::epsilon ());
509 CPPUNIT_ASSERT (string_to_float (MIN_FLOAT_WIN, val));
510 CPPUNIT_ASSERT_DOUBLES_EQUAL (
511 numeric_limits<float>::min (), val, numeric_limits<float>::epsilon ());
514 _test_infinity_conversion<float>();
518 StringConvertTest::test_float_conversion ()
520 test_function_for_locales(&_test_float_conversion);
523 static const std::string MAX_DOUBLE_STR ("1.7976931348623157e+308");
524 static const std::string MIN_DOUBLE_STR ("2.2250738585072014e-308");
527 _test_double_conversion ()
530 CPPUNIT_ASSERT (double_to_string (numeric_limits<double>::max (), str));
531 CPPUNIT_ASSERT_EQUAL (MAX_DOUBLE_STR, str);
534 CPPUNIT_ASSERT (string_to_double (str, val));
535 CPPUNIT_ASSERT_DOUBLES_EQUAL (
536 numeric_limits<double>::max (), val, numeric_limits<double>::epsilon ());
538 CPPUNIT_ASSERT (double_to_string (numeric_limits<double>::min (), str));
539 CPPUNIT_ASSERT_EQUAL (MIN_DOUBLE_STR, str);
541 CPPUNIT_ASSERT (string_to_double (str, val));
542 CPPUNIT_ASSERT_DOUBLES_EQUAL (
543 numeric_limits<double>::min (), val, numeric_limits<double>::epsilon ());
545 // test that overflow fails
546 CPPUNIT_ASSERT (!string_to_double ("1.8e+308", val));
547 // test that underflow fails
548 CPPUNIT_ASSERT (!string_to_double ("2.4e-310", val));
550 // test the string_to/to_string templates
551 double max = numeric_limits<double>::max ();
552 CPPUNIT_ASSERT_EQUAL (max, string_to<double>(to_string<double> (max)));
554 double min = numeric_limits<double>::min ();
555 CPPUNIT_ASSERT_EQUAL (min, string_to<double>(to_string<double> (min)));
557 _test_infinity_conversion<double>();
561 StringConvertTest::test_double_conversion ()
563 test_function_for_locales(&_test_double_conversion);
566 // we have to use these as CPPUNIT_ASSERT_EQUAL won't accept char arrays
567 static const std::string BOOL_TRUE_STR ("1");
568 static const std::string BOOL_FALSE_STR ("0");
571 StringConvertTest::test_bool_conversion ()
575 // check the normal case for true/false
576 CPPUNIT_ASSERT (bool_to_string (true, str));
577 CPPUNIT_ASSERT_EQUAL (BOOL_TRUE_STR, str);
580 CPPUNIT_ASSERT (string_to_bool (str, val));
581 CPPUNIT_ASSERT_EQUAL (val, true);
583 CPPUNIT_ASSERT (bool_to_string (false, str));
584 CPPUNIT_ASSERT_EQUAL (BOOL_FALSE_STR, str);
587 CPPUNIT_ASSERT (string_to_bool (str, val));
588 CPPUNIT_ASSERT_EQUAL (val, false);
590 // now check the other accepted values for true and false
591 // when converting from a string to bool
594 CPPUNIT_ASSERT (string_to_bool ("1", val));
595 CPPUNIT_ASSERT_EQUAL (val, true);
598 CPPUNIT_ASSERT (string_to_bool ("0", val));
599 CPPUNIT_ASSERT_EQUAL (val, false);
602 CPPUNIT_ASSERT (string_to_bool ("Y", val));
603 CPPUNIT_ASSERT_EQUAL (val, true);
606 CPPUNIT_ASSERT (string_to_bool ("N", val));
607 CPPUNIT_ASSERT_EQUAL (val, false);
610 CPPUNIT_ASSERT (string_to_bool ("y", val));
611 CPPUNIT_ASSERT_EQUAL (val, true);
614 CPPUNIT_ASSERT (string_to_bool ("n", val));
615 CPPUNIT_ASSERT_EQUAL (val, false);
618 CPPUNIT_ASSERT (!string_to_bool ("01234someYNtrueyesno junk0123", val));
620 // test the string_to/to_string templates
621 CPPUNIT_ASSERT_EQUAL (true, string_to<bool>(to_string (true)));
623 CPPUNIT_ASSERT_EQUAL (false, string_to<bool>(to_string (false)));
631 int32_t num = g_random_int ();
632 return (num == string_to<int32_t>(to_string (num)));
636 check_float_convert ()
638 float num = (float)g_random_double ();
639 return (num == string_to<float>(to_string<float> (num)));
643 check_double_convert ()
645 double num = g_random_double ();
646 return (num == string_to<double>(to_string<double> (num)));
649 static const int s_iter_count = 1000000;
652 check_int_convert_thread(void*)
654 for (int n = 0; n < s_iter_count; n++) {
655 assert (check_int_convert ());
661 check_float_convert_thread(void*)
663 for (int n = 0; n < s_iter_count; n++) {
664 assert (check_float_convert ());
670 check_double_convert_thread(void*)
672 for (int n = 0; n < s_iter_count; n++) {
673 assert (check_double_convert ());
678 static const double s_test_double = 31459.265359;
681 check_decimal_mark_is_comma_thread (void*)
683 for (int n = 0; n < s_iter_count; n++) {
684 assert (check_decimal_mark_is_comma ());
692 // Perform the test in the French locale as the format for decimals is
693 // different and a comma is used as a decimal point. Test that this has no
694 // impact on the string conversions which are expected to be the same as in the
697 StringConvertTest::test_convert_thread_safety ()
699 std::string locale_str;
701 CPPUNIT_ASSERT(get_locale_with_comma_decimal_mark(locale_str));
703 LocaleGuard guard (locale_str);
705 CPPUNIT_ASSERT (check_int_convert ());
706 CPPUNIT_ASSERT (check_float_convert ());
707 CPPUNIT_ASSERT (check_double_convert ());
708 CPPUNIT_ASSERT (check_decimal_mark_is_comma ());
710 pthread_t convert_int_thread;
711 pthread_t convert_float_thread;
712 pthread_t convert_double_thread;
713 pthread_t fr_printf_thread;
717 &convert_int_thread, NULL, check_int_convert_thread, NULL) == 0);
720 &convert_float_thread, NULL, check_float_convert_thread, NULL) == 0);
723 &convert_double_thread, NULL, check_double_convert_thread, NULL) == 0);
725 pthread_create (&fr_printf_thread, NULL, check_decimal_mark_is_comma_thread, NULL) ==
730 CPPUNIT_ASSERT (pthread_join (convert_int_thread, &return_value) == 0);
731 CPPUNIT_ASSERT (pthread_join (convert_float_thread, &return_value) == 0);
732 CPPUNIT_ASSERT (pthread_join (convert_double_thread, &return_value) == 0);
733 CPPUNIT_ASSERT (pthread_join (fr_printf_thread, &return_value) == 0);