/* * libjingle * Copyright 2004, Google Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include "talk/base/common.h" #include "talk/base/gunit.h" #include "talk/base/thread.h" #include "talk/xmllite/xmlelement.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("", elt.Str()); XmlElement elt2(QName("google:test", "first"), true); EXPECT_EQ("", 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("" "nested-valuebetween-value" "init-valuetrailing-value", 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("", elt.Str()); elt.SetAttr(QName("", "b"), "bvalue"); EXPECT_EQ("", elt.Str()); elt.SetAttr(QName("", "a"), "avalue2"); EXPECT_EQ("", elt.Str()); elt.SetAttr(QName("", "b"), "bvalue2"); EXPECT_EQ("", elt.Str()); elt.SetAttr(QName("", "c"), "cvalue"); EXPECT_EQ("", 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("", elt.Str()); EXPECT_TRUE(elt.HasAttr(QName("", "d"))); elt.ClearAttr(QName("", "z")); // not found, no effect EXPECT_EQ("", elt.Str()); elt.ClearAttr(QName("", "b")); EXPECT_EQ("", elt.Str()); elt.ClearAttr(QName("", "a")); EXPECT_EQ("", elt.Str()); elt.ClearAttr(QName("", "d")); EXPECT_EQ("", elt.Str()); elt.ClearAttr(QName("", "c")); EXPECT_EQ("", 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( "This is a " "little little test"); XmlElement * pelCopy = new XmlElement(*element); EXPECT_EQ("This is a " "little little test", pelCopy->Str()); delete pelCopy; pelCopy = new XmlElement(*(element->FirstChild()->NextChild()->AsElement())); EXPECT_EQ("" "little little", 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( "" "George" "X." "some text" "Harrison" "John" "Y." "Lennon" ""); 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 talk_base::Thread { public: XmlElementCreatorThread(int count, buzz::QName qname) : count_(count), qname_(qname) {} virtual ~XmlElementCreatorThread() { Stop(); } virtual void Run() { std::vector 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 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]; } }