summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swiften/Parser/UnitTest/XMLParserTest.cpp')
-rw-r--r--Swiften/Parser/UnitTest/XMLParserTest.cpp696
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>&lt;&gt;</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>&lt;&gt;</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