| … | … | @@ -11,7 +11,6 @@ ADD_DEFINITIONS( |
| 11 | 11 | ADD_LIBRARY(cogutil SHARED |
| 12 | 12 | algorithm.h |
| 13 | 13 | backtrace-symbols.c |
| 14 | Config.cc | |
| 15 | 14 | exceptions.cc |
| 16 | 15 | lazy_selector.cc |
| 17 | 16 | lazy_random_selector.cc |
| … | … | @@ -99,7 +98,6 @@ INSTALL(FILES |
| 99 | 98 | async_method_caller.h |
| 100 | 99 | backtrace-symbols.h |
| 101 | 100 | cogutil.h |
| 102 | Config.h | |
| 103 | 101 | Counter.h |
| 104 | 102 | concurrent_queue.h |
| 105 | 103 | concurrent_set.h |
| … | … | @@ -1,260 +0,0 @@ |
| 1 | /* | |
| 2 | * opencog/util/Config.cc | |
| 3 | * | |
| 4 | * Copyright (C) 2008 by OpenCog Foundation | |
| 5 | * All Rights Reserved | |
| 6 | * | |
| 7 | * Written by Gustavo Gama <gama@vettalabs.com> | |
| 8 | * | |
| 9 | * This program is free software; you can redistribute it and/or modify | |
| 10 | * it under the terms of the GNU Affero General Public License v3 as | |
| 11 | * published by the Free Software Foundation and including the exceptions | |
| 12 | * at http://opencog.org/wiki/Licenses | |
| 13 | * | |
| 14 | * This program is distributed in the hope that it will be useful, | |
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 17 | * GNU General Public License for more details. | |
| 18 | * | |
| 19 | * You should have received a copy of the GNU Affero General Public License | |
| 20 | * along with this program; if not, write to: | |
| 21 | * Free Software Foundation, Inc., | |
| 22 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 23 | */ | |
| 24 | ||
| 25 | #include "Config.h" | |
| 26 | #include "Logger.h" | |
| 27 | ||
| 28 | #include <iostream> | |
| 29 | #include <filesystem> | |
| 30 | #include <fstream> | |
| 31 | #include <sstream> | |
| 32 | #include <cstdio> | |
| 33 | #include <cstdlib> | |
| 34 | ||
| 35 | #include <errno.h> | |
| 36 | #include <unistd.h> | |
| 37 | ||
| 38 | #include <opencog/util/platform.h> | |
| 39 | #include <opencog/util/exceptions.h> | |
| 40 | ||
| 41 | using namespace opencog; | |
| 42 | using namespace std; | |
| 43 | ||
| 44 | // Returns a string with leading/trailing characters of a set stripped | |
| 45 | static char const* blank_chars = " \t\f\v\n\r"; | |
| 46 | static string strip(string const& str, char const *strip_chars = blank_chars) | |
| 47 | { | |
| 48 | string::size_type const first = str.find_first_not_of(strip_chars); | |
| 49 | return (first == string::npos) ? | |
| 50 | string() : | |
| 51 | str.substr(first, str.find_last_not_of(strip_chars) - first + 1); | |
| 52 | } | |
| 53 | ||
| 54 | Config::~Config() | |
| 55 | { | |
| 56 | } | |
| 57 | ||
| 58 | Config::Config() | |
| 59 | { | |
| 60 | reset(); | |
| 61 | } | |
| 62 | ||
| 63 | void Config::reset() | |
| 64 | { | |
| 65 | _table.clear(); | |
| 66 | } | |
| 67 | ||
| 68 | static const char* DEFAULT_CONFIG_FILENAME = "opencog.conf"; | |
| 69 | ||
| 70 | void Config::load(const char* filename) | |
| 71 | { | |
| 72 | if (NULL == filename or 0 == filename[0]) | |
| 73 | filename = DEFAULT_CONFIG_FILENAME; | |
| 74 | ||
| 75 | std::filesystem::path configPath(filename); | |
| 76 | if (not std::filesystem::exists(configPath)) | |
| 77 | { | |
| 78 | logger().warn("Can't find config file \"%s\"\n", filename); | |
| 79 | throw IOException(TRACE_INFO, | |
| 80 | "Can't find config file \"%s\"", filename); | |
| 81 | } | |
| 82 | ||
| 83 | // Try to open it | |
| 84 | ifstream fin; | |
| 85 | fin.open(filename); | |
| 86 | if (!fin or !fin.good() or !fin.is_open()) | |
| 87 | { | |
| 88 | logger().warn("Cannot open config file \"%s\"\n", filename); | |
| 89 | throw IOException(TRACE_INFO, | |
| 90 | "Unable to open config file \"%s\"", filename); | |
| 91 | } | |
| 92 | ||
| 93 | string line; | |
| 94 | string name; | |
| 95 | string value; | |
| 96 | unsigned int line_number = 0; | |
| 97 | bool have_name = false; | |
| 98 | bool have_value = false; | |
| 99 | ||
| 100 | // Read and parse the config file. | |
| 101 | while (++line_number, fin.good() and getline(fin, line)) | |
| 102 | { | |
| 103 | string::size_type idx; | |
| 104 | ||
| 105 | // Find comment and discard the rest of the line. | |
| 106 | if ((idx = line.find('#')) != string::npos) { | |
| 107 | line.replace(idx, line.size() - idx, ""); | |
| 108 | } | |
| 109 | ||
| 110 | // Search for the '=' character. | |
| 111 | if ((idx = line.find('=')) != string::npos) | |
| 112 | { | |
| 113 | // Select name and value | |
| 114 | name = line.substr(0, idx); | |
| 115 | value = line.substr(idx + 1); | |
| 116 | ||
| 117 | // Strip out whitespace, etc. | |
| 118 | name = strip(name); | |
| 119 | value = strip(value); | |
| 120 | value = strip(value, "\""); | |
| 121 | ||
| 122 | have_name = true; | |
| 123 | ||
| 124 | // Look for trailing comma. | |
| 125 | if (',' != value[value.size()-1]) | |
| 126 | have_value = true; | |
| 127 | } | |
| 128 | ||
| 129 | // Append more to value | |
| 130 | else if ((string::npos != line.find_first_not_of(blank_chars)) && | |
| 131 | have_name && | |
| 132 | !have_value) | |
| 133 | { | |
| 134 | value += strip(line); | |
| 135 | ||
| 136 | // Look for trailing comma. | |
| 137 | if (',' != value[value.size()-1]) | |
| 138 | have_value = true; | |
| 139 | } | |
| 140 | ||
| 141 | else if (line.find_first_not_of(blank_chars) != string::npos) | |
| 142 | { | |
| 143 | // This might print the diagnostics to the default log file | |
| 144 | // location. Note that the config file itself contains the | |
| 145 | // log file location that is supposed to be used, so this | |
| 146 | // printing is happening "too early", before the logger is | |
| 147 | // fully initialized. Such is life; this is still a lot easier | |
| 148 | // than debugging the thrown exception in a debugger. | |
| 149 | setup_logger(); | |
| 150 | logger().warn("Invalid config file entry at line %d in %s\n", | |
| 151 | line_number, filename); | |
| 152 | ||
| 153 | throw InvalidParamException(TRACE_INFO, | |
| 154 | "[ERROR] invalid configuration entry (line %d)", | |
| 155 | line_number); | |
| 156 | } | |
| 157 | ||
| 158 | if (have_name && have_value) | |
| 159 | { | |
| 160 | // Finally, store the entries. | |
| 161 | _table[name] = value; | |
| 162 | have_name = false; | |
| 163 | have_value = false; | |
| 164 | value = ""; | |
| 165 | } | |
| 166 | } | |
| 167 | fin.close(); | |
| 168 | ||
| 169 | // Finish configuring the logger... The config file itself | |
| 170 | // contains the location of the log file. This is working around | |
| 171 | // a chicken-and-egg problem with reporting config file issues. | |
| 172 | setup_logger(); | |
| 173 | } | |
| 174 | ||
| 175 | void Config::setup_logger() | |
| 176 | { | |
| 177 | if (has("LOG_FILE")) | |
| 178 | logger().set_filename(get("LOG_FILE")); | |
| 179 | if (has("LOG_LEVEL")) | |
| 180 | logger().set_level(get("LOG_LEVEL")); | |
| 181 | if (has("BACK_TRACE_LOG_LEVEL")) | |
| 182 | logger().set_backtrace_level(get("BACK_TRACE_LOG_LEVEL")); | |
| 183 | if (has("LOG_TO_STDOUT")) | |
| 184 | logger().set_print_to_stdout_flag(get_bool("LOG_TO_STDOUT")); | |
| 185 | if (has("LOG_TIMESTAMP")) | |
| 186 | logger().set_timestamp_flag(get_bool("LOG_TIMESTAMP")); | |
| 187 | } | |
| 188 | ||
| 189 | const bool Config::has(const string &name) const | |
| 190 | { | |
| 191 | return (_table.find(name) != _table.end()); | |
| 192 | } | |
| 193 | ||
| 194 | void Config::set(const std::string ¶meter_name, | |
| 195 | const std::string ¶meter_value) | |
| 196 | { | |
| 197 | _table[parameter_name] = parameter_value; | |
| 198 | } | |
| 199 | ||
| 200 | const string& Config::get(const string& name, const string& dfl) const | |
| 201 | { | |
| 202 | if (not has(name)) return dfl; | |
| 203 | return _table.find(name)->second; | |
| 204 | } | |
| 205 | ||
| 206 | const string& Config::operator[](const string &name) const | |
| 207 | { | |
| 208 | if (not has(name)) | |
| 209 | throw InvalidParamException(TRACE_INFO, | |
| 210 | "[ERROR] parameter not found (%s)", | |
| 211 | name.c_str()); | |
| 212 | return _table.find(name)->second; | |
| 213 | } | |
| 214 | ||
| 215 | int Config::get_int(const string &name, int dfl) const | |
| 216 | { | |
| 217 | if (not has(name)) return dfl; | |
| 218 | return std::stoi(get(name)); | |
| 219 | } | |
| 220 | ||
| 221 | long Config::get_long(const string &name, long dfl) const | |
| 222 | { | |
| 223 | if (not has(name)) return dfl; | |
| 224 | return std::stol(get(name)); | |
| 225 | } | |
| 226 | ||
| 227 | double Config::get_double(const string &name, double dfl) const | |
| 228 | { | |
| 229 | if (not has(name)) return dfl; | |
| 230 | return std::stod(get(name)); | |
| 231 | } | |
| 232 | ||
| 233 | bool Config::get_bool(const string &name, bool dfl) const | |
| 234 | { | |
| 235 | if (not has(name)) return dfl; | |
| 236 | if (0 == get(name).compare("true")) return true; | |
| 237 | if (0 == get(name).compare("false")) return false; | |
| 238 | throw InvalidParamException(TRACE_INFO, | |
| 239 | "[ERROR] invalid bool parameter (%s: %s)", | |
| 240 | name.c_str(), get(name).c_str()); | |
| 241 | } | |
| 242 | ||
| 243 | std::string Config::to_string() const | |
| 244 | { | |
| 245 | std::ostringstream oss; | |
| 246 | oss << "{\""; | |
| 247 | for (auto it = _table.begin(); it != _table.end(); ++it) { | |
| 248 | if (it != _table.begin()) oss << "\", \""; | |
| 249 | oss << it->first << "\" => \"" << it->second; | |
| 250 | } | |
| 251 | oss << "\"}"; | |
| 252 | return oss.str(); | |
| 253 | } | |
| 254 | ||
| 255 | // create and return the single instance | |
| 256 | Config& opencog::config() | |
| 257 | { | |
| 258 | static std::unique_ptr<Config> instance(new Config()); | |
| 259 | return *instance; | |
| 260 | } |
| … | … | @@ -1,87 +0,0 @@ |
| 1 | /* | |
| 2 | * opencog/util/Config.h | |
| 3 | * | |
| 4 | * Copyright (C) 2008 by OpenCog Foundation | |
| 5 | * All Rights Reserved | |
| 6 | * | |
| 7 | * Written by Gustavo Gama <gama@vettalabs.com> | |
| 8 | * | |
| 9 | * This program is free software; you can redistribute it and/or modify | |
| 10 | * it under the terms of the GNU Affero General Public License v3 as | |
| 11 | * published by the Free Software Foundation and including the exceptions | |
| 12 | * at http://opencog.org/wiki/Licenses | |
| 13 | * | |
| 14 | * This program is distributed in the hope that it will be useful, | |
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 17 | * GNU General Public License for more details. | |
| 18 | * | |
| 19 | * You should have received a copy of the GNU Affero General Public License | |
| 20 | * along with this program; if not, write to: | |
| 21 | * Free Software Foundation, Inc., | |
| 22 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 23 | */ | |
| 24 | ||
| 25 | #ifndef _OPENCOG_CONFIG_H | |
| 26 | #define _OPENCOG_CONFIG_H | |
| 27 | ||
| 28 | #include <map> | |
| 29 | #include <string> | |
| 30 | ||
| 31 | namespace opencog | |
| 32 | { | |
| 33 | /** \addtogroup grp_cogutil | |
| 34 | * @{ | |
| 35 | */ | |
| 36 | ||
| 37 | //! library-wide configuration; keys and values are strings | |
| 38 | class Config | |
| 39 | { | |
| 40 | protected: | |
| 41 | std::map<std::string, std::string> _table; | |
| 42 | void setup_logger(); | |
| 43 | ||
| 44 | public: | |
| 45 | Config(void); | |
| 46 | ~Config(); | |
| 47 | ||
| 48 | //! Reset configuration to default. | |
| 49 | void reset(); | |
| 50 | ||
| 51 | //! Parse the indicated file for parameter values. | |
| 52 | void load(const char* config_file); | |
| 53 | ||
| 54 | //! Return true if a parameter exists. | |
| 55 | const bool has(const std::string ¶meter_name) const; | |
| 56 | ||
| 57 | //! Set the value of a given parameter. | |
| 58 | void set(const std::string ¶meter_name, const std::string ¶meter_value); | |
| 59 | ||
| 60 | //! Return current value of a given parameter. | |
| 61 | const std::string& get(const std::string &, const std::string& = "") const; | |
| 62 | //! Return current value of a given parameter. | |
| 63 | const std::string& operator[](const std::string &) const; | |
| 64 | ||
| 65 | //! Return current value of a given parameter as an integer. | |
| 66 | int get_int(const std::string &, int = 0) const; | |
| 67 | ||
| 68 | //! Return current value of a given parameter as an long. | |
| 69 | long get_long(const std::string &, long = 0) const; | |
| 70 | ||
| 71 | //! Return current value of a given parameter as a double. | |
| 72 | double get_double(const std::string &, double = 0.0) const; | |
| 73 | ||
| 74 | //! Return current value of a given parameter as a boolean. | |
| 75 | bool get_bool(const std::string &, bool = false) const; | |
| 76 | ||
| 77 | //! Dump all configuration parameters to a string. | |
| 78 | std::string to_string() const; | |
| 79 | }; | |
| 80 | ||
| 81 | //! singleton instance (following meyer's design pattern) | |
| 82 | Config& config(); | |
| 83 | ||
| 84 | /** @}*/ | |
| 85 | } // namespace opencog | |
| 86 | ||
| 87 | #endif // _OPENCOG_CONFIG_H |
| … | … | @@ -12,7 +12,6 @@ LINK_LIBRARIES( |
| 12 | 12 | ) |
| 13 | 13 | |
| 14 | 14 | ADD_CXXTEST(algorithmUTest) |
| 15 | ADD_CXXTEST(ConfigUTest) | |
| 16 | 15 | ADD_CXXTEST(CounterUTest) |
| 17 | 16 | ADD_CXXTEST(LoggerUTest) |
| 18 | 17 | ADD_CXXTEST(numericUTest) |
| … | … | @@ -1,143 +0,0 @@ |
| 1 | /* | |
| 2 | * tests/util/ConfigUTest.cxxtest | |
| 3 | * | |
| 4 | * Copyright (C) 2008 by OpenCog Foundation | |
| 5 | * All Rights Reserved | |
| 6 | * | |
| 7 | * Written by Gustavo Gama <gama@vettalabs.com> | |
| 8 | * | |
| 9 | * This program is free software; you can redistribute it and/or modify | |
| 10 | * it under the terms of the GNU Affero General Public License v3 as | |
| 11 | * published by the Free Software Foundation and including the exceptions | |
| 12 | * at http://opencog.org/wiki/Licenses | |
| 13 | * | |
| 14 | * This program is distributed in the hope that it will be useful, | |
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 17 | * GNU General Public License for more details. | |
| 18 | * | |
| 19 | * You should have received a copy of the GNU Affero General Public License | |
| 20 | * along with this program; if not, write to: | |
| 21 | * Free Software Foundation, Inc., | |
| 22 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| 23 | */ | |
| 24 | ||
| 25 | #include <cstdio> | |
| 26 | #include <fstream> | |
| 27 | #include <iostream> | |
| 28 | ||
| 29 | #include <opencog/util/Config.h> | |
| 30 | #include <opencog/util/exceptions.h> | |
| 31 | ||
| 32 | using namespace opencog; | |
| 33 | ||
| 34 | class ConfigUTest : public CxxTest::TestSuite | |
| 35 | { | |
| 36 | ||
| 37 | public: | |
| 38 | ConfigUTest() {} | |
| 39 | void setUp() {} | |
| 40 | void tearDown() {} | |
| 41 | ||
| 42 | void testDefault() | |
| 43 | { | |
| 44 | TS_ASSERT_THROWS(config()["INVALID_PARAM"], InvalidParamException&); | |
| 45 | TS_ASSERT(config().get("SERVER_PORT", "17001") == "17001"); | |
| 46 | TS_ASSERT(config().get_int("SERVER_PORT", 17001) == 17001); | |
| 47 | TS_ASSERT(config().get_double("SERVER_PORT", 17001.0) == 17001.0); | |
| 48 | TS_ASSERT(config().get("LOG_FILE", "opencog_server.log") == "opencog_server.log"); | |
| 49 | TS_ASSERT(config().get("LOG_LEVEL", "info") == "info"); | |
| 50 | TS_ASSERT(config().get("BACK_TRACE_LOG_LEVEL", "error") == "error"); // C++ stack traces only on error! | |
| 51 | TS_ASSERT(config().get_bool("LOG_TO_STDOUT", true)); | |
| 52 | TS_ASSERT(config().get_int("SERVER_CYCLE_DURATION", 100) == 100); | |
| 53 | TS_ASSERT(!config().get_bool("EXTERNAL_TICK_MODE")); | |
| 54 | TS_ASSERT(config().get_int("STARTING_STI_FUNDS", 10000) == 10000); | |
| 55 | TS_ASSERT(config().get_int("STARTING_LTI_FUNDS", 10000) == 10000); | |
| 56 | TS_ASSERT(config().get_int("STI_FUNDS_BUFFER", 10000) == 10000); | |
| 57 | TS_ASSERT(config().get_int("LTI_FUNDS_BUFFER", 10000) == 10000); | |
| 58 | TS_ASSERT(config().get_int("MIN_STI", -400) == -400); | |
| 59 | TS_ASSERT(config().get("PROMPT", "opencog> ") == "opencog> "); | |
| 60 | TS_ASSERT(config().get("MODULES", "libbuiltinreqs.so") == "libbuiltinreqs.so"); | |
| 61 | } | |
| 62 | ||
| 63 | ||
| 64 | void testLoadFromFile() | |
| 65 | { | |
| 66 | // first, write the configuration file | |
| 67 | const char *config_file_name = "ConfigUTest.config"; | |
| 68 | std::ofstream out(config_file_name); | |
| 69 | out << "# ConfigUTest file; commented initial line\n"; | |
| 70 | out << " # Another comment line with blank prefix\n"; | |
| 71 | out << " PARAM1 = VALUE1\n"; | |
| 72 | out << " PARAM2 = VALUE2 \n"; | |
| 73 | out << "PARAM3=VALUE3\n"; | |
| 74 | out << "COMPOSED PARAMETER NAME 4 = VALUE4\n"; | |
| 75 | out << "# another comment, just for kicks\n"; | |
| 76 | out << "PARAM5 = COMPOSED PARAMETER VALUE 5 \n"; | |
| 77 | out << "PARAM6 = VALUE6 # end of line comments\n"; | |
| 78 | out << " PARAM7 = 248 # integer parameter\n"; | |
| 79 | out << "PARAM8 =1.2584 # double parameter\n"; | |
| 80 | //out << "PARAM9= -29847.167015 $&@*a786A!$alk # double parameter and useless discarded extra characters\n"; | |
| 81 | out << "PARAM9= -29847.167015 # double parameter\n"; | |
| 82 | out << "STI_FUNDS_BUFFER = 200\n"; | |
| 83 | out << "LTI_FUNDS_BUFFER = 10\n"; | |
| 84 | out << "LOG_TO_STDOUT = false\n"; | |
| 85 | out.close(); | |
| 86 | ||
| 87 | // reset configuration to default parameters | |
| 88 | config().reset(); | |
| 89 | ||
| 90 | // check default parameters before and after loading file | |
| 91 | TS_ASSERT(config().get_int("STI_FUNDS_BUFFER", 10000) == 10000); | |
| 92 | TS_ASSERT(config().get_int("LTI_FUNDS_BUFFER", 10000) == 10000); | |
| 93 | config().load(config_file_name); | |
| 94 | TS_ASSERT(config().get_int("STI_FUNDS_BUFFER", 10000) == 200); | |
| 95 | TS_ASSERT(config().get_int("LTI_FUNDS_BUFFER", 10000) == 10); | |
| 96 | TS_ASSERT(!config().get_bool("LOG_TO_STDOUT", true)); | |
| 97 | ||
| 98 | // check remaining parameters from file | |
| 99 | TS_ASSERT(config().get("PARAM1") == "VALUE1"); | |
| 100 | TS_ASSERT(config()["PARAM2"] == "VALUE2"); | |
| 101 | TS_ASSERT(config()["PARAM3"] == "VALUE3"); | |
| 102 | TS_ASSERT(config()["COMPOSED PARAMETER NAME 4"] == "VALUE4"); | |
| 103 | TS_ASSERT(config()["PARAM5"] == "COMPOSED PARAMETER VALUE 5"); | |
| 104 | TS_ASSERT(config()["PARAM6"] == "VALUE6"); | |
| 105 | TS_ASSERT(config().get_int("PARAM7", 999) == 248); | |
| 106 | TS_ASSERT(config().get_double("PARAM8", 3.14159) == 1.2584); | |
| 107 | TS_ASSERT(config().get_double("PARAM9", 2.718281828) == -29847.167015); | |
| 108 | ||
| 109 | // finally, remove the temporary file and free the string with its name | |
| 110 | std::remove(config_file_name); | |
| 111 | } | |
| 112 | ||
| 113 | void testSet() | |
| 114 | { | |
| 115 | // reset configuration to default parameters | |
| 116 | config().reset(); | |
| 117 | ||
| 118 | // check default parameters before and setting the new value | |
| 119 | TS_ASSERT(config().get("STI_FUNDS_BUFFER", "10000") == "10000"); | |
| 120 | TS_ASSERT(config().get_int("STI_FUNDS_BUFFER", 10000) == 10000); | |
| 121 | config().set("STI_FUNDS_BUFFER", "200"); | |
| 122 | TS_ASSERT(config().get("STI_FUNDS_BUFFER", "10000") == "200"); | |
| 123 | TS_ASSERT(config().get_int("STI_FUNDS_BUFFER", 10000) == 200); | |
| 124 | } | |
| 125 | ||
| 126 | /** | |
| 127 | * Check that setting a boolean parameter and getting an int | |
| 128 | * raises an InvalidParamException | |
| 129 | */ | |
| 130 | void testGetType() | |
| 131 | { | |
| 132 | config().reset(); | |
| 133 | ||
| 134 | config().set("BOOL_PARAM1", "true"); | |
| 135 | config().set("BOOL_PARAM2", "false"); | |
| 136 | ||
| 137 | TS_ASSERT_EQUALS(config().get_bool("BOOL_PARAM1"), true); | |
| 138 | TS_ASSERT_THROWS_ANYTHING(config().get_int("BOOL_PARAM2")); | |
| 139 | TS_ASSERT_THROWS_ANYTHING(config().get_long("BOOL_PARAM2")); | |
| 140 | TS_ASSERT_THROWS_ANYTHING(config().get_double("BOOL_PARAM2")); | |
| 141 | } | |
| 142 | ||
| 143 | }; // class |