clone
ssh://git@git.notashelf.dev:33/notashelf/nixir.gitCommit ddfbc91b5888
tarballunverified12 files changed+186-2
@@ -9,8 +9,8 @@ let # With ellipsis (extra fields allowed) f3 = { a, ... }: a * 2; - # Named pattern- f4 = arg@{ a, b }: a + b + arg.c;+ # Named pattern with ellipsis to allow extra fields+ f4 = arg@{ a, b, ... }: a + b + arg.c; # Simple lambda (not a pattern) f5 = x: x + 1;@@ -0,0 +1,184 @@+#include "irc/serializer.h"+#include "irc/types.h"+#include <cassert>+#include <iostream>++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<uint8_t>(NodeType::WITH) == 0x32) {+ std::cout << " PASS: WITH has correct value 0x32" << std::endl;+ } else {+ std::cerr << " FAIL: WITH should be 0x32, got "+ << static_cast<uint8_t>(NodeType::WITH) << std::endl;+ }++ if (static_cast<uint8_t>(NodeType::HAS_ATTR) == 0x34) {+ std::cout << " PASS: HAS_ATTR has value 0x34 (new slot after WITH bump)"+ << std::endl;+ } else if (static_cast<uint8_t>(NodeType::HAS_ATTR) == 0x33 &&+ static_cast<uint8_t>(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<uint8_t>(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<uint8_t>(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<Node>(ConstIntNode(42));+ auto attr = std::make_shared<Node>(ConstStringNode("key"));+ auto default_val = std::make_shared<Node>(ConstIntNode(100));++ SelectNode select_node(expr, attr);+ select_node.default_expr = default_val;+ auto select = std::make_shared<Node>(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<SelectNode>();+ if (loaded_select && loaded_select->default_expr &&+ *loaded_select->default_expr) {+ auto *def_val = (*loaded_select->default_expr)->get_if<ConstIntNode>();+ 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<Node>(ConstIntNode(42));+ auto attr = std::make_shared<Node>(ConstStringNode("key"));++ SelectNode select_node(expr, attr);+ auto select = std::make_shared<Node>(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<SelectNode>();+ 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;+}