#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>");
}