/src/log4cplus/src/property.cxx
Line | Count | Source |
1 | | // Module: Log4CPLUS |
2 | | // File: property.cxx |
3 | | // Created: 2/2002 |
4 | | // Author: Tad E. Smith |
5 | | // |
6 | | // |
7 | | // Copyright 2002-2017 Tad E. Smith |
8 | | // |
9 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
10 | | // you may not use this file except in compliance with the License. |
11 | | // You may obtain a copy of the License at |
12 | | // |
13 | | // http://www.apache.org/licenses/LICENSE-2.0 |
14 | | // |
15 | | // Unless required by applicable law or agreed to in writing, software |
16 | | // distributed under the License is distributed on an "AS IS" BASIS, |
17 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
18 | | // See the License for the specific language governing permissions and |
19 | | // limitations under the License. |
20 | | |
21 | | #include <log4cplus/config.hxx> |
22 | | |
23 | | #include <cstring> |
24 | | #if defined (UNICODE) |
25 | | # include <cwctype> |
26 | | #else |
27 | | # include <cctype> |
28 | | #endif |
29 | | #if defined (LOG4CPLUS_HAVE_CODECVT_UTF8_FACET) \ |
30 | | || defined (LOG4CPLUS_HAVE_CODECVT_UTF16_FACET) \ |
31 | | || defined (LOG4CPLUS_HAVE_CODECVT_UTF32_FACET) |
32 | | # include <codecvt> |
33 | | #endif |
34 | | #include <locale> |
35 | | #include <fstream> |
36 | | #include <sstream> |
37 | | #include <iostream> |
38 | | #include <log4cplus/streams.h> |
39 | | #include <log4cplus/fstreams.h> |
40 | | #include <log4cplus/helpers/stringhelper.h> |
41 | | #include <log4cplus/helpers/property.h> |
42 | | #include <log4cplus/internal/internal.h> |
43 | | #include <log4cplus/internal/env.h> |
44 | | #include <log4cplus/helpers/loglog.h> |
45 | | #include <log4cplus/exception.h> |
46 | | #include <log4cplus/configurator.h> |
47 | | |
48 | | #if defined (LOG4CPLUS_WITH_UNIT_TESTS) |
49 | | #include <catch.hpp> |
50 | | #endif |
51 | | |
52 | | |
53 | | namespace log4cplus { namespace helpers { |
54 | | |
55 | | |
56 | | const tchar Properties::PROPERTIES_COMMENT_CHAR = LOG4CPLUS_TEXT('#'); |
57 | | |
58 | | |
59 | | namespace |
60 | | { |
61 | | |
62 | | |
63 | | static |
64 | | int |
65 | | is_space (tchar ch) |
66 | 0 | { |
67 | | #if defined (UNICODE) |
68 | | return std::iswspace (ch); |
69 | | #else |
70 | 0 | return std::isspace (static_cast<unsigned char>(ch)); |
71 | 0 | #endif |
72 | 0 | } |
73 | | |
74 | | |
75 | | static |
76 | | void |
77 | | trim_leading_ws (tstring & str) |
78 | 0 | { |
79 | 0 | tstring::iterator it = str.begin (); |
80 | 0 | for (; it != str.end (); ++it) |
81 | 0 | { |
82 | 0 | if (! is_space (*it)) |
83 | 0 | break; |
84 | 0 | } |
85 | 0 | str.erase (str.begin (), it); |
86 | 0 | } |
87 | | |
88 | | |
89 | | static |
90 | | void |
91 | | trim_trailing_ws (tstring & str) |
92 | 0 | { |
93 | 0 | tstring::reverse_iterator rit = str.rbegin (); |
94 | 0 | for (; rit != str.rend (); ++rit) |
95 | 0 | { |
96 | 0 | if (! is_space (*rit)) |
97 | 0 | break; |
98 | 0 | } |
99 | 0 | str.erase (rit.base (), str.end ()); |
100 | 0 | } |
101 | | |
102 | | |
103 | | static |
104 | | void |
105 | | trim_ws (tstring & str) |
106 | 0 | { |
107 | 0 | trim_trailing_ws (str); |
108 | 0 | trim_leading_ws (str); |
109 | 0 | } |
110 | | |
111 | | |
112 | | #if defined (LOG4CPLUS_WITH_UNIT_TESTS) |
113 | | CATCH_TEST_CASE( "String trimming", "[strings][properties]") |
114 | | { |
115 | | CATCH_SECTION ("trim trailing whitespace") |
116 | | { |
117 | | tstring trailing_ws (LOG4CPLUS_TEXT ("abcd \t\n\v\f\r")); |
118 | | trim_trailing_ws (trailing_ws); |
119 | | CATCH_REQUIRE (trailing_ws == LOG4CPLUS_TEXT ("abcd")); |
120 | | } |
121 | | |
122 | | CATCH_SECTION ("trim leading whitespace") |
123 | | { |
124 | | tstring leading_ws (LOG4CPLUS_TEXT (" \t\n\v\f\rabcd")); |
125 | | trim_leading_ws (leading_ws); |
126 | | CATCH_REQUIRE (leading_ws == LOG4CPLUS_TEXT ("abcd")); |
127 | | } |
128 | | |
129 | | CATCH_SECTION ("trim all whitespace") |
130 | | { |
131 | | tstring ws (LOG4CPLUS_TEXT (" \t\n\v\f\rabcd \t\n\v\f\r")); |
132 | | trim_ws (ws); |
133 | | CATCH_REQUIRE (ws == LOG4CPLUS_TEXT ("abcd")); |
134 | | } |
135 | | } |
136 | | #endif |
137 | | |
138 | | |
139 | | void |
140 | | imbue_file_from_flags (tistream & file, unsigned flags) |
141 | 0 | { |
142 | 0 | switch (flags & (Properties::fEncodingMask << Properties::fEncodingShift)) |
143 | 0 | { |
144 | | #if defined (LOG4CPLUS_HAVE_CODECVT_UTF8_FACET) && defined (UNICODE) |
145 | | case Properties::fUTF8: |
146 | | file.imbue ( |
147 | | std::locale (file.getloc (), |
148 | | new std::codecvt_utf8<tchar, 0x10FFFF, |
149 | | static_cast<std::codecvt_mode>(std::consume_header | std::little_endian)>)); |
150 | | break; |
151 | | #endif |
152 | | |
153 | | #if defined (LOG4CPLUS_HAVE_CODECVT_UTF16_FACET) && defined (UNICODE) |
154 | | case Properties::fUTF16: |
155 | | file.imbue ( |
156 | | std::locale (file.getloc (), |
157 | | new std::codecvt_utf16<tchar, 0x10FFFF, |
158 | | static_cast<std::codecvt_mode>(std::consume_header | std::little_endian)>)); |
159 | | break; |
160 | | |
161 | | #elif defined (UNICODE) && defined (WIN32) |
162 | | case Properties::fUTF16: |
163 | | file.imbue ( |
164 | | std::locale (file.getloc (), |
165 | | // TODO: This should actually be a custom "null" facet |
166 | | // that just copies the chars to wchar_t buffer. |
167 | | new std::codecvt<wchar_t, char, std::mbstate_t>)); |
168 | | break; |
169 | | |
170 | | #endif |
171 | | |
172 | | #if defined (LOG4CPLUS_HAVE_CODECVT_UTF32_FACET) && defined (UNICODE) |
173 | | case Properties::fUTF32: |
174 | | file.imbue ( |
175 | | std::locale (file.getloc (), |
176 | | new std::codecvt_utf32<tchar, 0x10FFFF, |
177 | | static_cast<std::codecvt_mode>(std::consume_header | std::little_endian)>)); |
178 | | break; |
179 | | #endif |
180 | | |
181 | 0 | case Properties::fUnspecEncoding:; |
182 | 0 | default: |
183 | | // Do nothing. |
184 | 0 | ; |
185 | 0 | } |
186 | 0 | } |
187 | | |
188 | | |
189 | | } // namespace |
190 | | |
191 | | |
192 | | /** |
193 | | * Perform variable substitution in string <code>val</code> from |
194 | | * environment variables. |
195 | | * |
196 | | * <p>The variable substitution delimeters are <b>${</b> and <b>}</b>. |
197 | | * |
198 | | * <p>For example, if the System properties contains "key=value", then |
199 | | * the call |
200 | | * <pre> |
201 | | * string s; |
202 | | * substEnvironVars(s, "Value of key is ${key}."); |
203 | | * </pre> |
204 | | * |
205 | | * will set the variable <code>s</code> to "Value of key is value.". |
206 | | * |
207 | | * <p>If no value could be found for the specified key, then |
208 | | * substitution defaults to the empty string. |
209 | | * |
210 | | * <p>For example, if there is no environment variable "inexistentKey", |
211 | | * then the call |
212 | | * |
213 | | * <pre> |
214 | | * string s; |
215 | | * substEnvironVars(s, "Value of inexistentKey is [${inexistentKey}]"); |
216 | | * </pre> |
217 | | * will set <code>s</code> to "Value of inexistentKey is []" |
218 | | * |
219 | | * @param val The string on which variable substitution is performed. |
220 | | * @param dest The result. |
221 | | */ |
222 | | bool |
223 | | substVars (tstring & dest, const tstring & val, |
224 | | helpers::Properties const & props, helpers::LogLog& loglog, |
225 | | unsigned flags) |
226 | 0 | { |
227 | 0 | static tchar const DELIM_START[] = LOG4CPLUS_TEXT("${"); |
228 | 0 | static tchar const DELIM_STOP[] = LOG4CPLUS_TEXT("}"); |
229 | 0 | static std::size_t const DELIM_START_LEN = 2; |
230 | 0 | static std::size_t const DELIM_STOP_LEN = 1; |
231 | |
|
232 | 0 | tstring::size_type i = 0; |
233 | 0 | tstring::size_type var_start, var_end; |
234 | 0 | tstring pattern (val); |
235 | 0 | tstring key; |
236 | 0 | tstring replacement; |
237 | 0 | bool changed = false; |
238 | 0 | bool const empty_vars |
239 | 0 | = !! (flags & PropertyConfigurator::fAllowEmptyVars); |
240 | 0 | bool const shadow_env |
241 | 0 | = !! (flags & PropertyConfigurator::fShadowEnvironment); |
242 | 0 | bool const rec_exp |
243 | 0 | = !! (flags & PropertyConfigurator::fRecursiveExpansion); |
244 | |
|
245 | 0 | while (true) |
246 | 0 | { |
247 | | // Find opening paren of variable substitution. |
248 | 0 | var_start = pattern.find(DELIM_START, i); |
249 | 0 | if (var_start == tstring::npos) |
250 | 0 | { |
251 | 0 | dest = pattern; |
252 | 0 | return changed; |
253 | 0 | } |
254 | | |
255 | | // Find closing paren of variable substitution. |
256 | 0 | var_end = pattern.find(DELIM_STOP, var_start); |
257 | 0 | if (var_end == tstring::npos) |
258 | 0 | { |
259 | 0 | tostringstream buffer; |
260 | 0 | buffer << '"' << pattern |
261 | 0 | << "\" has no closing brace. " |
262 | 0 | << "Opening brace at position " << var_start << "."; |
263 | 0 | loglog.error(buffer.str()); |
264 | 0 | dest = val; |
265 | 0 | return false; |
266 | 0 | } |
267 | | |
268 | 0 | key.assign (pattern, var_start + DELIM_START_LEN, |
269 | 0 | var_end - (var_start + DELIM_START_LEN)); |
270 | 0 | replacement.clear (); |
271 | 0 | if (shadow_env) |
272 | 0 | replacement = props.getProperty (key); |
273 | 0 | if (! shadow_env || (! empty_vars && replacement.empty ())) |
274 | 0 | internal::get_env_var (replacement, key); |
275 | |
|
276 | 0 | if (empty_vars || ! replacement.empty ()) |
277 | 0 | { |
278 | | // Substitute the variable with its value in place. |
279 | 0 | pattern.replace (var_start, var_end - var_start + DELIM_STOP_LEN, |
280 | 0 | replacement); |
281 | 0 | changed = true; |
282 | 0 | if (rec_exp) |
283 | | // Retry expansion on the same spot. |
284 | 0 | continue; |
285 | 0 | else |
286 | | // Move beyond the just substituted part. |
287 | 0 | i = var_start + replacement.size (); |
288 | 0 | } |
289 | 0 | else |
290 | | // Nothing has been subtituted, just move beyond the |
291 | | // unexpanded variable. |
292 | 0 | i = var_end + DELIM_STOP_LEN; |
293 | 0 | } // end while loop |
294 | |
|
295 | 0 | } // end substVars() |
296 | | |
297 | | |
298 | | /////////////////////////////////////////////////////////////////////////////// |
299 | | // Properties ctors and dtor |
300 | | /////////////////////////////////////////////////////////////////////////////// |
301 | | |
302 | | Properties::Properties() |
303 | 797k | : flags (0) |
304 | 797k | { |
305 | 797k | } |
306 | | |
307 | | |
308 | | |
309 | | Properties::Properties(tistream& input) |
310 | 0 | : flags (0) |
311 | 0 | { |
312 | 0 | init(input); |
313 | 0 | } |
314 | | |
315 | | |
316 | | |
317 | | Properties::Properties(const tstring& inputFile, unsigned f) |
318 | 122k | : flags (f) |
319 | 122k | { |
320 | 122k | if (inputFile.empty ()) |
321 | 122k | return; |
322 | | |
323 | 0 | tifstream file; |
324 | 0 | imbue_file_from_flags (file, flags); |
325 | |
|
326 | 0 | file.open(LOG4CPLUS_FSTREAM_PREFERED_FILE_NAME(inputFile).c_str(), |
327 | 0 | std::ios::binary); |
328 | 0 | if (! file.good ()) |
329 | 0 | helpers::getLogLog ().error (LOG4CPLUS_TEXT ("could not open file ") |
330 | 0 | + inputFile, (flags & Properties::fThrow) != 0); |
331 | |
|
332 | 0 | init(file); |
333 | 0 | } |
334 | | |
335 | | |
336 | | |
337 | | void |
338 | | Properties::init(tistream& input) |
339 | 0 | { |
340 | 0 | if (! input) |
341 | 0 | return; |
342 | | |
343 | 0 | tstring buffer; |
344 | 0 | while (std::getline (input, buffer)) |
345 | 0 | { |
346 | 0 | trim_leading_ws (buffer); |
347 | |
|
348 | 0 | tstring::size_type const buffLen = buffer.size (); |
349 | 0 | if (buffLen == 0 || buffer[0] == PROPERTIES_COMMENT_CHAR) |
350 | 0 | continue; |
351 | | |
352 | | // Check if we have a trailing \r because we are |
353 | | // reading a properties file produced on Windows. |
354 | 0 | if (buffer[buffLen-1] == LOG4CPLUS_TEXT('\r')) |
355 | | // Remove trailing 'Windows' \r. |
356 | 0 | buffer.resize (buffLen - 1); |
357 | |
|
358 | 0 | if (buffer.size () >= 7 + 1 + 1 |
359 | 0 | && buffer.compare (0, 7, LOG4CPLUS_TEXT ("include")) == 0 |
360 | 0 | && is_space (buffer[7])) |
361 | 0 | { |
362 | 0 | tstring included (buffer, 8) ; |
363 | 0 | trim_ws (included); |
364 | |
|
365 | 0 | tstring subIncluded; |
366 | 0 | helpers::substVars(subIncluded, included, *this, helpers::getLogLog(), 0); |
367 | |
|
368 | 0 | tifstream file; |
369 | 0 | imbue_file_from_flags (file, flags); |
370 | |
|
371 | 0 | file.open (LOG4CPLUS_FSTREAM_PREFERED_FILE_NAME(subIncluded).c_str(), |
372 | 0 | std::ios::binary); |
373 | 0 | if (! file.good ()) |
374 | 0 | helpers::getLogLog ().error ( |
375 | 0 | LOG4CPLUS_TEXT ("could not open file ") + subIncluded); |
376 | |
|
377 | 0 | init (file); |
378 | 0 | } |
379 | 0 | else |
380 | 0 | { |
381 | 0 | tstring::size_type const idx = buffer.find(LOG4CPLUS_TEXT ('=')); |
382 | 0 | if (idx != tstring::npos) |
383 | 0 | { |
384 | 0 | tstring key = buffer.substr(0, idx); |
385 | 0 | tstring value = buffer.substr(idx + 1); |
386 | 0 | trim_trailing_ws (key); |
387 | 0 | trim_ws (value); |
388 | 0 | setProperty(key, value); |
389 | 0 | } |
390 | 0 | } |
391 | 0 | } |
392 | 0 | } |
393 | | |
394 | | |
395 | | |
396 | | Properties::~Properties() |
397 | 920k | { |
398 | 920k | } |
399 | | |
400 | | |
401 | | |
402 | | /////////////////////////////////////////////////////////////////////////////// |
403 | | // helpers::Properties public methods |
404 | | /////////////////////////////////////////////////////////////////////////////// |
405 | | |
406 | | |
407 | | bool |
408 | | Properties::exists(const log4cplus::tstring& key) const |
409 | 1.35M | { |
410 | 1.35M | return data.find(key) != data.end(); |
411 | 1.35M | } |
412 | | |
413 | | |
414 | | bool |
415 | | Properties::exists(tchar const * key) const |
416 | 368k | { |
417 | 368k | return data.find(key) != data.end(); |
418 | 368k | } |
419 | | |
420 | | |
421 | | tstring const & |
422 | | Properties::getProperty(const tstring& key) const |
423 | 613k | { |
424 | 613k | return get_property_worker (key); |
425 | 613k | } |
426 | | |
427 | | |
428 | | log4cplus::tstring const & |
429 | | Properties::getProperty(tchar const * key) const |
430 | 122k | { |
431 | 122k | return get_property_worker (key); |
432 | 122k | } |
433 | | |
434 | | |
435 | | tstring |
436 | | Properties::getProperty(const tstring& key, const tstring& defaultVal) const |
437 | 0 | { |
438 | 0 | StringMap::const_iterator it (data.find (key)); |
439 | 0 | if (it == data.end ()) |
440 | 0 | return defaultVal; |
441 | 0 | else |
442 | 0 | return it->second; |
443 | 0 | } |
444 | | |
445 | | |
446 | | std::vector<tstring> |
447 | | Properties::propertyNames() const |
448 | 1.22M | { |
449 | 1.22M | std::vector<tstring> tmp; |
450 | 1.22M | tmp.reserve (data.size ()); |
451 | 1.22M | for (auto const & kv : data) |
452 | 1.71M | tmp.push_back(kv.first); |
453 | | |
454 | 1.22M | return tmp; |
455 | 1.22M | } |
456 | | |
457 | | |
458 | | |
459 | | void |
460 | | Properties::setProperty(const log4cplus::tstring& key, |
461 | | const log4cplus::tstring& value) |
462 | 797k | { |
463 | 797k | data[key] = value; |
464 | 797k | } |
465 | | |
466 | | |
467 | | bool |
468 | | Properties::removeProperty(const log4cplus::tstring& key) |
469 | 0 | { |
470 | 0 | return data.erase(key) > 0; |
471 | 0 | } |
472 | | |
473 | | |
474 | | Properties |
475 | | Properties::getPropertySubset(const log4cplus::tstring& prefix) const |
476 | 736k | { |
477 | 736k | Properties ret; |
478 | 736k | auto const prefix_len = prefix.size (); |
479 | 736k | std::vector<tstring> keys = propertyNames(); |
480 | 736k | for (tstring const & key : keys) |
481 | 1.47M | { |
482 | 1.47M | int result = key.compare (0, prefix_len, prefix); |
483 | 1.47M | if (result == 0) |
484 | 368k | ret.setProperty (key.substr (prefix_len), getProperty(key)); |
485 | 1.47M | } |
486 | | |
487 | 736k | return ret; |
488 | 736k | } |
489 | | |
490 | | |
491 | | bool |
492 | | Properties::getInt (int & val, log4cplus::tstring const & key) const |
493 | 0 | { |
494 | 0 | return get_type_val_worker (val, key); |
495 | 0 | } |
496 | | |
497 | | |
498 | | bool |
499 | | Properties::getUInt (unsigned & val, log4cplus::tstring const & key) const |
500 | 245k | { |
501 | 245k | return get_type_val_worker (val, key); |
502 | 245k | } |
503 | | |
504 | | |
505 | | bool |
506 | | Properties::getLong (long & val, log4cplus::tstring const & key) const |
507 | 0 | { |
508 | 0 | return get_type_val_worker (val, key); |
509 | 0 | } |
510 | | |
511 | | |
512 | | bool |
513 | | Properties::getULong (unsigned long & val, log4cplus::tstring const & key) const |
514 | 0 | { |
515 | 0 | return get_type_val_worker (val, key); |
516 | 0 | } |
517 | | |
518 | | |
519 | | bool |
520 | | Properties::getBool (bool & val, log4cplus::tstring const & key) const |
521 | 982k | { |
522 | 982k | if (! exists (key)) |
523 | 859k | return false; |
524 | | |
525 | 122k | log4cplus::tstring const & prop_val = getProperty (key); |
526 | 122k | return internal::parse_bool (val, prop_val); |
527 | 982k | } |
528 | | |
529 | | |
530 | | bool |
531 | | Properties::getString (log4cplus::tstring & val, log4cplus::tstring const & key) |
532 | | const |
533 | 122k | { |
534 | 122k | StringMap::const_iterator it (data.find (key)); |
535 | 122k | if (it == data.end ()) |
536 | 122k | return false; |
537 | | |
538 | 0 | val = it->second; |
539 | 0 | return true; |
540 | 122k | } |
541 | | |
542 | | |
543 | | template <typename StringType> |
544 | | log4cplus::tstring const & |
545 | | Properties::get_property_worker (StringType const & key) const |
546 | 736k | { |
547 | 736k | StringMap::const_iterator it (data.find (key)); |
548 | 736k | if (it == data.end ()) |
549 | 0 | return log4cplus::internal::empty_str; |
550 | 736k | else |
551 | 736k | return it->second; |
552 | 736k | } std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const& log4cplus::helpers::Properties::get_property_worker<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) const Line | Count | Source | 546 | 613k | { | 547 | 613k | StringMap::const_iterator it (data.find (key)); | 548 | 613k | if (it == data.end ()) | 549 | 0 | return log4cplus::internal::empty_str; | 550 | 613k | else | 551 | 613k | return it->second; | 552 | 613k | } |
std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const& log4cplus::helpers::Properties::get_property_worker<char const*>(char const* const&) const Line | Count | Source | 546 | 122k | { | 547 | 122k | StringMap::const_iterator it (data.find (key)); | 548 | 122k | if (it == data.end ()) | 549 | 0 | return log4cplus::internal::empty_str; | 550 | 122k | else | 551 | 122k | return it->second; | 552 | 122k | } |
|
553 | | |
554 | | |
555 | | template <typename ValType> |
556 | | bool |
557 | | Properties::get_type_val_worker (ValType & val, log4cplus::tstring const & key) |
558 | | const |
559 | 245k | { |
560 | 245k | if (! exists (key)) |
561 | 245k | return false; |
562 | | |
563 | 0 | log4cplus::tstring const & prop_val = getProperty (key); |
564 | 0 | log4cplus::tistringstream iss (prop_val); |
565 | 0 | ValType tmp_val; |
566 | 0 | tchar ch; |
567 | |
|
568 | 0 | iss >> tmp_val; |
569 | 0 | if (! iss) |
570 | 0 | return false; |
571 | 0 | iss >> ch; |
572 | 0 | if (iss) |
573 | 0 | return false; |
574 | | |
575 | 0 | val = tmp_val; |
576 | 0 | return true; |
577 | 0 | } Unexecuted instantiation: bool log4cplus::helpers::Properties::get_type_val_worker<int>(int&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) const bool log4cplus::helpers::Properties::get_type_val_worker<unsigned int>(unsigned int&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) const Line | Count | Source | 559 | 245k | { | 560 | 245k | if (! exists (key)) | 561 | 245k | return false; | 562 | | | 563 | 0 | log4cplus::tstring const & prop_val = getProperty (key); | 564 | 0 | log4cplus::tistringstream iss (prop_val); | 565 | 0 | ValType tmp_val; | 566 | 0 | tchar ch; | 567 | |
| 568 | 0 | iss >> tmp_val; | 569 | 0 | if (! iss) | 570 | 0 | return false; | 571 | 0 | iss >> ch; | 572 | 0 | if (iss) | 573 | 0 | return false; | 574 | | | 575 | 0 | val = tmp_val; | 576 | 0 | return true; | 577 | 0 | } |
Unexecuted instantiation: bool log4cplus::helpers::Properties::get_type_val_worker<long>(long&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) const Unexecuted instantiation: bool log4cplus::helpers::Properties::get_type_val_worker<unsigned long>(unsigned long&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) const |
578 | | |
579 | | |
580 | | #if defined (LOG4CPLUS_WITH_UNIT_TESTS) |
581 | | CATCH_TEST_CASE ("Properties", "[properties]") |
582 | | { |
583 | | static tchar const PROP_ABC[] = LOG4CPLUS_TEXT ("a.b.c"); |
584 | | Properties props; |
585 | | |
586 | | CATCH_SECTION ("new object is empty") |
587 | | { |
588 | | CATCH_REQUIRE (props.size () == 0); |
589 | | } |
590 | | |
591 | | CATCH_SECTION ("added property can be retrieved") |
592 | | { |
593 | | props.setProperty (PROP_ABC, LOG4CPLUS_TEXT ("true")); |
594 | | CATCH_REQUIRE (props.exists (PROP_ABC)); |
595 | | CATCH_REQUIRE (props.exists (LOG4CPLUS_C_STR_TO_TSTRING (PROP_ABC))); |
596 | | CATCH_REQUIRE (props.getProperty (PROP_ABC) |
597 | | == LOG4CPLUS_TEXT ("true")); |
598 | | } |
599 | | |
600 | | CATCH_SECTION ("type conversions work") |
601 | | { |
602 | | bool bool_; |
603 | | int int_; |
604 | | unsigned int uint; |
605 | | long long_; |
606 | | unsigned long ulong; |
607 | | |
608 | | tistringstream iss ( |
609 | | LOG4CPLUS_TEXT ("bool=true\r\n") |
610 | | LOG4CPLUS_TEXT ("bool1=1\n") |
611 | | LOG4CPLUS_TEXT ("int=-1\n") |
612 | | LOG4CPLUS_TEXT ("uint=42\n") |
613 | | LOG4CPLUS_TEXT ("long=-65537\n") |
614 | | LOG4CPLUS_TEXT ("ulong=65537") |
615 | | ); |
616 | | Properties from_stream (iss); |
617 | | |
618 | | CATCH_REQUIRE (from_stream.getBool (bool_, LOG4CPLUS_TEXT ("bool"))); |
619 | | CATCH_REQUIRE (bool_); |
620 | | CATCH_REQUIRE (from_stream.getBool (bool_, LOG4CPLUS_TEXT ("bool1"))); |
621 | | CATCH_REQUIRE (bool_); |
622 | | CATCH_REQUIRE (from_stream.getInt (int_, LOG4CPLUS_TEXT ("int"))); |
623 | | CATCH_REQUIRE (int_ == -1); |
624 | | CATCH_REQUIRE (from_stream.getUInt (uint, LOG4CPLUS_TEXT ("uint"))); |
625 | | CATCH_REQUIRE (uint == 42); |
626 | | CATCH_REQUIRE (from_stream.getLong (long_, LOG4CPLUS_TEXT ("long"))); |
627 | | CATCH_REQUIRE (long_ == -65537); |
628 | | CATCH_REQUIRE (from_stream.getULong (ulong, LOG4CPLUS_TEXT ("ulong"))); |
629 | | CATCH_REQUIRE (ulong == 65537); |
630 | | } |
631 | | |
632 | | CATCH_SECTION ("remove property") |
633 | | { |
634 | | props.setProperty (PROP_ABC, LOG4CPLUS_TEXT ("true")); |
635 | | CATCH_REQUIRE (props.exists (PROP_ABC)); |
636 | | props.removeProperty (PROP_ABC); |
637 | | CATCH_REQUIRE (! props.exists (PROP_ABC)); |
638 | | } |
639 | | |
640 | | CATCH_SECTION ("retrieve property names") |
641 | | { |
642 | | props.setProperty (PROP_ABC, LOG4CPLUS_TEXT ("true")); |
643 | | static tchar const PROP_SECOND[] = LOG4CPLUS_TEXT ("second"); |
644 | | props.setProperty (LOG4CPLUS_TEXT ("second"), LOG4CPLUS_TEXT ("false")); |
645 | | std::vector<log4cplus::tstring> names (props.propertyNames ()); |
646 | | CATCH_REQUIRE (std::find (std::begin (names), std::end (names), |
647 | | PROP_ABC) != std::end (names)); |
648 | | CATCH_REQUIRE (std::find (std::begin (names), std::end (names), |
649 | | PROP_SECOND) != std::end (names)); |
650 | | } |
651 | | |
652 | | CATCH_SECTION ("throw on nonexistent file") |
653 | | { |
654 | | auto && f = [] { |
655 | | Properties props (LOG4CPLUS_TEXT ("xxx does not exist"), Properties::fThrow); |
656 | | }; |
657 | | CATCH_REQUIRE_THROWS_AS (f (), log4cplus::exception); |
658 | | } |
659 | | } |
660 | | #endif |
661 | | |
662 | | |
663 | | } } // namespace log4cplus { namespace helpers { |