BareGit
#include <gtest/gtest.h>
#include "macro_engine.h"
#include "parser.h"
#include "nodes.h"
#include <variant>

using namespace macrodown;

class MacroEngineTest : public ::testing::Test
{
protected:
    Evaluator evaluator;
};

// Test parsing of simple text
TEST_F(MacroEngineTest, ParseText)
{
    auto nodes = Parser::parse("Hello World");
    ASSERT_EQ(nodes.size(), 1);
    
    ASSERT_TRUE(std::holds_alternative<Text>(nodes[0]->data));
    EXPECT_EQ(std::get<Text>(nodes[0]->data).content, "Hello World");
}

// Test parsing of macro
TEST_F(MacroEngineTest, ParseMacro)
{
    auto nodes = Parser::parse("%m{arg}");
    ASSERT_EQ(nodes.size(), 1);
    
    ASSERT_TRUE(std::holds_alternative<Macro>(nodes[0]->data));
    const auto& macro = std::get<Macro>(nodes[0]->data);
    EXPECT_EQ(macro.name, "m");
    ASSERT_EQ(macro.arguments.size(), 1);
    
    // Argument should be a Group
    ASSERT_TRUE(std::holds_alternative<Group>(macro.arguments[0]->data));
    const auto& group = std::get<Group>(macro.arguments[0]->data);
    ASSERT_EQ(group.children.size(), 1);
    
    ASSERT_TRUE(std::holds_alternative<Text>(group.children[0]->data));
    EXPECT_EQ(std::get<Text>(group.children[0]->data).content, "arg");
}

// Test intrinsic %def and expansion
TEST_F(MacroEngineTest, DefAndExpand)
{
    // Define %hello{name} -> "Hello %name!"
    // We use the Parser to create the definition call
    std::string input = "%def[hello]{name}{Hello %name!}";
    auto nodes = Parser::parse(input);
    
    // Evaluate the definition
    for(const auto& node : nodes)
    {
        evaluator.evaluate(*node);
    }
    
    // Now call it: %hello{World}
    auto call_nodes = Parser::parse("%hello{World}");
    std::string result;
    for(const auto& node : call_nodes)
    {
        result += evaluator.evaluate(*node);
    }
    
    EXPECT_EQ(result, "Hello World!");
}

// Test nested macros
TEST_F(MacroEngineTest, NestedMacros)
{
    // %def[b]{t}{<b>%t</b>}
    // %def[p]{t}{<p>%t</p>}
    // Call: %p{Hello %b{World}} -> <p>Hello <b>World</b></p>
    
    std::vector<std::string> defs = {
        "%def[b]{t}{<b>%t</b>}",
        "%def[p]{t}{<p>%t</p>}"
    };
    
    for(const auto& def : defs)
    {
        auto nodes = Parser::parse(def);
        for(const auto& node : nodes) evaluator.evaluate(*node);
    }
    
    auto nodes = Parser::parse("%p{Hello %b{World}}");
    std::string result;
    for(const auto& node : nodes)
    {
        result += evaluator.evaluate(*node);
    }
    
    EXPECT_EQ(result, "<p>Hello <b>World</b></p>");
}