tests: cover flake refs and lexer/parser regressions
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I1b5f90bbb210262a9287a9b8eac02e9d6a6a6964
This commit is contained in:
parent
b319ef6f3f
commit
531855d91a
4 changed files with 171 additions and 2 deletions
|
|
@ -352,8 +352,6 @@ public:
|
|||
template <typename T> bool holds() const { return std::holds_alternative<T>(data); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct SourceFile {
|
||||
std::string path;
|
||||
std::string content;
|
||||
|
|
|
|||
19
tests/integration/flake_ref/flake.nix
Normal file
19
tests/integration/flake_ref/flake.nix
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
description = "Local flake fixture for nixir integration tests";
|
||||
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
|
||||
|
||||
outputs = { self, nixpkgs }: {
|
||||
value = 42;
|
||||
nixosConfigurations.demo = nixpkgs.lib.nixosSystem {
|
||||
system = "x86_64-linux";
|
||||
modules = [
|
||||
({ ... }: {
|
||||
networking.hostName = "nixir-demo";
|
||||
system.stateVersion = "24.11";
|
||||
services.openssh.enable = true;
|
||||
})
|
||||
];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -72,4 +72,32 @@ else
|
|||
fi
|
||||
echo ""
|
||||
|
||||
echo "Test 6: Flake Reference Compilation"
|
||||
echo "-----------------------------------"
|
||||
flake_ir=$(mktemp /tmp/nixir-flake-value-XXXXXX.nixir)
|
||||
"$(pwd)/build/nix-irc" "$TEST_DIR/flake_ref#value" "$flake_ir"
|
||||
result=$(nix-instantiate --plugin-files "$PLUGIN_PATH" --eval --strict --json --expr "builtins.nixIR_loadIR \"$flake_ir\"" 2>&1)
|
||||
if echo "$result" | grep -q '^42$'; then
|
||||
echo "[PASS] Flake reference compiles and evaluates correctly"
|
||||
else
|
||||
echo "[FAIL] Flake reference compilation broken"
|
||||
echo "$result"
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "Test 7: NixOS Configuration Attribute Path"
|
||||
echo "------------------------------------------"
|
||||
config_ir=$(mktemp /tmp/nixir-flake-config-XXXXXX.nixir)
|
||||
"$(pwd)/build/nix-irc" "$TEST_DIR/flake_ref#nixosConfigurations.demo.config.networking.hostName" "$config_ir"
|
||||
result=$(nix-instantiate --plugin-files "$PLUGIN_PATH" --eval --strict --json --expr "builtins.nixIR_loadIR \"$config_ir\"" 2>&1)
|
||||
if echo "$result" | grep -q '"nixir-demo"'; then
|
||||
echo "[PASS] Nested flake attribute selection works for nixosConfigurations"
|
||||
else
|
||||
echo "[FAIL] NixOS configuration flake selection broken"
|
||||
echo "$result"
|
||||
exit 1
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "Integration Tests Complete"
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#include "irc/lexer.h"
|
||||
#include "irc/parser.h"
|
||||
#include "irc/serializer.h"
|
||||
#include "irc/types.h"
|
||||
|
|
@ -166,6 +167,64 @@ void test_parser_expect_in_speculative_parsing() {
|
|||
}
|
||||
}
|
||||
|
||||
void test_implication_right_associativity() {
|
||||
std::cout << "> Implication right associativity..." << std::endl;
|
||||
|
||||
Parser parser;
|
||||
auto ast = parser.parse("a -> b -> c");
|
||||
|
||||
auto* outer = ast->get_if<BinaryOpNode>();
|
||||
TEST_CHECK(outer != nullptr, "Top-level node is BinaryOpNode");
|
||||
TEST_CHECK(outer && outer->op == BinaryOp::IMPL, "Top-level operator is implication");
|
||||
|
||||
if (outer) {
|
||||
auto* left = outer->left->get_if<VarNode>();
|
||||
auto* right = outer->right->get_if<BinaryOpNode>();
|
||||
TEST_CHECK(left != nullptr && left->name && *left->name == "a", "Left branch is variable 'a'");
|
||||
TEST_CHECK(right != nullptr && right->op == BinaryOp::IMPL,
|
||||
"Right branch is nested implication");
|
||||
}
|
||||
}
|
||||
|
||||
void test_lookup_path_lexer_position() {
|
||||
std::cout << "> Lookup path lexer position..." << std::endl;
|
||||
|
||||
Lexer lexer("<nixpkgs> x");
|
||||
auto tokens = lexer.tokenize();
|
||||
|
||||
TEST_CHECK(tokens.size() >= 3, "Lexer produced lookup path, identifier, and EOF");
|
||||
TEST_CHECK(tokens[0].type == Token::LOOKUP_PATH, "First token is LOOKUP_PATH");
|
||||
TEST_CHECK(tokens[1].type == Token::IDENT && tokens[1].value == "x",
|
||||
"Second token is identifier 'x'");
|
||||
TEST_CHECK(tokens[1].col == 11, "Identifier column reflects consumed lookup path width");
|
||||
}
|
||||
|
||||
void test_unterminated_block_comment_rejected() {
|
||||
std::cout << "> Unterminated block comment rejection..." << std::endl;
|
||||
|
||||
try {
|
||||
Lexer lexer("/* unterminated");
|
||||
auto tokens = lexer.tokenize();
|
||||
(void) tokens;
|
||||
TEST_FAIL("Lexer should reject unterminated block comments");
|
||||
} catch (const std::exception& e) {
|
||||
TEST_PASS("Lexer rejects unterminated block comments");
|
||||
}
|
||||
}
|
||||
|
||||
void test_unknown_character_rejected() {
|
||||
std::cout << "> Unknown character rejection..." << std::endl;
|
||||
|
||||
try {
|
||||
Lexer lexer("1 $ 2");
|
||||
auto tokens = lexer.tokenize();
|
||||
(void) tokens;
|
||||
TEST_FAIL("Lexer should reject unexpected characters");
|
||||
} catch (const std::exception& e) {
|
||||
TEST_PASS("Lexer rejects unexpected characters");
|
||||
}
|
||||
}
|
||||
|
||||
void test_lookup_path_node() {
|
||||
std::cout << "> Lookup path serialization..." << std::endl;
|
||||
|
||||
|
|
@ -233,6 +292,53 @@ void test_import_with_lookup_path() {
|
|||
}
|
||||
}
|
||||
|
||||
void test_relative_path_import_parsing() {
|
||||
std::cout << "> Relative path import parsing..." << std::endl;
|
||||
|
||||
Parser parser;
|
||||
auto ast = parser.parse("import ./simple.nix");
|
||||
|
||||
auto* import_node = ast->get_if<ImportNode>();
|
||||
TEST_CHECK(import_node != nullptr, "Parsed expression is ImportNode");
|
||||
|
||||
if (import_node && import_node->path) {
|
||||
auto* path_node = import_node->path->get_if<ConstPathNode>();
|
||||
TEST_CHECK(path_node != nullptr, "Import argument is ConstPathNode");
|
||||
TEST_CHECK(path_node && path_node->value == "./simple.nix",
|
||||
"Relative path is preserved as './simple.nix'");
|
||||
}
|
||||
}
|
||||
|
||||
void test_builtin_call_node() {
|
||||
std::cout << "> BuiltinCallNode serialization..." << std::endl;
|
||||
|
||||
auto arg = std::make_shared<Node>(ConstStringNode("/tmp/example-flake"));
|
||||
auto builtin =
|
||||
std::make_shared<Node>(BuiltinCallNode("getFlake", std::vector<std::shared_ptr<Node>>{arg}));
|
||||
|
||||
IRModule module;
|
||||
module.entry = builtin;
|
||||
|
||||
Serializer ser;
|
||||
auto bytes = ser.serialize_to_bytes(module);
|
||||
|
||||
Deserializer deser;
|
||||
auto loaded = deser.deserialize(bytes);
|
||||
|
||||
auto* loaded_builtin = loaded.entry->get_if<BuiltinCallNode>();
|
||||
TEST_CHECK(loaded_builtin != nullptr, "Deserialized node is BuiltinCallNode");
|
||||
TEST_CHECK(loaded_builtin && loaded_builtin->builtin_name == "getFlake",
|
||||
"Builtin name is 'getFlake'");
|
||||
TEST_CHECK(loaded_builtin && loaded_builtin->args.size() == 1, "Builtin has one argument");
|
||||
|
||||
if (loaded_builtin && loaded_builtin->args.size() == 1) {
|
||||
auto* loaded_arg = loaded_builtin->args[0]->get_if<ConstStringNode>();
|
||||
TEST_CHECK(loaded_arg != nullptr, "Builtin argument is ConstStringNode");
|
||||
TEST_CHECK(loaded_arg && loaded_arg->value == "/tmp/example-flake",
|
||||
"Builtin argument value round-trips");
|
||||
}
|
||||
}
|
||||
|
||||
void test_uri_node() {
|
||||
std::cout << "> URI node serialization..." << std::endl;
|
||||
|
||||
|
|
@ -642,6 +748,18 @@ int main() {
|
|||
test_parser_expect_in_speculative_parsing();
|
||||
std::cout << std::endl;
|
||||
|
||||
test_implication_right_associativity();
|
||||
std::cout << std::endl;
|
||||
|
||||
test_lookup_path_lexer_position();
|
||||
std::cout << std::endl;
|
||||
|
||||
test_unterminated_block_comment_rejected();
|
||||
std::cout << std::endl;
|
||||
|
||||
test_unknown_character_rejected();
|
||||
std::cout << std::endl;
|
||||
|
||||
test_lookup_path_node();
|
||||
std::cout << std::endl;
|
||||
|
||||
|
|
@ -651,6 +769,12 @@ int main() {
|
|||
test_import_with_lookup_path();
|
||||
std::cout << std::endl;
|
||||
|
||||
test_relative_path_import_parsing();
|
||||
std::cout << std::endl;
|
||||
|
||||
test_builtin_call_node();
|
||||
std::cout << std::endl;
|
||||
|
||||
test_uri_node();
|
||||
std::cout << std::endl;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue