Index: third_party/xmllite/xmlelement_unittest.cc |
diff --git a/third_party/xmllite/xmlelement_unittest.cc b/third_party/xmllite/xmlelement_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3efbb531eec094dd6ab850ae6a11a07b019e573f |
--- /dev/null |
+++ b/third_party/xmllite/xmlelement_unittest.cc |
@@ -0,0 +1,252 @@ |
+// Copyright 2004 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include <iostream> |
+#include <sstream> |
+#include <string> |
+#include "third_party/xmllite/xmlelement.h" |
+#include "webrtc/base/common.h" |
+#include "webrtc/base/gunit.h" |
+#include "webrtc/base/thread.h" |
+ |
+using buzz::QName; |
+using buzz::XmlAttr; |
+using buzz::XmlChild; |
+using buzz::XmlElement; |
+ |
+std::ostream& operator<<(std::ostream& os, const QName& name) { |
+ os << name.Namespace() << ":" << name.LocalPart(); |
+ return os; |
+} |
+ |
+TEST(XmlElementTest, TestConstructors) { |
+ XmlElement elt(QName("google:test", "first")); |
+ EXPECT_EQ("<test:first xmlns:test=\"google:test\"/>", elt.Str()); |
+ |
+ XmlElement elt2(QName("google:test", "first"), true); |
+ EXPECT_EQ("<first xmlns=\"google:test\"/>", elt2.Str()); |
+} |
+ |
+TEST(XmlElementTest, TestAdd) { |
+ XmlElement elt(QName("google:test", "root"), true); |
+ elt.AddElement(new XmlElement(QName("google:test", "first"))); |
+ elt.AddElement(new XmlElement(QName("google:test", "nested")), 1); |
+ elt.AddText("nested-value", 2); |
+ elt.AddText("between-", 1); |
+ elt.AddText("value", 1); |
+ elt.AddElement(new XmlElement(QName("google:test", "nested2")), 1); |
+ elt.AddElement(new XmlElement(QName("google:test", "second"))); |
+ elt.AddText("init-value", 1); |
+ elt.AddElement(new XmlElement(QName("google:test", "nested3")), 1); |
+ elt.AddText("trailing-value", 1); |
+ |
+ // make sure it looks ok overall |
+ EXPECT_EQ("<root xmlns=\"google:test\">" |
+ "<first><nested>nested-value</nested>between-value<nested2/></first>" |
+ "<second>init-value<nested3/>trailing-value</second></root>", |
+ elt.Str()); |
+ |
+ // make sure text was concatenated |
+ XmlChild * pchild = |
+ elt.FirstChild()->AsElement()->FirstChild()->NextChild(); |
+ EXPECT_TRUE(pchild->IsText()); |
+ EXPECT_EQ("between-value", pchild->AsText()->Text()); |
+} |
+ |
+TEST(XmlElementTest, TestAttrs) { |
+ XmlElement elt(QName("", "root")); |
+ elt.SetAttr(QName("", "a"), "avalue"); |
+ EXPECT_EQ("<root a=\"avalue\"/>", elt.Str()); |
+ |
+ elt.SetAttr(QName("", "b"), "bvalue"); |
+ EXPECT_EQ("<root a=\"avalue\" b=\"bvalue\"/>", elt.Str()); |
+ |
+ elt.SetAttr(QName("", "a"), "avalue2"); |
+ EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue\"/>", elt.Str()); |
+ |
+ elt.SetAttr(QName("", "b"), "bvalue2"); |
+ EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\"/>", elt.Str()); |
+ |
+ elt.SetAttr(QName("", "c"), "cvalue"); |
+ EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\" c=\"cvalue\"/>", elt.Str()); |
+ |
+ XmlAttr * patt = elt.FirstAttr(); |
+ EXPECT_EQ(QName("", "a"), patt->Name()); |
+ EXPECT_EQ("avalue2", patt->Value()); |
+ |
+ patt = patt->NextAttr(); |
+ EXPECT_EQ(QName("", "b"), patt->Name()); |
+ EXPECT_EQ("bvalue2", patt->Value()); |
+ |
+ patt = patt->NextAttr(); |
+ EXPECT_EQ(QName("", "c"), patt->Name()); |
+ EXPECT_EQ("cvalue", patt->Value()); |
+ |
+ patt = patt->NextAttr(); |
+ EXPECT_TRUE(NULL == patt); |
+ |
+ EXPECT_TRUE(elt.HasAttr(QName("", "a"))); |
+ EXPECT_TRUE(elt.HasAttr(QName("", "b"))); |
+ EXPECT_TRUE(elt.HasAttr(QName("", "c"))); |
+ EXPECT_FALSE(elt.HasAttr(QName("", "d"))); |
+ |
+ elt.SetAttr(QName("", "d"), "dvalue"); |
+ EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\" c=\"cvalue\" d=\"dvalue\"/>", |
+ elt.Str()); |
+ EXPECT_TRUE(elt.HasAttr(QName("", "d"))); |
+ |
+ elt.ClearAttr(QName("", "z")); // not found, no effect |
+ EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\" c=\"cvalue\" d=\"dvalue\"/>", |
+ elt.Str()); |
+ |
+ elt.ClearAttr(QName("", "b")); |
+ EXPECT_EQ("<root a=\"avalue2\" c=\"cvalue\" d=\"dvalue\"/>", elt.Str()); |
+ |
+ elt.ClearAttr(QName("", "a")); |
+ EXPECT_EQ("<root c=\"cvalue\" d=\"dvalue\"/>", elt.Str()); |
+ |
+ elt.ClearAttr(QName("", "d")); |
+ EXPECT_EQ("<root c=\"cvalue\"/>", elt.Str()); |
+ |
+ elt.ClearAttr(QName("", "c")); |
+ EXPECT_EQ("<root/>", elt.Str()); |
+} |
+ |
+TEST(XmlElementTest, TestBodyText) { |
+ XmlElement elt(QName("", "root")); |
+ EXPECT_EQ("", elt.BodyText()); |
+ |
+ elt.AddText("body value text"); |
+ |
+ EXPECT_EQ("body value text", elt.BodyText()); |
+ |
+ elt.ClearChildren(); |
+ elt.AddText("more value "); |
+ elt.AddText("text"); |
+ |
+ EXPECT_EQ("more value text", elt.BodyText()); |
+ |
+ elt.ClearChildren(); |
+ elt.AddText("decoy"); |
+ elt.AddElement(new XmlElement(QName("", "dummy"))); |
+ EXPECT_EQ("", elt.BodyText()); |
+ |
+ elt.SetBodyText("replacement"); |
+ EXPECT_EQ("replacement", elt.BodyText()); |
+ |
+ elt.SetBodyText(""); |
+ EXPECT_TRUE(NULL == elt.FirstChild()); |
+ |
+ elt.SetBodyText("goodbye"); |
+ EXPECT_EQ("goodbye", elt.FirstChild()->AsText()->Text()); |
+ EXPECT_EQ("goodbye", elt.BodyText()); |
+} |
+ |
+TEST(XmlElementTest, TestCopyConstructor) { |
+ XmlElement * element = XmlElement::ForStr( |
+ "<root xmlns='test-foo'>This is a <em a='avalue' b='bvalue'>" |
+ "little <b>little</b></em> test</root>"); |
+ |
+ XmlElement * pelCopy = new XmlElement(*element); |
+ EXPECT_EQ("<root xmlns=\"test-foo\">This is a <em a=\"avalue\" b=\"bvalue\">" |
+ "little <b>little</b></em> test</root>", pelCopy->Str()); |
+ delete pelCopy; |
+ |
+ pelCopy = new XmlElement(*(element->FirstChild()->NextChild()->AsElement())); |
+ EXPECT_EQ("<foo:em a=\"avalue\" b=\"bvalue\" xmlns:foo=\"test-foo\">" |
+ "little <foo:b>little</foo:b></foo:em>", pelCopy->Str()); |
+ |
+ XmlAttr * patt = pelCopy->FirstAttr(); |
+ EXPECT_EQ(QName("", "a"), patt->Name()); |
+ EXPECT_EQ("avalue", patt->Value()); |
+ |
+ patt = patt->NextAttr(); |
+ EXPECT_EQ(QName("", "b"), patt->Name()); |
+ EXPECT_EQ("bvalue", patt->Value()); |
+ |
+ patt = patt->NextAttr(); |
+ EXPECT_TRUE(NULL == patt); |
+ delete pelCopy; |
+ delete element; |
+} |
+ |
+TEST(XmlElementTest, TestNameSearch) { |
+ XmlElement * element = XmlElement::ForStr( |
+ "<root xmlns='test-foo'>" |
+ "<firstname>George</firstname>" |
+ "<middlename>X.</middlename>" |
+ "some text" |
+ "<lastname>Harrison</lastname>" |
+ "<firstname>John</firstname>" |
+ "<middlename>Y.</middlename>" |
+ "<lastname>Lennon</lastname>" |
+ "</root>"); |
+ EXPECT_TRUE(NULL == |
+ element->FirstNamed(QName("", "firstname"))); |
+ EXPECT_EQ(element->FirstChild(), |
+ element->FirstNamed(QName("test-foo", "firstname"))); |
+ EXPECT_EQ(element->FirstChild()->NextChild(), |
+ element->FirstNamed(QName("test-foo", "middlename"))); |
+ EXPECT_EQ(element->FirstElement()->NextElement(), |
+ element->FirstNamed(QName("test-foo", "middlename"))); |
+ EXPECT_EQ("Harrison", |
+ element->TextNamed(QName("test-foo", "lastname"))); |
+ EXPECT_EQ(element->FirstElement()->NextElement()->NextElement(), |
+ element->FirstNamed(QName("test-foo", "lastname"))); |
+ EXPECT_EQ("John", element->FirstNamed(QName("test-foo", "firstname"))-> |
+ NextNamed(QName("test-foo", "firstname"))->BodyText()); |
+ EXPECT_EQ("Y.", element->FirstNamed(QName("test-foo", "middlename"))-> |
+ NextNamed(QName("test-foo", "middlename"))->BodyText()); |
+ EXPECT_EQ("Lennon", element->FirstNamed(QName("test-foo", "lastname"))-> |
+ NextNamed(QName("test-foo", "lastname"))->BodyText()); |
+ EXPECT_TRUE(NULL == element->FirstNamed(QName("test-foo", "firstname"))-> |
+ NextNamed(QName("test-foo", "firstname"))-> |
+ NextNamed(QName("test-foo", "firstname"))); |
+ |
+ delete element; |
+} |
+ |
+class XmlElementCreatorThread : public rtc::Thread { |
+ public: |
+ XmlElementCreatorThread(int count, buzz::QName qname) : |
+ count_(count), qname_(qname) {} |
+ |
+ virtual ~XmlElementCreatorThread() { |
+ Stop(); |
+ } |
+ |
+ virtual void Run() { |
+ std::vector<buzz::XmlElement*> elems; |
+ for (int i = 0; i < count_; i++) { |
+ elems.push_back(new XmlElement(qname_)); |
+ } |
+ for (int i = 0; i < count_; i++) { |
+ delete elems[i]; |
+ } |
+ } |
+ |
+ private: |
+ int count_; |
+ buzz::QName qname_; |
+}; |
+ |
+// If XmlElement creation and destruction isn't thread safe, |
+// this test should crash. |
+TEST(XmlElementTest, TestMultithread) { |
+ int thread_count = 2; // Was 100, but that's too slow. |
+ int elem_count = 100; // Was 100000, but that's too slow. |
+ buzz::QName qname("foo", "bar"); |
+ |
+ std::vector<rtc::Thread*> threads; |
+ for (int i = 0; i < thread_count; i++) { |
+ threads.push_back( |
+ new XmlElementCreatorThread(elem_count, qname)); |
+ threads[i]->Start(); |
+ } |
+ |
+ for (int i = 0; i < thread_count; i++) { |
+ threads[i]->Stop(); |
+ delete threads[i]; |
+ } |
+} |