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