mirror of
https://github.com/Mudlet/Mudlet
synced 2026-08-13 18:26:27 -04:00
#### Brief overview of PR changes/additions - MXP tag parsing: Adds extra conditions for identifying closing tags with prefix, allowing parsing to continue when slashes are found inside an unquoted attribute value; Test case for the example in the issue - SOUND and MUSIC tag processing: extra check for detecting unnamed volume attribute - Refactorings to remove duplicated code Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Stephen Lyons <slysven@virginmedia.com>
400 lines
13 KiB
C++
400 lines
13 KiB
C++
|
|
#include "TMxpTagParser.h"
|
|
#include <MxpTag.h>
|
|
#include <QtTest/QtTest>
|
|
|
|
class TMxpTagParserTest : public QObject {
|
|
Q_OBJECT
|
|
|
|
private:
|
|
private slots:
|
|
|
|
void initTestCase()
|
|
{
|
|
}
|
|
|
|
QSharedPointer<MxpNode> parseNode(const QString& tagText) const
|
|
{
|
|
auto nodes = TMxpTagParser::parseToMxpNodeList(tagText);
|
|
return nodes.size() > 0 ? nodes.first() : nullptr;
|
|
}
|
|
|
|
void testMateriaMagicaScriptedActionEndTag()
|
|
{
|
|
auto node = parseNode("<play hangman/scripted_action>");
|
|
QVERIFY(node->isEndTag());
|
|
QCOMPARE(node->asEndTag()->getName(), "scripted_action");
|
|
}
|
|
|
|
void testMateriaMagicaScriptedActionTag()
|
|
{
|
|
TMxpTagParser parser;
|
|
QString tagText = R"(<scripted_action desc="hangman start">play hangman<play hangman/scripted_action>)";
|
|
|
|
auto list = parser.parseToMxpNodeList(tagText, false);
|
|
QCOMPARE(list.size(), 3);
|
|
|
|
QVERIFY(list[0]->isStartTag());
|
|
QCOMPARE(list[0]->asStartTag()->getName(), "scripted_action");
|
|
|
|
QVERIFY(!list[1]->isTag());
|
|
QCOMPARE(list[1]->asText()->getContent(), "play hangman");
|
|
|
|
QVERIFY(list[2]->isEndTag());
|
|
QCOMPARE(list[2]->asEndTag()->getName(), "scripted_action");
|
|
}
|
|
|
|
void testSimpleEndTag()
|
|
{
|
|
TMxpTagParser parser;
|
|
QString tagText = R"(<tag_name desc="blabla">tag content</tag_name>)";
|
|
|
|
auto list = parser.parseToMxpNodeList(tagText, true);
|
|
QCOMPARE(list.size(), 2);
|
|
|
|
QVERIFY(list[0]->isStartTag());
|
|
QVERIFY(list[1]->isEndTag());
|
|
QCOMPARE(list[0]->asStartTag()->getName(), "tag_name");
|
|
|
|
QVERIFY(list[1]->isEndTag());
|
|
QCOMPARE(list[1]->asEndTag()->getName(), "tag_name");
|
|
}
|
|
|
|
void testSimpleTagQuotedSlash()
|
|
{
|
|
TMxpTagParser parser;
|
|
QString tagText = R"(<tag_name desc="a/b">)";
|
|
|
|
auto list = parser.parseToMxpNodeList(tagText, true);
|
|
QCOMPARE(list.size(), 1);
|
|
|
|
QVERIFY(list[0]->isStartTag());
|
|
QCOMPARE(list[0]->asStartTag()->getName(), "tag_name");
|
|
QCOMPARE(list[0]->asStartTag()->getAttributeValue("desc"), "a/b");
|
|
}
|
|
|
|
void testParseUrl()
|
|
{
|
|
QString tagText = R"(<A HREF="https://www.google.com/search?q=mudlet">)";
|
|
auto node = parseNode(tagText);
|
|
QVERIFY(node);
|
|
|
|
QVERIFY(node->isStartTag());
|
|
QCOMPARE(node->asStartTag()->getName(), "A");
|
|
QCOMPARE(node->asStartTag()->getAttributeValue("HREF"), "https://www.google.com/search?q=mudlet");
|
|
}
|
|
|
|
void testParseWithEqualSymbol()
|
|
{
|
|
QString tagText = R"(<SEND HREF="1+1=2">)";
|
|
auto node = parseNode(tagText);
|
|
|
|
QVERIFY(node);
|
|
QVERIFY(node->isStartTag());
|
|
QCOMPARE(node->asStartTag()->getName(), "SEND");
|
|
QCOMPARE(node->asStartTag()->getAttributeValue("HREF"), "1+1=2");
|
|
}
|
|
|
|
void testParseWithQuotes()
|
|
{
|
|
TMxpTagParser parser;
|
|
QList<QSharedPointer<MxpNode>> list = parser.parseToMxpNodeList(" <!EN quot '\"'>", true);
|
|
|
|
QCOMPARE(list.size(), 1);
|
|
QCOMPARE(list[0]->asStartTag()->getName(), "!EN");
|
|
QCOMPARE(list[0]->asStartTag()->getAttrName(0), "quot");
|
|
QCOMPARE(list[0]->asStartTag()->getAttrName(1), "\"");
|
|
}
|
|
|
|
void testParseToNodes()
|
|
{
|
|
TMxpTagParser parser;
|
|
QList<QSharedPointer<MxpNode>> list = parser.parseToMxpNodeList("<COLOR fore=red><B>");
|
|
|
|
QCOMPARE(list.size(), 2);
|
|
QVERIFY(list[0].get()->isTag());
|
|
QCOMPARE(list[0]->asStartTag()->getName(), "COLOR");
|
|
QCOMPARE(list[0]->asStartTag()->getAttributeValue("FORE"), "red");
|
|
QCOMPARE(list[1]->asStartTag()->getName(), "B");
|
|
}
|
|
|
|
void testParseToNodesWithText()
|
|
{
|
|
TMxpTagParser parser;
|
|
QList<QSharedPointer<MxpNode>> list = parser.parseToMxpNodeList("<SEND>north</SEND>");
|
|
|
|
QCOMPARE(list.size(), 3);
|
|
QVERIFY(list[0].get()->isTag());
|
|
QCOMPARE(list[0]->asStartTag()->getName(), "SEND");
|
|
|
|
QVERIFY(!list[1]->isTag());
|
|
QCOMPARE(list[1]->asText()->getContent(), "north");
|
|
QCOMPARE(list[2]->asEndTag()->getName(), "SEND");
|
|
}
|
|
|
|
void testParseToNodesIgnoreText()
|
|
{
|
|
TMxpTagParser parser;
|
|
QList<QSharedPointer<MxpNode>> list = parser.parseToMxpNodeList(" <COLOR fore=red>asafsdf<B>asdf", true);
|
|
|
|
QCOMPARE(list.size(), 2);
|
|
QVERIFY(list[0].get()->isTag());
|
|
QCOMPARE(list[0]->asStartTag()->getName(), "COLOR");
|
|
QCOMPARE(list[0]->asStartTag()->getAttributeValue("FORE"), "red");
|
|
QCOMPARE(list[1]->asStartTag()->getName(), "B");
|
|
}
|
|
|
|
void testParseToNodesWithClosedAndEndTag()
|
|
{
|
|
TMxpTagParser parser;
|
|
QList<QSharedPointer<MxpNode>> list = parser.parseToMxpNodeList("<RNum 2 /><SEND>text</ SEND>");
|
|
|
|
QCOMPARE(list.size(), 4);
|
|
QVERIFY(list[0].get()->isTag());
|
|
QVERIFY(list[0].get()->asStartTag()->isEmpty());
|
|
QCOMPARE(list[0].get()->asStartTag()->getAttrName(0), "2");
|
|
|
|
QVERIFY(list[3].get()->isEndTag());
|
|
QCOMPARE(list[3].get()->asEndTag()->getName(), "SEND");
|
|
}
|
|
|
|
void testParseToNodesWithTextAndSpaces()
|
|
{
|
|
TMxpTagParser parser;
|
|
QList<QSharedPointer<MxpNode>> list = parser.parseToMxpNodeList("<SEND href=\"&text;\"> go north... </SEND>");
|
|
|
|
QCOMPARE(list.size(), 3);
|
|
QVERIFY(list[0].get()->isTag());
|
|
QCOMPARE(list[0]->asStartTag()->getName(), "SEND");
|
|
QCOMPARE(list[0]->asStartTag()->getAttributeValue("href"), "&text;");
|
|
|
|
QVERIFY(!list[1]->isTag());
|
|
QCOMPARE(list[1]->asText()->getContent(), " go north... ");
|
|
QCOMPARE(list[2]->asEndTag()->getName(), "SEND");
|
|
}
|
|
|
|
void testComplexElementDefinitionToTag()
|
|
{
|
|
QString tagLine =
|
|
"<!EL get \"<send href='examine "&name;"|get "&name;"' hint='Right mouse click to act on this item|Get &desc;|Examine &desc;|Look in &desc;' expire=get>\" ATT='name desc'>";
|
|
TMxpTagParser parser;
|
|
auto list = parser.parseToMxpNodeList(tagLine);
|
|
|
|
QCOMPARE(list.size(), 1);
|
|
QVERIFY(list[0]->isStartTag());
|
|
|
|
MxpStartTag* tag = list[0]->asStartTag();
|
|
|
|
QCOMPARE(tag->getName(), "!EL");
|
|
QCOMPARE(tag->getAttributesCount(), 3);
|
|
|
|
QCOMPARE(tag->getAttribute(0).getName(), "get");
|
|
QCOMPARE(tag->getAttribute(0).getValue(), "");
|
|
|
|
QCOMPARE(tag->getAttribute(1).getName(),
|
|
"<send href='examine "&name;"|get "&name;"' hint='Right mouse click to act on this item|Get &desc;|Examine &desc;|Look in &desc;' expire=get>");
|
|
QCOMPARE(tag->getAttributeValue("ATT"), "name desc");
|
|
|
|
auto sendTagNodeList = parser.parseToMxpNodeList(tag->getAttribute(1).getName());
|
|
MxpStartTag* sendTag = sendTagNodeList[0]->asStartTag();
|
|
QCOMPARE(sendTag->getName(), "send");
|
|
}
|
|
|
|
void testMxpTagParser()
|
|
{
|
|
TMxpTagParser parser;
|
|
|
|
auto list = parser.parseToMxpNodeList("<!EL RExit FLAG=RoomExit>");
|
|
QCOMPARE(list.size(), 1);
|
|
QVERIFY(list[0]->isStartTag());
|
|
|
|
MxpStartTag* tag = list[0]->asStartTag();
|
|
|
|
QCOMPARE(tag->getName(), "!EL");
|
|
|
|
QVERIFY(tag->hasAttribute("RExit"));
|
|
QCOMPARE(tag->getAttributeValue("RExit"), "");
|
|
QCOMPARE(tag->getAttribute(0).getName(), "RExit");
|
|
QCOMPARE(tag->getAttribute(0).getValue(), "");
|
|
|
|
QVERIFY(tag->hasAttribute("FLAG"));
|
|
QCOMPARE(tag->getAttributeValue("FLAG"), "RoomExit");
|
|
}
|
|
|
|
void testAttrDefinition()
|
|
{
|
|
QString tagLine = R"(<!ATTLIST boldtext 'color=red background=white flags'>)";
|
|
TMxpTagParser parser;
|
|
auto list = parser.parseToMxpNodeList(tagLine);
|
|
|
|
QCOMPARE(list.size(), 1);
|
|
QVERIFY(list[0]->isStartTag());
|
|
|
|
MxpStartTag* tag = list[0]->asStartTag();
|
|
QCOMPARE(tag->getName(), "!ATTLIST");
|
|
QCOMPARE(tag->getAttribute(0).getName(), "boldtext");
|
|
QCOMPARE(tag->getAttribute(1).getName(), "color=red background=white flags");
|
|
}
|
|
|
|
void testSimpleElementDefinition()
|
|
{
|
|
QString tagLine = "<!EL RExit FLAG=RoomExit>";
|
|
auto node = parseNode(tagLine);
|
|
|
|
QVERIFY(node->isStartTag());
|
|
QCOMPARE(node->asStartTag()->getName(), "!EL");
|
|
QVERIFY(node->asStartTag()->hasAttribute("RExit"));
|
|
QCOMPARE(node->asStartTag()->getAttributeValue("FLAG"), "RoomExit");
|
|
}
|
|
|
|
void testElementDefinitionWithExtraSpaces()
|
|
{
|
|
QString tagLine = "<!EL RExit FLAG=RoomExit>";
|
|
auto node = parseNode(tagLine);
|
|
|
|
QVERIFY(node->isStartTag());
|
|
QCOMPARE(node->asStartTag()->getName(), "!EL");
|
|
QVERIFY(node->asStartTag()->hasAttribute("RExit"));
|
|
QCOMPARE(node->asStartTag()->getAttributeValue("FLAG"), "RoomExit");
|
|
}
|
|
|
|
void testElementDefinitionQuotedAttributeSpaces()
|
|
{
|
|
QString tagLine = "<!EL sHp FLAG='Set Hp'>";
|
|
auto node = parseNode(tagLine);
|
|
|
|
QVERIFY(node->isStartTag());
|
|
QCOMPARE(node->asStartTag()->getName(), "!EL");
|
|
QVERIFY(node->asStartTag()->hasAttribute("sHp"));
|
|
QCOMPARE(node->asStartTag()->getAttributeValue("FLAG"), "Set Hp");
|
|
}
|
|
|
|
void testAccessAttrCaseInsensitive()
|
|
{
|
|
TMxpTagParser parser;
|
|
QString tagLine = "<!EL sHp FLAG='Set Hp'>";
|
|
|
|
auto node = parseNode(tagLine);
|
|
|
|
QVERIFY(node->isStartTag());
|
|
MxpStartTag* tag = node->asStartTag();
|
|
|
|
QVERIFY(tag->hasAttribute("sHp"));
|
|
QVERIFY(tag->hasAttribute("shp"));
|
|
QVERIFY(tag->hasAttribute("shP"));
|
|
QCOMPARE(tag->getAttributeValue("flag"), "Set Hp");
|
|
}
|
|
|
|
void testElementDefinitionQuotesInQuotes()
|
|
{
|
|
QString tagLine = "<!EL x FLAG='Quote \" ex'>";
|
|
auto node = parseNode(tagLine);
|
|
|
|
QVERIFY(node->isStartTag());
|
|
QCOMPARE(node->asStartTag()->getName(), "!EL");
|
|
QVERIFY(node->asStartTag()->hasAttribute("x"));
|
|
QCOMPARE(node->asStartTag()->getAttributeValue("FLAG"), "Quote \" ex");
|
|
}
|
|
|
|
void testCompleteElement()
|
|
{
|
|
TMxpTagParser parser;
|
|
|
|
QString tagLine = R"(<FRAME Name="Map" Left="-20c" Top="0" Width="20c" Height="20c">)";
|
|
auto node = parseNode(tagLine);
|
|
|
|
QVERIFY(node->isStartTag());
|
|
MxpStartTag* tag = node->asStartTag();
|
|
|
|
QCOMPARE(tag->getName(), "FRAME");
|
|
QCOMPARE(tag->getAttributeValue("Name"), "Map");
|
|
QCOMPARE(tag->getAttributeValue("Left"), "-20c");
|
|
QCOMPARE(tag->getAttributeValue("Top"), "0");
|
|
QCOMPARE(tag->getAttributeValue("Width"), "20c");
|
|
QCOMPARE(tag->getAttributeValue("Height"), "20c");
|
|
}
|
|
|
|
void testEndTag()
|
|
{
|
|
auto node = parseNode("</V>");
|
|
QVERIFY(node->isEndTag());
|
|
|
|
MxpEndTag* endTag = node->asEndTag();
|
|
QCOMPARE(endTag->getName(), "V");
|
|
QCOMPARE(endTag->asStartTag(), nullptr);
|
|
}
|
|
|
|
void testParseEndTag()
|
|
{
|
|
auto node = parseNode("</V>");
|
|
QVERIFY(node);
|
|
QVERIFY(node->isEndTag());
|
|
|
|
MxpEndTag* tag = node->asEndTag();
|
|
|
|
QCOMPARE(tag->getName(), "V");
|
|
QVERIFY(!tag->asStartTag());
|
|
}
|
|
|
|
void testStartTagClosed()
|
|
{
|
|
auto node = parseNode("<RNum 212 />");
|
|
|
|
QVERIFY(node);
|
|
QVERIFY(node->isStartTag());
|
|
|
|
MxpStartTag* tag = node->asStartTag();
|
|
|
|
QVERIFY(tag->isEmpty());
|
|
QCOMPARE(tag->getName(), "RNum");
|
|
QCOMPARE(tag->getAttribute(0).getName(), "212");
|
|
QCOMPARE(tag->getAttributesCount(), 1);
|
|
}
|
|
|
|
void testQuotedAttrValue()
|
|
{
|
|
auto node = parseNode("<color fore='red' back=\"blue\">");
|
|
|
|
QVERIFY(node);
|
|
QVERIFY(node->isStartTag());
|
|
|
|
MxpStartTag* tag = node->asStartTag();
|
|
|
|
QVERIFY(tag->isStartTag());
|
|
QCOMPARE(tag->getName(), "color");
|
|
QCOMPARE(tag->asStartTag()->getAttributesCount(), 2);
|
|
QCOMPARE(tag->asStartTag()->getAttribute("fore").getValue(), "red");
|
|
QCOMPARE(tag->asStartTag()->getAttribute("back").getValue(), "blue");
|
|
}
|
|
|
|
void testUnquotedUrl() {
|
|
auto node = parseNode("<sound FName=\"cow.wav\" U=https://raw.githubusercontent.com/StickMUD/StickMUDSounds/master/sounds/>");
|
|
|
|
QVERIFY(node);
|
|
QVERIFY(node->isStartTag());
|
|
|
|
MxpStartTag* tag = node->asStartTag();
|
|
QCOMPARE(tag->getName(), "sound");
|
|
QCOMPARE(tag->getAttributeValue("FName"), "cow.wav");
|
|
QCOMPARE(tag->getAttributeValue("U"), "https://raw.githubusercontent.com/StickMUD/StickMUDSounds/master/sounds/");
|
|
|
|
}
|
|
|
|
void testEmptyTagWithSlash() {
|
|
auto node = parseNode("<send url=http://www.gogle.com/ />");
|
|
|
|
QVERIFY(node);
|
|
QVERIFY(node->isStartTag());
|
|
|
|
MxpStartTag* tag = node->asStartTag();
|
|
QVERIFY(tag->isEmpty());
|
|
QCOMPARE(tag->getName(), "send");
|
|
QCOMPARE(tag->getAttributeValue("url"), "http://www.gogle.com/");
|
|
}
|
|
|
|
|
|
void cleanupTestCase() {}
|
|
};
|
|
|
|
#include "TMxpTagParserTest.moc"
|
|
QTEST_MAIN(TMxpTagParserTest)
|