diff options
Diffstat (limited to 'Swiften/Parser/UnitTest/XMLParserTest.cpp')
-rw-r--r-- | Swiften/Parser/UnitTest/XMLParserTest.cpp | 696 |
1 files changed, 415 insertions, 281 deletions
diff --git a/Swiften/Parser/UnitTest/XMLParserTest.cpp b/Swiften/Parser/UnitTest/XMLParserTest.cpp index 4bdeb54..89229c9 100644 --- a/Swiften/Parser/UnitTest/XMLParserTest.cpp +++ b/Swiften/Parser/UnitTest/XMLParserTest.cpp @@ -1,11 +1,12 @@ /* - * Copyright (c) 2010 Remko Tronçon - * Licensed under the GNU General Public License v3. - * See Documentation/Licenses/GPLv3.txt for more information. + * Copyright (c) 2010 Isode Limited. + * All rights reserved. + * See the COPYING file for more information. */ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/extensions/TestFactoryRegistry.h> +#include <unordered_map> #include <vector> #include <string> @@ -21,337 +22,470 @@ using namespace Swift; template <typename ParserType> class XMLParserTest : public CppUnit::TestFixture { - CPPUNIT_TEST_SUITE(XMLParserTest); - CPPUNIT_TEST(testParse_NestedElements); - CPPUNIT_TEST(testParse_ElementInNamespacedElement); - CPPUNIT_TEST(testParse_CharacterData); - CPPUNIT_TEST(testParse_XMLEntity); - CPPUNIT_TEST(testParse_NamespacePrefix); - CPPUNIT_TEST(testParse_UnhandledXML); - CPPUNIT_TEST(testParse_InvalidXML); - CPPUNIT_TEST(testParse_InErrorState); - CPPUNIT_TEST(testParse_Incremental); - CPPUNIT_TEST(testParse_WhitespaceInAttribute); - CPPUNIT_TEST(testParse_AttributeWithoutNamespace); - CPPUNIT_TEST(testParse_AttributeWithNamespace); - CPPUNIT_TEST(testParse_BillionLaughs); - CPPUNIT_TEST(testParse_InternalEntity); - //CPPUNIT_TEST(testParse_UndefinedPrefix); - //CPPUNIT_TEST(testParse_UndefinedAttributePrefix); - CPPUNIT_TEST_SUITE_END(); + CPPUNIT_TEST_SUITE(XMLParserTest); + CPPUNIT_TEST(testParse_NestedElements); + CPPUNIT_TEST(testParse_ElementInNamespacedElement); + CPPUNIT_TEST(testParse_CharacterData); + CPPUNIT_TEST(testParse_XMLEntity); + CPPUNIT_TEST(testParse_NamespacePrefix); + CPPUNIT_TEST(testParse_UnhandledXML); + CPPUNIT_TEST(testParse_InvalidXML); + CPPUNIT_TEST(testParse_InErrorState); + CPPUNIT_TEST(testParse_Incremental); + CPPUNIT_TEST(testParse_WhitespaceInAttribute); + CPPUNIT_TEST(testParse_AttributeWithoutNamespace); + CPPUNIT_TEST(testParse_AttributeWithNamespace); + CPPUNIT_TEST(testParse_AttributeWithNamespaceNoPrefix); + CPPUNIT_TEST(testParse_BillionLaughs); + CPPUNIT_TEST(testParse_InternalEntity); + //CPPUNIT_TEST(testParse_UndefinedPrefix); + //CPPUNIT_TEST(testParse_UndefinedAttributePrefix); + CPPUNIT_TEST(testParse_AllowCommentsInXML); + CPPUNIT_TEST(testParse_DisallowCommentsInXML); + CPPUNIT_TEST(testParse_Doctype); + CPPUNIT_TEST(testParse_ProcessingInstructions); + CPPUNIT_TEST(testParse_ProcessingPrefixedElement); + CPPUNIT_TEST(testParse_InvalidlyEncodedInput); + CPPUNIT_TEST_SUITE_END(); + + public: + void testParse_NestedElements() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(testling.parse( + "<iq type=\"get\">" + "<query xmlns='jabber:iq:version'/>" + "</iq>")); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), client_.events.size()); + + CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); + CPPUNIT_ASSERT_EQUAL(std::string("iq"), client_.events[0].data); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); + CPPUNIT_ASSERT_EQUAL(std::string("get"), client_.events[0].attributes.getAttribute("type")); + CPPUNIT_ASSERT_EQUAL(std::string(), client_.events[0].ns); + + CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); + CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[1].data); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[1].attributes.getEntries().size()); + CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].ns); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[1].namespaces.size()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[1].namespaces.count("")); + CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].namespaces[""]); + + CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type); + CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[2].data); + CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[2].ns); + + CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[3].type); + CPPUNIT_ASSERT_EQUAL(std::string("iq"), client_.events[3].data); + CPPUNIT_ASSERT_EQUAL(std::string(), client_.events[3].ns); + } + + void testParse_ElementInNamespacedElement() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(testling.parse( + "<query xmlns='jabber:iq:version'>" + "<name>Swift</name>" + "</query>")); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(5), client_.events.size()); + + CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); + CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[0].data); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[0].attributes.getEntries().size()); + CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[0].ns); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].namespaces.size()); + CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[0].namespaces[""]); + + CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); + CPPUNIT_ASSERT_EQUAL(std::string("name"), client_.events[1].data); + CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].ns); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[1].namespaces.size()); + + CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[2].type); + CPPUNIT_ASSERT_EQUAL(std::string("Swift"), client_.events[2].data); + + CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[3].type); + CPPUNIT_ASSERT_EQUAL(std::string("name"), client_.events[3].data); + CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[3].ns); - public: - void testParse_NestedElements() { - ParserType testling(&client_); + CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[4].type); + CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[4].data); + CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[4].ns); + } - CPPUNIT_ASSERT(testling.parse( - "<iq type=\"get\">" - "<query xmlns='jabber:iq:version'/>" - "</iq>")); + void testParse_CharacterData() { + ParserType testling(&client_); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), client_.events.size()); + CPPUNIT_ASSERT(testling.parse("<html>bla<i>bli</i>blo</html>")); - CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); - CPPUNIT_ASSERT_EQUAL(std::string("iq"), client_.events[0].data); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); - CPPUNIT_ASSERT_EQUAL(std::string("get"), client_.events[0].attributes.getAttribute("type")); - CPPUNIT_ASSERT_EQUAL(std::string(), client_.events[0].ns); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(7), client_.events.size()); - CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); - CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[1].data); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[1].attributes.getEntries().size()); - CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].ns); + CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); + CPPUNIT_ASSERT_EQUAL(std::string("html"), client_.events[0].data); - CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type); - CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[2].data); - CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[2].ns); + CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[1].type); + CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[1].data); - CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[3].type); - CPPUNIT_ASSERT_EQUAL(std::string("iq"), client_.events[3].data); - CPPUNIT_ASSERT_EQUAL(std::string(), client_.events[3].ns); - } + CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[2].type); + CPPUNIT_ASSERT_EQUAL(std::string("i"), client_.events[2].data); - void testParse_ElementInNamespacedElement() { - ParserType testling(&client_); + CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[3].type); + CPPUNIT_ASSERT_EQUAL(std::string("bli"), client_.events[3].data); - CPPUNIT_ASSERT(testling.parse( - "<query xmlns='jabber:iq:version'>" - "<name>Swift</name>" - "</query>")); + CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[4].type); + CPPUNIT_ASSERT_EQUAL(std::string("i"), client_.events[4].data); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(5), client_.events.size()); + CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[5].type); + CPPUNIT_ASSERT_EQUAL(std::string("blo"), client_.events[5].data); - CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); - CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[0].data); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[0].attributes.getEntries().size()); - CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[0].ns); + CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[6].type); + CPPUNIT_ASSERT_EQUAL(std::string("html"), client_.events[6].data); + } - CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); - CPPUNIT_ASSERT_EQUAL(std::string("name"), client_.events[1].data); - CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[1].ns); + void testParse_XMLEntity() { + ParserType testling(&client_); - CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[2].type); - CPPUNIT_ASSERT_EQUAL(std::string("Swift"), client_.events[2].data); + CPPUNIT_ASSERT(testling.parse("<html><></html>")); - CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[3].type); - CPPUNIT_ASSERT_EQUAL(std::string("name"), client_.events[3].data); - CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[3].ns); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), client_.events.size()); - CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[4].type); - CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[4].data); - CPPUNIT_ASSERT_EQUAL(std::string("jabber:iq:version"), client_.events[4].ns); - } + CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); + CPPUNIT_ASSERT_EQUAL(std::string("html"), client_.events[0].data); - void testParse_CharacterData() { - ParserType testling(&client_); + CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[1].type); + CPPUNIT_ASSERT_EQUAL(std::string("<"), client_.events[1].data); - CPPUNIT_ASSERT(testling.parse("<html>bla<i>bli</i>blo</html>")); + CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[2].type); + CPPUNIT_ASSERT_EQUAL(std::string(">"), client_.events[2].data); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(7), client_.events.size()); + CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[3].type); + CPPUNIT_ASSERT_EQUAL(std::string("html"), client_.events[3].data); + } - CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); - CPPUNIT_ASSERT_EQUAL(std::string("html"), client_.events[0].data); + void testParse_NamespacePrefix() { + ParserType testling(&client_); - CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[1].type); - CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[1].data); + CPPUNIT_ASSERT(testling.parse("<p:x xmlns:p='bla'><p:y/></p:x>")); - CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[2].type); - CPPUNIT_ASSERT_EQUAL(std::string("i"), client_.events[2].data); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), client_.events.size()); - CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[3].type); - CPPUNIT_ASSERT_EQUAL(std::string("bli"), client_.events[3].data); + CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); + CPPUNIT_ASSERT_EQUAL(std::string("x"), client_.events[0].data); + CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[0].ns); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].namespaces.size()); + CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[0].namespaces["p"]); - CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[4].type); - CPPUNIT_ASSERT_EQUAL(std::string("i"), client_.events[4].data); + CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); + CPPUNIT_ASSERT_EQUAL(std::string("y"), client_.events[1].data); + CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[1].ns); - CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[5].type); - CPPUNIT_ASSERT_EQUAL(std::string("blo"), client_.events[5].data); + CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type); + CPPUNIT_ASSERT_EQUAL(std::string("y"), client_.events[2].data); + CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[2].ns); - CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[6].type); - CPPUNIT_ASSERT_EQUAL(std::string("html"), client_.events[6].data); - } + CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[3].type); + CPPUNIT_ASSERT_EQUAL(std::string("x"), client_.events[3].data); + CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[3].ns); + } - void testParse_XMLEntity() { - ParserType testling(&client_); + void testParse_UnhandledXML() { + ParserType testling(&client_, true); - CPPUNIT_ASSERT(testling.parse("<html><></html>")); + CPPUNIT_ASSERT(testling.parse("<iq><!-- Testing --></iq>")); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), client_.events.size()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events.size()); - CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); - CPPUNIT_ASSERT_EQUAL(std::string("html"), client_.events[0].data); + CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); + CPPUNIT_ASSERT_EQUAL(std::string("iq"), client_.events[0].data); - CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[1].type); - CPPUNIT_ASSERT_EQUAL(std::string("<"), client_.events[1].data); + CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[1].type); + CPPUNIT_ASSERT_EQUAL(std::string("iq"), client_.events[1].data); + } - CPPUNIT_ASSERT_EQUAL(Client::CharacterData, client_.events[2].type); - CPPUNIT_ASSERT_EQUAL(std::string(">"), client_.events[2].data); + void testParse_InvalidXML() { + ParserType testling(&client_); - CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[3].type); - CPPUNIT_ASSERT_EQUAL(std::string("html"), client_.events[3].data); - } + CPPUNIT_ASSERT(!testling.parse("<iq><bla></iq>")); + } - void testParse_NamespacePrefix() { - ParserType testling(&client_); + void testParse_InErrorState() { + ParserType testling(&client_); - CPPUNIT_ASSERT(testling.parse("<p:x xmlns:p='bla'><p:y/></p:x>")); + CPPUNIT_ASSERT(!testling.parse("<iq><bla></iq>")); + CPPUNIT_ASSERT(!testling.parse("<iq/>")); + } - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), client_.events.size()); + void testParse_Incremental() { + ParserType testling(&client_); - CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); - CPPUNIT_ASSERT_EQUAL(std::string("x"), client_.events[0].data); - CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[0].ns); + CPPUNIT_ASSERT(testling.parse("<iq")); + CPPUNIT_ASSERT(testling.parse("></iq>")); - CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); - CPPUNIT_ASSERT_EQUAL(std::string("y"), client_.events[1].data); - CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[1].ns); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events.size()); - CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type); - CPPUNIT_ASSERT_EQUAL(std::string("y"), client_.events[2].data); - CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[2].ns); + CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); + CPPUNIT_ASSERT_EQUAL(std::string("iq"), client_.events[0].data); - CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[3].type); - CPPUNIT_ASSERT_EQUAL(std::string("x"), client_.events[3].data); - CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[3].ns); - } + CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[1].type); + CPPUNIT_ASSERT_EQUAL(std::string("iq"), client_.events[1].data); + } - void testParse_UnhandledXML() { - ParserType testling(&client_); + void testParse_CompleteDocument() { + ParserType testling(&client_); - CPPUNIT_ASSERT(testling.parse("<iq><!-- Testing --></iq>")); + CPPUNIT_ASSERT(!testling.parse("<iq", true)); + CPPUNIT_ASSERT(!testling.parse("<iq>", true)); + CPPUNIT_ASSERT(!testling.parse("<iq><child>foo</child>", true)); + CPPUNIT_ASSERT(testling.parse("<iq><child>foo</child></iq>", true)); + } - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events.size()); + void testParse_WhitespaceInAttribute() { + ParserType testling(&client_); - CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); - CPPUNIT_ASSERT_EQUAL(std::string("iq"), client_.events[0].data); + CPPUNIT_ASSERT(testling.parse( + "<query xmlns='http://www.xmpp.org/extensions/xep-0084.html#ns-data '>")); + CPPUNIT_ASSERT(testling.parse( + "<presence/>")); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), client_.events.size()); + CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); + CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[0].data); + CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); + CPPUNIT_ASSERT_EQUAL(std::string("presence"), client_.events[1].data); + CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type); + CPPUNIT_ASSERT_EQUAL(std::string("presence"), client_.events[2].data); + } - CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[1].type); - CPPUNIT_ASSERT_EQUAL(std::string("iq"), client_.events[1].data); - } + void testParse_AttributeWithoutNamespace() { + ParserType testling(&client_); - void testParse_InvalidXML() { - ParserType testling(&client_); + CPPUNIT_ASSERT(testling.parse( + "<query xmlns='http://swift.im' attr='3'/>")); - CPPUNIT_ASSERT(!testling.parse("<iq><bla></iq>")); - } + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); + CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); + CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); + CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getPrefix()); + } - void testParse_InErrorState() { - ParserType testling(&client_); + void testParse_AttributeWithNamespace() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(testling.parse( + "<query xmlns='http://swift.im' xmlns:f='http://swift.im/f' f:attr='3'/>")); - CPPUNIT_ASSERT(!testling.parse("<iq><bla></iq>")); - CPPUNIT_ASSERT(!testling.parse("<iq/>")); - } + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); + CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); + CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); + CPPUNIT_ASSERT_EQUAL(std::string("f"), client_.events[0].attributes.getEntries()[0].getAttribute().getPrefix()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events[0].namespaces.size()); + CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im"), client_.events[0].namespaces[""]); + CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].namespaces["f"]); + } - void testParse_Incremental() { - ParserType testling(&client_); + void testParse_AttributeWithNamespaceNoPrefix() { + ParserType testling(&client_); - CPPUNIT_ASSERT(testling.parse("<iq")); - CPPUNIT_ASSERT(testling.parse("></iq>")); + CPPUNIT_ASSERT(testling.parse( + "<query xmlns='http://swift.im' xmlns:f='http://swift.im/f' attr='3'/>")); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events.size()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); + CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); + CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); + CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getPrefix()); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events[0].namespaces.size()); + CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im"), client_.events[0].namespaces[""]); + CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].namespaces["f"]); + } - CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); - CPPUNIT_ASSERT_EQUAL(std::string("iq"), client_.events[0].data); + void testParse_BillionLaughs() { + ParserType testling(&client_); - CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[1].type); - CPPUNIT_ASSERT_EQUAL(std::string("iq"), client_.events[1].data); - } - - void testParse_WhitespaceInAttribute() { - ParserType testling(&client_); - - CPPUNIT_ASSERT(testling.parse( - "<query xmlns='http://www.xmpp.org/extensions/xep-0084.html#ns-data '>")); - CPPUNIT_ASSERT(testling.parse( - "<presence/>")); - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), client_.events.size()); - CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); - CPPUNIT_ASSERT_EQUAL(std::string("query"), client_.events[0].data); - CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); - CPPUNIT_ASSERT_EQUAL(std::string("presence"), client_.events[1].data); - CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type); - CPPUNIT_ASSERT_EQUAL(std::string("presence"), client_.events[2].data); - } - - void testParse_AttributeWithoutNamespace() { - ParserType testling(&client_); - - CPPUNIT_ASSERT(testling.parse( - "<query xmlns='http://swift.im' attr='3'/>")); - - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); - CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); - CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); - } - - void testParse_AttributeWithNamespace() { - ParserType testling(&client_); - - CPPUNIT_ASSERT(testling.parse( - "<query xmlns='http://swift.im' xmlns:f='http://swift.im/f' f:attr='3'/>")); - - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); - CPPUNIT_ASSERT_EQUAL(std::string("attr"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); - CPPUNIT_ASSERT_EQUAL(std::string("http://swift.im/f"), client_.events[0].attributes.getEntries()[0].getAttribute().getNamespace()); - } - - void testParse_BillionLaughs() { - ParserType testling(&client_); - - CPPUNIT_ASSERT(!testling.parse( - "<?xml version=\"1.0\"?>" - "<!DOCTYPE lolz [" - " <!ENTITY lol \"lol\">" - " <!ENTITY lol2 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\">" - " <!ENTITY lol3 \"&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;\">" - " <!ENTITY lol4 \"&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;\">" - " <!ENTITY lol5 \"&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;\">" - " <!ENTITY lol6 \"&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;\">" - " <!ENTITY lol7 \"&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;\">" - " <!ENTITY lol8 \"&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;\">" - " <!ENTITY lol9 \"&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;\">" - "]>" - "<lolz>&lol9;</lolz>" - )); - } - - void testParse_InternalEntity() { - ParserType testling(&client_); - - CPPUNIT_ASSERT(!testling.parse("<!DOCTYPE foo [<!ENTITY bar \"Bar\">]><foo>&bar;</foo>")); - } - - void testParse_UndefinedPrefix() { - ParserType testling(&client_); - - CPPUNIT_ASSERT(testling.parse( - "<foo:bar><bla/></foo:bar>")); - - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), client_.events.size()); - - CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); - CPPUNIT_ASSERT_EQUAL(std::string("foo:bar"), client_.events[0].data); - CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].ns); - - CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); - CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[1].data); - CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[1].ns); - - CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type); - CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[2].data); - CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[2].ns); - - CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[3].type); - CPPUNIT_ASSERT_EQUAL(std::string("foo:bar"), client_.events[3].data); - CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[3].ns); - } - - void testParse_UndefinedAttributePrefix() { - ParserType testling(&client_); - - CPPUNIT_ASSERT(testling.parse( - "<foo bar:baz='bla'/>")); - - CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); - CPPUNIT_ASSERT_EQUAL(std::string("bar:baz"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); - } - - private: - class Client : public XMLParserClient { - public: - enum Type { StartElement, EndElement, CharacterData }; - struct Event { - Event( - Type type, - const std::string& data, - const std::string& ns, - const AttributeMap& attributes) - : type(type), data(data), ns(ns), attributes(attributes) {} - Event(Type type, const std::string& data, const std::string& ns = std::string()) - : type(type), data(data), ns(ns) {} - - Type type; - std::string data; - std::string ns; - AttributeMap attributes; - }; - - Client() {} - - virtual void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) { - events.push_back(Event(StartElement, element, ns, attributes)); - } - - virtual void handleEndElement(const std::string& element, const std::string& ns) { - events.push_back(Event(EndElement, element, ns)); - } - - virtual void handleCharacterData(const std::string& data) { - events.push_back(Event(CharacterData, data)); - } - - std::vector<Event> events; - } client_; + CPPUNIT_ASSERT(!testling.parse( + "<?xml version=\"1.0\"?>" + "<!DOCTYPE lolz [" + " <!ENTITY lol \"lol\">" + " <!ENTITY lol2 \"&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;\">" + " <!ENTITY lol3 \"&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;\">" + " <!ENTITY lol4 \"&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;\">" + " <!ENTITY lol5 \"&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;\">" + " <!ENTITY lol6 \"&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;\">" + " <!ENTITY lol7 \"&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;\">" + " <!ENTITY lol8 \"&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;\">" + " <!ENTITY lol9 \"&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;\">" + "]>" + "<lolz>&lol9;</lolz>" + )); + } + + void testParse_InternalEntity() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(!testling.parse("<!DOCTYPE foo [<!ENTITY bar \"Bar\">]><foo>&bar;</foo>")); + } + + void testParse_UndefinedPrefix() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(testling.parse( + "<foo:bar><bla/></foo:bar>")); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), client_.events.size()); + + CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); + CPPUNIT_ASSERT_EQUAL(std::string("foo:bar"), client_.events[0].data); + CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[0].ns); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), client_.events[0].namespaces.size()); + + CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[1].type); + CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[1].data); + CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[1].ns); + + CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[2].type); + CPPUNIT_ASSERT_EQUAL(std::string("bla"), client_.events[2].data); + CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[2].ns); + + CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[3].type); + CPPUNIT_ASSERT_EQUAL(std::string("foo:bar"), client_.events[3].data); + CPPUNIT_ASSERT_EQUAL(std::string(""), client_.events[3].ns); + } + + void testParse_UndefinedAttributePrefix() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(testling.parse("<foo bar:baz='bla'/>")); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), client_.events[0].attributes.getEntries().size()); + CPPUNIT_ASSERT_EQUAL(std::string("bar:baz"), client_.events[0].attributes.getEntries()[0].getAttribute().getName()); + } + + void testParse_AllowCommentsInXML() { + ParserType testling(&client_, true); + + CPPUNIT_ASSERT(testling.parse("<message><!-- Some More Comments Testing --></message>")); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events.size()); + + CPPUNIT_ASSERT_EQUAL(Client::StartElement, client_.events[0].type); + CPPUNIT_ASSERT_EQUAL(std::string("message"), client_.events[0].data); + + CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[1].type); + CPPUNIT_ASSERT_EQUAL(std::string("message"), client_.events[1].data); + } + + void testParse_DisallowCommentsInXML() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(!testling.parse("<message><!-- Some More Comments Testing --></message>")); + } + + void testParse_Doctype() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(!testling.parse("<!DOCTYPE greeting SYSTEM \"hello.dtd\">")); + } + + void testParse_ProcessingInstructions() { + ParserType testling(&client_); + + CPPUNIT_ASSERT(!testling.parse("<?xml-stylesheet type=\"text/xsl\" href=\"Sample.xsl\"?>")); + } + + void testParse_ProcessingPrefixedElement() { + client_.testingStartElementPrefix = true; + ParserType testling(&client_); + + CPPUNIT_ASSERT(testling.parse("<prefix:message xmlns='uri' xmlns:prefix='uriPrefix'/>")); + + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), client_.events.size()); + + CPPUNIT_ASSERT_EQUAL(Client::StartElementPrefix, client_.events[0].type); + CPPUNIT_ASSERT_EQUAL(std::string("message"), client_.events[0].data); + CPPUNIT_ASSERT_EQUAL(std::string("uriPrefix"), client_.events[0].ns); + CPPUNIT_ASSERT_EQUAL(std::string("prefix"), client_.events[0].prefix); + + CPPUNIT_ASSERT_EQUAL(Client::EndElement, client_.events[1].type); + CPPUNIT_ASSERT_EQUAL(std::string("message"), client_.events[1].data); + CPPUNIT_ASSERT_EQUAL(std::string("uriPrefix"), client_.events[1].ns); + } + + void testParse_InvalidlyEncodedInput() { + ParserType testling(&client_); + + // The following input was generated by a fuzzer, and triggered a crash in the LibXML2 parser because + // some types of error (buffer I/O errors, for instance) will not update the error in the parser context, + // and the code used to rely on that error always being set if parsing failed. + // This particular input will trick the parser into believing the encoding is UTF-16LE, which eventually will lead + // to two invalid encodings, followed by an I/O error. The latter will end parsing without updating the + // error in the parsing context, which used to trigger a crash. + testling.parse(std::string("<\0?\0\x80q type='get' id='aab9a'<<query xmlns='jabber:iq:roster'/>\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9b\x9br:i><quq:private'><storage xml s='s'\x00\x10</query></iq>", 271)); + testling.parse("<iq type='get'\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e\x9e to='ad5d8d2b25' ext='ca cs min@wonderland.t' id='aabda'><vCard xmlnr='vcard-temp'/>O/iq>"); + testling.parse("<\xff\xff\xff\x7fype:'get' to='won\x84" "erland.lit' id='aabea'><tuery xmlns='\xd8Vtp://jabber.org/p\x88ot\x8b" "col/disco#info'/>abber.org/protocol/disco#Nnfo'/></iq>"); + } + + private: + class Client : public XMLParserClient { + public: + using NamespaceMap = std::unordered_map<std::string /* prefix */, std::string /* uri */>; + enum Type { StartElement, StartElementPrefix, EndElement, CharacterData, NamespaceDefined }; + struct Event { + Event( + Type type, + const std::string& data, + const std::string& ns, + const std::string& prefix, + const AttributeMap& attributes, + NamespaceMap namespaces) + : type(type), data(data), ns(ns), prefix(prefix), attributes(attributes), namespaces(std::move(namespaces)) {} + Event( + Type type, + const std::string& data, + const std::string& ns, + const AttributeMap& attributes, + NamespaceMap namespaces = {}) + : Event(type, data, ns, {}, attributes, std::move(namespaces)) {} + Event(Type type, const std::string& data, const std::string& ns = std::string()) + : Event(type, data, ns, "", AttributeMap(), NamespaceMap()) {} + + Type type; + std::string data; + std::string ns; + std::string prefix; + AttributeMap attributes; + NamespaceMap namespaces; + }; + + Client() {} + + void handleStartElement(const std::string& element, const std::string& ns, const AttributeMap& attributes) override { + if (testingStartElementPrefix) return; + events.push_back(Event(StartElement, element, ns, attributes, std::move(namespaces_))); + } + + void handleStartElementPrefix(const std::string& prefix, const std::string& uri, const std::string& name, const AttributeMap&) override { + if (!testingStartElementPrefix) return; + events.push_back(Event(StartElementPrefix, name, uri, prefix, AttributeMap(), NamespaceMap())); + } + + void handleEndElement(const std::string& element, const std::string& ns) override { + events.push_back(Event(EndElement, element, ns)); + } + + void handleCharacterData(const std::string& data) override { + events.push_back(Event(CharacterData, data)); + } + + void handleNamespaceDeclaration(const std::string& prefix, const std::string& uri) override { + namespaces_[prefix] = uri; + } + + std::vector<Event> events; + bool testingStartElementPrefix = false; + private: + NamespaceMap namespaces_; + } client_; }; #ifdef HAVE_EXPAT |