mirror of https://github.com/nirenjan/libx52.git
				
				
				
			
		
			
				
	
	
		
			205 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			205 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			C
		
	
	
| /*
 | |
|  * Pinelog lightweight logging library - test harness
 | |
|  *
 | |
|  * Copyright (C) 2021 Nirenjan Krishnan (nirenjan@nirenjan.org)
 | |
|  *
 | |
|  * SPDX-License-Identifier: MIT
 | |
|  */
 | |
| 
 | |
| #include "pinelog.h"
 | |
| #include <stdio.h>
 | |
| #include <stdarg.h>
 | |
| #include <stdbool.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <limits.h>
 | |
| #include <time.h>
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <fcntl.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| /**********************************************************************
 | |
|  * Global variables
 | |
|  *********************************************************************/
 | |
| // Test ID (of current test case)
 | |
| static unsigned int test_id;
 | |
| 
 | |
| // Observed output stream
 | |
| static FILE *observed_stream_w;
 | |
| static FILE *observed_stream_r;
 | |
| 
 | |
| // Temporary pipe for observed data
 | |
| static char observed_fifo[NAME_MAX];
 | |
| 
 | |
| // Buffer for expected output
 | |
| static char expected_output[1024];
 | |
| static size_t expected_len;
 | |
| 
 | |
| static void test_case(const char *desc, bool test)
 | |
| {
 | |
|     test_id++;
 | |
|     if (test) {
 | |
|         printf("ok %u %s\n", test_id, desc);
 | |
|     } else {
 | |
|         printf("not ok %u %s\n", test_id, desc);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void pinelog_exit(int status)
 | |
| {
 | |
|     fprintf(observed_stream_w, "EXIT(%d)\n", status);
 | |
|     expected_len += snprintf(&expected_output[expected_len],
 | |
|                              sizeof(expected_output) - expected_len,
 | |
|                              "EXIT(%d)\n", status);
 | |
| }
 | |
| 
 | |
| static void dump_data(const char *type, size_t len, char *data)
 | |
| {
 | |
|     char *line;
 | |
|     printf("# %s (%lu bytes):\n", type, len);
 | |
|     line = strtok(data, "\n");
 | |
|     while (line != NULL) {
 | |
|         printf("#\t%s\n", line);
 | |
|         line = strtok(NULL, "\n");
 | |
|     }
 | |
|     printf("\n");
 | |
| }
 | |
| 
 | |
| static int test_setup(int level, int filter, const char *file, int line)
 | |
| {
 | |
|     expected_len = 0;
 | |
|     memset(expected_output, 0, sizeof(expected_output));
 | |
| 
 | |
|     if (level <= filter) {
 | |
|         if (PINELOG_SHOW_DATE) {
 | |
|             time_t t;
 | |
|             struct tm *tmp;
 | |
| 
 | |
|             t = time(NULL);
 | |
|             tmp = localtime(&t);
 | |
|             expected_len += strftime(&expected_output[expected_len],
 | |
|                                      sizeof(expected_output) - expected_len,
 | |
|                                      "%F %T ", tmp);
 | |
|         }
 | |
| 
 | |
|         if (PINELOG_SHOW_LEVEL) {
 | |
|             const char * level_string[] = {
 | |
|                 PINELOG_FATAL_STR,
 | |
|                 PINELOG_ERROR_STR,
 | |
|                 PINELOG_WARNING_STR,
 | |
|                 PINELOG_INFO_STR,
 | |
|                 PINELOG_DEBUG_STR,
 | |
|                 PINELOG_TRACE_STR,
 | |
|             };
 | |
|             expected_len += snprintf(&expected_output[expected_len],
 | |
|                                      sizeof(expected_output) - expected_len,
 | |
|                                      "%s: ", level_string[level]);
 | |
|         }
 | |
| 
 | |
|         if (PINELOG_SHOW_BACKTRACE) {
 | |
|             char * basename = NULL;
 | |
|             #if defined __has_builtin
 | |
|             #if __has_builtin(__builtin_strrchr)
 | |
|             basename = strrchr(file, '/');
 | |
|             #endif
 | |
|             #endif
 | |
| 
 | |
|             if (basename != NULL) {
 | |
|                 basename++;
 | |
|             } else {
 | |
|                 // Override the const
 | |
|                 basename = (char *)file;
 | |
|             }
 | |
|             expected_len += snprintf(&expected_output[expected_len],
 | |
|                                      sizeof(expected_output) - expected_len,
 | |
|                                      "%s:%d ", basename, line);
 | |
|         }
 | |
| 
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static void test_teardown(const char *desc)
 | |
| {
 | |
|     // Compare the output
 | |
|     static char observed[1024];
 | |
|     size_t observed_len;
 | |
|     int result;
 | |
| 
 | |
|     observed_len = fread(observed, 1, sizeof(observed), observed_stream_r);
 | |
| 
 | |
|     result = ((expected_len == observed_len) &&
 | |
|               (memcmp(expected_output, observed, expected_len) == 0));
 | |
|     test_case(desc, result);
 | |
|     if (!result) {
 | |
|         dump_data("expected", expected_len, expected_output);
 | |
|         dump_data("observed", observed_len, observed);
 | |
|     }
 | |
| }
 | |
| 
 | |
| static void verify_defaults(void)
 | |
| {
 | |
|     test_case("Get default output stream",
 | |
|               pinelog_get_output_stream() == PINELOG_DEFAULT_STREAM);
 | |
|     test_case("Get default logging level",
 | |
|               pinelog_get_level() == PINELOG_DEFAULT_LEVEL);
 | |
| }
 | |
| 
 | |
| #define PINELOG_WARNING PINELOG_WARN
 | |
| 
 | |
| #define TEST_LOG(lvl, filter, fmt, ...) do { \
 | |
|     if (test_setup(PINELOG_LVL_ ## lvl, PINELOG_LVL_ ## filter, \
 | |
|                __FILE__, __LINE__)) \
 | |
|        expected_len += snprintf(&expected_output[expected_len], \
 | |
|                                 sizeof(expected_output) - expected_len, \
 | |
|                                 fmt "\n", ##__VA_ARGS__); \
 | |
|     PINELOG_ ## lvl (fmt, ##__VA_ARGS__); \
 | |
|     test_teardown("Log " #lvl " filter " #filter); \
 | |
| } while(0)
 | |
| 
 | |
| #define TEST(filter, fmt, ...) do { \
 | |
|     pinelog_set_level(PINELOG_LVL_ ## filter); \
 | |
|     TEST_LOG(TRACE, filter, fmt, ##__VA_ARGS__); \
 | |
|     TEST_LOG(DEBUG, filter, fmt, ##__VA_ARGS__); \
 | |
|     TEST_LOG(INFO, filter, fmt, ##__VA_ARGS__); \
 | |
|     TEST_LOG(WARNING, filter, fmt, ##__VA_ARGS__); \
 | |
|     TEST_LOG(ERROR, filter, fmt, ##__VA_ARGS__); \
 | |
|     TEST_LOG(FATAL, filter, fmt, ##__VA_ARGS__); \
 | |
| } while (0)
 | |
| 
 | |
| int main(int argc, char **argv)
 | |
| {
 | |
|     int fifo_fd_r, fifo_fd_w;
 | |
|     snprintf(observed_fifo, sizeof(observed_fifo), "%s.fifo", argv[0]);
 | |
|     mkfifo(observed_fifo, 0777);
 | |
| 
 | |
|     fifo_fd_r = open(observed_fifo, O_RDONLY | O_NONBLOCK);
 | |
|     fifo_fd_w = open(observed_fifo, O_WRONLY | O_NONBLOCK);
 | |
|     observed_stream_r = fdopen(fifo_fd_r, "r");
 | |
|     observed_stream_w = fdopen(fifo_fd_w, "w");
 | |
| 
 | |
|     verify_defaults();
 | |
| 
 | |
|     pinelog_set_output_stream(observed_stream_w);
 | |
|     TEST(TRACE, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1);
 | |
|     TEST(DEBUG, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1);
 | |
|     TEST(INFO, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1);
 | |
|     TEST(WARNING, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1);
 | |
|     TEST(ERROR, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1);
 | |
|     TEST(FATAL, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1);
 | |
|     TEST(NONE, "testing %s... %d, %f, %u", "testing", -1, 0.0, 1);
 | |
| 
 | |
|     printf("1..%u\n", test_id);
 | |
| 
 | |
|     pinelog_close_output_stream();
 | |
|     fclose(observed_stream_r);
 | |
|     close(fifo_fd_w);
 | |
|     close(fifo_fd_r);
 | |
|     unlink(observed_fifo);
 | |
| 
 | |
|     return 0;
 | |
| }
 |