tests: move fixtures to dedicated dir

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: I9d6ce6a264780f215b1b57d947b5264c6a6a6964
This commit is contained in:
raf 2026-02-23 02:24:48 +03:00
commit ae505188fc
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF
75 changed files with 478 additions and 438 deletions

View file

@ -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 */

24
tests/fixtures/block_comments.nix vendored Normal file
View file

@ -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
*/

14
tests/fixtures/dynamic_attr_full.nix vendored Normal file
View file

@ -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;
}

View file

@ -1,11 +1,9 @@
# Test import expression # Test import expression
# Import evaluates the file and returns its value # Import evaluates the file and returns its value
# Import a file that returns a simple value (42) # Import a file that returns a simple value (42)
import ./simple.nix import ./simple.nix
# Can also import lookup paths: # Can also import lookup paths:
# import <nixpkgs> { } # import <nixpkgs> { }
# Import with path expressions: # Import with path expressions:
# import (./dir + "/file.nix") # import (./dir + "/file.nix")

8
tests/fixtures/list_simple.nix vendored Normal file
View file

@ -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;
}

View file

@ -1,9 +1,8 @@
# Test lookup path syntax # Test lookup path syntax
# Lookup paths resolve via NIX_PATH environment variable # Lookup paths resolve via NIX_PATH environment variable
# Example: <nixpkgs> -> /nix/var/nix/profiles/per-user/root/channels/nixpkgs # Example: <nixpkgs> -> /nix/var/nix/profiles/per-user/root/channels/nixpkgs
# Simple lookup path # Simple lookup path
<nixpkgs> <nixpkgs>
# Nested lookup path (common pattern) # Nested lookup path (common pattern)
# <nixpkgs/lib> # <nixpkgs/lib>

View file

@ -1,6 +1,6 @@
# Test 'or' in attrset context # Test 'or' in attrset context
let let
attrs = { a = 1; }; attrs = {a = 1;};
in { in {
test = attrs.a or 999; test = attrs.a or 999;
} }

5
tests/fixtures/or_simple.nix vendored Normal file
View file

@ -0,0 +1,5 @@
# Simplest 'or' test
let
x = {a = 1;};
in
x.a or 2

View file

@ -1,6 +1,9 @@
# Test selection with 'or' default # Test selection with 'or' default
let let
attrs = { a = 1; b = 2; }; attrs = {
a = 1;
b = 2;
};
in { in {
# Attribute exists - should use value from attrs # Attribute exists - should use value from attrs
has_attr = attrs.a or 999; has_attr = attrs.a or 999;

View file

@ -1,4 +0,0 @@
# Simplest 'or' test
let
x = { a = 1; };
in x.a or 2

View file

@ -1,3 +1,4 @@
#include "irc/parser.h"
#include "irc/serializer.h" #include "irc/serializer.h"
#include "irc/types.h" #include "irc/types.h"
#include <cassert> #include <cassert>
@ -7,21 +8,21 @@ using namespace nix_irc;
int failures = 0; int failures = 0;
#define TEST_CHECK(cond, msg) \ #define TEST_CHECK(cond, msg) \
do { \ do { \
if (!(cond)) { \ if (!(cond)) { \
std::cerr << " FAIL: " << msg << std::endl; \ std::cerr << " FAIL: " << msg << std::endl; \
failures++; \ failures++; \
} else { \ } else { \
std::cout << " PASS: " << msg << std::endl; \ std::cout << " PASS: " << msg << std::endl; \
} \ } \
} while (0) } while (0)
#define TEST_PASS(msg) std::cout << " PASS: " << msg << std::endl #define TEST_PASS(msg) std::cout << " PASS: " << msg << std::endl
#define TEST_FAIL(msg) \ #define TEST_FAIL(msg) \
do { \ do { \
std::cerr << " FAIL: " << msg << std::endl; \ std::cerr << " FAIL: " << msg << std::endl; \
failures++; \ failures++; \
} while (0) } while (0)
void test_enum_compatibility() { void test_enum_compatibility() {
@ -30,33 +31,28 @@ void test_enum_compatibility() {
if (static_cast<uint8_t>(NodeType::WITH) == 0x32) { if (static_cast<uint8_t>(NodeType::WITH) == 0x32) {
std::cout << " PASS: WITH has correct value 0x32" << std::endl; std::cout << " PASS: WITH has correct value 0x32" << std::endl;
} else { } else {
std::cerr << " FAIL: WITH should be 0x32, got " std::cerr << " FAIL: WITH should be 0x32, got " << static_cast<uint8_t>(NodeType::WITH)
<< static_cast<uint8_t>(NodeType::WITH) << std::endl; << std::endl;
} }
if (static_cast<uint8_t>(NodeType::HAS_ATTR) == 0x34) { if (static_cast<uint8_t>(NodeType::HAS_ATTR) == 0x34) {
std::cout << " PASS: HAS_ATTR has value 0x34 (new slot after WITH bump)" std::cout << " PASS: HAS_ATTR has value 0x34 (new slot after WITH bump)" << std::endl;
<< std::endl;
} else if (static_cast<uint8_t>(NodeType::HAS_ATTR) == 0x33 && } else if (static_cast<uint8_t>(NodeType::HAS_ATTR) == 0x33 &&
static_cast<uint8_t>(NodeType::WITH) == 0x32) { static_cast<uint8_t>(NodeType::WITH) == 0x32) {
std::cout << " PASS: HAS_ATTR has value 0x33 (restored original with WITH " std::cout << " PASS: HAS_ATTR has value 0x33 (restored original with WITH "
"at 0x32)" "at 0x32)"
<< std::endl; << std::endl;
} else { } else {
std::cerr << " FAIL: HAS_ATTR value is " std::cerr << " FAIL: HAS_ATTR value is " << static_cast<uint8_t>(NodeType::HAS_ATTR)
<< static_cast<uint8_t>(NodeType::HAS_ATTR)
<< " (expected 0x34 or 0x33 with WITH=0x32)" << std::endl; << " (expected 0x34 or 0x33 with WITH=0x32)" << std::endl;
} }
if (IR_VERSION == 2) { if (IR_VERSION == 2) {
std::cout << " PASS: IR_VERSION bumped to 2 for breaking change" std::cout << " PASS: IR_VERSION bumped to 2 for breaking change" << std::endl;
<< std::endl;
} else if (static_cast<uint8_t>(NodeType::WITH) == 0x32) { } else if (static_cast<uint8_t>(NodeType::WITH) == 0x32) {
std::cout << " PASS: IR_VERSION unchanged but WITH restored to 0x32" std::cout << " PASS: IR_VERSION unchanged but WITH restored to 0x32" << std::endl;
<< std::endl;
} else { } else {
std::cerr << " FAIL: Either bump IR_VERSION or fix enum values" std::cerr << " FAIL: Either bump IR_VERSION or fix enum values" << std::endl;
<< std::endl;
} }
} }
@ -80,19 +76,16 @@ void test_serializer_select_with_default() {
Deserializer deser; Deserializer deser;
auto loaded = deser.deserialize(bytes); auto loaded = deser.deserialize(bytes);
auto *loaded_select = loaded.entry->get_if<SelectNode>(); auto* loaded_select = loaded.entry->get_if<SelectNode>();
if (loaded_select && loaded_select->default_expr && if (loaded_select && loaded_select->default_expr && *loaded_select->default_expr) {
*loaded_select->default_expr) { auto* def_val = (*loaded_select->default_expr)->get_if<ConstIntNode>();
auto *def_val = (*loaded_select->default_expr)->get_if<ConstIntNode>();
if (def_val && def_val->value == 100) { if (def_val && def_val->value == 100) {
std::cout << " PASS: SELECT with default_expr round-trips correctly" std::cout << " PASS: SELECT with default_expr round-trips correctly" << std::endl;
<< std::endl;
} else { } else {
std::cerr << " FAIL: default_expr value incorrect" << std::endl; std::cerr << " FAIL: default_expr value incorrect" << std::endl;
} }
} else { } else {
std::cerr << " FAIL: default_expr not deserialized (missing u8 flag read)" std::cerr << " FAIL: default_expr not deserialized (missing u8 flag read)" << std::endl;
<< std::endl;
} }
} }
@ -114,11 +107,9 @@ void test_serializer_select_without_default() {
Deserializer deser; Deserializer deser;
auto loaded = deser.deserialize(bytes); auto loaded = deser.deserialize(bytes);
auto *loaded_select = loaded.entry->get_if<SelectNode>(); auto* loaded_select = loaded.entry->get_if<SelectNode>();
if (loaded_select && if (loaded_select && (!loaded_select->default_expr || !*loaded_select->default_expr)) {
(!loaded_select->default_expr || !*loaded_select->default_expr)) { std::cout << " PASS: SELECT without default_expr round-trips correctly" << std::endl;
std::cout << " PASS: SELECT without default_expr round-trips correctly"
<< std::endl;
} else { } else {
std::cerr << " FAIL: default_expr should be null/absent" << std::endl; 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() { void test_parser_brace_depth_in_strings() {
std::cout << "> Parser brace depth handling in strings..." << std::endl; std::cout << "> Parser brace depth handling in strings..." << std::endl;
std::string test_input = R"( std::string test_input = R"(let s = "test}"; in s)";
let s = "test}"; in ${s}
)";
std::cout << " Test input contains '}' inside string - should not end " try {
"interpolation" Parser parser;
<< std::endl; auto ast = parser.parse(test_input);
std::cout << " NOTE: This test requires running through actual parser" TEST_PASS("Brace inside string does not confuse parser");
<< std::endl; } catch (const std::exception& e) {
TEST_FAIL("Parser should handle '}' inside strings");
}
} }
void test_parser_has_ellipsis_usage() { void test_parser_has_ellipsis_usage() {
std::cout << "> Parser has_ellipsis usage..." << std::endl; std::cout << "> Parser has_ellipsis usage..." << std::endl;
std::cout << " NOTE: LambdaNode should have strict_pattern field when " std::string with_ellipsis = "{ a, ... }: a";
"has_ellipsis is false" std::string without_ellipsis = "{ a, b }: a + b";
<< std::endl;
std::cout << " This requires checking the parser output for strict patterns" try {
<< std::endl; 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() { void test_parser_expect_in_speculative_parsing() {
std::cout << "> Parser expect() in speculative parsing..." << std::endl; std::cout << "> Parser expect() in speculative parsing..." << std::endl;
std::cout << " NOTE: try_parse_lambda should not throw on non-lambda input" std::string not_a_lambda = "1 + 2";
<< std::endl; std::string actual_lambda = "x: x + 1";
std::cout << " This requires testing parser with invalid lambda patterns"
<< std::endl; 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() { void test_lookup_path_node() {
@ -170,10 +180,9 @@ void test_lookup_path_node() {
Deserializer deser; Deserializer deser;
auto loaded = deser.deserialize(bytes); 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 != nullptr, "Deserialized node is ConstLookupPathNode");
TEST_CHECK(loaded_lookup && loaded_lookup->value == "nixpkgs", TEST_CHECK(loaded_lookup && loaded_lookup->value == "nixpkgs", "Lookup path value is 'nixpkgs'");
"Lookup path value is 'nixpkgs'");
} }
void test_import_node() { void test_import_node() {
@ -190,16 +199,14 @@ void test_import_node() {
Deserializer deser; Deserializer deser;
auto loaded = deser.deserialize(bytes); 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 != nullptr, "Deserialized node is ImportNode");
TEST_CHECK(loaded_import && loaded_import->path != nullptr, TEST_CHECK(loaded_import && loaded_import->path != nullptr, "Import node has path");
"Import node has path");
if (loaded_import && loaded_import->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 != nullptr, "Import path is ConstPathNode");
TEST_CHECK(path_node && path_node->value == "./test.nix", TEST_CHECK(path_node && path_node->value == "./test.nix", "Import path value is './test.nix'");
"Import path value is './test.nix'");
} }
} }
@ -217,14 +224,13 @@ void test_import_with_lookup_path() {
Deserializer deser; Deserializer deser;
auto loaded = deser.deserialize(bytes); 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 != nullptr, "Deserialized node is ImportNode");
if (loaded_import && loaded_import->path) { 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 != nullptr, "Import path is ConstLookupPathNode");
TEST_CHECK(lookup_node && lookup_node->value == "nixpkgs", TEST_CHECK(lookup_node && lookup_node->value == "nixpkgs", "Lookup path value is 'nixpkgs'");
"Lookup path value is 'nixpkgs'");
} }
} }
@ -241,7 +247,7 @@ void test_uri_node() {
Deserializer deser; Deserializer deser;
auto loaded = deser.deserialize(bytes); 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 != nullptr, "Deserialized node is ConstURINode");
TEST_CHECK(loaded_uri && loaded_uri->value == "https://example.com", TEST_CHECK(loaded_uri && loaded_uri->value == "https://example.com",
"URI value is 'https://example.com'"); "URI value is 'https://example.com'");
@ -260,10 +266,9 @@ void test_float_node() {
Deserializer deser; Deserializer deser;
auto loaded = deser.deserialize(bytes); 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 != nullptr, "Deserialized node is ConstFloatNode");
TEST_CHECK(loaded_float && loaded_float->value > 3.14 && TEST_CHECK(loaded_float && loaded_float->value > 3.14 && loaded_float->value < 3.15,
loaded_float->value < 3.15,
"Float value is approximately 3.14159"); "Float value is approximately 3.14159");
} }