6 #include <dlogutil-internal.h>
10 static char buffer[10240];
11 static size_t buffer_count = 0;
12 static bool fake_write;
13 static int partial_write;
14 ssize_t __real_write(int fd, const void *buf, size_t count);
15 ssize_t __wrap_write(int fd, const void *buf, size_t count)
21 return __real_write(fd, buf, count);
23 assert(count < sizeof buffer);
24 memcpy(buffer, buf, count);
31 static bool fail_localtime_r;
32 struct tm *__real_localtime_r(const time_t *timep, struct tm *result);
33 struct tm *__wrap_localtime_r(const time_t *timep, struct tm *result)
35 return fail_localtime_r ? NULL : __real_localtime_r(timep, result);
38 static int fail_alloc;
39 void *__real_malloc(size_t size);
40 void *__real_calloc(size_t nmemb, size_t size);
41 void *__wrap_malloc(size_t size)
48 return __real_malloc(size);
50 void *__wrap_calloc(size_t nmemb, size_t size)
52 return fail_alloc ? NULL : __real_calloc(nmemb, size);
55 static bool fail_strndup;
56 char *__real_strndup(const char *s, size_t n);
57 char *__wrap_strndup(const char *s, size_t n)
59 return fail_strndup ? NULL : __real_strndup(s, n);
62 static bool fail_strdup;
63 char *__real_strdup(const char *s);
64 char *__wrap_strdup(const char *s)
66 return fail_strdup ? NULL : __real_strdup(s);
69 static bool fail_list_add;
70 bool __real_list_add(list_head *head, elem_value value);
71 bool __wrap_list_add(list_head *head, elem_value value)
73 return fail_list_add ? false : __real_list_add(head, value);
76 /* Timestamps are shown in the everyday format so
77 * it's good to be able to work with those numbers
78 * where possible instead of the underlying single
79 * integer (but see below). */
81 #define SECONDS 1 // the base unit of the sec timestamp
82 #define MINUTES (60 * SECONDS)
83 #define HOURS (60 * MINUTES)
84 #define DAYS (24 * HOURS)
86 #define JANUARY (-1 * DAYS) // dates start from Jan 01, not Jan 00
87 #define FEBRUARY (JANUARY + 31 * DAYS)
88 #define MARCH (FEBRUARY + 28 * DAYS) // 1970, so no 29th
90 /* The nano timestamp is a bit more of a monolith,
91 * but can still be meaningfully split up into the
92 * milliseconds part and the remainder since all
93 * timestamps seem to only show the former. */
96 #define MICROSECONDS (1000 * NANOSECONDS)
97 #define MILLISECONDS (1000 * MICROSECONDS)
99 static void standard_test_msg(struct dlogutil_entry_with_msg *entry, const char *msg, size_t msg_len)
101 *entry = (struct dlogutil_entry_with_msg) {
103 .len = sizeof entry->header + msg_len,
104 .priority = DLOG_INFO,
107 .sec_sent_mono = 3205048,
108 .sec_sent_real = MARCH + 14*DAYS + 23*HOURS + 22*MINUTES + 51*SECONDS,
109 .sec_recv_mono = 365467,
110 .sec_recv_real = FEBRUARY + 1*DAYS + 0*HOURS + 5*MINUTES + 17*SECONDS,
111 .nsec_sent_mono = 235*MILLISECONDS + 123*MICROSECONDS + 213*NANOSECONDS,
112 .nsec_sent_real = 451*MILLISECONDS + 435*MICROSECONDS + 135*NANOSECONDS,
113 .nsec_recv_mono = 346*MILLISECONDS + 253*MICROSECONDS + 662*NANOSECONDS,
114 .nsec_recv_real = 734*MILLISECONDS + 543*MICROSECONDS + 254*NANOSECONDS,
119 memcpy(entry->msg, msg, msg_len); // strcpy won't do because msg has an embedded \0 as the tag delimiter
120 for (size_t i = 0; i < msg_len; ++i)
122 entry->header.tag_len = i;
125 assert(entry->header.tag_len >= 0);
127 /* Despite the comment about the single int above,
128 * sometimes we still have to work with it. Make
129 * sure we know the other representation in each
130 * case so that we can easily identify failures. */
131 assert(entry->header.sec_sent_mono == FEBRUARY + 7*DAYS + 2*HOURS + 17*MINUTES + 28*SECONDS);
132 assert(entry->header.sec_sent_real == 6304971);
133 assert(entry->header.sec_recv_mono == JANUARY + 5*DAYS + 5*HOURS + 31*MINUTES + 7*SECONDS);
134 assert(entry->header.sec_recv_real == 2678717);
137 static void invalid_test_msg(struct dlogutil_entry_with_msg *entry, const char *msg, size_t msg_len)
139 standard_test_msg(entry, msg, msg_len);
141 entry->header.pid = -123;
142 entry->header.tid = -456;
143 entry->header.nsec_sent_mono = -78;
144 entry->header.nsec_sent_real = -90;
146 fixup_pipe_msg(entry, msg_len);
149 struct logprint_test_case {
150 log_print_format format;
151 log_priority priority;
156 void check_logprint_testcases(struct dlogutil_entry_with_msg *entry, const struct logprint_test_case *tests, size_t tests_n)
160 for (size_t i = 0; i < tests_n; ++i) {
161 entry->header.priority = tests[i].priority;
162 assert(log_print_log_line((struct log_format){
163 .format = tests[i].format,
164 .color = tests[i].color_enabled,
165 }, 0, &entry->header, &(struct log_write_buffer) { }) == 1);
166 fprintf(stderr, "format=%d, expected %s<, got %s<", tests[i].format, tests[i].result, buffer);
167 assert(!strcmp(tests[i].result, buffer));
173 void check_logprint_testcases_standard(const char *msg, size_t msg_len, const struct logprint_test_case *tests, size_t tests_n)
175 struct dlogutil_entry_with_msg entry;
176 standard_test_msg(&entry, msg, msg_len);
178 check_logprint_testcases(&entry, tests, tests_n);
181 void check_logprint_testcases_invalid(const char *msg, size_t msg_len, const struct logprint_test_case *tests, size_t tests_n)
183 struct dlogutil_entry_with_msg entry;
184 invalid_test_msg(&entry, msg, msg_len);
186 check_logprint_testcases(&entry, tests, tests_n);
189 #define CHECK_LOGPRINT_TESTCASES(MSG, TESTS) check_logprint_testcases_standard(MSG, sizeof MSG, TESTS, NELEMS(TESTS))
190 #define CHECK_LOGPRINT_TESTCASES_INVALID(MSG, TESTS) check_logprint_testcases_invalid(MSG, sizeof MSG, TESTS, NELEMS(TESTS))
192 void check_log_print_log_line(void)
194 static const struct logprint_test_case tests_basic[] = {
195 // formats using the SENT timestamp
196 {FORMAT_TIME , DLOG_INFO, false, "03-14 23:22:51.451+0000 I/BASIC TAG( 4228): Basic message.\n" },
197 {FORMAT_LONG , DLOG_INFO, false, "[ 03-14 23:22:51.451 I/BASIC TAG P 4228, T 4567]\nBasic message.\n\n" },
198 {FORMAT_THREADTIME , DLOG_INFO, false, "03-14 23:22:51.451+0000 I/BASIC TAG (P 4228, T 4567): Basic message.\n" },
199 {FORMAT_KERNELTIME , DLOG_INFO, false, "3205048.235 I/BASIC TAG(P 4228, T 4567): Basic message.\n" },
201 // formats using the RECV timestamp
202 {FORMAT_RECV_REALTIME, DLOG_INFO, false, "02-01 00:05:17.734 I/BASIC TAG(P 4228, T 4567): Basic message.\n" },
203 {FORMAT_RWTIME , DLOG_INFO, false, "02-01 00:05:17 [3205048.235] I/BASIC TAG(P 4228, T 4567): Basic message.\n"},
205 // formats without a timestamp
206 {FORMAT_BRIEF , DLOG_INFO, false, "I/BASIC TAG( 4228): Basic message.\n" },
207 {FORMAT_PROCESS , DLOG_INFO, false, "I( 4228) Basic message. (BASIC TAG)\n" },
208 {FORMAT_TAG , DLOG_INFO, false, "I/BASIC TAG: Basic message.\n" },
209 {FORMAT_THREAD , DLOG_INFO, false, "I(P 4228, T 4567) Basic message.\n" },
210 {FORMAT_RAW , DLOG_INFO, false, "Basic message.\n" },
212 {FORMAT_JSON , DLOG_INFO, false, "{"
213 "\"priority\":\"info\","
216 "\"recv_real\":\"1970-02-01T00:05:17+0000\","
217 "\"recv_mono\":365467.346253662,"
218 "\"sent_real\":\"1970-03-14T23:22:51+0000\","
219 "\"sent_mono\":3205048.235123213,"
220 "\"tag\":\"BASIC TAG\","
221 "\"msg\":\"Basic message.\""
224 CHECK_LOGPRINT_TESTCASES("BASIC TAG\0Basic message.", tests_basic);
227 static const struct logprint_test_case tests_short_tag[] = {
228 {FORMAT_TIME , DLOG_INFO, false, "03-14 23:22:51.451+0000 I/SHORT ( 4228): Basic message.\n" },
229 {FORMAT_LONG , DLOG_INFO, false, "[ 03-14 23:22:51.451 I/SHORT P 4228, T 4567]\nBasic message.\n\n" },
230 {FORMAT_THREADTIME , DLOG_INFO, false, "03-14 23:22:51.451+0000 I/SHORT (P 4228, T 4567): Basic message.\n" },
231 {FORMAT_KERNELTIME , DLOG_INFO, false, "3205048.235 I/SHORT (P 4228, T 4567): Basic message.\n" },
232 {FORMAT_RECV_REALTIME, DLOG_INFO, false, "02-01 00:05:17.734 I/SHORT (P 4228, T 4567): Basic message.\n" },
233 {FORMAT_RWTIME , DLOG_INFO, false, "02-01 00:05:17 [3205048.235] I/SHORT (P 4228, T 4567): Basic message.\n"},
234 {FORMAT_BRIEF , DLOG_INFO, false, "I/SHORT ( 4228): Basic message.\n" },
235 {FORMAT_PROCESS , DLOG_INFO, false, "I( 4228) Basic message. (SHORT)\n" },
236 {FORMAT_TAG , DLOG_INFO, false, "I/SHORT : Basic message.\n" },
238 CHECK_LOGPRINT_TESTCASES("SHORT\0Basic message.", tests_short_tag);
240 // Color coded headers
241 static const struct logprint_test_case tests_colors[] = {
243 {FORMAT_TIME , DLOG_FATAL, true, "\033[35;1m03-14 23:22:51.451+0000 F/COLORFUL TAG( 4228): \033[0mBasic message.\n" },
244 {FORMAT_LONG , DLOG_FATAL, true, "\033[35;1m[ 03-14 23:22:51.451 F/COLORFUL TAG P 4228, T 4567]\n\033[0mBasic message.\n\n" },
245 {FORMAT_THREADTIME , DLOG_FATAL, true, "\033[35;1m03-14 23:22:51.451+0000 F/COLORFUL TAG (P 4228, T 4567): \033[0mBasic message.\n" },
246 {FORMAT_KERNELTIME , DLOG_FATAL, true, "\033[35;1m3205048.235 F/COLORFUL TAG(P 4228, T 4567): \033[0mBasic message.\n" },
247 {FORMAT_RECV_REALTIME, DLOG_FATAL, true, "\033[35;1m02-01 00:05:17.734 F/COLORFUL TAG(P 4228, T 4567): \033[0mBasic message.\n" },
248 {FORMAT_RWTIME , DLOG_FATAL, true, "\033[35;1m02-01 00:05:17 [3205048.235] F/COLORFUL TAG(P 4228, T 4567): \033[0mBasic message.\n"},
249 {FORMAT_BRIEF , DLOG_FATAL, true, "\033[35;1mF/COLORFUL TAG( 4228): \033[0mBasic message.\n" },
250 {FORMAT_PROCESS , DLOG_FATAL, true, "\033[35;1mF( 4228) \033[0mBasic message.\033[35;1m (COLORFUL TAG)\n\033[0m" },
251 {FORMAT_TAG , DLOG_FATAL, true, "\033[35;1mF/COLORFUL TAG: \033[0mBasic message.\n" },
252 {FORMAT_THREAD , DLOG_FATAL, true, "\033[35;1mF(P 4228, T 4567) \033[0mBasic message.\n" },
253 {FORMAT_RAW , DLOG_FATAL, true, "Basic message.\n" },
256 {FORMAT_TIME , DLOG_ERROR, true, "\033[31;1m03-14 23:22:51.451+0000 E/COLORFUL TAG( 4228): \033[0mBasic message.\n" },
257 {FORMAT_LONG , DLOG_ERROR, true, "\033[31;1m[ 03-14 23:22:51.451 E/COLORFUL TAG P 4228, T 4567]\n\033[0mBasic message.\n\n" },
258 {FORMAT_THREADTIME , DLOG_ERROR, true, "\033[31;1m03-14 23:22:51.451+0000 E/COLORFUL TAG (P 4228, T 4567): \033[0mBasic message.\n" },
259 {FORMAT_KERNELTIME , DLOG_ERROR, true, "\033[31;1m3205048.235 E/COLORFUL TAG(P 4228, T 4567): \033[0mBasic message.\n" },
260 {FORMAT_RECV_REALTIME, DLOG_ERROR, true, "\033[31;1m02-01 00:05:17.734 E/COLORFUL TAG(P 4228, T 4567): \033[0mBasic message.\n" },
261 {FORMAT_RWTIME , DLOG_ERROR, true, "\033[31;1m02-01 00:05:17 [3205048.235] E/COLORFUL TAG(P 4228, T 4567): \033[0mBasic message.\n"},
262 {FORMAT_BRIEF , DLOG_ERROR, true, "\033[31;1mE/COLORFUL TAG( 4228): \033[0mBasic message.\n" },
263 {FORMAT_PROCESS , DLOG_ERROR, true, "\033[31;1mE( 4228) \033[0mBasic message.\033[31;1m (COLORFUL TAG)\n\033[0m" },
264 {FORMAT_TAG , DLOG_ERROR, true, "\033[31;1mE/COLORFUL TAG: \033[0mBasic message.\n" },
265 {FORMAT_THREAD , DLOG_ERROR, true, "\033[31;1mE(P 4228, T 4567) \033[0mBasic message.\n" },
266 {FORMAT_RAW , DLOG_ERROR, true, "Basic message.\n" },
269 {FORMAT_TIME , DLOG_WARN , true, "\033[33;1m03-14 23:22:51.451+0000 W/COLORFUL TAG( 4228): \033[0mBasic message.\n" },
270 {FORMAT_LONG , DLOG_WARN , true, "\033[33;1m[ 03-14 23:22:51.451 W/COLORFUL TAG P 4228, T 4567]\n\033[0mBasic message.\n\n" },
271 {FORMAT_THREADTIME , DLOG_WARN , true, "\033[33;1m03-14 23:22:51.451+0000 W/COLORFUL TAG (P 4228, T 4567): \033[0mBasic message.\n" },
272 {FORMAT_KERNELTIME , DLOG_WARN , true, "\033[33;1m3205048.235 W/COLORFUL TAG(P 4228, T 4567): \033[0mBasic message.\n" },
273 {FORMAT_RECV_REALTIME, DLOG_WARN , true, "\033[33;1m02-01 00:05:17.734 W/COLORFUL TAG(P 4228, T 4567): \033[0mBasic message.\n" },
274 {FORMAT_RWTIME , DLOG_WARN , true, "\033[33;1m02-01 00:05:17 [3205048.235] W/COLORFUL TAG(P 4228, T 4567): \033[0mBasic message.\n"},
275 {FORMAT_BRIEF , DLOG_WARN , true, "\033[33;1mW/COLORFUL TAG( 4228): \033[0mBasic message.\n" },
276 {FORMAT_PROCESS , DLOG_WARN , true, "\033[33;1mW( 4228) \033[0mBasic message.\033[33;1m (COLORFUL TAG)\n\033[0m" },
277 {FORMAT_TAG , DLOG_WARN , true, "\033[33;1mW/COLORFUL TAG: \033[0mBasic message.\n" },
278 {FORMAT_THREAD , DLOG_WARN , true, "\033[33;1mW(P 4228, T 4567) \033[0mBasic message.\n" },
279 {FORMAT_RAW , DLOG_WARN , true, "Basic message.\n" },
281 // Information -- no color coding needed
282 {FORMAT_TIME , DLOG_INFO , true , "03-14 23:22:51.451+0000 I/COLORFUL TAG( 4228): Basic message.\n" },
283 {FORMAT_LONG , DLOG_INFO , true , "[ 03-14 23:22:51.451 I/COLORFUL TAG P 4228, T 4567]\nBasic message.\n\n" },
284 {FORMAT_THREADTIME , DLOG_INFO , true , "03-14 23:22:51.451+0000 I/COLORFUL TAG (P 4228, T 4567): Basic message.\n" },
285 {FORMAT_KERNELTIME , DLOG_INFO , true , "3205048.235 I/COLORFUL TAG(P 4228, T 4567): Basic message.\n" },
286 {FORMAT_RECV_REALTIME, DLOG_INFO , true , "02-01 00:05:17.734 I/COLORFUL TAG(P 4228, T 4567): Basic message.\n" },
287 {FORMAT_RWTIME , DLOG_INFO , true , "02-01 00:05:17 [3205048.235] I/COLORFUL TAG(P 4228, T 4567): Basic message.\n"},
288 {FORMAT_BRIEF , DLOG_INFO , true , "I/COLORFUL TAG( 4228): Basic message.\n" },
289 {FORMAT_PROCESS , DLOG_INFO , true , "I( 4228) Basic message. (COLORFUL TAG)\n" },
290 {FORMAT_TAG , DLOG_INFO , true , "I/COLORFUL TAG: Basic message.\n" },
291 {FORMAT_THREAD , DLOG_INFO , true , "I(P 4228, T 4567) Basic message.\n" },
292 {FORMAT_RAW , DLOG_INFO , true , "Basic message.\n" },
294 // Color coding disabled
295 {FORMAT_TIME , DLOG_FATAL, false, "03-14 23:22:51.451+0000 F/COLORFUL TAG( 4228): Basic message.\n" },
297 CHECK_LOGPRINT_TESTCASES("COLORFUL TAG\0Basic message.", tests_colors);
299 // Empty tag has special handling and gets replaced.
300 static const struct logprint_test_case tests_tagless[] = {
301 // formats using the SENT timestamp
302 {FORMAT_RECV_REALTIME, DLOG_INFO, false, "02-01 00:05:17.734 I/DLOG_ERROR_NOTAG(P 4228, T 4567): Tagless\n"},
303 {FORMAT_BRIEF , DLOG_INFO, false, "I/DLOG_ERROR_NOTAG( 4228): Tagless\n" },
304 {FORMAT_PROCESS , DLOG_INFO, false, "I( 4228) Tagless (DLOG_ERROR_NOTAG)\n" },
305 {FORMAT_JSON , DLOG_INFO, false, "{"
306 "\"priority\":\"info\","
309 "\"recv_real\":\"1970-02-01T00:05:17+0000\","
310 "\"recv_mono\":365467.346253662,"
311 "\"sent_real\":\"1970-03-14T23:22:51+0000\","
312 "\"sent_mono\":3205048.235123213,"
313 "\"tag\":\"DLOG_ERROR_NOTAG\","
314 "\"msg\":\"Tagless\""
317 CHECK_LOGPRINT_TESTCASES("\0Tagless", tests_tagless);
319 /* Some formats insert the extra info (timestamp, tag etc) every time they
320 * find a line break. The tag itself is never broken up though. */
321 static const struct logprint_test_case tests_linebreak[] = {
322 {FORMAT_TIME, DLOG_INFO, false,
323 "03-14 23:22:51.451+0000 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES( 4228): And\n"
324 "03-14 23:22:51.451+0000 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES( 4228): so\n"
325 "03-14 23:22:51.451+0000 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES( 4228): does\n"
326 "03-14 23:22:51.451+0000 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES( 4228): this\n"
327 "03-14 23:22:51.451+0000 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES( 4228): message.\n" },
328 {FORMAT_LONG, DLOG_INFO, false,
329 "[ 03-14 23:22:51.451 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES P 4228, T 4567]\n"
330 "And\nso\ndoes\nthis\nmessage.\n\n" },
331 {FORMAT_THREADTIME, DLOG_INFO, true ,
332 "03-14 23:22:51.451+0000 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES (P 4228, T 4567): And\n"
333 "03-14 23:22:51.451+0000 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES (P 4228, T 4567): so\n"
334 "03-14 23:22:51.451+0000 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES (P 4228, T 4567): does\n"
335 "03-14 23:22:51.451+0000 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES (P 4228, T 4567): this\n"
336 "03-14 23:22:51.451+0000 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES (P 4228, T 4567): message.\n" },
337 {FORMAT_KERNELTIME, DLOG_INFO, false,
338 "3205048.235 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES(P 4228, T 4567): And\n"
339 "3205048.235 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES(P 4228, T 4567): so\n"
340 "3205048.235 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES(P 4228, T 4567): does\n"
341 "3205048.235 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES(P 4228, T 4567): this\n"
342 "3205048.235 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES(P 4228, T 4567): message.\n" },
343 {FORMAT_RECV_REALTIME, DLOG_INFO, false,
344 "02-01 00:05:17.734 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES(P 4228, T 4567): And\n"
345 "02-01 00:05:17.734 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES(P 4228, T 4567): so\n"
346 "02-01 00:05:17.734 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES(P 4228, T 4567): does\n"
347 "02-01 00:05:17.734 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES(P 4228, T 4567): this\n"
348 "02-01 00:05:17.734 I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES(P 4228, T 4567): message.\n" },
349 {FORMAT_RWTIME, DLOG_INFO, false,
350 "02-01 00:05:17 [3205048.235] I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES(P 4228, T 4567): And\n"
351 "02-01 00:05:17 [3205048.235] I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES(P 4228, T 4567): so\n"
352 "02-01 00:05:17 [3205048.235] I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES(P 4228, T 4567): does\n"
353 "02-01 00:05:17 [3205048.235] I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES(P 4228, T 4567): this\n"
354 "02-01 00:05:17 [3205048.235] I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES(P 4228, T 4567): message.\n" },
355 {FORMAT_BRIEF, DLOG_INFO, false,
356 "I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES( 4228): And\n"
357 "I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES( 4228): so\n"
358 "I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES( 4228): does\n"
359 "I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES( 4228): this\n"
360 "I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES( 4228): message.\n" },
361 {FORMAT_PROCESS, DLOG_INFO, false,
362 "I( 4228) And (THIS\nTAG\nTAKES\nMULTIPLE\nLINES)\n"
363 "I( 4228) so (THIS\nTAG\nTAKES\nMULTIPLE\nLINES)\n"
364 "I( 4228) does (THIS\nTAG\nTAKES\nMULTIPLE\nLINES)\n"
365 "I( 4228) this (THIS\nTAG\nTAKES\nMULTIPLE\nLINES)\n"
366 "I( 4228) message. (THIS\nTAG\nTAKES\nMULTIPLE\nLINES)\n" },
367 {FORMAT_TAG, DLOG_INFO, false,
368 "I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES: And\n"
369 "I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES: so\n"
370 "I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES: does\n"
371 "I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES: this\n"
372 "I/THIS\nTAG\nTAKES\nMULTIPLE\nLINES: message.\n" },
373 {FORMAT_THREAD, DLOG_INFO, false,
374 "I(P 4228, T 4567) And\n"
375 "I(P 4228, T 4567) so\n"
376 "I(P 4228, T 4567) does\n"
377 "I(P 4228, T 4567) this\n"
378 "I(P 4228, T 4567) message.\n" },
379 {FORMAT_RAW, DLOG_INFO, false,
380 "And\nso\ndoes\nthis\nmessage.\n" },
382 CHECK_LOGPRINT_TESTCASES("THIS\nTAG\nTAKES\nMULTIPLE\nLINES\0And\nso\ndoes\nthis\nmessage.", tests_linebreak);
384 /* The extras' length gets to be capped (regardless
385 * of which side of the message they are put on). */
386 static const struct logprint_test_case tests_long_metadata[] = {
388 {FORMAT_LONG, DLOG_INFO, false,
389 "[ 03-14 23:22:51.451 I/THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS"
391 {FORMAT_KERNELTIME, DLOG_INFO, false,
392 "3205048.235 I/THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTfoo1\n"
393 "3205048.235 I/THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTfoo2\n" },
394 {FORMAT_RECV_REALTIME, DLOG_INFO, false,
395 "02-01 00:05:17.734 I/THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS Ifoo1\n"
396 "02-01 00:05:17.734 I/THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS Ifoo2\n" },
397 {FORMAT_PROCESS, DLOG_INFO, false,
398 "I( 4228) foo1 (THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TA"
399 "I( 4228) foo2 (THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TA" },
402 {FORMAT_LONG, DLOG_WARN, true,
403 "\033[33;1m[ 03-14 23:22:51.451 W/THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS\033[0m"
405 {FORMAT_KERNELTIME, DLOG_WARN, true,
406 "\033[33;1m3205048.235 W/THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGT\033[0mfoo1\n"
407 "\033[33;1m3205048.235 W/THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGT\033[0mfoo2\n" },
408 {FORMAT_RECV_REALTIME, DLOG_WARN, true,
409 "\033[33;1m02-01 00:05:17.734 W/THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS I\033[0mfoo1\n"
410 "\033[33;1m02-01 00:05:17.734 W/THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS I\033[0mfoo2\n" },
411 {FORMAT_PROCESS, DLOG_WARN, true,
412 "\033[33;1mW( 4228) \033[0mfoo1\033[33;1m (THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TA\033[0m"
413 "\033[33;1mW( 4228) \033[0mfoo2\033[33;1m (THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TA\033[0m" },
415 CHECK_LOGPRINT_TESTCASES("THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH ~ THIS TAG IS OVER 128 CHARS IN LENGTH\0foo1\nfoo2", tests_long_metadata);
417 static const struct logprint_test_case tests_no_msg[] = {
418 {FORMAT_BRIEF , DLOG_INFO, false, "I/SOME_TAG( 4228): DLOG_ERROR_NOMSG\n" },
419 {FORMAT_RAW , DLOG_INFO, false, "DLOG_ERROR_NOMSG\n" },
420 {FORMAT_PROCESS, DLOG_INFO, false, "I( 4228) DLOG_ERROR_NOMSG (SOME_TAG)\n" },
421 {FORMAT_LONG , DLOG_INFO, false, "[ 03-14 23:22:51.451 I/SOME_TAG P 4228, T 4567]\n"
422 "DLOG_ERROR_NOMSG\n\n" },
423 {FORMAT_JSON , DLOG_INFO, false, "{"
424 "\"priority\":\"info\","
427 "\"recv_real\":\"1970-02-01T00:05:17+0000\","
428 "\"recv_mono\":365467.346253662,"
429 "\"sent_real\":\"1970-03-14T23:22:51+0000\","
430 "\"sent_mono\":3205048.235123213,"
431 "\"tag\":\"SOME_TAG\","
432 "\"msg\":\"DLOG_ERROR_NOMSG\""
435 {FORMAT_BRIEF , DLOG_WARN, true, "\033[33;1mW/SOME_TAG( 4228): \033[0mDLOG_ERROR_NOMSG\n" },
436 {FORMAT_RAW , DLOG_WARN, true, "DLOG_ERROR_NOMSG\n" },
437 {FORMAT_PROCESS, DLOG_WARN, true, "\033[33;1mW( 4228) \033[0mDLOG_ERROR_NOMSG\033[33;1m (SOME_TAG)\n\033[0m"},
438 {FORMAT_LONG , DLOG_WARN, true, "\033[33;1m[ 03-14 23:22:51.451 W/SOME_TAG P 4228, T 4567]\n\033[0m"
439 "DLOG_ERROR_NOMSG\n\n" },
441 CHECK_LOGPRINT_TESTCASES("SOME_TAG\0", tests_no_msg);
443 static const struct logprint_test_case tests_no_nothing[] = {
444 {FORMAT_BRIEF , DLOG_INFO, false, "I/DLOG_ERROR_NOTAG( 4228): DLOG_ERROR_NOMSG\n" },
445 {FORMAT_RAW , DLOG_INFO, false, "DLOG_ERROR_NOMSG\n" },
446 {FORMAT_PROCESS, DLOG_INFO, false, "I( 4228) DLOG_ERROR_NOMSG (DLOG_ERROR_NOTAG)\n" },
447 {FORMAT_LONG , DLOG_INFO, false, "[ 03-14 23:22:51.451 I/DLOG_ERROR_NOTAG P 4228, T 4567]\n"
448 "DLOG_ERROR_NOMSG\n\n" },
450 {FORMAT_BRIEF , DLOG_WARN, true, "\033[33;1mW/DLOG_ERROR_NOTAG( 4228): \033[0mDLOG_ERROR_NOMSG\n" },
451 {FORMAT_RAW , DLOG_WARN, true, "DLOG_ERROR_NOMSG\n" },
452 {FORMAT_PROCESS, DLOG_WARN, true, "\033[33;1mW( 4228) \033[0mDLOG_ERROR_NOMSG\033[33;1m "
453 "(DLOG_ERROR_NOTAG)\n\033[0m"},
454 {FORMAT_LONG , DLOG_WARN, true, "\033[33;1m[ 03-14 23:22:51.451 W/DLOG_ERROR_NOTAG P 4228, T 4567]\n\033[0m"
455 "DLOG_ERROR_NOMSG\n\n" },
457 CHECK_LOGPRINT_TESTCASES("\0", tests_no_nothing);
459 static const struct logprint_test_case tests_two_zeros[] = {
460 {FORMAT_BRIEF , DLOG_INFO, false, "I/DLOG_ERROR_NOTAG( 4228): DLOG_ERROR_NOMSG\n" },
461 {FORMAT_RAW , DLOG_INFO, false, "DLOG_ERROR_NOMSG\n" },
462 {FORMAT_PROCESS, DLOG_INFO, false, "I( 4228) DLOG_ERROR_NOMSG (DLOG_ERROR_NOTAG)\n" },
463 {FORMAT_LONG , DLOG_INFO, false, "[ 03-14 23:22:51.451 I/DLOG_ERROR_NOTAG P 4228, T 4567]\n"
464 "DLOG_ERROR_NOMSG\n\n" },
466 {FORMAT_BRIEF , DLOG_WARN, true, "\033[33;1mW/DLOG_ERROR_NOTAG( 4228): \033[0mDLOG_ERROR_NOMSG\n" },
467 {FORMAT_RAW , DLOG_WARN, true, "DLOG_ERROR_NOMSG\n" },
468 {FORMAT_PROCESS, DLOG_WARN, true, "\033[33;1mW( 4228) \033[0mDLOG_ERROR_NOMSG\033[33;1m "
469 "(DLOG_ERROR_NOTAG)\n\033[0m"},
470 {FORMAT_LONG , DLOG_WARN, true, "\033[33;1m[ 03-14 23:22:51.451 W/DLOG_ERROR_NOTAG P 4228, T 4567]\n\033[0m"
471 "DLOG_ERROR_NOMSG\n\n" },
473 CHECK_LOGPRINT_TESTCASES("\0\0", tests_two_zeros);
475 static const struct logprint_test_case tests_garbage[] = {
476 {FORMAT_BRIEF , DLOG_INFO, false, "I/DLOG_ERROR_NOTAG( 4228): DLOG_ERROR_NOMSG\n" },
477 {FORMAT_RAW , DLOG_INFO, false, "DLOG_ERROR_NOMSG\n" },
478 {FORMAT_PROCESS, DLOG_INFO, false, "I( 4228) DLOG_ERROR_NOMSG (DLOG_ERROR_NOTAG)\n" },
479 {FORMAT_LONG , DLOG_INFO, false, "[ 03-14 23:22:51.451 I/DLOG_ERROR_NOTAG P 4228, T 4567]\n"
480 "DLOG_ERROR_NOMSG\n\n" },
482 {FORMAT_BRIEF , DLOG_WARN, true, "\033[33;1mW/DLOG_ERROR_NOTAG( 4228): \033[0mDLOG_ERROR_NOMSG\n" },
483 {FORMAT_RAW , DLOG_WARN, true, "DLOG_ERROR_NOMSG\n" },
484 {FORMAT_PROCESS, DLOG_WARN, true, "\033[33;1mW( 4228) \033[0mDLOG_ERROR_NOMSG\033[33;1m "
485 "(DLOG_ERROR_NOTAG)\n\033[0m"},
486 {FORMAT_LONG , DLOG_WARN, true, "\033[33;1m[ 03-14 23:22:51.451 W/DLOG_ERROR_NOTAG P 4228, T 4567]\n\033[0m"
487 "DLOG_ERROR_NOMSG\n\n" },
489 CHECK_LOGPRINT_TESTCASES("\0\0GARBAGE", tests_garbage);
491 static const struct logprint_test_case tests_only_one_zero[] = {
492 {FORMAT_BRIEF , DLOG_INFO, false, "I/THIS_IS_WEIRD( 4228): DLOG_ERROR_NOMSG\n" },
493 {FORMAT_RAW , DLOG_INFO, false, "DLOG_ERROR_NOMSG\n" },
494 {FORMAT_PROCESS, DLOG_INFO, false, "I( 4228) DLOG_ERROR_NOMSG (THIS_IS_WEIRD)\n" },
495 {FORMAT_LONG , DLOG_INFO, false, "[ 03-14 23:22:51.451 I/THIS_IS_WEIRD P 4228, T 4567]\n"
496 "DLOG_ERROR_NOMSG\n\n" },
498 {FORMAT_BRIEF , DLOG_WARN, true, "\033[33;1mW/THIS_IS_WEIRD( 4228): \033[0mDLOG_ERROR_NOMSG\n" },
499 {FORMAT_RAW , DLOG_WARN, true, "DLOG_ERROR_NOMSG\n" },
500 {FORMAT_PROCESS, DLOG_WARN, true, "\033[33;1mW( 4228) \033[0mDLOG_ERROR_NOMSG\033[33;1m "
501 "(THIS_IS_WEIRD)\n\033[0m"},
502 {FORMAT_LONG , DLOG_WARN, true, "\033[33;1m[ 03-14 23:22:51.451 W/THIS_IS_WEIRD P 4228, T 4567]\n\033[0m"
503 "DLOG_ERROR_NOMSG\n\n" },
505 CHECK_LOGPRINT_TESTCASES("THIS_IS_WEIRD", tests_only_one_zero);
507 static const struct logprint_test_case tests_fixup_pipe[] = {
508 // formats using the SENT timestamp (nominally)
509 {FORMAT_TIME , DLOG_INFO, false, "02-01 00:05:17.734+0000 I/BASIC TAG( 0): Basic message.\n"
510 "02-01 00:05:17.734+0000 I/BASIC TAG( 0): [dlog inline warning: modified invalid timestamp]\n" },
511 {FORMAT_LONG , DLOG_INFO, false, "[ 02-01 00:05:17.734 I/BASIC TAG P 0, T 0]\n"
513 "[dlog inline warning: modified invalid timestamp]\n\n" },
514 {FORMAT_THREADTIME , DLOG_INFO, false, "02-01 00:05:17.734+0000 I/BASIC TAG (P 0, T 0): Basic message.\n"
515 "02-01 00:05:17.734+0000 I/BASIC TAG (P 0, T 0): [dlog inline warning: modified invalid timestamp]\n" },
516 {FORMAT_KERNELTIME , DLOG_INFO, false, "365467.346 I/BASIC TAG(P 0, T 0): Basic message.\n"
517 "365467.346 I/BASIC TAG(P 0, T 0): [dlog inline warning: modified invalid timestamp]\n" },
519 // formats using the RECV timestamp
520 {FORMAT_RECV_REALTIME, DLOG_INFO, false, "02-01 00:05:17.734 I/BASIC TAG(P 0, T 0): Basic message.\n"
521 "02-01 00:05:17.734 I/BASIC TAG(P 0, T 0): [dlog inline warning: modified invalid timestamp]\n" },
522 {FORMAT_RWTIME , DLOG_INFO, false, "02-01 00:05:17 [365467.346] I/BASIC TAG(P 0, T 0): Basic message.\n"
523 "02-01 00:05:17 [365467.346] I/BASIC TAG(P 0, T 0): [dlog inline warning: modified invalid timestamp]\n" },
525 // formats without a timestamp
526 {FORMAT_BRIEF , DLOG_INFO, false, "I/BASIC TAG( 0): Basic message.\n"
527 "I/BASIC TAG( 0): [dlog inline warning: modified invalid timestamp]\n" },
528 {FORMAT_PROCESS , DLOG_INFO, false, "I( 0) Basic message. (BASIC TAG)\n"
529 "I( 0) [dlog inline warning: modified invalid timestamp] (BASIC TAG)\n" },
530 {FORMAT_TAG , DLOG_INFO, false, "I/BASIC TAG: Basic message.\n"
531 "I/BASIC TAG: [dlog inline warning: modified invalid timestamp]\n" },
532 {FORMAT_THREAD , DLOG_INFO, false, "I(P 0, T 0) Basic message.\n"
533 "I(P 0, T 0) [dlog inline warning: modified invalid timestamp]\n" },
534 {FORMAT_RAW , DLOG_INFO, false, "Basic message.\n"
535 "[dlog inline warning: modified invalid timestamp]\n" },
537 {FORMAT_JSON , DLOG_INFO, false, "{"
538 "\"priority\":\"info\","
541 "\"recv_real\":\"1970-02-01T00:05:17+0000\","
542 "\"recv_mono\":365467.346253662,"
543 "\"sent_real\":\"1970-02-01T00:05:17+0000\","
544 "\"sent_mono\":365467.346253662,"
545 "\"tag\":\"BASIC TAG\","
546 "\"msg\":\"Basic message.\\n"
547 "[dlog inline warning: modified invalid timestamp]\""
550 CHECK_LOGPRINT_TESTCASES_INVALID("BASIC TAG\0Basic message.", tests_fixup_pipe);
553 void check_log_print_log_line_buffer(void)
555 struct dlogutil_entry_with_msg entry;
556 const char tag_msg[] = "tag\0msg";
557 const char msg[] = "msg\n";
558 standard_test_msg(&entry, tag_msg, sizeof(tag_msg));
561 struct log_write_buffer wbuf = {
564 .size = sizeof(data),
570 for (int cpos = 0; cpos < sizeof(data); cpos += strlen(msg)) {
571 assert(wbuf.position == cpos);
572 assert(strlen(buffer) == 0);
573 assert(log_print_log_line((struct log_format){
574 .format = FORMAT_RAW,
576 }, 0, &entry.header, &wbuf) == 1);
579 assert(wbuf.position == strlen(msg));
580 assert(memcmp(wbuf.data, msg, strlen(msg)) == 0);
582 int total_count = sizeof(data) / strlen(msg);
583 assert(strlen(buffer) == total_count * strlen(msg));
584 for (int i = 0; i < total_count; ++i)
585 assert(memcmp(buffer + i * strlen(msg), msg, strlen(msg)) == 0);
590 char *json_escape_string(char *in);
591 void check_json_escape_string_testcase(char *in, char *correct)
593 char *out = json_escape_string(in);
595 assert(!strcmp(out, correct));
603 const char *json_priority_name(log_priority prio);
604 struct timespec entry_get_ts(const dlogutil_entry_s *entry, bool sent, bool mono);
605 char *log_format_json(char *default_buffer, size_t default_buffer_size, const dlogutil_entry_s *entry, size_t *p_outLength, char *tag, char *msg);
606 void check_json(void)
608 // TODO: Failure testing
609 check_json_escape_string_testcase("abc/def", "abc/def");
610 check_json_escape_string_testcase("\x01\x02\x03", "\\u0001\\u0002\\u0003");
611 check_json_escape_string_testcase("\x1A\x1B\x1C", "\\u001A\\u001B\\u001C");
612 check_json_escape_string_testcase("\x1D\x1E\x1F", "\\u001D\\u001E\\u001F");
613 check_json_escape_string_testcase("\"\\\b\f\n\r\t", "\\\"\\\\\\b\\f\\n\\r\\t");
614 check_json_escape_string_testcase("zażółć gęślą jaźń", "zażółć gęślą jaźń");
615 check_json_escape_string_testcase("삼성", "삼성");
616 check_json_escape_string_testcase("タイゼン", "タイゼン");
617 check_json_escape_string_testcase("🏀", "🏀");
619 assert(!strcmp(json_priority_name(DLOG_VERBOSE), "verbose"));
620 assert(!strcmp(json_priority_name(DLOG_DEBUG), "debug"));
621 assert(!strcmp(json_priority_name(DLOG_INFO), "info"));
622 assert(!strcmp(json_priority_name(DLOG_WARN), "warning"));
623 assert(!strcmp(json_priority_name(DLOG_ERROR), "error"));
624 assert(!strcmp(json_priority_name(DLOG_FATAL), "fatal"));
625 assert(!strcmp(json_priority_name(DLOG_SILENT), "silent"));
626 assert(!strcmp(json_priority_name(DLOG_UNKNOWN), "unknown"));
627 assert(!strcmp(json_priority_name(123), "unknown"));
629 char data[] = "tag\0important message";
630 dlogutil_entry_s *ent = calloc(1, sizeof(*ent) + sizeof data);
632 ent->len = sizeof data;
634 strncpy(ent->msg, data, ent->len);
635 ent->priority = DLOG_DEBUG;
641 #define TEST_EMPTY_TIMESTAMP() \
642 ent->nsec_sent_mono = ent->nsec_recv_mono = ent->nsec_sent_real = ent->nsec_recv_real = -1; \
643 ts = entry_get_ts(ent, CURRENT_SENT, CURRENT_MONO); \
644 assert(ts.tv_sec == 0); \
645 assert(ts.tv_nsec == 0)
646 #define TEST_SINGLE_TIMESTAMP(which, to_set, expected) \
647 ent->sec_##which = ent->nsec_##which = to_set; \
648 ts = entry_get_ts(ent, CURRENT_SENT, CURRENT_MONO); \
649 assert(ts.tv_sec == expected); \
650 assert(ts.tv_nsec == expected)
652 #define CURRENT_MONO true
653 #define CURRENT_SENT true
654 TEST_EMPTY_TIMESTAMP();
655 TEST_SINGLE_TIMESTAMP(recv_real, 1, 1);
656 TEST_SINGLE_TIMESTAMP(sent_real, 2, 2);
657 TEST_SINGLE_TIMESTAMP(recv_mono, 3, 3);
658 TEST_SINGLE_TIMESTAMP(sent_mono, 4, 4);
661 #define CURRENT_SENT false
662 TEST_EMPTY_TIMESTAMP();
663 TEST_SINGLE_TIMESTAMP(sent_real, 1, 1);
664 TEST_SINGLE_TIMESTAMP(recv_real, 2, 2);
665 TEST_SINGLE_TIMESTAMP(sent_mono, 3, 3);
666 TEST_SINGLE_TIMESTAMP(recv_mono, 4, 4);
670 #define CURRENT_MONO false
671 #define CURRENT_SENT true
672 TEST_EMPTY_TIMESTAMP();
673 TEST_SINGLE_TIMESTAMP(recv_mono, 1, 0);
674 TEST_SINGLE_TIMESTAMP(sent_mono, 2, 0);
675 TEST_SINGLE_TIMESTAMP(recv_real, 3, 3);
676 TEST_SINGLE_TIMESTAMP(sent_real, 4, 4);
679 #define CURRENT_SENT false
680 TEST_EMPTY_TIMESTAMP();
681 TEST_SINGLE_TIMESTAMP(sent_mono, 1, 0);
682 TEST_SINGLE_TIMESTAMP(recv_mono, 2, 0);
683 TEST_SINGLE_TIMESTAMP(sent_real, 3, 3);
684 TEST_SINGLE_TIMESTAMP(recv_real, 4, 4);
688 #undef TEST_EMPTY_TIMESTAMP
689 #undef TEST_SINGLE_TIMESTAMP
694 ent->nsec_sent_mono = ent->nsec_recv_mono = ent->nsec_sent_real = ent->nsec_recv_real = -1;
695 assert(log_format_json(buf, sizeof(buf), ent, &out_len, "tag", "message") == buf);
696 assert(strlen(buf) == out_len);
697 assert(!strcmp(buf, "{" \
698 "\"priority\":\"debug\"," \
702 "\"msg\":\"message\"" \
706 target = log_format_json(NULL, out_len, ent, &out_len, "tag", "message");
708 assert(target != buf);
709 assert(strlen(target) == out_len);
710 assert(!strcmp(buf, target));
713 ent->sec_sent_mono = ent->nsec_sent_mono = 21;
714 ent->sec_recv_mono = ent->nsec_recv_mono = 22;
715 ent->sec_sent_real = ent->nsec_sent_real = 23242527;
716 ent->sec_recv_real = ent->nsec_recv_real = 28293031;
717 assert(log_format_json(buf, sizeof(buf), ent, &out_len, "tag", "message") == buf);
718 assert(strlen(buf) == out_len);
719 assert(!strcmp(buf, "{"\
720 "\"priority\":\"debug\","\
723 "\"recv_real\":\"1970-11-24T11:10:31+0000\","\
724 "\"recv_mono\":22.000000022,"\
725 "\"sent_real\":\"1970-09-27T00:15:27+0000\","\
726 "\"sent_mono\":21.000000021,"\
728 "\"msg\":\"message\""\
731 char data2[] = "∫\0\x01\x02\x03\x14\x15\x16\"\\\b\f\n\r\t🤔";
732 assert(sizeof data == sizeof data2);
733 strncpy(ent->msg, data2, ent->len);
734 assert(log_format_json(buf, sizeof(buf), ent, &out_len, "∫", "\x01\x02\x03\x14\x15\x16\"\\\b\f\n\r\t🤔") == buf);
735 assert(strlen(buf) == out_len);
736 assert(!strcmp(buf, "{"\
737 "\"priority\":\"debug\","\
740 "\"recv_real\":\"1970-11-24T11:10:31+0000\","\
741 "\"recv_mono\":22.000000022,"\
742 "\"sent_real\":\"1970-09-27T00:15:27+0000\","\
743 "\"sent_mono\":21.000000021,"\
745 "\"msg\":\"\\u0001\\u0002\\u0003\\u0014\\u0015\\u0016\\\"\\\\\\b\\f\\n\\r\\t🤔\""\
751 void check_utf8_correctness(void)
754 static const struct logprint_test_case test_2_bytes_0_shift[] = {
755 {FORMAT_KERNELTIME, DLOG_INFO, false,
756 "3205048.235 I/©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©foo1\n"},
757 {FORMAT_PROCESS, DLOG_INFO, false,
758 "I( 4228) foo1 (©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©"},
760 CHECK_LOGPRINT_TESTCASES("©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©\0foo1", test_2_bytes_0_shift);
761 static const struct logprint_test_case test_2_bytes_1_shift[] = {
762 {FORMAT_KERNELTIME, DLOG_INFO, false,
763 "3205048.235 I/1©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©foo1\n"},
764 {FORMAT_PROCESS, DLOG_INFO, false,
765 "I( 4228) foo1 (1©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©"},
767 CHECK_LOGPRINT_TESTCASES("1©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©\0foo1", test_2_bytes_1_shift);
769 /* ♘ is three bytes */
770 static const struct logprint_test_case test_3_bytes_0_shift[] = {
771 {FORMAT_KERNELTIME, DLOG_INFO, false,
772 "3205048.235 I/♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘foo1\n"},
773 {FORMAT_PROCESS, DLOG_INFO, false,
774 "I( 4228) foo1 (♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘"},
776 CHECK_LOGPRINT_TESTCASES("♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘\0foo1", test_3_bytes_0_shift);
777 static const struct logprint_test_case test_3_bytes_1_shift[] = {
778 {FORMAT_KERNELTIME, DLOG_INFO, false,
779 "3205048.235 I/1♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘foo1\n"},
780 {FORMAT_PROCESS, DLOG_INFO, false,
781 "I( 4228) foo1 (1♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘"},
783 CHECK_LOGPRINT_TESTCASES("1♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘\0foo1", test_3_bytes_1_shift);
784 static const struct logprint_test_case test_3_bytes_2_shift[] = {
785 {FORMAT_KERNELTIME, DLOG_INFO, false,
786 "3205048.235 I/12♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘foo1\n"},
787 {FORMAT_PROCESS, DLOG_INFO, false,
788 "I( 4228) foo1 (12♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘"},
790 CHECK_LOGPRINT_TESTCASES("12♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘♘\0foo1", test_3_bytes_2_shift);
792 /* 💯 is four bytes */
793 static const struct logprint_test_case test_4_bytes_0_shift[] = {
794 {FORMAT_KERNELTIME, DLOG_INFO, false,
795 "3205048.235 I/💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯foo1\n"},
796 {FORMAT_PROCESS, DLOG_INFO, false,
797 "I( 4228) foo1 (💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯"},
799 CHECK_LOGPRINT_TESTCASES("💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯\0foo1", test_4_bytes_0_shift);
800 static const struct logprint_test_case test_4_bytes_1_shift[] = {
801 {FORMAT_KERNELTIME, DLOG_INFO, false,
802 "3205048.235 I/1💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯foo1\n"},
803 {FORMAT_PROCESS, DLOG_INFO, false,
804 "I( 4228) foo1 (1💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯"},
806 CHECK_LOGPRINT_TESTCASES("1💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯\0foo1", test_4_bytes_1_shift);
807 static const struct logprint_test_case test_4_bytes_2_shift[] = {
808 {FORMAT_KERNELTIME, DLOG_INFO, false,
809 "3205048.235 I/12💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯foo1\n"},
810 {FORMAT_PROCESS, DLOG_INFO, false,
811 "I( 4228) foo1 (12💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯"},
813 CHECK_LOGPRINT_TESTCASES("12💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯\0foo1", test_4_bytes_2_shift);
814 static const struct logprint_test_case test_4_bytes_3_shift[] = {
815 {FORMAT_KERNELTIME, DLOG_INFO, false,
816 "3205048.235 I/123💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯foo1\n"},
817 {FORMAT_PROCESS, DLOG_INFO, false,
818 "I( 4228) foo1 (123💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯"},
820 CHECK_LOGPRINT_TESTCASES("123💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯💯\0foo1", test_4_bytes_3_shift);
823 void check_syscall_failure_handling(void)
825 struct log_filter *const filter = log_filter_new();
827 assert(!log_filter_set_tid(filter, 123));
828 assert(!log_filter_set_pid(filter, 456));
829 assert(!log_add_filter_rule(filter, "FOO:E"));
831 struct log_filter *const clone = log_filter_from_filter(filter);
833 log_filter_free(clone);
836 assert(!log_filter_new());
837 assert(!log_filter_from_filter(filter));
838 assert(TIZEN_ERROR_OUT_OF_MEMORY == log_filter_set_tid(filter, 123));
839 assert(TIZEN_ERROR_OUT_OF_MEMORY == log_filter_set_pid(filter, 456));
842 // Not really a syscall, but eh
843 fail_list_add = true;
844 assert(TIZEN_ERROR_OUT_OF_MEMORY == log_add_filter_rule(filter, "FOO:E"));
845 fail_list_add = false;
848 assert(!log_filter_from_filter(filter));
849 assert(TIZEN_ERROR_OUT_OF_MEMORY == log_filter_set_filterspec(filter, "FOO:E"));
850 assert(TIZEN_ERROR_OUT_OF_MEMORY == log_add_filter_rule(filter, "FOO:E"));
853 fail_strndup = true; // N
854 assert(TIZEN_ERROR_OUT_OF_MEMORY == log_filter_set_filterspec(filter, "FOO:E"));
855 fail_strndup = false;
857 /* the array size is an arbitrary value between 512, i.e. the size of the default buffer,
858 * and 4096, i.e. LOG_MAX_PAYLOAD_SIZE (higher should also work but would be pointless). */
860 [0 ... 41] = 'A', // tag
862 [43 ... sizeof msg - 2] = 'a', // msg
863 [sizeof msg - 1] = '\0'
865 struct dlogutil_entry_with_msg entry;
866 standard_test_msg(&entry, msg, sizeof msg);
868 struct log_format format = {
869 .format = FORMAT_TIME,
874 assert(-1 == log_print_log_line(format, 0, &entry.header, &(struct log_write_buffer) { }));
877 fail_localtime_r = true;
878 assert(-1 == log_print_log_line(format, 0, &entry.header, &(struct log_write_buffer) { }));
879 fail_localtime_r = false;
882 assert(0 == log_print_log_line(format, 0, &entry.header, &(struct log_write_buffer) { }));
885 assert(1 == log_print_log_line(format, 0, &entry.header, &(struct log_write_buffer) { }));
888 log_filter_free(filter);
891 void check_invalid_input(void)
893 const dlogutil_entry_s entry = { .len = 1 };
896 assert(dlogutil_entry_get_message(&entry, &data) == TIZEN_ERROR_NO_DATA);
899 assert(dlogutil_entry_get_tag(&entry, &data) == TIZEN_ERROR_NO_DATA);
902 struct log_filter *const filter = log_filter_new();
904 assert(TIZEN_ERROR_INVALID_PARAMETER == log_add_filter_rule(filter, ":D")); // >mfw tagless rule gets processed correctly
905 log_filter_free(filter);
908 void check_log_format_from_string(void)
910 static const struct {
912 log_print_format format;
913 } expected_formats[] = {
914 {"brief" , FORMAT_BRIEF },
915 {" brief" , FORMAT_OFF },
916 {"tag" , FORMAT_TAG },
917 {"tagging up turf", FORMAT_OFF },
918 {"process" , FORMAT_PROCESS },
919 {"long" , FORMAT_LONG },
920 {"thien long" , FORMAT_OFF },
921 {"threadtime" , FORMAT_THREADTIME},
922 {"kerneltime" , FORMAT_KERNELTIME},
923 {"hammertime" , FORMAT_OFF },
926 for (size_t i = 0; i < NELEMS(expected_formats); ++i)
927 assert(log_format_from_string(expected_formats[i].string) == expected_formats[i].format);
930 void check_get_format_sorting(void)
932 static const struct {
933 log_print_format format;
934 dlogutil_sorting_order_e sorting;
935 } expected_sorting[] = {
936 {FORMAT_TAG , DLOGUTIL_SORT_DEFAULT },
937 {FORMAT_PROCESS , DLOGUTIL_SORT_DEFAULT },
938 {FORMAT_THREAD , DLOGUTIL_SORT_DEFAULT },
939 {FORMAT_RAW , DLOGUTIL_SORT_DEFAULT },
940 {FORMAT_BRIEF , DLOGUTIL_SORT_DEFAULT },
941 {FORMAT_TIME , DLOGUTIL_SORT_SENT_REAL},
942 {FORMAT_THREADTIME , DLOGUTIL_SORT_SENT_REAL},
943 {FORMAT_KERNELTIME , DLOGUTIL_SORT_SENT_MONO},
944 {FORMAT_LONG , DLOGUTIL_SORT_SENT_REAL},
945 {FORMAT_RWTIME , DLOGUTIL_SORT_RECV_REAL},
946 {FORMAT_RECV_REALTIME, DLOGUTIL_SORT_RECV_REAL},
949 for (size_t i = 0; i < NELEMS(expected_sorting); ++i) {
950 assert(get_format_sorting(expected_sorting[i].format) == expected_sorting[i].sorting);
954 void check_filter_pri_to_char(void)
956 static const struct {
960 {DLOG_VERBOSE , 'V' },
966 {DLOG_SILENT , 'S' },
967 }, expected_pris[] = {
968 {DLOG_UNKNOWN , '0' },
969 {DLOG_DEFAULT , '1' },
970 {DLOG_VERBOSE , '2' },
976 {DLOG_VERBOSE , '8' }, // makes little sense but ok
977 {DLOG_VERBOSE , '9' }, // ditto
979 {DLOG_VERBOSE , 'v' },
985 {DLOG_SILENT , 's' },
986 {DLOG_DEFAULT , '*' },
988 {DLOG_UNKNOWN , 'l' },
989 {DLOG_UNKNOWN , 'L' },
990 {DLOG_UNKNOWN , ' ' },
991 {DLOG_UNKNOWN , '\a'},
992 {DLOG_UNKNOWN , '\0'},
993 }, expected_chars[] = {
994 {DLOG_DEFAULT , '?' },
995 {DLOG_UNKNOWN , '?' },
996 {(log_priority)42, '?' },
997 {(log_priority)-9, '?' },
1000 for (size_t i = 0; i < NELEMS(convertibles); ++i) {
1001 assert(filter_pri_to_char(convertibles[i].pri) == convertibles[i].c);
1002 assert(filter_char_to_pri(convertibles[i].c) == convertibles[i].pri);
1005 for (size_t i = 0; i < NELEMS(expected_pris); ++i)
1006 assert(filter_char_to_pri(expected_pris[i].c) == expected_pris[i].pri);
1008 for (size_t i = 0; i < NELEMS(expected_chars); ++i)
1009 assert(filter_pri_to_char(expected_chars[i].pri) == expected_chars[i].c);
1012 void log_filter_default(void)
1014 struct log_filter *const filter = log_filter_new();
1015 bool ret = log_filter_need_apply_default(filter);
1017 log_filter_free(filter);
1022 check_log_format_from_string();
1023 check_get_format_sorting();
1024 check_filter_pri_to_char();
1025 check_log_print_log_line();
1026 check_log_print_log_line_buffer();
1027 check_invalid_input();
1028 check_syscall_failure_handling();
1029 check_utf8_correctness();
1031 log_filter_default();