#include "irc/serializer.h" #include "irc/types.h" #include #include using namespace nix_irc; int failures = 0; #define TEST_CHECK(cond, msg) \ do { \ if (!(cond)) { \ std::cerr << " FAIL: " << msg << std::endl; \ failures++; \ } else { \ std::cout << " PASS: " << msg << std::endl; \ } \ } while (0) #define TEST_PASS(msg) std::cout << " PASS: " << msg << std::endl #define TEST_FAIL(msg) \ do { \ std::cerr << " FAIL: " << msg << std::endl; \ failures++; \ } while (0) void test_enum_compatibility() { std::cout << "> Enum compatibility..." << std::endl; if (static_cast(NodeType::WITH) == 0x32) { std::cout << " PASS: WITH has correct value 0x32" << std::endl; } else { std::cerr << " FAIL: WITH should be 0x32, got " << static_cast(NodeType::WITH) << std::endl; } if (static_cast(NodeType::HAS_ATTR) == 0x34) { std::cout << " PASS: HAS_ATTR has value 0x34 (new slot after WITH bump)" << std::endl; } else if (static_cast(NodeType::HAS_ATTR) == 0x33 && static_cast(NodeType::WITH) == 0x32) { std::cout << " PASS: HAS_ATTR has value 0x33 (restored original with WITH " "at 0x32)" << std::endl; } else { std::cerr << " FAIL: HAS_ATTR value is " << static_cast(NodeType::HAS_ATTR) << " (expected 0x34 or 0x33 with WITH=0x32)" << std::endl; } if (IR_VERSION == 2) { std::cout << " PASS: IR_VERSION bumped to 2 for breaking change" << std::endl; } else if (static_cast(NodeType::WITH) == 0x32) { std::cout << " PASS: IR_VERSION unchanged but WITH restored to 0x32" << std::endl; } else { std::cerr << " FAIL: Either bump IR_VERSION or fix enum values" << std::endl; } } void test_serializer_select_with_default() { std::cout << "> SELECT serialization with default_expr..." << std::endl; auto expr = std::make_shared(ConstIntNode(42)); auto attr = std::make_shared(ConstStringNode("key")); auto default_val = std::make_shared(ConstIntNode(100)); SelectNode select_node(expr, attr); select_node.default_expr = default_val; auto select = std::make_shared(select_node); IRModule module; module.entry = select; Serializer ser; auto bytes = ser.serialize_to_bytes(module); Deserializer deser; auto loaded = deser.deserialize(bytes); auto *loaded_select = loaded.entry->get_if(); if (loaded_select && loaded_select->default_expr && *loaded_select->default_expr) { auto *def_val = (*loaded_select->default_expr)->get_if(); if (def_val && def_val->value == 100) { std::cout << " PASS: SELECT with default_expr round-trips correctly" << std::endl; } else { std::cerr << " FAIL: default_expr value incorrect" << std::endl; } } else { std::cerr << " FAIL: default_expr not deserialized (missing u8 flag read)" << std::endl; } } void test_serializer_select_without_default() { std::cout << "> SELECT serialization without default_expr..." << std::endl; auto expr = std::make_shared(ConstIntNode(42)); auto attr = std::make_shared(ConstStringNode("key")); SelectNode select_node(expr, attr); auto select = std::make_shared(select_node); IRModule module; module.entry = select; Serializer ser; auto bytes = ser.serialize_to_bytes(module); Deserializer deser; auto loaded = deser.deserialize(bytes); auto *loaded_select = loaded.entry->get_if(); if (loaded_select && (!loaded_select->default_expr || !*loaded_select->default_expr)) { std::cout << " PASS: SELECT without default_expr round-trips correctly" << std::endl; } else { std::cerr << " FAIL: default_expr should be null/absent" << std::endl; } } void test_parser_brace_depth_in_strings() { std::cout << "> Parser brace depth handling in strings..." << std::endl; std::string test_input = R"( let s = "test}"; in ${s} )"; std::cout << " Test input contains '}' inside string - should not end " "interpolation" << std::endl; std::cout << " NOTE: This test requires running through actual parser" << std::endl; } void test_parser_has_ellipsis_usage() { std::cout << "> Parser has_ellipsis usage..." << std::endl; std::cout << " NOTE: LambdaNode should have strict_pattern field when " "has_ellipsis is false" << std::endl; std::cout << " This requires checking the parser output for strict patterns" << std::endl; } void test_parser_expect_in_speculative_parsing() { std::cout << "> Parser expect() in speculative parsing..." << std::endl; std::cout << " NOTE: try_parse_lambda should not throw on non-lambda input" << std::endl; std::cout << " This requires testing parser with invalid lambda patterns" << std::endl; } int main() { std::cout << "=== Regression Tests for Nixir ===" << std::endl << std::endl; test_enum_compatibility(); std::cout << std::endl; test_serializer_select_with_default(); std::cout << std::endl; test_serializer_select_without_default(); std::cout << std::endl; test_parser_brace_depth_in_strings(); std::cout << std::endl; test_parser_has_ellipsis_usage(); std::cout << std::endl; test_parser_expect_in_speculative_parsing(); std::cout << std::endl; std::cout << "=== Tests Complete ===" << std::endl; std::cout << "Failures: " << failures << std::endl; return failures > 0 ? 1 : 0; }