clone
ssh://git@git.notashelf.dev:33/notashelf/nixir.gitCommit 2c9ad890b293
tarballunverified75 files changed+478-438
@@ -1,8 +0,0 @@-# Test ancient let syntax: let { bindings; body = expr; }-# This is equivalent to: let bindings in expr, but has been deprecated-# in newer Nix versions.-let {- x = 10;- y = 20;- body = x + y;-}@@ -1,8 +0,0 @@-# Attrset test-{- name = "test";- value = 123;- nested = {- inner = true;- };-}@@ -1,3 +0,0 @@-let- x = 10;-in {a = x;}@@ -1,12 +0,0 @@-# Test block comments /* */-/* This is a block comment */-let- x = 42; /* inline block comment */- /* Multi-line- block- comment */- y = 100;-in-/* Comment before expression */-x + y-/* Trailing comment */@@ -1,8 +0,0 @@-# Test comparison operators-let- a = 10;- b = 20;-in- if a < b- then true- else false@@ -1,15 +0,0 @@-# Test dynamic attribute names-# Note: Full dynamic attrs require runtime evaluation-# For now, testing that syntax is recognized-let- key = "mykey";-in {- # Static attribute for comparison- static = "value";-- # Dynamic attribute name (basic string interpolation)- # "${key}" = "dynamic_value";-- # For now, use workaround with static names- mykey = "works";-}@@ -0,0 +1,8 @@+# Test ancient let syntax: let { bindings; body = expr; }+# This is equivalent to: let bindings in expr, but has been deprecated+# in newer Nix versions.+let {+ x = 10;+ y = 20;+ body = x + y;+}@@ -0,0 +1,8 @@+# Attrset test+{+ name = "test";+ value = 123;+ nested = {+ inner = true;+ };+}@@ -0,0 +1,3 @@+let+ x = 10;+in {a = x;}@@ -0,0 +1,24 @@+# Test block comments /* */+/*+This is a block comment+*/+let+ x = 42;+ /*+ inline block comment+ */+ /*+ Multi-line+ block+ comment+ */+ y = 100;+in+ /*+ Comment before expression+ */+ x + y+/*+Trailing comment+*/+@@ -0,0 +1,8 @@+# Test comparison operators+let+ a = 10;+ b = 20;+in+ if a < b+ then true+ else false@@ -0,0 +1,14 @@+# Test dynamic attribute names+let+ key = "mykey";+ value = 42;+in {+ # Dynamic attribute with string interpolation+ "${key}" = value;++ # Another dynamic attribute+ "${key}_suffix" = value + 1;++ # Static attribute for comparison+ static = 100;+}@@ -0,0 +1,15 @@+# Test dynamic attribute names+# Note: Full dynamic attrs require runtime evaluation+# For now, testing that syntax is recognized+let+ key = "mykey";+in {+ # Static attribute for comparison+ static = "value";++ # Dynamic attribute name (basic string interpolation)+ # "${key}" = "dynamic_value";++ # For now, use workaround with static names+ mykey = "works";+}@@ -0,0 +1 @@+1.5@@ -0,0 +1,11 @@+# Test home-relative paths+# Note: This will resolve to the actual home directory at evaluation time+let+ # Example home path (will be expanded by evaluator)+ config = ~/..config;+ file = ~/.bashrc;+in {+ # These are just path values that will be expanded+ configPath = config;+ filePath = file;+}@@ -0,0 +1,4 @@+# Conditional test+if true+then 1+else 2@@ -0,0 +1,3 @@+# Test import with lookup path+# Common pattern: import <nixpkgs> { }+import <nixpkgs>@@ -0,0 +1,9 @@+# Test import expression+# Import evaluates the file and returns its value+# Import a file that returns a simple value (42)+import ./simple.nix+# Can also import lookup paths:+# import <nixpkgs> { }+# Import with path expressions:+# import (./dir + "/file.nix")+@@ -0,0 +1,31 @@+# Test indented strings (multi-line strings with '' delimiters)+let+ # Simple indented string+ simple = ''+ Hello+ World+ '';++ # Indented string with interpolation+ name = "Nix";+ greeting = ''+ Welcome to ${name}!+ This is indented.+ '';++ # Escape sequences+ escapes = ''+ Literal dollar: ''$+ Literal quotes: '''+ Regular text+ '';++ # Shell script example (common use case)+ script = ''+ #!/bin/bash+ echo "Running script"+ ls -la+ '';+in {+ inherit simple greeting escapes script;+}@@ -0,0 +1,20 @@+# Test inherit keyword+let+ x = 10;+ y = 20;+ attrs = {+ a = 1;+ b = 2;+ c = 3;+ };+in {+ # Basic inherit from outer scope+ inherit x y;++ # Inherit from expression+ inherit (attrs) a b;++ # Mixed+ z = 30;+ inherit (attrs) c;+}@@ -0,0 +1,3 @@+let+ attrs = {a = 1;};+in {inherit (attrs) a;}@@ -0,0 +1,3 @@+let+ x = 10;+in {inherit x;}@@ -0,0 +1,61 @@+# Test lambda patterns+let+ # Basic destructuring+ f1 = {+ a,+ b,+ }:+ a + b;++ # With default values+ f2 = {+ a,+ b ? 10,+ }:+ a + b;++ # With ellipsis (extra fields allowed)+ f3 = {a, ...}: a * 2;++ # 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;+in {+ # Test basic destructuring+ test1 = f1 {+ a = 3;+ b = 4;+ };++ # Test with defaults (provide both)+ test2a = f2 {+ a = 5;+ b = 6;+ };++ # Test with defaults (use default for b)+ test2b = f2 {a = 5;};++ # Test ellipsis (extra field ignored)+ test3 = f3 {+ a = 7;+ extra = 999;+ };++ # Test named pattern+ test4 = f4 {+ a = 1;+ b = 2;+ c = 3;+ };++ # Test simple lambda+ test5 = f5 10;+}@@ -0,0 +1,6 @@+# Let binding test+let+ x = 10;+ y = 20;+in+ x@@ -0,0 +1,15 @@+# Test list concatenation operator +++let+ list1 = [1 2 3];+ list2 = [4 5 6];+ empty = [];+in {+ # Basic concatenation+ combined = list1 ++ list2;++ # Concatenate with empty list+ with_empty = list1 ++ empty;++ # Nested concatenation+ triple = [1] ++ [2] ++ [3];+}@@ -0,0 +1,8 @@+# Test basic list support+let+ x = [1 2 3];+ y = [4 5 6];+ z = x ++ y; # List concatenation+in {+ inherit x y z;+}@@ -0,0 +1,10 @@+# Test logical operators+let+ x = true;+ y = false;+in+ if x && y+ then 1+ else if x || y+ then 2+ else 3@@ -0,0 +1,8 @@+# Test lookup path syntax+# Lookup paths resolve via NIX_PATH environment variable+# Example: <nixpkgs> -> /nix/var/nix/profiles/per-user/root/channels/nixpkgs+# Simple lookup path+<nixpkgs>+# Nested lookup path (common pattern)+# <nixpkgs/lib>+@@ -0,0 +1,3 @@+# Test nested lookup path+# Common pattern in Nix: <nixpkgs/lib> or <nixpkgs/pkgs/stdenv>+<nixpkgs/lib>@@ -0,0 +1,2 @@+# Test attrset merge operator (//)+{a = {x = 1;} // {y = 2;};}@@ -0,0 +1,13 @@+# Test nested attribute paths+{+ # Simple nested path+ a.b.c = 42;++ # Multiple nested paths+ x.y = 1;+ x.z = 2;++ # Mix of nested and non-nested+ foo = "bar";+ nested.deep.value = 100;+}@@ -0,0 +1,6 @@+# Test arithmetic operators+let+ x = 10;+ y = 5;+in+ (x + y) * 2@@ -0,0 +1,6 @@+# Test 'or' in attrset context+let+ attrs = {a = 1;};+in {+ test = attrs.a or 999;+}@@ -0,0 +1,5 @@+# Simplest 'or' test+let+ x = {a = 1;};+in+ x.a or 2@@ -0,0 +1,13 @@+# Test path concatenation+let+ # Path + string = path+ p1 = ./foo + "/bar";++ # String + path = path+ p2 = "/prefix" + ./suffix;++ # Path + path = path+ p3 = ./dir + ./file;+in {+ inherit p1 p2 p3;+}@@ -0,0 +1,12 @@+# Test operator precedence+let+ a = 1 + 2 * 3; # Should be 1 + (2 * 3) = 7+ b = 10 - 5 - 2; # Should be (10 - 5) - 2 = 3+ c = true && false || true; # Should be (true && false) || true = true+ d = 1 < 2 && 3 > 2; # Should be (1 < 2) && (3 > 2) = true+in {+ a = a;+ b = b;+ c = c;+ d = d;+}@@ -0,0 +1,19 @@+# Test selection with 'or' default+let+ attrs = {+ a = 1;+ b = 2;+ };+in {+ # Attribute exists - should use value from attrs+ has_attr = attrs.a or 999;++ # Attribute doesn't exist - should use default+ missing_attr = attrs.c or 100;++ # Nested default expression+ nested = attrs.d or (attrs.a + attrs.b);++ # Default with literal+ with_string = attrs.name or "default_name";+}@@ -0,0 +1,10 @@+# Test short-circuit evaluation+let+ alwaysFalse = false;+ alwaysTrue = true;+ x = 10;+in {+ and_false = alwaysFalse && alwaysTrue;+ or_true = alwaysTrue || alwaysFalse;+ impl_false = alwaysFalse -> alwaysFalse;+}@@ -0,0 +1,6 @@+# Test short-circuit evaluation+{+ and_false = false && true;+ or_true = true || false;+ impl_false = false -> false;+}@@ -0,0 +1,2 @@+# Simple constant test+42@@ -0,0 +1 @@+1 + 2@@ -0,0 +1,20 @@+# Test string interpolation+let+ name = "world";+ x = 42;+ bool_val = true;+in {+ # Simple interpolation+ greeting = "Hello ${name}!";++ # Multiple interpolations+ multi = "x is ${x} and name is ${name}";++ # Expression evaluation in interpolation+ computed = "x + 10 = ${x + 10}";++ bool_check = "${bool_val} is true!";++ # Just a string, no interpolation+ plain = "plain text";+}@@ -0,0 +1,8 @@+# Test unary operators+let+ x = 10;+ y = true;+in {+ neg = -x;+ not = !y;+}@@ -0,0 +1,3 @@+https://example.com/path?query=1+#frag+@@ -1 +0,0 @@-1.5@@ -1,11 +0,0 @@-# Test home-relative paths-# Note: This will resolve to the actual home directory at evaluation time-let- # Example home path (will be expanded by evaluator)- config = ~/..config;- file = ~/.bashrc;-in {- # These are just path values that will be expanded- configPath = config;- filePath = file;-}@@ -1,4 +0,0 @@-# Conditional test-if true-then 1-else 2@@ -1,3 +0,0 @@-# Test import with lookup path-# Common pattern: import <nixpkgs> { }-import <nixpkgs>@@ -1,11 +0,0 @@-# Test import expression-# Import evaluates the file and returns its value--# Import a file that returns a simple value (42)-import ./simple.nix--# Can also import lookup paths:-# import <nixpkgs> { }--# Import with path expressions:-# import (./dir + "/file.nix")@@ -1,31 +0,0 @@-# Test indented strings (multi-line strings with '' delimiters)-let- # Simple indented string- simple = ''- Hello- World- '';-- # Indented string with interpolation- name = "Nix";- greeting = ''- Welcome to ${name}!- This is indented.- '';-- # Escape sequences- escapes = ''- Literal dollar: ''$- Literal quotes: '''- Regular text- '';-- # Shell script example (common use case)- script = ''- #!/bin/bash- echo "Running script"- ls -la- '';-in {- inherit simple greeting escapes script;-}@@ -1,20 +0,0 @@-# Test inherit keyword-let- x = 10;- y = 20;- attrs = {- a = 1;- b = 2;- c = 3;- };-in {- # Basic inherit from outer scope- inherit x y;-- # Inherit from expression- inherit (attrs) a b;-- # Mixed- z = 30;- inherit (attrs) c;-}@@ -1,3 +0,0 @@-let- attrs = {a = 1;};-in {inherit (attrs) a;}@@ -1,3 +0,0 @@-let- x = 10;-in {inherit x;}@@ -1,61 +0,0 @@-# Test lambda patterns-let- # Basic destructuring- f1 = {- a,- b,- }:- a + b;-- # With default values- f2 = {- a,- b ? 10,- }:- a + b;-- # With ellipsis (extra fields allowed)- f3 = {a, ...}: a * 2;-- # 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;-in {- # Test basic destructuring- test1 = f1 {- a = 3;- b = 4;- };-- # Test with defaults (provide both)- test2a = f2 {- a = 5;- b = 6;- };-- # Test with defaults (use default for b)- test2b = f2 {a = 5;};-- # Test ellipsis (extra field ignored)- test3 = f3 {- a = 7;- extra = 999;- };-- # Test named pattern- test4 = f4 {- a = 1;- b = 2;- c = 3;- };-- # Test simple lambda- test5 = f5 10;-}@@ -1,6 +0,0 @@-# Let binding test-let- x = 10;- y = 20;-in- x@@ -1,15 +0,0 @@-# Test list concatenation operator ++-let- list1 = [1 2 3];- list2 = [4 5 6];- empty = [];-in {- # Basic concatenation- combined = list1 ++ list2;-- # Concatenate with empty list- with_empty = list1 ++ empty;-- # Nested concatenation- triple = [1] ++ [2] ++ [3];-}@@ -1,10 +0,0 @@-# Test logical operators-let- x = true;- y = false;-in- if x && y- then 1- else if x || y- then 2- else 3@@ -1,9 +0,0 @@-# Test lookup path syntax-# Lookup paths resolve via NIX_PATH environment variable-# Example: <nixpkgs> -> /nix/var/nix/profiles/per-user/root/channels/nixpkgs--# Simple lookup path-<nixpkgs>--# Nested lookup path (common pattern)-# <nixpkgs/lib>@@ -1,3 +0,0 @@-# Test nested lookup path-# Common pattern in Nix: <nixpkgs/lib> or <nixpkgs/pkgs/stdenv>-<nixpkgs/lib>@@ -1,2 +0,0 @@-# Test attrset merge operator (//)-{a = {x = 1;} // {y = 2;};}@@ -1,13 +0,0 @@-# Test nested attribute paths-{- # Simple nested path- a.b.c = 42;-- # Multiple nested paths- x.y = 1;- x.z = 2;-- # Mix of nested and non-nested- foo = "bar";- nested.deep.value = 100;-}@@ -1,6 +0,0 @@-# Test arithmetic operators-let- x = 10;- y = 5;-in- (x + y) * 2@@ -1,6 +0,0 @@-# Test 'or' in attrset context-let- attrs = { a = 1; };-in {- test = attrs.a or 999;-}@@ -1,4 +0,0 @@-# Simplest 'or' test-let- x = { a = 1; };-in x.a or 2@@ -1,13 +0,0 @@-# Test path concatenation-let- # Path + string = path- p1 = ./foo + "/bar";-- # String + path = path- p2 = "/prefix" + ./suffix;-- # Path + path = path- p3 = ./dir + ./file;-in {- inherit p1 p2 p3;-}@@ -1,12 +0,0 @@-# Test operator precedence-let- a = 1 + 2 * 3; # Should be 1 + (2 * 3) = 7- b = 10 - 5 - 2; # Should be (10 - 5) - 2 = 3- c = true && false || true; # Should be (true && false) || true = true- d = 1 < 2 && 3 > 2; # Should be (1 < 2) && (3 > 2) = true-in {- a = a;- b = b;- c = c;- d = d;-}@@ -1,3 +1,4 @@+#include "irc/parser.h" #include "irc/serializer.h" #include "irc/types.h" #include <cassert>@@ -7,21 +8,21 @@ 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; \- } \+#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++; \+#define TEST_FAIL(msg) \+ do { \+ std::cerr << " FAIL: " << msg << std::endl; \+ failures++; \ } while (0) void test_enum_compatibility() {@@ -30,33 +31,28 @@ void test_enum_compatibility() { 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;+ 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;+ 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)+ 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;+ 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;+ 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;+ std::cerr << " FAIL: Either bump IR_VERSION or fix enum values" << std::endl; } } @@ -80,19 +76,16 @@ void test_serializer_select_with_default() { 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>();+ 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;+ 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;+ std::cerr << " FAIL: default_expr not deserialized (missing u8 flag read)" << std::endl; } } @@ -114,11 +107,9 @@ void test_serializer_select_without_default() { 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;+ 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; }@@ -127,34 +118,53 @@ void test_serializer_select_without_default() { 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::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;+ try {+ Parser parser;+ auto ast = parser.parse(test_input);+ TEST_PASS("Brace inside string does not confuse parser");+ } catch (const std::exception& e) {+ TEST_FAIL("Parser should handle '}' inside strings");+ } } 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;+ std::string with_ellipsis = "{ a, ... }: a";+ std::string without_ellipsis = "{ a, b }: a + b";++ try {+ Parser parser1;+ auto ast1 = parser1.parse(with_ellipsis);+ TEST_PASS("Pattern with ellipsis parses correctly");++ Parser parser2;+ auto ast2 = parser2.parse(without_ellipsis);+ TEST_PASS("Pattern without ellipsis parses correctly");+ } catch (const std::exception& e) {+ TEST_FAIL("Pattern parsing failed");+ } } 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;+ std::string not_a_lambda = "1 + 2";+ std::string actual_lambda = "x: x + 1";++ try {+ Parser parser1;+ auto ast1 = parser1.parse(not_a_lambda);+ TEST_PASS("Non-lambda input does not cause parser to throw");++ Parser parser2;+ auto ast2 = parser2.parse(actual_lambda);+ TEST_PASS("Actual lambda parses correctly");+ } catch (const std::exception& e) {+ TEST_FAIL("Parser should handle both lambda and non-lambda input");+ } } void test_lookup_path_node() {@@ -170,10 +180,9 @@ void test_lookup_path_node() { Deserializer deser; auto loaded = deser.deserialize(bytes); - auto *loaded_lookup = loaded.entry->get_if<ConstLookupPathNode>();+ auto* loaded_lookup = loaded.entry->get_if<ConstLookupPathNode>(); TEST_CHECK(loaded_lookup != nullptr, "Deserialized node is ConstLookupPathNode");- TEST_CHECK(loaded_lookup && loaded_lookup->value == "nixpkgs",- "Lookup path value is 'nixpkgs'");+ TEST_CHECK(loaded_lookup && loaded_lookup->value == "nixpkgs", "Lookup path value is 'nixpkgs'"); } void test_import_node() {@@ -190,16 +199,14 @@ void test_import_node() { Deserializer deser; auto loaded = deser.deserialize(bytes); - auto *loaded_import = loaded.entry->get_if<ImportNode>();+ auto* loaded_import = loaded.entry->get_if<ImportNode>(); TEST_CHECK(loaded_import != nullptr, "Deserialized node is ImportNode");- TEST_CHECK(loaded_import && loaded_import->path != nullptr,- "Import node has path");+ TEST_CHECK(loaded_import && loaded_import->path != nullptr, "Import node has path"); if (loaded_import && loaded_import->path) {- auto *path_node = loaded_import->path->get_if<ConstPathNode>();+ auto* path_node = loaded_import->path->get_if<ConstPathNode>(); TEST_CHECK(path_node != nullptr, "Import path is ConstPathNode");- TEST_CHECK(path_node && path_node->value == "./test.nix",- "Import path value is './test.nix'");+ TEST_CHECK(path_node && path_node->value == "./test.nix", "Import path value is './test.nix'"); } } @@ -217,14 +224,13 @@ void test_import_with_lookup_path() { Deserializer deser; auto loaded = deser.deserialize(bytes); - auto *loaded_import = loaded.entry->get_if<ImportNode>();+ auto* loaded_import = loaded.entry->get_if<ImportNode>(); TEST_CHECK(loaded_import != nullptr, "Deserialized node is ImportNode"); if (loaded_import && loaded_import->path) {- auto *lookup_node = loaded_import->path->get_if<ConstLookupPathNode>();+ auto* lookup_node = loaded_import->path->get_if<ConstLookupPathNode>(); TEST_CHECK(lookup_node != nullptr, "Import path is ConstLookupPathNode");- TEST_CHECK(lookup_node && lookup_node->value == "nixpkgs",- "Lookup path value is 'nixpkgs'");+ TEST_CHECK(lookup_node && lookup_node->value == "nixpkgs", "Lookup path value is 'nixpkgs'"); } } @@ -241,7 +247,7 @@ void test_uri_node() { Deserializer deser; auto loaded = deser.deserialize(bytes); - auto *loaded_uri = loaded.entry->get_if<ConstURINode>();+ auto* loaded_uri = loaded.entry->get_if<ConstURINode>(); TEST_CHECK(loaded_uri != nullptr, "Deserialized node is ConstURINode"); TEST_CHECK(loaded_uri && loaded_uri->value == "https://example.com", "URI value is 'https://example.com'");@@ -260,10 +266,9 @@ void test_float_node() { Deserializer deser; auto loaded = deser.deserialize(bytes); - auto *loaded_float = loaded.entry->get_if<ConstFloatNode>();+ auto* loaded_float = loaded.entry->get_if<ConstFloatNode>(); TEST_CHECK(loaded_float != nullptr, "Deserialized node is ConstFloatNode");- TEST_CHECK(loaded_float && loaded_float->value > 3.14 &&- loaded_float->value < 3.15,+ TEST_CHECK(loaded_float && loaded_float->value > 3.14 && loaded_float->value < 3.15, "Float value is approximately 3.14159"); } @@ -1,16 +0,0 @@-# Test selection with 'or' default-let- attrs = { a = 1; b = 2; };-in {- # Attribute exists - should use value from attrs- has_attr = attrs.a or 999;-- # Attribute doesn't exist - should use default- missing_attr = attrs.c or 100;-- # Nested default expression- nested = attrs.d or (attrs.a + attrs.b);-- # Default with literal- with_string = attrs.name or "default_name";-}@@ -1,10 +0,0 @@-# Test short-circuit evaluation-let- alwaysFalse = false;- alwaysTrue = true;- x = 10;-in {- and_false = alwaysFalse && alwaysTrue;- or_true = alwaysTrue || alwaysFalse;- impl_false = alwaysFalse -> alwaysFalse;-}@@ -1,6 +0,0 @@-# Test short-circuit evaluation-{- and_false = false && true;- or_true = true || false;- impl_false = false -> false;-}@@ -1,2 +0,0 @@-# Simple constant test-42@@ -1 +0,0 @@-1 + 2@@ -1,20 +0,0 @@-# Test string interpolation-let- name = "world";- x = 42;- bool_val = true;-in {- # Simple interpolation- greeting = "Hello ${name}!";-- # Multiple interpolations- multi = "x is ${x} and name is ${name}";-- # Expression evaluation in interpolation- computed = "x + 10 = ${x + 10}";-- bool_check = "${bool_val} is true!";-- # Just a string, no interpolation- plain = "plain text";-}@@ -1,8 +0,0 @@-# Test unary operators-let- x = 10;- y = true;-in {- neg = -x;- not = !y;-}@@ -1,3 +0,0 @@-https://example.com/path?query=1-#frag-