#include #include #include #include static cbool process_input(const char *input, scc_cstring_t *output) { scc_pproc_t pp; scc_mem_probe_stream_t mem_stream; scc_probe_stream_t *output_stream; // 初始化预处理器 output_stream = scc_pproc_init(&pp, scc_mem_probe_stream_init(&mem_stream, input, strlen(input), false)); // 获取输出结果 int ch; *output = scc_cstring_new(); while (1) { ch = scc_probe_stream_consume(output_stream); if (ch == scc_stream_eof) { break; } scc_cstring_append_ch(output, (char)ch); } // 清理资源 scc_pproc_drop(&pp); return true; } #define CHECK_PP_OUTPUT_EXACT(input, expect) \ do { \ scc_cstring_t output; \ process_input(input, &output); \ assert(output.data != NULL); \ TEST_CHECK(strcmp(output.data, expect) == 0); \ TEST_MSG("Expected: %s", expect); \ TEST_MSG("Produced: %s", output.data); \ } while (0) #define CHECK_PP_OUTPUT_CONTAIN(input, expect) \ do { \ scc_cstring_t output; \ process_input(input, &output); \ assert(output.data != NULL); \ TEST_CHECK(strstr(output.data, expect) != NULL); \ TEST_MSG("Expected: %s", expect); \ TEST_MSG("Produced: %s", output.data); \ } while (0) static void test_define_simple_object_macro(void) { TEST_CASE("simple object-like macro"); CHECK_PP_OUTPUT_EXACT("#define MAX 100\nMAX\n", "100\n"); CHECK_PP_OUTPUT_EXACT("#define NAME test\r\nNAME\n", "test\n"); } static void test_define_complex_object_macro(void) { TEST_CASE("complex object-like macro"); CHECK_PP_OUTPUT_EXACT("#define VALUE (100 + 50)\nVALUE\n", "(100 + 50)\n"); CHECK_PP_OUTPUT_EXACT("#define PI 3.14159\nPI\n", "3.14159\n"); } static void test_define_object_macro_backspace(void) { TEST_CASE("object-like macro check backspace"); CHECK_PP_OUTPUT_EXACT("#define MAX 100\nMAX\n", "100\n"); CHECK_PP_OUTPUT_EXACT("#define NAME \ttest\r\nNAME\n", "test\n"); CHECK_PP_OUTPUT_EXACT("#define \tVALUE (100 \t+ 50)\nVALUE\n", "(100 + 50)\n"); CHECK_PP_OUTPUT_EXACT("#define \tPI \t 3.14159\nPI\n", "3.14159\n"); } static void test_define_function_macro(void) { TEST_CASE("function-like macro"); CHECK_PP_OUTPUT_EXACT("#define ADD(a,b) a + b\nADD(1, 2)\n", "1 + 2\n"); CHECK_PP_OUTPUT_EXACT( "#define MAX(a,b) ((a) > (b) ? (a) : (b))\nMAX(10, 20)\n", "((10) > (20) ? (10) : (20))\n"); } static void test_define_stringify_operator(void) { TEST_CASE("stringify operator (#)"); CHECK_PP_OUTPUT_EXACT("#define STRINGIFY(x) #x\nSTRINGIFY(hello)\n", "\"hello\"\n"); CHECK_PP_OUTPUT_EXACT("#define STR(x) #x\nSTR(test value)\n", "\"test value\"\n"); } static void test_define_concat_operator(void) { TEST_CASE("concatenation operator (##)"); CHECK_PP_OUTPUT_EXACT("#define CONCAT(a,b) a##b\nCONCAT(hello,world)\n", "helloworld\n"); CHECK_PP_OUTPUT_EXACT("#define JOIN(pre,suf) pre ## suf\nJOIN(var, 123)\n", "var123\n"); } static void test_define_nested_macros(void) { TEST_CASE("nested macros"); CHECK_PP_OUTPUT_EXACT( "#define MAX 100\n#define TWICE_MAX (MAX * 2)\nTWICE_MAX\n", "(100 * 2)\n"); CHECK_PP_OUTPUT_EXACT( "#define A 1\n#define B (A + 1)\n#define C (B + 1)\nC\n", "((1 + 1) + 1)\n"); } static void test_conditional_compilation(void) { TEST_CASE("conditional compilation"); CHECK_PP_OUTPUT_EXACT("#if 1\ntrue\n#endif\n", "true\n"); CHECK_PP_OUTPUT_EXACT("#if 0\nfalse\n#endif\n", ""); CHECK_PP_OUTPUT_EXACT("#define FLAG 1\n#if FLAG\ntrue\n#endif\n", "true\n"); } static void test_error_cases(void) { TEST_CASE("macro redefinition"); // 应检测到警告或错误 // CHECK_PP_OUTPUT_CONTAIN("#define A 1\n#define A 2\n", "warning"); TEST_CASE("undefined macro"); CHECK_PP_OUTPUT_EXACT("UNDEFINED_MACRO\n", "UNDEFINED_MACRO\n"); } static void test_edge_cases(void) { TEST_CASE("empty macro"); CHECK_PP_OUTPUT_EXACT("#define EMPTY\nEMPTY\n", "\n"); TEST_CASE("macro with only spaces"); CHECK_PP_OUTPUT_EXACT("#define SPACE \nSPACE\n", "\n"); TEST_CASE("deep nesting"); CHECK_PP_OUTPUT_EXACT("#define A B\n#define B C\n#define C 1\nA\n", "1\n"); } #define TEST_LIST_CASE(func_name) {#func_name, func_name} TEST_LIST = { TEST_LIST_CASE(test_define_simple_object_macro), TEST_LIST_CASE(test_define_complex_object_macro), TEST_LIST_CASE(test_define_object_macro_backspace), TEST_LIST_CASE(test_define_function_macro), TEST_LIST_CASE(test_define_stringify_operator), TEST_LIST_CASE(test_define_concat_operator), TEST_LIST_CASE(test_define_nested_macros), {NULL, NULL}, };