Home | History | Annotate | Download | only in xmllite
      1 /*
      2  *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include <iostream>
     12 #include <sstream>
     13 #include <string>
     14 #include "webrtc/libjingle/xmllite/xmlelement.h"
     15 #include "webrtc/base/common.h"
     16 #include "webrtc/base/gunit.h"
     17 #include "webrtc/base/thread.h"
     18 
     19 using buzz::QName;
     20 using buzz::XmlAttr;
     21 using buzz::XmlChild;
     22 using buzz::XmlElement;
     23 
     24 std::ostream& operator<<(std::ostream& os, const QName& name) {
     25   os << name.Namespace() << ":" << name.LocalPart();
     26   return os;
     27 }
     28 
     29 TEST(XmlElementTest, TestConstructors) {
     30   XmlElement elt(QName("google:test", "first"));
     31   EXPECT_EQ("<test:first xmlns:test=\"google:test\"/>", elt.Str());
     32 
     33   XmlElement elt2(QName("google:test", "first"), true);
     34   EXPECT_EQ("<first xmlns=\"google:test\"/>", elt2.Str());
     35 }
     36 
     37 TEST(XmlElementTest, TestAdd) {
     38   XmlElement elt(QName("google:test", "root"), true);
     39   elt.AddElement(new XmlElement(QName("google:test", "first")));
     40   elt.AddElement(new XmlElement(QName("google:test", "nested")), 1);
     41   elt.AddText("nested-value", 2);
     42   elt.AddText("between-", 1);
     43   elt.AddText("value", 1);
     44   elt.AddElement(new XmlElement(QName("google:test", "nested2")), 1);
     45   elt.AddElement(new XmlElement(QName("google:test", "second")));
     46   elt.AddText("init-value", 1);
     47   elt.AddElement(new XmlElement(QName("google:test", "nested3")), 1);
     48   elt.AddText("trailing-value", 1);
     49 
     50   // make sure it looks ok overall
     51   EXPECT_EQ("<root xmlns=\"google:test\">"
     52         "<first><nested>nested-value</nested>between-value<nested2/></first>"
     53         "<second>init-value<nested3/>trailing-value</second></root>",
     54         elt.Str());
     55 
     56   // make sure text was concatenated
     57   XmlChild * pchild =
     58     elt.FirstChild()->AsElement()->FirstChild()->NextChild();
     59   EXPECT_TRUE(pchild->IsText());
     60   EXPECT_EQ("between-value", pchild->AsText()->Text());
     61 }
     62 
     63 TEST(XmlElementTest, TestAttrs) {
     64   XmlElement elt(QName("", "root"));
     65   elt.SetAttr(QName("", "a"), "avalue");
     66   EXPECT_EQ("<root a=\"avalue\"/>", elt.Str());
     67 
     68   elt.SetAttr(QName("", "b"), "bvalue");
     69   EXPECT_EQ("<root a=\"avalue\" b=\"bvalue\"/>", elt.Str());
     70 
     71   elt.SetAttr(QName("", "a"), "avalue2");
     72   EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue\"/>", elt.Str());
     73 
     74   elt.SetAttr(QName("", "b"), "bvalue2");
     75   EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\"/>", elt.Str());
     76 
     77   elt.SetAttr(QName("", "c"), "cvalue");
     78   EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\" c=\"cvalue\"/>", elt.Str());
     79 
     80   XmlAttr * patt = elt.FirstAttr();
     81   EXPECT_EQ(QName("", "a"), patt->Name());
     82   EXPECT_EQ("avalue2", patt->Value());
     83 
     84   patt = patt->NextAttr();
     85   EXPECT_EQ(QName("", "b"), patt->Name());
     86   EXPECT_EQ("bvalue2", patt->Value());
     87 
     88   patt = patt->NextAttr();
     89   EXPECT_EQ(QName("", "c"), patt->Name());
     90   EXPECT_EQ("cvalue", patt->Value());
     91 
     92   patt = patt->NextAttr();
     93   EXPECT_TRUE(NULL == patt);
     94 
     95   EXPECT_TRUE(elt.HasAttr(QName("", "a")));
     96   EXPECT_TRUE(elt.HasAttr(QName("", "b")));
     97   EXPECT_TRUE(elt.HasAttr(QName("", "c")));
     98   EXPECT_FALSE(elt.HasAttr(QName("", "d")));
     99 
    100   elt.SetAttr(QName("", "d"), "dvalue");
    101   EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\" c=\"cvalue\" d=\"dvalue\"/>",
    102       elt.Str());
    103   EXPECT_TRUE(elt.HasAttr(QName("", "d")));
    104 
    105   elt.ClearAttr(QName("", "z"));  // not found, no effect
    106   EXPECT_EQ("<root a=\"avalue2\" b=\"bvalue2\" c=\"cvalue\" d=\"dvalue\"/>",
    107       elt.Str());
    108 
    109   elt.ClearAttr(QName("", "b"));
    110   EXPECT_EQ("<root a=\"avalue2\" c=\"cvalue\" d=\"dvalue\"/>", elt.Str());
    111 
    112   elt.ClearAttr(QName("", "a"));
    113   EXPECT_EQ("<root c=\"cvalue\" d=\"dvalue\"/>", elt.Str());
    114 
    115   elt.ClearAttr(QName("", "d"));
    116   EXPECT_EQ("<root c=\"cvalue\"/>", elt.Str());
    117 
    118   elt.ClearAttr(QName("", "c"));
    119   EXPECT_EQ("<root/>", elt.Str());
    120 }
    121 
    122 TEST(XmlElementTest, TestBodyText) {
    123   XmlElement elt(QName("", "root"));
    124   EXPECT_EQ("", elt.BodyText());
    125 
    126   elt.AddText("body value text");
    127 
    128   EXPECT_EQ("body value text", elt.BodyText());
    129 
    130   elt.ClearChildren();
    131   elt.AddText("more value ");
    132   elt.AddText("text");
    133 
    134   EXPECT_EQ("more value text", elt.BodyText());
    135 
    136   elt.ClearChildren();
    137   elt.AddText("decoy");
    138   elt.AddElement(new XmlElement(QName("", "dummy")));
    139   EXPECT_EQ("", elt.BodyText());
    140 
    141   elt.SetBodyText("replacement");
    142   EXPECT_EQ("replacement", elt.BodyText());
    143 
    144   elt.SetBodyText("");
    145   EXPECT_TRUE(NULL == elt.FirstChild());
    146 
    147   elt.SetBodyText("goodbye");
    148   EXPECT_EQ("goodbye", elt.FirstChild()->AsText()->Text());
    149   EXPECT_EQ("goodbye", elt.BodyText());
    150 }
    151 
    152 TEST(XmlElementTest, TestCopyConstructor) {
    153   XmlElement * element = XmlElement::ForStr(
    154       "<root xmlns='test-foo'>This is a <em a='avalue' b='bvalue'>"
    155       "little <b>little</b></em> test</root>");
    156 
    157   XmlElement * pelCopy = new XmlElement(*element);
    158   EXPECT_EQ("<root xmlns=\"test-foo\">This is a <em a=\"avalue\" b=\"bvalue\">"
    159       "little <b>little</b></em> test</root>", pelCopy->Str());
    160   delete pelCopy;
    161 
    162   pelCopy = new XmlElement(*(element->FirstChild()->NextChild()->AsElement()));
    163   EXPECT_EQ("<foo:em a=\"avalue\" b=\"bvalue\" xmlns:foo=\"test-foo\">"
    164       "little <foo:b>little</foo:b></foo:em>", pelCopy->Str());
    165 
    166   XmlAttr * patt = pelCopy->FirstAttr();
    167   EXPECT_EQ(QName("", "a"), patt->Name());
    168   EXPECT_EQ("avalue", patt->Value());
    169 
    170   patt = patt->NextAttr();
    171   EXPECT_EQ(QName("", "b"), patt->Name());
    172   EXPECT_EQ("bvalue", patt->Value());
    173 
    174   patt = patt->NextAttr();
    175   EXPECT_TRUE(NULL == patt);
    176   delete pelCopy;
    177   delete element;
    178 }
    179 
    180 TEST(XmlElementTest, TestNameSearch) {
    181   XmlElement * element = XmlElement::ForStr(
    182     "<root xmlns='test-foo'>"
    183       "<firstname>George</firstname>"
    184       "<middlename>X.</middlename>"
    185       "some text"
    186       "<lastname>Harrison</lastname>"
    187       "<firstname>John</firstname>"
    188       "<middlename>Y.</middlename>"
    189       "<lastname>Lennon</lastname>"
    190     "</root>");
    191   EXPECT_TRUE(NULL ==
    192       element->FirstNamed(QName("", "firstname")));
    193   EXPECT_EQ(element->FirstChild(),
    194       element->FirstNamed(QName("test-foo", "firstname")));
    195   EXPECT_EQ(element->FirstChild()->NextChild(),
    196       element->FirstNamed(QName("test-foo", "middlename")));
    197   EXPECT_EQ(element->FirstElement()->NextElement(),
    198       element->FirstNamed(QName("test-foo", "middlename")));
    199   EXPECT_EQ("Harrison",
    200       element->TextNamed(QName("test-foo", "lastname")));
    201   EXPECT_EQ(element->FirstElement()->NextElement()->NextElement(),
    202       element->FirstNamed(QName("test-foo", "lastname")));
    203   EXPECT_EQ("John", element->FirstNamed(QName("test-foo", "firstname"))->
    204       NextNamed(QName("test-foo", "firstname"))->BodyText());
    205   EXPECT_EQ("Y.", element->FirstNamed(QName("test-foo", "middlename"))->
    206       NextNamed(QName("test-foo", "middlename"))->BodyText());
    207   EXPECT_EQ("Lennon", element->FirstNamed(QName("test-foo", "lastname"))->
    208       NextNamed(QName("test-foo", "lastname"))->BodyText());
    209   EXPECT_TRUE(NULL == element->FirstNamed(QName("test-foo", "firstname"))->
    210       NextNamed(QName("test-foo", "firstname"))->
    211       NextNamed(QName("test-foo", "firstname")));
    212 
    213   delete element;
    214 }
    215 
    216 class XmlElementCreatorThread : public rtc::Thread {
    217  public:
    218   XmlElementCreatorThread(int count, buzz::QName qname) :
    219       count_(count), qname_(qname) {}
    220 
    221   virtual ~XmlElementCreatorThread() {
    222     Stop();
    223   }
    224 
    225   virtual void Run() {
    226     std::vector<buzz::XmlElement*> elems;
    227     for (int i = 0; i < count_; i++) {
    228       elems.push_back(new XmlElement(qname_));
    229     }
    230     for (int i = 0; i < count_; i++) {
    231       delete elems[i];
    232     }
    233   }
    234 
    235  private:
    236   int count_;
    237   buzz::QName qname_;
    238 };
    239 
    240 // If XmlElement creation and destruction isn't thread safe,
    241 // this test should crash.
    242 TEST(XmlElementTest, TestMultithread) {
    243   int thread_count = 2;  // Was 100, but that's too slow.
    244   int elem_count = 100;  // Was 100000, but that's too slow.
    245   buzz::QName qname("foo", "bar");
    246 
    247   std::vector<rtc::Thread*> threads;
    248   for (int i = 0; i < thread_count; i++) {
    249     threads.push_back(
    250         new XmlElementCreatorThread(elem_count, qname));
    251     threads[i]->Start();
    252   }
    253 
    254   for (int i = 0; i < thread_count; i++) {
    255     threads[i]->Stop();
    256     delete threads[i];
    257   }
    258 }
    259