mudlet/test/TMxpTagParserTest.cpp
Gustavo Sousa 032b429a80
Fix: MXP Sound/Music Tags not functioning with U Attribute (#5877)
#### 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>
2022-01-22 13:12:19 +01:00

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 &#34;&name;&#34;|get &#34;&name;&#34;' 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 &#34;&name;&#34;|get &#34;&name;&#34;' 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)