Line data Source code
1 : /*
2 : * Copyright (c) 2006-2019 Made to Order Software Corp. All Rights Reserved
3 : *
4 : * https://snapwebsites.org/project/snaplogger
5 : * contact@m2osw.com
6 : *
7 : * This program is free software; you can redistribute it and/or modify
8 : * it under the terms of the GNU General Public License as published by
9 : * the Free Software Foundation; either version 2 of the License, or
10 : * (at your option) any later version.
11 : *
12 : * This program is distributed in the hope that it will be useful,
13 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : * GNU General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License along
18 : * with this program; if not, write to the Free Software Foundation, Inc.,
19 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 : */
21 :
22 : // self
23 : //
24 : #include "main.h"
25 :
26 :
27 : // snaplogger lib
28 : //
29 : #include <snaplogger/buffer_appender.h>
30 : #include <snaplogger/exception.h>
31 : #include <snaplogger/format.h>
32 : #include <snaplogger/logger.h>
33 : #include <snaplogger/map_diagnostic.h>
34 : #include <snaplogger/message.h>
35 : #include <snaplogger/severity.h>
36 : #include <snaplogger/version.h>
37 :
38 :
39 : // C lib
40 : //
41 : #include <unistd.h>
42 : #include <netdb.h>
43 : #include <sys/param.h>
44 :
45 :
46 :
47 :
48 :
49 3 : CATCH_TEST_CASE("variable_param", "[variable][param]")
50 : {
51 2 : CATCH_START_SECTION("Param Name is Mandatory")
52 : {
53 1 : CATCH_REQUIRE_THROWS_MATCHES(
54 : new snaplogger::param(std::string())
55 : , snaplogger::invalid_parameter
56 : , Catch::Matchers::ExceptionMessage(
57 : "a parameter must have a non-empty name."));
58 : }
59 : CATCH_END_SECTION()
60 1 : }
61 :
62 :
63 :
64 7 : CATCH_TEST_CASE("system_variable", "[variable][param]")
65 : {
66 10 : CATCH_START_SECTION("get_type() to use padding as integer or string (hostname)")
67 : {
68 1 : snaplogger::set_diagnostic(snaplogger::DIAG_KEY_PROGNAME, "message-logging");
69 :
70 2 : snaplogger::logger::pointer_t l(snaplogger::logger::get_instance());
71 2 : snaplogger::buffer_appender::pointer_t buffer(std::make_shared<snaplogger::buffer_appender>("test-buffer"));
72 :
73 1 : advgetopt::options_environment opt_env;
74 1 : opt_env.f_project_name = "test-logger";
75 2 : advgetopt::getopt opts(opt_env);
76 1 : buffer->set_config(opts);
77 :
78 2 : snaplogger::format::pointer_t f(std::make_shared<snaplogger::format>("${hostname:padding=3:align=right:min_width=30} ${message}"));
79 1 : buffer->set_format(f);
80 :
81 1 : l->add_appender(buffer);
82 :
83 : char host[HOST_NAME_MAX + 2 + 30];
84 1 : CATCH_REQUIRE(gethostname(host, HOST_NAME_MAX + 1) == 0);
85 1 : host[HOST_NAME_MAX + 1] = '\0';
86 2 : std::string aligned(host);
87 53 : while(aligned.length() < 30)
88 : {
89 26 : aligned = "3" + aligned;
90 : }
91 :
92 1 : SNAP_LOG_ERROR << "Check the param::get_type()" << SNAP_LOG_SEND;
93 1 : CATCH_REQUIRE(buffer->str() == aligned + " Check the param::get_type()\n");
94 :
95 1 : buffer->clear();
96 :
97 1 : f = std::make_shared<snaplogger::format>("${hostname:padding=\"t\":align=center:min_width=30} ${message}");
98 1 : buffer->set_format(f);
99 :
100 1 : aligned = host;
101 27 : while(aligned.length() < 17)
102 : {
103 13 : aligned = "t" + aligned;
104 : }
105 27 : while(aligned.length() < 30)
106 : {
107 13 : aligned = aligned + "t";
108 : }
109 :
110 1 : SNAP_LOG_ERROR << "Try again with a string" << SNAP_LOG_SEND;
111 1 : CATCH_REQUIRE(buffer->str() == aligned + " Try again with a string\n");
112 :
113 1 : buffer->clear();
114 :
115 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"t\":align=center:max_width=30}");
116 1 : buffer->set_format(f);
117 :
118 1 : SNAP_LOG_ERROR << "This message will have a maximum width of 30 chars" << SNAP_LOG_SEND;
119 1 : CATCH_REQUIRE(buffer->str() == std::string(host) + " ge will have a maximum width o\n");
120 :
121 1 : buffer->clear();
122 :
123 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"t\":align=right:max_width=25}");
124 1 : buffer->set_format(f);
125 :
126 1 : SNAP_LOG_ERROR << "This message will have a maximum width of 25 chars" << SNAP_LOG_SEND;
127 1 : CATCH_REQUIRE(buffer->str() == std::string(host) + " maximum width of 25 chars\n");
128 :
129 1 : buffer->clear();
130 :
131 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"t\":align=center:min_width=25}");
132 1 : buffer->set_format(f);
133 :
134 1 : SNAP_LOG_ERROR << "minimum width 25" << SNAP_LOG_SEND;
135 1 : CATCH_REQUIRE(buffer->str() == std::string(host) + " ttttminimum width 25ttttt\n");
136 :
137 1 : buffer->clear();
138 :
139 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"t\":align=left:min_width=25}");
140 1 : buffer->set_format(f);
141 :
142 1 : SNAP_LOG_ERROR << "minimum width 25" << SNAP_LOG_SEND;
143 1 : CATCH_REQUIRE(buffer->str() == std::string(host) + " minimum width 25ttttttttt\n");
144 :
145 1 : buffer->clear();
146 :
147 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"t\":align=left:exact_width=25}");
148 1 : buffer->set_format(f);
149 :
150 1 : SNAP_LOG_ERROR << "First we get this message cut to the specified width." << SNAP_LOG_SEND;
151 1 : CATCH_REQUIRE(buffer->str() == std::string(host) + " First we get this message\n");
152 :
153 1 : buffer->clear();
154 :
155 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"t\":align=center:exact_width=25}");
156 1 : buffer->set_format(f);
157 :
158 1 : SNAP_LOG_ERROR << "First we get this message cut to the specified width." << SNAP_LOG_SEND;
159 1 : CATCH_REQUIRE(buffer->str() == std::string(host) + " his message cut to the sp\n");
160 :
161 1 : buffer->clear();
162 :
163 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"t\":align=right:exact_width=25}");
164 1 : buffer->set_format(f);
165 :
166 1 : SNAP_LOG_ERROR << "First we get this message cut to the specified width." << SNAP_LOG_SEND;
167 1 : CATCH_REQUIRE(buffer->str() == std::string(host) + " t to the specified width.\n");
168 :
169 1 : buffer->clear();
170 :
171 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"x\":align=left:exact_width=25}");
172 1 : buffer->set_format(f);
173 :
174 1 : SNAP_LOG_ERROR << "Small Message" << SNAP_LOG_SEND;
175 1 : CATCH_REQUIRE(buffer->str() == std::string(host) + " Small Messagexxxxxxxxxxxx\n");
176 :
177 1 : buffer->clear();
178 :
179 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"x\":align=center:exact_width=25}");
180 1 : buffer->set_format(f);
181 :
182 1 : SNAP_LOG_ERROR << "Small Message" << SNAP_LOG_SEND;
183 1 : CATCH_REQUIRE(buffer->str() == std::string(host) + " xxxxxxSmall Messagexxxxxx\n");
184 :
185 1 : buffer->clear();
186 :
187 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"x\":align=center:exact_width=25}");
188 1 : buffer->set_format(f);
189 :
190 1 : SNAP_LOG_ERROR << "Small Message (even)" << SNAP_LOG_SEND;
191 1 : CATCH_REQUIRE(buffer->str() == std::string(host) + " xxSmall Message (even)xxx\n");
192 :
193 1 : buffer->clear();
194 :
195 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:padding=\"x\":align=right:exact_width=25}");
196 1 : buffer->set_format(f);
197 :
198 1 : SNAP_LOG_ERROR << "Small Message" << SNAP_LOG_SEND;
199 1 : CATCH_REQUIRE(buffer->str() == std::string(host) + " xxxxxxxxxxxxSmall Message\n");
200 :
201 1 : buffer->clear();
202 :
203 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:prepend=\"(P) \":padding=\"z\":align=right:exact_width=25}");
204 1 : buffer->set_format(f);
205 :
206 1 : SNAP_LOG_ERROR << "Small Message" << SNAP_LOG_SEND;
207 1 : CATCH_REQUIRE(buffer->str() == std::string(host) + " zzzzzzzz(P) Small Message\n");
208 :
209 1 : buffer->clear();
210 :
211 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:append=\" (A)\":padding=\"z\":align=right:exact_width=25}");
212 1 : buffer->set_format(f);
213 :
214 1 : SNAP_LOG_ERROR << "Small Message" << SNAP_LOG_SEND;
215 1 : CATCH_REQUIRE(buffer->str() == std::string(host) + " zzzzzzzzSmall Message (A)\n");
216 :
217 1 : buffer->clear();
218 :
219 1 : f = std::make_shared<snaplogger::format>("${hostname:padding=\"q\":align=101:min_width=30} ${message}");
220 1 : buffer->set_format(f);
221 :
222 : snaplogger::message::pointer_t msg(std::make_shared<snaplogger::message>
223 2 : (::snaplogger::severity_t::SEVERITY_ERROR, __FILE__, __func__, __LINE__));
224 1 : *msg << "The align=101 parameter is the wrong type";
225 1 : CATCH_REQUIRE_THROWS_MATCHES(
226 : l->log_message(*msg)
227 : , snaplogger::invalid_parameter
228 : , Catch::Matchers::ExceptionMessage(
229 : "the ${...:align=<value>} parameter must be a valid string (not an integer)."));
230 :
231 : // this is important here because we want to make sure that the
232 : // `message` destructor works as expected (i.e. it does not call
233 : // std::terminate() because of the throw as the align=101 is
234 : // invalid)
235 : //
236 1 : msg.reset();
237 :
238 1 : buffer->clear();
239 :
240 1 : f = std::make_shared<snaplogger::format>("${hostname:padding=\"t\":align=justify:min_width=30} ${message}");
241 1 : buffer->set_format(f);
242 :
243 : msg = std::make_shared<snaplogger::message>
244 1 : (::snaplogger::severity_t::SEVERITY_ERROR, __FILE__, __func__, __LINE__);
245 1 : *msg << "Try align=\"justify\" which has to fail.";
246 1 : CATCH_REQUIRE_THROWS_MATCHES(
247 : l->log_message(*msg)
248 : , snaplogger::invalid_parameter
249 : , Catch::Matchers::ExceptionMessage(
250 : "the ${...:align=left|center|right} was expected, got \"justify\"."));
251 :
252 1 : buffer->clear();
253 :
254 1 : f = std::make_shared<snaplogger::format>("${hostname:padding=\"q\":align=left:min_width=wide} ${message}");
255 1 : buffer->set_format(f);
256 :
257 : msg = std::make_shared<snaplogger::message>
258 1 : (::snaplogger::severity_t::SEVERITY_ERROR, __FILE__, __func__, __LINE__);
259 1 : *msg << "The min_width=wide parameter is the wrong type";
260 1 : CATCH_REQUIRE_THROWS_MATCHES(
261 : l->log_message(*msg)
262 : , snaplogger::invalid_parameter
263 : , Catch::Matchers::ExceptionMessage(
264 : "the ${...:min_width=<value>} parameter must be a valid integer."));
265 :
266 : // this is important here because we want to make sure that the
267 : // `message` destructor works as expected (i.e. it does not call
268 : // std::terminate() because of the throw as the align=101 is
269 : // invalid)
270 : //
271 1 : msg.reset();
272 :
273 1 : buffer->clear();
274 :
275 1 : f = std::make_shared<snaplogger::format>("${hostname:padding=99:align=left:min_width=wide} ${message}");
276 1 : buffer->set_format(f);
277 :
278 : msg = std::make_shared<snaplogger::message>
279 1 : (::snaplogger::severity_t::SEVERITY_ERROR, __FILE__, __func__, __LINE__);
280 1 : *msg << "The padding=... accepts a number between 0 and 9 inclusive";
281 1 : CATCH_REQUIRE_THROWS_MATCHES(
282 : l->log_message(*msg)
283 : , snaplogger::invalid_parameter
284 : , Catch::Matchers::ExceptionMessage(
285 : "the ${...:padding=<value>} when set to a number must be one digit ('0' to '9'), not \"99\"."));
286 :
287 : // this is important here because we want to make sure that the
288 : // `message` destructor works as expected (i.e. it does not call
289 : // std::terminate() because of the throw as the align=101 is
290 : // invalid)
291 : //
292 1 : msg.reset();
293 :
294 1 : buffer->clear();
295 :
296 1 : f = std::make_shared<snaplogger::format>("${hostname:padding='abc':align=left:min_width=wide} ${message}");
297 1 : buffer->set_format(f);
298 :
299 : msg = std::make_shared<snaplogger::message>
300 1 : (::snaplogger::severity_t::SEVERITY_ERROR, __FILE__, __func__, __LINE__);
301 1 : *msg << "The padding=... accepts one character";
302 1 : CATCH_REQUIRE_THROWS_MATCHES(
303 : l->log_message(*msg)
304 : , snaplogger::invalid_parameter
305 : , Catch::Matchers::ExceptionMessage(
306 : "the ${...:padding=' '} must be exactly one character, not \"abc\"."));
307 :
308 : // this is important here because we want to make sure that the
309 : // `message` destructor works as expected (i.e. it does not call
310 : // std::terminate() because of the throw as the align=101 is
311 : // invalid)
312 : //
313 1 : msg.reset();
314 :
315 1 : l->reset();
316 : }
317 : CATCH_END_SECTION()
318 :
319 10 : CATCH_START_SECTION("escape")
320 : {
321 1 : snaplogger::set_diagnostic(snaplogger::DIAG_KEY_PROGNAME, "escape");
322 :
323 2 : snaplogger::logger::pointer_t l(snaplogger::logger::get_instance());
324 2 : snaplogger::buffer_appender::pointer_t buffer(std::make_shared<snaplogger::buffer_appender>("test-buffer"));
325 :
326 1 : advgetopt::options_environment opt_env;
327 1 : opt_env.f_project_name = "test-logger";
328 2 : advgetopt::getopt opts(opt_env);
329 1 : buffer->set_config(opts);
330 :
331 2 : snaplogger::format::pointer_t f(std::make_shared<snaplogger::format>("${hostname} ${message:escape}"));
332 1 : buffer->set_format(f);
333 :
334 1 : l->add_appender(buffer);
335 :
336 : char host[HOST_NAME_MAX + 2 + 30];
337 1 : CATCH_REQUIRE(gethostname(host, HOST_NAME_MAX + 1) == 0);
338 1 : host[HOST_NAME_MAX + 1] = '\0';
339 :
340 1 : SNAP_LOG_ERROR << "Default escape for newline (\n), carriage return (\r), and tab (\t)" << SNAP_LOG_SEND;
341 1 : CATCH_REQUIRE(buffer->str() == std::string(host) + " Default escape for newline (\\n), carriage return (\\r), and tab (\\t)\n");
342 :
343 1 : buffer->clear();
344 :
345 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:escape=\"[]\"}");
346 1 : buffer->set_format(f);
347 :
348 1 : SNAP_LOG_ERROR << "Try again [with a string]" << SNAP_LOG_SEND;
349 1 : CATCH_REQUIRE(buffer->str() == std::string(host) + " Try again \\[with a string\\]\n");
350 :
351 1 : buffer->clear();
352 :
353 1 : f = std::make_shared<snaplogger::format>("${hostname} ${message:escape=\"\a\b\f\n\r\t\v\x1f\xC2\x88\xC2\x97\"}");
354 1 : buffer->set_format(f);
355 :
356 1 : SNAP_LOG_ERROR << "Escape all \a\b\f\n\r\t\v\x1f\xC2\x88\xC2\x97 types" << SNAP_LOG_SEND;
357 1 : CATCH_REQUIRE(buffer->str() == std::string(host) + " Escape all \\a\\b\\f\\n\\r\\t\\v^_@H@W types\n");
358 : }
359 : CATCH_END_SECTION()
360 :
361 10 : CATCH_START_SECTION("caps")
362 : {
363 1 : snaplogger::set_diagnostic(snaplogger::DIAG_KEY_PROGNAME, "caps");
364 :
365 2 : snaplogger::logger::pointer_t l(snaplogger::logger::get_instance());
366 2 : snaplogger::buffer_appender::pointer_t buffer(std::make_shared<snaplogger::buffer_appender>("test-buffer"));
367 :
368 1 : advgetopt::options_environment opt_env;
369 1 : opt_env.f_project_name = "test-logger";
370 2 : advgetopt::getopt opts(opt_env);
371 1 : buffer->set_config(opts);
372 :
373 2 : snaplogger::format::pointer_t f(std::make_shared<snaplogger::format>("${message:caps}"));
374 1 : buffer->set_format(f);
375 :
376 1 : l->add_appender(buffer);
377 :
378 1 : SNAP_LOG_ERROR << "this message words will get their FIRST-LETTER capitalized." << SNAP_LOG_SEND;
379 1 : CATCH_REQUIRE(buffer->str() == "This Message Words Will Get Their First-Letter Capitalized.\n");
380 : }
381 : CATCH_END_SECTION()
382 :
383 10 : CATCH_START_SECTION("lower/upper")
384 : {
385 1 : snaplogger::set_diagnostic(snaplogger::DIAG_KEY_PROGNAME, "case");
386 :
387 2 : snaplogger::logger::pointer_t l(snaplogger::logger::get_instance());
388 2 : snaplogger::buffer_appender::pointer_t buffer(std::make_shared<snaplogger::buffer_appender>("test-buffer"));
389 :
390 1 : advgetopt::options_environment opt_env;
391 1 : opt_env.f_project_name = "test-logger";
392 2 : advgetopt::getopt opts(opt_env);
393 1 : buffer->set_config(opts);
394 :
395 2 : snaplogger::format::pointer_t f(std::make_shared<snaplogger::format>("${message:lower}"));
396 1 : buffer->set_format(f);
397 :
398 1 : l->add_appender(buffer);
399 :
400 1 : SNAP_LOG_ERROR << "This message words will get their FIRST-LETTER capitalized." << SNAP_LOG_SEND;
401 1 : CATCH_REQUIRE(buffer->str() == "this message words will get their first-letter capitalized.\n");
402 :
403 1 : buffer->clear();
404 :
405 1 : f = std::make_shared<snaplogger::format>("${message:upper}");
406 1 : buffer->set_format(f);
407 :
408 1 : SNAP_LOG_ERROR << "This message words will get their FIRST-LETTER capitalized." << SNAP_LOG_SEND;
409 1 : CATCH_REQUIRE(buffer->str() == "THIS MESSAGE WORDS WILL GET THEIR FIRST-LETTER CAPITALIZED.\n");
410 : }
411 : CATCH_END_SECTION()
412 :
413 10 : CATCH_START_SECTION("default align value")
414 : {
415 1 : snaplogger::set_diagnostic(snaplogger::DIAG_KEY_PROGNAME, "message-variable-default-param");
416 :
417 2 : snaplogger::logger::pointer_t l(snaplogger::logger::get_instance());
418 2 : snaplogger::buffer_appender::pointer_t buffer(std::make_shared<snaplogger::buffer_appender>("test-buffer"));
419 :
420 1 : advgetopt::options_environment opt_env;
421 1 : opt_env.f_project_name = "test-logger";
422 2 : advgetopt::getopt opts(opt_env);
423 1 : buffer->set_config(opts);
424 :
425 2 : snaplogger::format::pointer_t f(std::make_shared<snaplogger::format>("${hostname:max_width=3} ${message}"));
426 1 : buffer->set_format(f);
427 :
428 1 : l->add_appender(buffer);
429 :
430 : char host[HOST_NAME_MAX + 2 + 30];
431 1 : CATCH_REQUIRE(gethostname(host, HOST_NAME_MAX + 1) == 0);
432 1 : host[HOST_NAME_MAX + 1] = '\0';
433 2 : std::string aligned(host);
434 1 : aligned = aligned.substr(0, 3);
435 1 : while(aligned.length() < 3)
436 : {
437 0 : aligned = " " + aligned;
438 : }
439 :
440 1 : SNAP_LOG_ERROR << "<- first three letters of hostname" << SNAP_LOG_SEND;
441 1 : CATCH_REQUIRE(buffer->str() == aligned + " <- first three letters of hostname\n");
442 : }
443 : CATCH_END_SECTION()
444 5 : }
445 :
446 :
447 :
448 5 : CATCH_TEST_CASE("duplicate_factory", "[variable][factory]")
449 : {
450 6 : CATCH_START_SECTION("attempt dynamically creating a factory which already exists")
451 : {
452 1 : class fake_variable_factory final
453 : : public snaplogger::variable_factory
454 : {
455 : public:
456 1 : fake_variable_factory()
457 1 : : variable_factory("version")
458 : {
459 1 : }
460 :
461 0 : virtual snaplogger::variable::pointer_t create_variable() override final
462 : {
463 : // we can't even register this one so returning an empty
464 : // pointer is perfectly safe here
465 : //
466 0 : return snaplogger::variable::pointer_t();
467 : }
468 : };
469 :
470 1 : CATCH_REQUIRE_THROWS_MATCHES(
471 : snaplogger::register_variable_factory(std::make_shared<fake_variable_factory>())
472 : , snaplogger::duplicate_error
473 : , Catch::Matchers::ExceptionMessage("trying to add two variable factories of type \"version\"."));
474 : }
475 : CATCH_END_SECTION()
476 :
477 6 : CATCH_START_SECTION("attempt creating a variable with a non-existant type")
478 : {
479 1 : CATCH_REQUIRE_THROWS_MATCHES(
480 : snaplogger::get_variable("fake")
481 : , snaplogger::invalid_variable
482 : , Catch::Matchers::ExceptionMessage("You can't create variable with type \"fake\", no such variable type was registered."));
483 : }
484 : CATCH_END_SECTION()
485 :
486 6 : CATCH_START_SECTION("attempt creating a function factory with an existing name")
487 : {
488 1 : class fake_function final
489 : : public snaplogger::function
490 : {
491 : public:
492 1 : fake_function()
493 1 : : function("padding")
494 : {
495 1 : }
496 :
497 0 : virtual void apply(
498 : ::snaplogger::message const & msg
499 : , ::snaplogger::function_data & d
500 : , ::snaplogger::param::pointer_t const & p) override
501 : {
502 0 : snap::NOTUSED(msg);
503 0 : snap::NOTUSED(d);
504 0 : snap::NOTUSED(p);
505 0 : }
506 : };
507 :
508 1 : CATCH_REQUIRE_THROWS_MATCHES(
509 : snaplogger::register_function(std::make_shared<fake_function>())
510 : , snaplogger::duplicate_error
511 : , Catch::Matchers::ExceptionMessage("trying to add two functions named \"padding\"."));
512 : }
513 : CATCH_END_SECTION()
514 9 : }
515 :
516 :
517 : // vim: ts=4 sw=4 et
|