BareGit
#include <gtest/gtest.h>
#include "macrodown.h"

using namespace macrodown;

TEST(CustomMarkupTest, PrefixMarkup)
{
    MacroDown md;
    // Define # as prefix markup for 'tag'
    md.definePrefixMarkup({"#", "tag", ""});
    // We also need to define what the 'tag' macro does in HTML
    md.evaluator().define("tag", {"content"}, "<span class=\"tag\">#%content</span>");

    std::string input = "This is a #test markup.";
    auto root = md.parse(input);
    std::string html = md.render(*root);

    EXPECT_EQ(html, "<p>This is a <span class=\"tag\">#test</span> markup.</p>\n");
}

TEST(CustomMarkupTest, PrefixMarkupPunctuation)
{
    MacroDown md;
    md.definePrefixMarkup({"#", "tag", ""});
    md.evaluator().define("tag", {"content"}, "[%content]");

    // Punctuation should end the prefix markup, except for underscore
    std::string input = "#test. #more_test! #final";
    std::string html = md.render(*md.parse(input));

    EXPECT_EQ(html, "<p>[test]. [more_test]! [final]</p>\n");
}

TEST(CustomMarkupTest, DelimitedMarkup)
{
    MacroDown md;
    // Define : as delimited markup for 'highlight'
    md.defineDelimitedMarkup({":", "highlight", ""});
    md.evaluator().define("highlight", {"content"}, "<mark>%content</mark>");

    std::string input = "This is :important: text.";
    std::string html = md.render(*md.parse(input));

    EXPECT_EQ(html, "<p>This is <mark>important</mark> text.</p>\n");
}

TEST(CustomMarkupTest, DelimitedMarkupInvalid)
{
    MacroDown md;
    md.defineDelimitedMarkup({":", "highlight", ""});
    md.evaluator().define("highlight", {"content"}, "<mark>%content</mark>");

    // Whitespace or punctuation (except _ and -) makes it invalid
    std::string input = "This is :not valid: because of space. And :this.too: because of dot.";
    std::string html = md.render(*md.parse(input));

    // Should remain as plain text
    EXPECT_EQ(html, "<p>This is :not valid: because of space. And :this.too: because of dot.</p>\n");
}

TEST(CustomMarkupTest, DelimitedMarkupUnderscoreDash)
{
    MacroDown md;
    md.defineDelimitedMarkup({":", "highlight", ""});
    md.evaluator().define("highlight", {"content"}, "<mark>%content</mark>");

    std::string input = "This is :valid_with-extra: text.";
    std::string html = md.render(*md.parse(input));

    EXPECT_EQ(html, "<p>This is <mark>valid_with-extra</mark> text.</p>\n");
}

TEST(CustomMarkupTest, UnicodeMarkup)
{
    MacroDown md;
    // Multi-byte prefix (e.g., symbol)
    md.definePrefixMarkup({"§", "section", ""});
    md.evaluator().define("section", {"content"}, "Sec. %content");

    std::string input = "See §A.1";
    std::string html = md.render(*md.parse(input));

    EXPECT_EQ(html, "<p>See Sec. A.1</p>\n");
}

TEST(CustomMarkupTest, PrefixMarkupExtendedCharacters)
{
    MacroDown md;
    md.definePrefixMarkup({"#", "tag", ""});
    md.evaluator().define("tag", {"content"}, "[%content]");

    // Dash and @ should NOT end the prefix markup per updated PRD
    std::string input = "#test-case #user@domain";
    std::string html = md.render(*md.parse(input));

    EXPECT_EQ(html, "<p>[test-case] [user@domain]</p>\n");
}

TEST(CustomMarkupTest, PrefixMarkupAtPrefix)
{
    MacroDown md;
    md.definePrefixMarkup({"@", "mention", ""});
    md.evaluator().define("mention", {"content"}, "<a href=\" /u/%content\">@%content</a>");

    // Dash, @ and . allowed inside.
    std::string input = "Hello @user-name! Email: @user@domain.com";
    std::string html = md.render(*md.parse(input));

    EXPECT_EQ(html, "<p>Hello <a href=\" /u/user-name\">@user-name</a>! Email: <a href=\" /u/user@domain.com\">@user@domain.com</a></p>\n");
}

TEST(CustomMarkupTest, PrefixMarkupTrailingDot)
{
    MacroDown md;
    md.definePrefixMarkup({"@", "mention", ""});
    md.evaluator().define("mention", {"content"}, "(%content)");

    std::string input = "End of sentence @mention. Another @mention..";
    std::string html = md.render(*md.parse(input));

    // @mention. -> mention
    // @mention.. -> mention. (first dot kept, second excluded)
    EXPECT_EQ(html, "<p>End of sentence (mention). Another (mention.).</p>\n");
}