1 /* 2 * libjingle 3 * Copyright 2004, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <iostream> 29 #include <sstream> 30 #include <string> 31 #include "talk/xmllite/qname.h" 32 #include "talk/xmllite/xmlparser.h" 33 #include "webrtc/base/common.h" 34 #include "webrtc/base/gunit.h" 35 36 using buzz::QName; 37 using buzz::XmlParser; 38 using buzz::XmlParseContext; 39 using buzz::XmlParseHandler; 40 41 class XmlParserTestHandler : public XmlParseHandler { 42 public: 43 virtual void StartElement(XmlParseContext * pctx, 44 const char * name, const char ** atts) { 45 ss_ << "START (" << pctx->ResolveQName(name, false).Merged(); 46 while (*atts) { 47 ss_ << ", " << pctx->ResolveQName(*atts, true).Merged() 48 << "='" << *(atts+1) << "'"; 49 atts += 2; 50 } 51 ss_ << ") "; 52 } 53 virtual void EndElement(XmlParseContext * pctx, const char * name) { 54 RTC_UNUSED(pctx); 55 RTC_UNUSED(name); 56 ss_ << "END "; 57 } 58 virtual void CharacterData(XmlParseContext * pctx, 59 const char * text, int len) { 60 RTC_UNUSED(pctx); 61 ss_ << "TEXT (" << std::string(text, len) << ") "; 62 } 63 virtual void Error(XmlParseContext * pctx, XML_Error code) { 64 RTC_UNUSED(pctx); 65 ss_ << "ERROR (" << static_cast<int>(code) << ") "; 66 } 67 virtual ~XmlParserTestHandler() { 68 } 69 70 std::string Str() { 71 return ss_.str(); 72 } 73 74 std::string StrClear() { 75 std::string result = ss_.str(); 76 ss_.str(""); 77 return result; 78 } 79 80 private: 81 std::stringstream ss_; 82 }; 83 84 85 TEST(XmlParserTest, TestTrivial) { 86 XmlParserTestHandler handler; 87 XmlParser::ParseXml(&handler, "<testing/>"); 88 EXPECT_EQ("START (testing) END ", handler.Str()); 89 } 90 91 TEST(XmlParserTest, TestAttributes) { 92 { 93 XmlParserTestHandler handler; 94 XmlParser::ParseXml(&handler, "<testing a='b'/>"); 95 EXPECT_EQ("START (testing, a='b') END ", handler.Str()); 96 } 97 { 98 XmlParserTestHandler handler; 99 XmlParser::ParseXml(&handler, "<testing e='' long='some text'/>"); 100 EXPECT_EQ("START (testing, e='', long='some text') END ", handler.Str()); 101 } 102 } 103 104 TEST(XmlParserTest, TestNesting) { 105 { 106 XmlParserTestHandler handler; 107 XmlParser::ParseXml(&handler, 108 "<top><first/><second><third></third></second></top>"); 109 EXPECT_EQ("START (top) START (first) END START (second) START (third) " 110 "END END END ", handler.Str()); 111 } 112 { 113 XmlParserTestHandler handler; 114 XmlParser::ParseXml(&handler, "<top><fifth><deeper><and><deeper/></and>" 115 "<sibling><leaf/></sibling></deeper></fifth><first/><second>" 116 "<third></third></second></top>"); 117 EXPECT_EQ("START (top) START (fifth) START (deeper) START (and) START " 118 "(deeper) END END START (sibling) START (leaf) END END END " 119 "END START (first) END START (second) START (third) END END END ", 120 handler.Str()); 121 } 122 } 123 124 TEST(XmlParserTest, TestXmlDecl) { 125 { 126 XmlParserTestHandler handler; 127 XmlParser::ParseXml(&handler, "<?xml version=\"1.0\"?><testing/>"); 128 EXPECT_EQ("START (testing) END ", handler.Str()); 129 } 130 { 131 XmlParserTestHandler handler; 132 XmlParser::ParseXml(&handler, 133 "<?xml version=\"1.0\" encoding=\"utf-8\"?><testing/>"); 134 EXPECT_EQ("START (testing) END ", handler.Str()); 135 } 136 { 137 XmlParserTestHandler handler; 138 XmlParser::ParseXml(&handler, 139 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" 140 "<testing/>"); 141 EXPECT_EQ("START (testing) END ", handler.Str()); 142 } 143 } 144 145 TEST(XmlParserTest, TestNamespace) { 146 { 147 XmlParserTestHandler handler; 148 XmlParser::ParseXml(&handler, "<top xmlns='my-namespace' a='b'/>"); 149 EXPECT_EQ("START (my-namespace:top, xmlns='my-namespace', a='b') END ", 150 handler.Str()); 151 } 152 { 153 XmlParserTestHandler handler; 154 XmlParser::ParseXml(&handler, "<foo:top xmlns:foo='my-namespace' " 155 "a='b' foo:c='d'/>"); 156 EXPECT_EQ("START (my-namespace:top, " 157 "http://www.w3.org/2000/xmlns/:foo='my-namespace', " 158 "a='b', my-namespace:c='d') END ", handler.Str()); 159 } 160 { 161 XmlParserTestHandler handler; 162 XmlParser::ParseXml(&handler, "<top><nested xmlns='my-namespace'><leaf/>" 163 "</nested><sibling/></top>"); 164 EXPECT_EQ("START (top) START (my-namespace:nested, xmlns='my-namespace') " 165 "START (my-namespace:leaf) END END START (sibling) END END ", 166 handler.Str()); 167 } 168 } 169 170 TEST(XmlParserTest, TestIncremental) { 171 XmlParserTestHandler handler; 172 XmlParser parser(&handler); 173 std::string fragment; 174 175 fragment = "<stream:stream"; 176 parser.Parse(fragment.c_str(), fragment.length(), false); 177 EXPECT_EQ("", handler.StrClear()); 178 179 fragment = " id=\"abcdefg\" xmlns=\""; 180 parser.Parse(fragment.c_str(), fragment.length(), false); 181 EXPECT_EQ("", handler.StrClear()); 182 183 fragment = "j:c\" xmlns:stream='hm"; 184 parser.Parse(fragment.c_str(), fragment.length(), false); 185 EXPECT_EQ("", handler.StrClear()); 186 187 fragment = "ph'><test"; 188 parser.Parse(fragment.c_str(), fragment.length(), false); 189 EXPECT_EQ("START (hmph:stream, id='abcdefg', xmlns='j:c', " 190 "http://www.w3.org/2000/xmlns/:stream='hmph') ", handler.StrClear()); 191 192 fragment = "ing/><again/>abracad"; 193 parser.Parse(fragment.c_str(), fragment.length(), false); 194 EXPECT_EQ("START (j:c:testing) END START (j:c:again) END TEXT (abracad) ", 195 handler.StrClear()); 196 197 fragment = "abra</stream:"; 198 parser.Parse(fragment.c_str(), fragment.length(), false); 199 EXPECT_EQ("TEXT (abra) ", handler.StrClear()); 200 201 fragment = "stream>"; 202 parser.Parse(fragment.c_str(), fragment.length(), false); 203 EXPECT_EQ("END ", handler.StrClear()); 204 } 205 206 TEST(XmlParserTest, TestReset) { 207 { 208 XmlParserTestHandler handler; 209 XmlParser parser(&handler); 210 std::string fragment; 211 212 fragment = "<top><first/><second><third></third>"; 213 parser.Parse(fragment.c_str(), fragment.length(), false); 214 EXPECT_EQ("START (top) START (first) END START (second) START (third) END ", 215 handler.StrClear()); 216 217 parser.Reset(); 218 fragment = "<tip><first/><second><third></third>"; 219 parser.Parse(fragment.c_str(), fragment.length(), false); 220 EXPECT_EQ("START (tip) START (first) END START (second) START (third) END ", 221 handler.StrClear()); 222 } 223 { 224 XmlParserTestHandler handler; 225 XmlParser parser(&handler); 226 std::string fragment; 227 228 fragment = "<top xmlns='m'>"; 229 parser.Parse(fragment.c_str(), fragment.length(), false); 230 EXPECT_EQ("START (m:top, xmlns='m') ", handler.StrClear()); 231 232 fragment = "<testing/><frag"; 233 parser.Parse(fragment.c_str(), fragment.length(), false); 234 EXPECT_EQ("START (m:testing) END ", handler.StrClear()); 235 236 parser.Reset(); 237 fragment = "<testing><fragment/"; 238 parser.Parse(fragment.c_str(), fragment.length(), false); 239 EXPECT_EQ("START (testing) ", handler.StrClear()); 240 241 fragment = ">"; 242 parser.Parse(fragment.c_str(), fragment.length(), false); 243 EXPECT_EQ("START (fragment) END ", handler.StrClear()); 244 } 245 } 246 247 TEST(XmlParserTest, TestError) { 248 { 249 XmlParserTestHandler handler; 250 XmlParser::ParseXml(&handler, "junk"); 251 EXPECT_EQ("ERROR (2) ", handler.Str()); 252 } 253 { 254 XmlParserTestHandler handler; 255 XmlParser::ParseXml(&handler, "<top/> garbage "); 256 EXPECT_EQ("START (top) END ERROR (9) ", handler.Str()); 257 } 258 { 259 XmlParserTestHandler handler; 260 XmlParser::ParseXml(&handler, "<-hm->"); 261 EXPECT_EQ("ERROR (4) ", handler.Str()); 262 } 263 { 264 XmlParserTestHandler handler; 265 XmlParser::ParseXml(&handler, "<hello>&foobar;</hello>"); 266 EXPECT_EQ("START (hello) ERROR (11) ", handler.Str()); 267 } 268 { 269 XmlParserTestHandler handler; 270 XmlParser::ParseXml(&handler, 271 "<!DOCTYPE HTML PUBLIC \"foobar\" \"barfoo\">"); 272 EXPECT_EQ("ERROR (3) ", handler.Str()); 273 } 274 { 275 // XmlParser requires utf-8 276 XmlParserTestHandler handler; 277 XmlParser::ParseXml(&handler, 278 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><test/>"); 279 EXPECT_EQ("ERROR (19) ", handler.Str()); 280 } 281 { 282 // XmlParser requires version 1.0 283 XmlParserTestHandler handler; 284 XmlParser::ParseXml(&handler, 285 "<?xml version=\"2.0\"?><test/>"); 286 EXPECT_EQ("ERROR (2) ", handler.Str()); 287 } 288 { 289 // XmlParser requires standalone documents 290 XmlParserTestHandler handler; 291 XmlParser::ParseXml(&handler, 292 "<?xml version=\"1.0\" standalone=\"no\"?><test/>"); 293 EXPECT_EQ("ERROR (2) ", handler.Str()); 294 } 295 { 296 // XmlParser doesn't like empty namespace URIs 297 XmlParserTestHandler handler; 298 XmlParser::ParseXml(&handler, 299 "<test xmlns:foo='' foo:bar='huh?'>"); 300 EXPECT_EQ("ERROR (2) ", handler.Str()); 301 } 302 } 303