diff libpurple/tests/test_xmlnode.c @ 32498:114a98da1a5f

xmlnode: Fix some brokeness in xmlnode serialization with prefixed elements. Basically we were treating node->xmlns as the default namespace, but that isn't the case with prefexed elements. In our serialization, I believe we were adding an extraneous xmlns='' to a prefixed element, which changes the (default) namespace for its children. (It's been a bit too long with this in my tree, so I've forgotten the exact details)
author Paul Aurich <paul@darkrain42.org>
date Sun, 04 Sep 2011 18:52:18 +0000
parents c8f91310bfbf
children 8d3b5853b017
line wrap: on
line diff
--- a/libpurple/tests/test_xmlnode.c	Sun Sep 04 18:45:51 2011 +0000
+++ b/libpurple/tests/test_xmlnode.c	Sun Sep 04 18:52:18 2011 +0000
@@ -21,6 +21,66 @@
 }
 END_TEST
 
+#define check_doc_structure(x) { \
+	xmlnode *ping, *child1, *child2; \
+	fail_if(x == NULL, "Failed to parse document"); \
+	ping = xmlnode_get_child(x, "ping"); \
+	fail_if(ping == NULL, "Failed to find 'ping' child"); \
+	child1 = xmlnode_get_child(ping, "child1"); \
+	fail_if(child1 == NULL, "Failed to find 'child1'"); \
+	child2 = xmlnode_get_child(child1, "child2"); \
+	fail_if(child2 == NULL, "Failed to find 'child2'"); \
+	xmlnode_new_child(child2, "a"); \
+	\
+	assert_string_equal("jabber:client", xmlnode_get_namespace(x)); \
+	/* NOTE: xmlnode_get_namespace() returns the namespace of the element, not the
+	 * current default namespace.  See http://www.w3.org/TR/xml-names/#defaulting and
+	 * http://www.w3.org/TR/xml-names/#dt-defaultNS.
+	 */ \
+	assert_string_equal("urn:xmpp:ping", xmlnode_get_namespace(ping)); \
+	assert_string_equal("jabber:client", xmlnode_get_namespace(child1)); \
+	assert_string_equal("urn:xmpp:ping", xmlnode_get_namespace(child2)); \
+	/*
+	 * This fails (well, actually crashes [the ns is NULL]) unless
+	 * xmlnode_new_child() actually sets the element namespace.
+	assert_string_equal("jabber:client", xmlnode_get_namespace(xmlnode_get_child(child2, "a")));
+	 */ \
+	\
+	assert_string_equal("jabber:client", xmlnode_get_default_namespace(x)); \
+	assert_string_equal("jabber:client", xmlnode_get_default_namespace(ping)); \
+	assert_string_equal("jabber:client", xmlnode_get_default_namespace(child1)); \
+	assert_string_equal("jabber:client", xmlnode_get_default_namespace(child2)); \
+}
+
+START_TEST(test_xmlnode_prefixes)
+{
+	const char *xml_doc =
+		"<iq type='get' xmlns='jabber:client' xmlns:ping='urn:xmpp:ping'>"
+			"<ping:ping>"
+				"<child1>"
+					"<ping:child2></ping:child2>" /* xmlns='jabber:child' */
+				"</child1>"
+			"</ping:ping>"
+		"</iq>";
+	char *str;
+	xmlnode *xml, *reparsed;
+
+	xml = xmlnode_from_str(xml_doc, -1);
+	check_doc_structure(xml);
+
+	/* Check that xmlnode_from_str(xmlnode_to_str(xml, NULL), -1) is idempotent. */
+	str = xmlnode_to_str(xml, NULL);
+	fail_if(str == NULL, "Failed to serialize XMLnode");
+	reparsed = xmlnode_from_str(str, -1);
+	fail_if(reparsed == NULL, "Failed to reparse xml document");
+	check_doc_structure(reparsed);
+
+	g_free(str);
+	xmlnode_free(xml);
+	xmlnode_free(reparsed);
+}
+END_TEST
+
 Suite *
 xmlnode_suite(void)
 {
@@ -28,6 +88,8 @@
 
 	TCase *tc = tcase_create("xmlnode");
 	tcase_add_test(tc, test_xmlnode_billion_laughs_attack);
+	tcase_add_test(tc, test_xmlnode_prefixes);
+
 	suite_add_tcase(s, tc);
 
 	return s;