/** * Comprehensive test for debug configuration system * Tests runtime debug control, categories, levels, and formatting */ #define _GNU_SOURCE // For setenv/unsetenv #include #include #include #include #include "../lib/debug_config.h" static int test_passed = 0; static int test_failed = 0; #define TEST_START(name) do { \ printf("TEST: %s... ", name); \ } while(0) #define TEST_PASS() do { \ printf("PASS\n"); \ test_passed++; \ } while(0) #define TEST_FAIL(msg) do { \ printf("FAIL: %s\n", msg); \ test_failed++; \ } while(0) #define ASSERT_TRUE(cond, msg) do { \ if (!(cond)) { TEST_FAIL(msg); return; } \ } while(0) #define ASSERT_FALSE(cond, msg) do { \ if (cond) { TEST_FAIL(msg); return; } \ } while(0) #define ASSERT_EQ(a, b, msg) do { \ if ((a) != (b)) { TEST_FAIL(msg); return; } \ } while(0) static void test_basic_functionality(void) { TEST_START("Basic functionality"); debug_config_init(); /* Test default configuration */ ASSERT_EQ(g_debug_config.level, DEBUG_LEVEL_ERROR, "Default level should be ERROR"); ASSERT_EQ(g_debug_config.categories, DEBUG_CATEGORY_ALL, "All categories should be enabled by default"); ASSERT_FALSE(g_debug_config.timestamp_enabled, "Timestamps should be disabled by default"); ASSERT_FALSE(g_debug_config.function_name_enabled, "Function names should be disabled by default"); ASSERT_FALSE(g_debug_config.color_enabled, "Colors should be disabled by default"); TEST_PASS(); } static void test_debug_levels(void) { TEST_START("Debug levels"); debug_config_init(); /* Test level changes */ debug_set_level(DEBUG_LEVEL_DEBUG); ASSERT_EQ(g_debug_config.level, DEBUG_LEVEL_DEBUG, "Level should be set to DEBUG"); debug_set_level(DEBUG_LEVEL_NONE); ASSERT_EQ(g_debug_config.level, DEBUG_LEVEL_NONE, "Level should be set to NONE"); /* Test output filtering */ ASSERT_FALSE(debug_should_output(DEBUG_LEVEL_INFO, DEBUG_CATEGORY_ALL), "INFO should not output at NONE level"); ASSERT_TRUE(debug_should_output(DEBUG_LEVEL_ERROR, DEBUG_CATEGORY_ALL), "ERROR should output at NONE level (fallback)"); TEST_PASS(); } static void test_categories(void) { TEST_START("Categories"); debug_config_init(); debug_set_categories(DEBUG_CATEGORY_NONE); // Start with none /* Test enabling specific categories */ debug_enable_category(DEBUG_CATEGORY_UASYNC); ASSERT_TRUE(g_debug_config.categories & DEBUG_CATEGORY_UASYNC, "UASYNC should be enabled"); ASSERT_FALSE(g_debug_config.categories & DEBUG_CATEGORY_LL_QUEUE, "LL_QUEUE should be disabled"); /* Test disabling categories */ debug_disable_category(DEBUG_CATEGORY_UASYNC); ASSERT_FALSE(g_debug_config.categories & DEBUG_CATEGORY_UASYNC, "UASYNC should be disabled"); /* Test output filtering by category */ debug_set_level(DEBUG_LEVEL_DEBUG); debug_enable_category(DEBUG_CATEGORY_UASYNC); ASSERT_TRUE(debug_should_output(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_UASYNC), "UASYNC debug should output when enabled"); ASSERT_FALSE(debug_should_output(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_LL_QUEUE), "LL_QUEUE debug should not output when disabled"); TEST_PASS(); } static void test_output_formatting(void) { TEST_START("Output formatting"); debug_config_init(); debug_set_level(DEBUG_LEVEL_DEBUG); debug_set_categories(DEBUG_CATEGORY_ALL); /* Test enabling different formatting options */ debug_enable_timestamp(1); ASSERT_TRUE(g_debug_config.timestamp_enabled, "Timestamps should be enabled"); debug_enable_function_name(1); ASSERT_TRUE(g_debug_config.function_name_enabled, "Function names should be enabled"); debug_enable_file_line(1); ASSERT_TRUE(g_debug_config.file_line_enabled, "File:line should be enabled"); debug_enable_color(1); ASSERT_TRUE(g_debug_config.color_enabled, "Colors should be enabled"); /* Test disabling */ debug_enable_timestamp(0); ASSERT_FALSE(g_debug_config.timestamp_enabled, "Timestamps should be disabled"); TEST_PASS(); } static void test_rate_limiting(void) { TEST_START("Rate limiting"); debug_config_init(); debug_set_rate_limit(10); // 10 messages per second ASSERT_EQ(g_debug_config.max_output_per_second, 10, "Rate limit should be set to 10"); /* Test that rate limiting works (basic test) */ int allowed_count = 0; for (int i = 0; i < 20; i++) { if (debug_should_output(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_ALL)) allowed_count++; } /* Should allow at least 10 messages (first batch) */ ASSERT_TRUE(allowed_count >= 10, "Should allow at least 10 messages initially"); TEST_PASS(); } static void test_config_parsing(void) { TEST_START("Configuration parsing"); debug_config_init(); /* Test simple level format */ ASSERT_EQ(debug_parse_config("debug"), 0, "Should parse 'debug' successfully"); ASSERT_EQ(g_debug_config.level, DEBUG_LEVEL_DEBUG, "Level should be set to DEBUG"); ASSERT_EQ(g_debug_config.categories, DEBUG_CATEGORY_ALL, "All categories should be enabled"); /* Test category:level format */ debug_set_categories(DEBUG_CATEGORY_NONE); debug_set_level(DEBUG_LEVEL_ERROR); ASSERT_EQ(debug_parse_config("uasync:debug,ll_queue:info"), 0, "Should parse category:level format"); ASSERT_TRUE(g_debug_config.categories & DEBUG_CATEGORY_UASYNC, "UASYNC should be enabled"); ASSERT_TRUE(g_debug_config.categories & DEBUG_CATEGORY_LL_QUEUE, "LL_QUEUE should be enabled"); ASSERT_EQ(g_debug_config.level, DEBUG_LEVEL_DEBUG, "Level should be set to highest requested"); TEST_PASS(); } static void test_environment_variable(void) { TEST_START("Environment variable parsing"); /* Set environment variable */ setenv("UTUN_DEBUG", "uasync:debug,connection:warn", 1); debug_config_init(); // Should read from environment ASSERT_TRUE(g_debug_config.categories & DEBUG_CATEGORY_UASYNC, "UASYNC should be enabled from env"); ASSERT_TRUE(g_debug_config.categories & DEBUG_CATEGORY_CONNECTION, "CONNECTION should be enabled from env"); ASSERT_FALSE(g_debug_config.categories & DEBUG_CATEGORY_LL_QUEUE, "LL_QUEUE should be disabled from env"); /* Clean up */ unsetenv("UTUN_DEBUG"); TEST_PASS(); } static void test_debug_output(void) { TEST_START("Debug output functionality"); debug_config_init(); debug_set_level(DEBUG_LEVEL_DEBUG); debug_set_categories(DEBUG_CATEGORY_ALL); debug_enable_timestamp(1); debug_enable_function_name(1); debug_enable_file_line(1); printf("\n--- Sample debug output ---\n"); DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Test error message"); DEBUG_WARN(DEBUG_CATEGORY_UASYNC, "Test warning message"); DEBUG_INFO(DEBUG_CATEGORY_LL_QUEUE, "Test info message"); DEBUG_DEBUG(DEBUG_CATEGORY_CONNECTION, "Test debug message"); DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "Test trace message"); printf("--- End sample output ---\n\n"); TEST_PASS(); } static void test_effective_level(void) { TEST_START("Effective level calculation"); debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO); debug_set_categories(DEBUG_CATEGORY_UASYNC); ASSERT_EQ(debug_get_effective_level(DEBUG_CATEGORY_UASYNC), DEBUG_LEVEL_INFO, "UASYNC should have INFO level"); ASSERT_EQ(debug_get_effective_level(DEBUG_CATEGORY_LL_QUEUE), DEBUG_LEVEL_NONE, "LL_QUEUE should have NONE level"); TEST_PASS(); } static void test_output_file(void) { TEST_START("Output file configuration"); debug_config_init(); debug_set_level(DEBUG_LEVEL_DEBUG); debug_set_categories(DEBUG_CATEGORY_ALL); /* Test file output */ const char* test_file = "/tmp/debug_test.log"; debug_set_output_file(test_file); ASSERT_TRUE(g_debug_config.output_file != NULL, "Output file should be set"); ASSERT_TRUE(strcmp(g_debug_config.output_file, test_file) == 0, "Output file path should match"); /* Output some messages */ DEBUG_INFO(DEBUG_CATEGORY_ALL, "Test message to file"); DEBUG_DEBUG(DEBUG_CATEGORY_ALL, "Another test message to file"); /* Reset to stderr */ debug_set_output_file(NULL); /* Can't directly check debug_output_file, but we can test functionality */ /* Check that file was created */ if (access(test_file, F_OK) == 0) { printf(" Debug file created successfully: %s\n", test_file); unlink(test_file); // Clean up } else { TEST_FAIL("Debug file was not created"); } TEST_PASS(); } int main(void) { printf("=== Debug Configuration System Test ===\n"); printf("Testing runtime debug control system\n\n"); /* Run all tests */ test_basic_functionality(); test_debug_levels(); test_categories(); test_output_formatting(); test_rate_limiting(); test_config_parsing(); test_environment_variable(); test_debug_output(); test_effective_level(); test_output_file(); /* Summary */ printf("\n=== Test Summary ===\n"); printf("Tests passed: %d\n", test_passed); printf("Tests failed: %d\n", test_failed); printf("Total tests: %d\n", test_passed + test_failed); if (test_failed == 0) { printf("\n✅ All tests passed! Debug configuration system is working correctly.\n"); printf("\nKey features verified:\n"); printf("- Runtime debug level control\n"); printf("- Category-based filtering\n"); printf("- Flexible output formatting (timestamps, colors, etc.)\n"); printf("- Rate limiting for high-frequency debug output\n"); printf("- Environment variable configuration\n"); printf("- File output support\n"); printf("- Backward compatibility with existing code\n"); return 0; } else { printf("\n❌ Some tests failed. Please check the implementation.\n"); return 1; } }