/** * @file llmessagetemplateparser_tut.cpp * @date April 2007 * @brief LLMessageTemplateParser unit tests * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" #include "llmessagetemplateparser.h" #include "lltut.h" namespace tut { struct LLMessageTemplateParserTestData { LLMessageTemplateParserTestData() : mMessage("unset message") { } ~LLMessageTemplateParserTestData() { } void ensure_next(LLTemplateTokenizer & tokens, std::string value, U32 line) { std::string next = tokens.next(); ensure_equals(mMessage + " token matches", next, value); ensure_equals(mMessage + " line matches", tokens.line(), line); } char * prehash(const char * name) { return LLMessageStringTable::getInstance()->getString(name); } void ensure_block_attributes(std::string identifier, const LLMessageTemplate * message, const char * name, EMsgBlockType type, S32 number, S32 total_size) { const LLMessageBlock * block = message->getBlock(prehash(name)); identifier = identifier + ":" + message->mName + ":" + name + " block"; ensure(identifier + " exists", block != NULL); ensure_equals(identifier + " name", block->mName, prehash(name)); ensure_equals(identifier + " type", block->mType, type); ensure_equals(identifier + " number", block->mNumber, number); ensure_equals(identifier + " total size", block->mTotalSize, total_size); } void ensure_variable_attributes(std::string identifier, const LLMessageBlock * block, const char * name, EMsgVariableType type, S32 size) { const LLMessageVariable * var = block->getVariable(prehash(name)); identifier = identifier + ":" + block->mName + ":" + name + " variable"; ensure(identifier + " exists", var != NULL); ensure_equals( identifier + " name", var->getName(), prehash(name)); ensure_equals( identifier + " type", var->getType(), type); ensure_equals(identifier + " size", var->getSize(), size); } std::string mMessage; }; typedef test_group LLMessageTemplateParserTestGroup; typedef LLMessageTemplateParserTestGroup::object LLMessageTemplateParserTestObject; LLMessageTemplateParserTestGroup llMessageTemplateParserTestGroup("LLMessageTemplateParser"); template<> template<> void LLMessageTemplateParserTestObject::test<1>() // tests tokenizer constructor and next methods { mMessage = "test method 1 walkthrough"; LLTemplateTokenizer tokens("first line\nnext\t line\n\nfourth"); ensure_next(tokens, "first", 1); ensure_next(tokens, "line", 1); ensure_next(tokens, "next", 2); ensure_next(tokens, "line", 2); ensure_next(tokens, "fourth", 4); tokens = LLTemplateTokenizer("\n\t{ \t Test1 Fixed \n 523 }\n\n"); ensure(tokens.want("{")); ensure_next(tokens, "Test1", 2); ensure_next(tokens, "Fixed", 2); ensure_next(tokens, "523", 3); ensure(tokens.want("}")); tokens = LLTemplateTokenizer("first line\nnext\t line\n\nfourth"); ensure(tokens.want("first")); ensure_next(tokens, "line", 1); ensure_next(tokens, "next", 2); ensure_next(tokens, "line", 2); ensure(tokens.want("fourth")); } template<> template<> void LLMessageTemplateParserTestObject::test<2>() // tests tokenizer want method { // *NOTE: order matters LLTemplateTokenizer tokens("first line\nnext\t line\n\nfourth"); ensure_equals("wants first token", tokens.want("first"), true); ensure_equals("doesn't want blar token", tokens.want("blar"), false); ensure_equals("wants line token", tokens.want("line"), true); } template<> template<> void LLMessageTemplateParserTestObject::test<3>() // tests tokenizer eof methods { LLTemplateTokenizer tokens("single\n\n"); ensure_equals("is not at eof at beginning", tokens.atEOF(), false); ensure_equals("doesn't want eof", tokens.wantEOF(), false); ensure_equals("wants the first token just to consume it", tokens.want("single"), true); ensure_equals("is not at eof in middle", tokens.atEOF(), false); ensure_equals("wants eof", tokens.wantEOF(), true); ensure_equals("is at eof at end", tokens.atEOF(), true); } template<> template<> void LLMessageTemplateParserTestObject::test<4>() // tests variable parsing method { LLTemplateTokenizer tokens(std::string("{ Test0 \n\t\n U32 \n\n }")); LLMessageVariable * var = LLTemplateParser::parseVariable(tokens); ensure("test0 var parsed", var != 0); ensure_equals("name of variable", std::string(var->getName()), std::string("Test0")); ensure_equals("type of variable is U32", var->getType(), MVT_U32); ensure_equals("size of variable", var->getSize(), 4); delete var; std::string message_string("\n\t{ \t Test1 Fixed \n 523 }\n\n"); tokens = LLTemplateTokenizer(message_string); var = LLTemplateParser::parseVariable(tokens); ensure("test1 var parsed", var != 0); ensure_equals("name of variable", std::string(var->getName()), std::string("Test1")); ensure_equals("type of variable is Fixed", var->getType(), MVT_FIXED); ensure_equals("size of variable", var->getSize(), 523); delete var; // *NOTE: the parsers call LL_ERRS() on invalid input, so we can't really // test that :-( } template<> template<> void LLMessageTemplateParserTestObject::test<5>() // tests block parsing method { LLTemplateTokenizer tokens("{ BlockA Single { VarX F32 } }"); LLMessageBlock * block = LLTemplateParser::parseBlock(tokens); ensure("blockA block parsed", block != 0); ensure_equals("name of block", std::string(block->mName), std::string("BlockA")); ensure_equals("type of block is Single", block->mType, MBT_SINGLE); ensure_equals("total size of block", block->mTotalSize, 4); ensure_equals("number of block defaults to 1", block->mNumber, 1); ensure_equals("variable type of VarX is F32", block->getVariableType(prehash("VarX")), MVT_F32); ensure_equals("variable size of VarX", block->getVariableSize(prehash("VarX")), 4); delete block; tokens = LLTemplateTokenizer("{ Stuff Variable { Id LLUUID } }"); block = LLTemplateParser::parseBlock(tokens); ensure("stuff block parsed", block != 0); ensure_equals("name of block", std::string(block->mName), std::string("Stuff")); ensure_equals("type of block is Multiple", block->mType, MBT_VARIABLE); ensure_equals("total size of block", block->mTotalSize, 16); ensure_equals("number of block defaults to 1", block->mNumber, 1); ensure_equals("variable type of Id is LLUUID", block->getVariableType(prehash("Id")), MVT_LLUUID); ensure_equals("variable size of Id", block->getVariableSize(prehash("Id")), 16); delete block; tokens = LLTemplateTokenizer("{ Stuff2 Multiple 45 { Shid LLVector3d } }"); block = LLTemplateParser::parseBlock(tokens); ensure("stuff2 block parsed", block != 0); ensure_equals("name of block", std::string(block->mName), std::string("Stuff2")); ensure_equals("type of block is Multiple", block->mType, MBT_MULTIPLE); ensure_equals("total size of block", block->mTotalSize, 24); ensure_equals("number of blocks", block->mNumber, 45); ensure_equals("variable type of Shid is Vector3d", block->getVariableType(prehash("Shid")), MVT_LLVector3d); ensure_equals("variable size of Shid", block->getVariableSize(prehash("Shid")), 24); delete block; } template<> template<> void LLMessageTemplateParserTestObject::test<6>() // tests message parsing method on a simple message { std::string message_skel( "{\n" "TestMessage Low 1 NotTrusted Zerocoded\n" "// comment \n" " {\n" "TestBlock1 Single\n" " { Test1 U32 }\n" " }\n" " {\n" " NeighborBlock Multiple 4\n" " { Test0 U32 }\n" " { Test1 U32 }\n" " { Test2 U32 }\n" " }\n" "}"); LLTemplateTokenizer tokens(message_skel); LLMessageTemplate * message = LLTemplateParser::parseMessage(tokens); ensure("simple message parsed", message != 0); ensure_equals("name of message", std::string(message->mName), std::string("TestMessage")); ensure_equals("frequency is Low", message->mFrequency, MFT_LOW); ensure_equals("trust is untrusted", message->mTrust, MT_NOTRUST); ensure_equals("message number", message->mMessageNumber, (U32)((255 << 24) | (255 << 16) | 1)); ensure_equals("message encoding is zerocoded", message->mEncoding, ME_ZEROCODED); ensure_equals("message deprecation is notdeprecated", message->mDeprecation, MD_NOTDEPRECATED); LLMessageBlock * block = message->getBlock(prehash("NonexistantBlock")); ensure("Nonexistant block does not exist", block == 0); delete message; } template<> template<> void LLMessageTemplateParserTestObject::test<7>() // tests message parsing method on a deprecated message { std::string message_skel( "{\n" "TestMessageDeprecated High 34 Trusted Unencoded Deprecated\n" " {\n" "TestBlock2 Single\n" " { Test2 S32 }\n" " }\n" "}"); LLTemplateTokenizer tokens(message_skel); LLMessageTemplate * message = LLTemplateParser::parseMessage(tokens); ensure("deprecated message parsed", message != 0); ensure_equals("name of message", std::string(message->mName), std::string("TestMessageDeprecated")); ensure_equals("frequency is High", message->mFrequency, MFT_HIGH); ensure_equals("trust is trusted", message->mTrust, MT_TRUST); ensure_equals("message number", message->mMessageNumber, (U32)34); ensure_equals("message encoding is unencoded", message->mEncoding, ME_UNENCODED); ensure_equals("message deprecation is deprecated", message->mDeprecation, MD_DEPRECATED); delete message; } template<> template<> void LLMessageTemplateParserTestObject::test<8>() // tests message parsing on RezMultipleAttachmentsFromInv, a possibly-faulty message { std::string message_skel( "{\n\ RezMultipleAttachmentsFromInv Low 452 NotTrusted Zerocoded\n\ {\n\ AgentData Single\n\ { AgentID LLUUID }\n\ { SessionID LLUUID }\n\ } \n\ {\n\ HeaderData Single\n\ { CompoundMsgID LLUUID } // All messages a single \"compound msg\" must have the same id\n\ { TotalObjects U8 }\n\ { FirstDetachAll BOOL }\n\ }\n\ {\n\ ObjectData Variable // 1 to 4 of these per packet\n\ { ItemID LLUUID }\n\ { OwnerID LLUUID }\n\ { AttachmentPt U8 } // 0 for default\n\ { ItemFlags U32 }\n\ { GroupMask U32 }\n\ { EveryoneMask U32 }\n\ { NextOwnerMask U32 }\n\ { Name Variable 1 }\n\ { Description Variable 1 }\n\ }\n\ }\n\ "); LLTemplateTokenizer tokens(message_skel); LLMessageTemplate * message = LLTemplateParser::parseMessage(tokens); ensure("RezMultipleAttachmentsFromInv message parsed", message != 0); ensure_equals("name of message", message->mName, prehash("RezMultipleAttachmentsFromInv")); ensure_equals("frequency is low", message->mFrequency, MFT_LOW); ensure_equals("trust is not trusted", message->mTrust, MT_NOTRUST); ensure_equals("message number", message->mMessageNumber, (U32)((255 << 24) | (255 << 16) | 452)); ensure_equals("message encoding is zerocoded", message->mEncoding, ME_ZEROCODED); ensure_block_attributes( "RMAFI", message, "AgentData", MBT_SINGLE, 1, 16+16); LLMessageBlock * block = message->getBlock(prehash("AgentData")); ensure_variable_attributes("RMAFI", block, "AgentID", MVT_LLUUID, 16); ensure_variable_attributes("RMAFI", block, "SessionID", MVT_LLUUID, 16); ensure_block_attributes( "RMAFI", message, "HeaderData", MBT_SINGLE, 1, 16+1+1); block = message->getBlock(prehash("HeaderData")); ensure_variable_attributes( "RMAFI", block, "CompoundMsgID", MVT_LLUUID, 16); ensure_variable_attributes( "RMAFI", block, "TotalObjects", MVT_U8, 1); ensure_variable_attributes( "RMAFI", block, "FirstDetachAll", MVT_BOOL, 1); ensure_block_attributes( "RMAFI", message, "ObjectData", MBT_VARIABLE, 1, -1); block = message->getBlock(prehash("ObjectData")); ensure_variable_attributes("RMAFI", block, "ItemID", MVT_LLUUID, 16); ensure_variable_attributes("RMAFI", block, "OwnerID", MVT_LLUUID, 16); ensure_variable_attributes("RMAFI", block, "AttachmentPt", MVT_U8, 1); ensure_variable_attributes("RMAFI", block, "ItemFlags", MVT_U32, 4); ensure_variable_attributes("RMAFI", block, "GroupMask", MVT_U32, 4); ensure_variable_attributes("RMAFI", block, "EveryoneMask", MVT_U32, 4); ensure_variable_attributes("RMAFI", block, "NextOwnerMask", MVT_U32, 4); ensure_variable_attributes("RMAFI", block, "Name", MVT_VARIABLE, 1); ensure_variable_attributes("RMAFI", block, "Description", MVT_VARIABLE, 1); delete message; } }