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/qname.h"
15#include "webrtc/libjingle/xmllite/xmlparser.h"
16#include "webrtc/base/common.h"
17#include "webrtc/base/gunit.h"
18
19using buzz::QName;
20using buzz::XmlParser;
21using buzz::XmlParseContext;
22using buzz::XmlParseHandler;
23
24class XmlParserTestHandler : public XmlParseHandler {
25 public:
26  virtual void StartElement(XmlParseContext * pctx,
27                            const char * name, const char ** atts) {
28    ss_ << "START (" << pctx->ResolveQName(name, false).Merged();
29    while (*atts) {
30      ss_ << ", " << pctx->ResolveQName(*atts, true).Merged()
31          << "='" << *(atts+1) << "'";
32      atts += 2;
33    }
34    ss_ << ") ";
35  }
36  virtual void EndElement(XmlParseContext * pctx, const char * name) {
37    RTC_UNUSED(pctx);
38    RTC_UNUSED(name);
39    ss_ << "END ";
40  }
41  virtual void CharacterData(XmlParseContext * pctx,
42                             const char * text, int len) {
43    RTC_UNUSED(pctx);
44    ss_ << "TEXT (" << std::string(text, len) << ") ";
45  }
46  virtual void Error(XmlParseContext * pctx, XML_Error code) {
47    RTC_UNUSED(pctx);
48    ss_ << "ERROR (" << static_cast<int>(code) << ") ";
49  }
50  virtual ~XmlParserTestHandler() {
51  }
52
53  std::string Str() {
54    return ss_.str();
55  }
56
57  std::string StrClear() {
58    std::string result = ss_.str();
59    ss_.str("");
60    return result;
61  }
62
63 private:
64  std::stringstream ss_;
65};
66
67
68TEST(XmlParserTest, TestTrivial) {
69  XmlParserTestHandler handler;
70  XmlParser::ParseXml(&handler, "<testing/>");
71  EXPECT_EQ("START (testing) END ", handler.Str());
72}
73
74TEST(XmlParserTest, TestAttributes) {
75  {
76    XmlParserTestHandler handler;
77    XmlParser::ParseXml(&handler, "<testing a='b'/>");
78    EXPECT_EQ("START (testing, a='b') END ", handler.Str());
79  }
80  {
81    XmlParserTestHandler handler;
82    XmlParser::ParseXml(&handler, "<testing e='' long='some text'/>");
83    EXPECT_EQ("START (testing, e='', long='some text') END ", handler.Str());
84  }
85}
86
87TEST(XmlParserTest, TestNesting) {
88  {
89    XmlParserTestHandler handler;
90    XmlParser::ParseXml(&handler,
91        "<top><first/><second><third></third></second></top>");
92    EXPECT_EQ("START (top) START (first) END START (second) START (third) "
93        "END END END ", handler.Str());
94  }
95  {
96    XmlParserTestHandler handler;
97    XmlParser::ParseXml(&handler, "<top><fifth><deeper><and><deeper/></and>"
98        "<sibling><leaf/></sibling></deeper></fifth><first/><second>"
99        "<third></third></second></top>");
100    EXPECT_EQ("START (top) START (fifth) START (deeper) START (and) START "
101            "(deeper) END END START (sibling) START (leaf) END END END "
102            "END START (first) END START (second) START (third) END END END ",
103            handler.Str());
104  }
105}
106
107TEST(XmlParserTest, TestXmlDecl) {
108  {
109    XmlParserTestHandler handler;
110    XmlParser::ParseXml(&handler, "<?xml version=\"1.0\"?><testing/>");
111    EXPECT_EQ("START (testing) END ", handler.Str());
112  }
113  {
114    XmlParserTestHandler handler;
115    XmlParser::ParseXml(&handler,
116        "<?xml version=\"1.0\" encoding=\"utf-8\"?><testing/>");
117    EXPECT_EQ("START (testing) END ", handler.Str());
118  }
119  {
120    XmlParserTestHandler handler;
121    XmlParser::ParseXml(&handler,
122        "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
123        "<testing/>");
124    EXPECT_EQ("START (testing) END ", handler.Str());
125  }
126}
127
128TEST(XmlParserTest, TestNamespace) {
129  {
130    XmlParserTestHandler handler;
131    XmlParser::ParseXml(&handler, "<top xmlns='my-namespace' a='b'/>");
132    EXPECT_EQ("START (my-namespace:top, xmlns='my-namespace', a='b') END ",
133        handler.Str());
134  }
135  {
136    XmlParserTestHandler handler;
137    XmlParser::ParseXml(&handler, "<foo:top xmlns:foo='my-namespace' "
138          "a='b' foo:c='d'/>");
139    EXPECT_EQ("START (my-namespace:top, "
140        "http://www.w3.org/2000/xmlns/:foo='my-namespace', "
141        "a='b', my-namespace:c='d') END ", handler.Str());
142  }
143  {
144    XmlParserTestHandler handler;
145    XmlParser::ParseXml(&handler, "<top><nested xmlns='my-namespace'><leaf/>"
146        "</nested><sibling/></top>");
147    EXPECT_EQ("START (top) START (my-namespace:nested, xmlns='my-namespace') "
148        "START (my-namespace:leaf) END END START (sibling) END END ",
149        handler.Str());
150  }
151}
152
153TEST(XmlParserTest, TestIncremental) {
154  XmlParserTestHandler handler;
155  XmlParser parser(&handler);
156  std::string fragment;
157
158  fragment = "<stream:stream";
159  parser.Parse(fragment.c_str(), fragment.length(), false);
160  EXPECT_EQ("", handler.StrClear());
161
162  fragment = " id=\"abcdefg\" xmlns=\"";
163  parser.Parse(fragment.c_str(), fragment.length(), false);
164  EXPECT_EQ("", handler.StrClear());
165
166  fragment = "j:c\" xmlns:stream='hm";
167  parser.Parse(fragment.c_str(), fragment.length(), false);
168  EXPECT_EQ("", handler.StrClear());
169
170  fragment = "ph'><test";
171  parser.Parse(fragment.c_str(), fragment.length(), false);
172  EXPECT_EQ("START (hmph:stream, id='abcdefg', xmlns='j:c', "
173      "http://www.w3.org/2000/xmlns/:stream='hmph') ", handler.StrClear());
174
175  fragment = "ing/><again/>abracad";
176  parser.Parse(fragment.c_str(), fragment.length(), false);
177  EXPECT_EQ("START (j:c:testing) END START (j:c:again) END TEXT (abracad) ",
178      handler.StrClear());
179
180  fragment = "abra</stream:";
181  parser.Parse(fragment.c_str(), fragment.length(), false);
182  EXPECT_EQ("TEXT (abra) ", handler.StrClear());
183
184  fragment = "stream>";
185  parser.Parse(fragment.c_str(), fragment.length(), false);
186  EXPECT_EQ("END ", handler.StrClear());
187}
188
189TEST(XmlParserTest, TestReset) {
190  {
191    XmlParserTestHandler handler;
192    XmlParser parser(&handler);
193    std::string fragment;
194
195    fragment = "<top><first/><second><third></third>";
196    parser.Parse(fragment.c_str(), fragment.length(), false);
197    EXPECT_EQ("START (top) START (first) END START (second) START (third) END ",
198        handler.StrClear());
199
200    parser.Reset();
201    fragment = "<tip><first/><second><third></third>";
202    parser.Parse(fragment.c_str(), fragment.length(), false);
203    EXPECT_EQ("START (tip) START (first) END START (second) START (third) END ",
204        handler.StrClear());
205  }
206  {
207    XmlParserTestHandler handler;
208    XmlParser parser(&handler);
209    std::string fragment;
210
211    fragment = "<top xmlns='m'>";
212    parser.Parse(fragment.c_str(), fragment.length(), false);
213    EXPECT_EQ("START (m:top, xmlns='m') ", handler.StrClear());
214
215    fragment = "<testing/><frag";
216    parser.Parse(fragment.c_str(), fragment.length(), false);
217    EXPECT_EQ("START (m:testing) END ", handler.StrClear());
218
219    parser.Reset();
220    fragment = "<testing><fragment/";
221    parser.Parse(fragment.c_str(), fragment.length(), false);
222    EXPECT_EQ("START (testing) ", handler.StrClear());
223
224    fragment = ">";
225    parser.Parse(fragment.c_str(), fragment.length(), false);
226    EXPECT_EQ("START (fragment) END ", handler.StrClear());
227  }
228}
229
230TEST(XmlParserTest, TestError) {
231  {
232    XmlParserTestHandler handler;
233    XmlParser::ParseXml(&handler, "junk");
234    EXPECT_EQ("ERROR (2) ", handler.Str());
235  }
236  {
237    XmlParserTestHandler handler;
238    XmlParser::ParseXml(&handler, "<top/> garbage ");
239    EXPECT_EQ("START (top) END ERROR (9) ", handler.Str());
240  }
241  {
242    XmlParserTestHandler handler;
243    XmlParser::ParseXml(&handler, "<-hm->");
244    EXPECT_EQ("ERROR (4) ", handler.Str());
245  }
246  {
247    XmlParserTestHandler handler;
248    XmlParser::ParseXml(&handler, "<hello>&foobar;</hello>");
249    EXPECT_EQ("START (hello) ERROR (11) ", handler.Str());
250  }
251  {
252    XmlParserTestHandler handler;
253    XmlParser::ParseXml(&handler,
254        "<!DOCTYPE HTML PUBLIC \"foobar\" \"barfoo\">");
255    EXPECT_EQ("ERROR (3) ", handler.Str());
256  }
257  {
258    // XmlParser requires utf-8
259    XmlParserTestHandler handler;
260    XmlParser::ParseXml(&handler,
261        "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><test/>");
262    EXPECT_EQ("ERROR (19) ", handler.Str());
263  }
264  {
265    // XmlParser requires version 1.0
266    XmlParserTestHandler handler;
267    XmlParser::ParseXml(&handler,
268        "<?xml version=\"2.0\"?><test/>");
269    EXPECT_EQ("ERROR (2) ", handler.Str());
270  }
271  {
272    // XmlParser requires standalone documents
273    XmlParserTestHandler handler;
274    XmlParser::ParseXml(&handler,
275        "<?xml version=\"1.0\" standalone=\"no\"?><test/>");
276    EXPECT_EQ("ERROR (2) ", handler.Str());
277  }
278  {
279    // XmlParser doesn't like empty namespace URIs
280    XmlParserTestHandler handler;
281    XmlParser::ParseXml(&handler,
282        "<test xmlns:foo='' foo:bar='huh?'>");
283    EXPECT_EQ("ERROR (2) ", handler.Str());
284  }
285}
286