From de57fe2fc9193113dbdf4d53233d47147769173d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6=20Fahlke?= <jorrit@jorrit.de> Date: Sat, 8 Nov 2014 12:59:38 +0100 Subject: [PATCH] [parametertree][locale][fs1528] Check ParameterTree::get() with a locale using "," as the decimal seperator. ParameterTrees are usually read from configuration files. The format of the configuration file should not depend on the locale. For the commandline parser it would likewise be surprising if "progname -param 0.5" stopped working in a german locale. Not long ago these kinds of errors would not even generate a diagnosis due to FS#1527. However, the locale of the program is "C" by default, so probably not many poeple are actually affected by this problem. It can happen however that other libraries linked into the same program set the locale from the environment. --- dune/common/test/.gitignore | 1 + dune/common/test/CMakeLists.txt | 4 + dune/common/test/Makefile.am | 2 + dune/common/test/parametertreelocaletest.cc | 97 +++++++++++++++++++++ 4 files changed, 104 insertions(+) create mode 100644 dune/common/test/parametertreelocaletest.cc diff --git a/dune/common/test/.gitignore b/dune/common/test/.gitignore index c88d294bb..590b258e0 100644 --- a/dune/common/test/.gitignore +++ b/dune/common/test/.gitignore @@ -31,6 +31,7 @@ /mpihelpertest /mpihelpertest2 /nullptr-test +/parametertreelocaletest /parametertreetest /pathtest /poolallocatortest diff --git a/dune/common/test/CMakeLists.txt b/dune/common/test/CMakeLists.txt index a1120ebc3..cc90aab94 100644 --- a/dune/common/test/CMakeLists.txt +++ b/dune/common/test/CMakeLists.txt @@ -24,6 +24,7 @@ set(TESTS mpihelpertest2 nullptr_test pathtest + parametertreelocaletest parametertreetest poolallocatortest shared_ptrtest_config @@ -126,6 +127,9 @@ add_executable("nullptr_test_fail" EXCLUDE_FROM_ALL nullptr-test.cc) target_link_libraries(nullptr_test_fail "dunecommon") set_target_properties(nullptr_test_fail PROPERTIES COMPILE_FLAGS "-DFAIL") +add_executable("parametertreelocaletest" parametertreelocaletest.cc) +target_link_libraries("parametertreelocaletest" "dunecommon") + add_executable("parametertreetest" parametertreetest.cc) target_link_libraries("parametertreetest" "dunecommon") diff --git a/dune/common/test/Makefile.am b/dune/common/test/Makefile.am index fe06436d7..72fea70ad 100644 --- a/dune/common/test/Makefile.am +++ b/dune/common/test/Makefile.am @@ -25,6 +25,7 @@ TESTPROGS = \ mpihelpertest2 \ nullptr-test \ pathtest \ + parametertreelocaletest \ parametertreetest \ poolallocatortest \ shared_ptrtest_config \ @@ -155,6 +156,7 @@ nullptr_test_SOURCES = nullptr-test.cc nullptr-test2.cc nullptr_test_fail_SOURCES = nullptr-test.cc nullptr_test_fail_CPPFLAGS = $(AM_CPPFLAGS) -DFAIL +parametertreelocaletest_SOURCES = parametertreelocaletest.cc parametertreetest_SOURCES = parametertreetest.cc pathtest_SOURCES = pathtest.cc diff --git a/dune/common/test/parametertreelocaletest.cc b/dune/common/test/parametertreelocaletest.cc new file mode 100644 index 000000000..2a2dc2a31 --- /dev/null +++ b/dune/common/test/parametertreelocaletest.cc @@ -0,0 +1,97 @@ +#if HAVE_CONFIG_H +#include <config.h> +#endif + +#include <cstdlib> +#include <iostream> +#include <locale> +#include <ostream> +#include <stdexcept> +#include <string> + +#include <dune/common/exceptions.hh> +#include <dune/common/parametertree.hh> + +// This assert macro does not depend on the value of NDEBUG +#define check_assert(expr) \ + do \ + { \ + if(!(expr)) \ + { \ + std::cerr << __FILE__ << ":" << __LINE__ << ": check_assert(" \ + << #expr << ") failed" << std::endl; \ + std::abort(); \ + } \ + } while(false) + +// Check that the given expression throws the given exception +#define check_throw(expr, except) \ + do { \ + try { \ + expr; \ + std::cerr << __FILE__ << ":" << __LINE__ << ": " << #expr \ + << " should throw " << #except << std::endl; \ + std::abort(); \ + } \ + catch(except) {} \ + catch(...) { \ + std::cerr << __FILE__ << ":" << __LINE__ << ": " << #expr \ + << " should throw " << #except << std::endl; \ + std::abort(); \ + } \ + } while(false) + +// globally set a locale that uses "," as the decimal seperator. +// return false if no such locale is installed on the system +bool setCommaLocale() +{ + static char const* const commaLocales[] = { + "de", "de@euro", "de.UTF-8", + "de_AT", "de_AT@euro", "de_AT.UTF-8", + "de_BE", "de_BE@euro", "de_BE.UTF-8", + "de_CH", "de_CH@euro", "de_CH.UTF-8", + "de_DE", "de_DE@euro", "de_DE.UTF-8", + "de_LI", "de_LI@euro", "de_LI.UTF-8", + "de_LU", "de_LU@euro", "de_LU.UTF-8", + NULL + }; + for(char const* const* loc = commaLocales; *loc; ++loc) + { + try { + std::locale::global(std::locale(*loc)); + std::cout << "Using comma-locale " << std::locale().name() << std::endl; + return true; + } + catch(std::runtime_error) { } + } + + std::cout << "No comma-using locale found on system, tried the following:"; + std::string sep = " "; + for(char const* const* loc = commaLocales; *loc; ++loc) + { + std::cout << sep << *loc; + sep = ", "; + } + std::cout << std::endl; + return false; +} + +int main() +{ + if(!setCommaLocale()) + { + std::cerr << "No locale using comma as decimal seperator found on system" + << std::endl; + return 77; + } + { // Try with comma + Dune::ParameterTree ptree; + check_throw(ptree["setting"] = "42,42"; ptree.get<double>("setting"), + Dune::RangeError); + } + { // Try with point + Dune::ParameterTree ptree; + check_assert((ptree["setting"] = "42.42", + ptree.get<double>("setting") == 42.42)); + } +} -- GitLab