• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package libcore.xml;
17 
18 import static org.junit.Assert.assertThrows;
19 
20 import java.io.IOException;
21 import java.io.StringReader;
22 import java.util.ArrayList;
23 import junit.framework.TestCase;
24 import org.junit.Assert;
25 import org.xml.sax.Attributes;
26 import org.xml.sax.ContentHandler;
27 import org.xml.sax.ErrorHandler;
28 import org.xml.sax.InputSource;
29 import org.xml.sax.SAXException;
30 import org.xml.sax.SAXNotRecognizedException;
31 import org.xml.sax.SAXNotSupportedException;
32 import org.xml.sax.SAXParseException;
33 import org.xml.sax.helpers.DefaultHandler;
34 import org.xmlpull.v1.XmlPullParser;
35 import org.xmlpull.v1.XmlPullParserException;
36 import org.xmlpull.v1.XmlPullParserFactory;
37 import org.xmlpull.v1.sax2.Driver;
38 
39 public class XmlToSax2DriverTest extends TestCase {
40 
41     private static final String XML =
42             "<note type=\"email\" foo=\"bar\">"
43             + "<to>John</to>"
44             + "<from>Smith</from>"
45             + "<heading>Lunch today</heading>"
46             + "<body>Hi, shall we go to lunch at 12?</body>"
47             + "</note>";
48 
49     private Driver driver;
50 
51     @Override
setUp()52     protected void setUp() throws Exception {
53         super.setUp();
54 
55         driver = new Driver();
56     }
57 
testConstructor()58     public void testConstructor() {
59         Driver driver = null;
60         try {
61             driver = new Driver();
62         } catch (XmlPullParserException e) {
63             fail("Unexpected exception: " + e.getMessage());
64         }
65 
66         assertEquals(0, driver.getLength());
67         assertEquals(1, driver.getColumnNumber());
68         assertEquals(1, driver.getLineNumber());
69     }
70 
testConstructor_parametrized()71     public void testConstructor_parametrized() {
72         XmlPullParserFactory factory;
73         XmlPullParser parser = null;
74 
75         try {
76             factory = XmlPullParserFactory.newInstance(null, null);
77             parser = factory.newPullParser();
78         } catch (XmlPullParserException e) {
79             fail("Couldn't create factory and parser");
80         }
81         Driver driver = null;
82 
83         try {
84              driver = new Driver(parser);
85         } catch (XmlPullParserException e) {
86             fail("Unexpected exception: " + e.getMessage());
87         }
88 
89         assertEquals(0, driver.getLength());
90         assertEquals(1, driver.getColumnNumber());
91         assertEquals(1, driver.getLineNumber());
92     }
93 
testGetColumnNumber()94     public void testGetColumnNumber() {
95         assertEquals(driver.getColumnNumber(), 1);
96     }
97 
testSetProperty()98     public void testSetProperty() throws Exception {
99         assertThrows(SAXNotSupportedException.class , () -> driver.setProperty(
100                 "http://xml.org/sax/properties/declaration-handler", // DECLARATION_HANDLER_PROPERTY
101                 ""));
102 
103         assertThrows(SAXNotSupportedException.class ,() -> driver.setProperty(
104                 "http://xml.org/sax/properties/lexical-handler", // LEXICAL_HANDLER_PROPERTY
105                 ""));
106 
107         // This may be the only key accpeted by the KXmlParser.
108         String key = "http://xmlpull.org/v1/doc/properties.html#location";
109         driver.setProperty(key, "123");
110         assertEquals("123", driver.getProperty(key));
111 
112         assertThrows(SAXNotSupportedException.class ,() -> driver.setProperty("abc", ""));
113     }
114 
testGetSetContentHandler()115     public void testGetSetContentHandler() throws XmlPullParserException {
116         assertTrue(driver.getContentHandler() instanceof DefaultHandler);
117 
118         ContentHandler handler = new DefaultHandler();
119         driver.setContentHandler(handler);
120         assertEquals(driver.getContentHandler(), handler);
121 
122         driver.setContentHandler(null);
123         assertNull(driver.getContentHandler());
124     }
125 
testGetSetDTDHandler()126     public void testGetSetDTDHandler() {
127         assertNull(driver.getDTDHandler());
128 
129         driver.setDTDHandler(new DefaultHandler());
130         assertNull(driver.getDTDHandler());
131 
132         driver.setDTDHandler(null);
133         assertNull(driver.getDTDHandler());
134     }
135 
testGetSetEntityResolver()136     public void testGetSetEntityResolver() {
137         assertNull(driver.getEntityResolver());
138 
139         driver.setEntityResolver(new DefaultHandler());
140         assertNull(driver.getEntityResolver());
141 
142         driver.setEntityResolver((publicId, systemId) -> null);
143         assertNull(driver.getEntityResolver());
144 
145         driver.setEntityResolver(null);
146         assertNull(driver.getEntityResolver());
147     }
148 
testGetSetErrorHandler()149     public void testGetSetErrorHandler() {
150         assertTrue(driver.getContentHandler() instanceof DefaultHandler);
151 
152         ErrorHandler handler = new DefaultHandler();
153         driver.setErrorHandler(handler);
154         assertEquals(handler, driver.getErrorHandler());
155 
156         driver.setErrorHandler(null);
157         assertNull(driver.getErrorHandler());
158     }
159 
testGetSetFeature()160     public void testGetSetFeature() throws SAXNotSupportedException, SAXNotRecognizedException {
161         final String NAMESPACES_FEATURE = "http://xml.org/sax/features/namespaces";
162         final String NAMESPACE_PREFIXES_FEATURE = "http://xml.org/sax/features/namespace-prefixes";
163         final String VALIDATION_FEATURE = "http://xml.org/sax/features/validation";
164         final String PROCESS_DOCDECL_FEATURE =
165                 "http://xmlpull.org/v1/doc/features.html#process-docdecl";
166         final String REPORT_NAMESPACE_ATTRIBUTES_FEATURE =
167                 "http://xmlpull.org/v1/doc/features.html#report-namespace-prefixes";
168         final String RELAXED_FEATURE = "http://xmlpull.org/v1/doc/features.html#relaxed";
169 
170         final Object[][] expectations = {
171                 {NAMESPACE_PREFIXES_FEATURE, false},
172                 {VALIDATION_FEATURE, false},
173                 {PROCESS_DOCDECL_FEATURE, false},
174                 {REPORT_NAMESPACE_ATTRIBUTES_FEATURE, false},
175                 {NAMESPACES_FEATURE, true},
176         };
177 
178         for (Object[] f : expectations) {
179             final String feature = (String) f[0];
180             final boolean result = (boolean) f[1];
181             try {
182                 assertEquals(result, driver.getFeature(feature));
183             } catch (SAXNotSupportedException | SAXNotRecognizedException e) {
184                 fail("Unexpected exception: " + e.getMessage());
185             }
186         }
187 
188         final String[] settable = {
189                 NAMESPACES_FEATURE,
190                 PROCESS_DOCDECL_FEATURE,
191                 RELAXED_FEATURE,
192         };
193         for (String feature : settable) {
194             for (boolean value : new boolean[]{ false, true }) {
195                 driver.setFeature(feature, value);
196                 assertEquals(feature, value, driver.getFeature(feature));
197             }
198         }
199     }
200 
testGetIndex()201     public void testGetIndex() throws NoSuchFieldException, IllegalAccessException {
202         assertEquals(-1, driver.getIndex("hello"));
203         assertEquals(-1, driver.getIndex("encoding"));
204         assertEquals(-1, driver.getIndex("version"));
205     }
206 
testGetIndex_namespaced()207     public void testGetIndex_namespaced() {
208         assertEquals(-1, driver.getIndex("", "version"));
209     }
210 
testGetLength()211     public void testGetLength() {
212         assertEquals(0, driver.getLength());
213     }
214 
testGetLineNumber()215     public void testGetLineNumber() {
216         assertEquals(1, driver.getLineNumber());
217     }
218 
testGetLocalName()219     public void testGetLocalName() {
220         try {
221             driver.getLocalName(0);
222         } catch (IndexOutOfBoundsException e) {
223             // expected
224         }
225     }
226 
testGetProperty()227     public void testGetProperty() {
228         try {
229             driver.getProperty("");
230         } catch (IndexOutOfBoundsException e) {
231             // expected
232         } catch (SAXNotSupportedException | SAXNotRecognizedException e) {
233             fail("Unexpected exception: " + e.getMessage());
234         }
235     }
236 
testGetPublicId()237     public void testGetPublicId() {
238         assertNull(driver.getPublicId());
239     }
240 
testGetQName()241     public void testGetQName() {
242         try {
243             driver.getQName(0);
244         } catch (IndexOutOfBoundsException e) {
245             // expected
246         }
247     }
248 
testGetSystemId()249     public void testGetSystemId() {
250         assertNull(driver.getSystemId());
251     }
252 
testGetType()253     public void testGetType() {
254         assertEquals("CDATA", driver.getType(0));
255         assertNull(driver.getType("value"));
256         assertNull(driver.getType("", "value"));
257     }
258 
testGetUri()259     public void testGetUri() {
260         try {
261             driver.getURI(0);
262         } catch (IndexOutOfBoundsException e) {
263             // expected
264         }
265     }
266 
testGetValue()267     public void testGetValue() {
268         try {
269             driver.getValue(0);
270         } catch (IndexOutOfBoundsException e) {
271             // expected
272         }
273         assertNull("CDATA", driver.getValue("value"));
274         assertNull("CDATA", driver.getValue("", "value"));
275     }
276 
testParse_String()277     public void testParse_String() {
278         try {
279             driver.parse("systemId");
280         } catch (SAXException | IOException e) {
281             // expected
282         }
283 
284         String systemId = null;
285         try {
286             driver.parse(systemId);
287         } catch (SAXException | IOException e) {
288             // expected
289         }
290     }
291 
testParse_InputSource()292     public void testParse_InputSource() throws IOException, SAXException {
293         InputSource source = new InputSource();
294         source.setCharacterStream(new StringReader(XML));
295         source.setSystemId("systemId");
296 
297         final int[] errors = {0, 0, 0};
298         driver.setErrorHandler(new ErrorHandler() {
299             @Override
300             public void warning(SAXParseException exception) throws SAXException {
301                 errors[0]++;
302             }
303 
304             @Override
305             public void error(SAXParseException exception) throws SAXException {
306                 errors[1]++;
307             }
308 
309             @Override
310             public void fatalError(SAXParseException exception) throws SAXException {
311                 errors[2]++;
312             }
313         });
314 
315         // Four events counter: { "startDocument", "endDocument", "startElement", "endElement" }
316         final int[] events = {0, 0, 0, 0};
317         final ArrayList<String> tagsEncountered = new ArrayList<>();
318         final ArrayList<String> textsEncountered = new ArrayList<>();
319         driver.setContentHandler(new DefaultHandler() {
320             @Override
321             public void startDocument() throws SAXException {
322                 super.startDocument();
323                 events[0]++;
324             }
325 
326             @Override
327             public void endDocument() throws SAXException {
328                 super.endDocument();
329                 events[1]++;
330             }
331 
332             @Override
333             public void startElement(String uri, String localName, String qName,
334                     Attributes attributes) throws SAXException {
335                 super.startElement(uri, localName, qName, attributes);
336                 events[2]++;
337                 tagsEncountered.add(localName);
338                 if ("note".equals(localName)) {
339                     assertEquals(2, attributes.getLength());
340                     assertEquals("type", attributes.getLocalName(0));
341                     assertEquals("email", attributes.getValue(0));
342                     assertEquals("foo", attributes.getLocalName(1));
343                     assertEquals("bar", attributes.getValue(1));
344                 }
345             }
346 
347             @Override
348             public void characters(char[] ch, int start, int length) throws SAXException {
349                 super.characters(ch, start, length);
350                 textsEncountered.add(StringFactory.newStringFromChars(ch, start, length));
351             }
352 
353             @Override
354             public void endElement(String uri, String localName, String qName) throws SAXException {
355                 super.endElement(uri, localName, qName);
356                 events[3]++;
357             }
358         });
359         driver.parse(source);
360 
361         assertEquals("systemId", driver.getSystemId());
362         Assert.assertArrayEquals(new int[]{0, 0, 0}, errors);
363         Assert.assertArrayEquals(new int[]{1, 1, 5, 5}, events);
364         Assert.assertArrayEquals(new String[]{"note", "to", "from", "heading", "body"},
365                 tagsEncountered.toArray());
366         Assert.assertArrayEquals(new String[]{
367                 "John", "Smith", "Lunch today", "Hi, shall we go to lunch at 12?"
368         }, textsEncountered.toArray());
369     }
370 
testParseSubtree()371     public void testParseSubtree() throws XmlPullParserException, IOException {
372         XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
373         parser.setInput(new StringReader(XML));
374 
375         final int[] errors = {0, 0, 0};
376         driver.setErrorHandler(new ErrorHandler() {
377             @Override
378             public void warning(SAXParseException exception) throws SAXException {
379                 errors[0]++;
380             }
381 
382             @Override
383             public void error(SAXParseException exception) throws SAXException {
384                 errors[1]++;
385             }
386 
387             @Override
388             public void fatalError(SAXParseException exception) throws SAXException {
389                 errors[2]++;
390             }
391         });
392 
393         // Four events counter: { "startDocument", "endDocument", "startElement", "endElement" }
394         final int[] events = {0, 0, 0, 0};
395         final ArrayList<String> tagsEncountered = new ArrayList<>();
396         final ArrayList<String> textsEncountered = new ArrayList<>();
397         driver.setContentHandler(new DefaultHandler() {
398             @Override
399             public void startDocument() throws SAXException {
400                 super.startDocument();
401                 events[0]++;
402             }
403 
404             @Override
405             public void endDocument() throws SAXException {
406                 super.endDocument();
407                 events[1]++;
408             }
409 
410             @Override
411             public void startElement(String uri, String localName, String qName,
412                     Attributes attributes) throws SAXException {
413                 super.startElement(uri, localName, qName, attributes);
414                 events[2]++;
415                 tagsEncountered.add(localName);
416                 if ("note".equals(localName)) {
417                     assertEquals(2, attributes.getLength());
418                     assertEquals("type", attributes.getLocalName(0));
419                     assertEquals("email", attributes.getValue(0));
420                     assertEquals("foo", attributes.getLocalName(1));
421                     assertEquals("bar", attributes.getValue(1));
422                 }
423             }
424 
425             @Override
426             public void characters(char[] ch, int start, int length) throws SAXException {
427                 super.characters(ch, start, length);
428                 textsEncountered.add(StringFactory.newStringFromChars(ch, start, length));
429             }
430 
431             @Override
432             public void endElement(String uri, String localName, String qName) throws SAXException {
433                 super.endElement(uri, localName, qName);
434                 events[3]++;
435             }
436         });
437 
438         try {
439             driver.parseSubTree(parser);
440         } catch (SAXException e) {
441             // expected, as START_TAG should have been read already
442         } catch (IOException e) {
443             fail("Unexpected exception: " + e.getMessage());
444         }
445         assertEquals(XmlPullParser.START_TAG, parser.next());
446         try {
447             driver.parseSubTree(parser);
448         } catch (SAXException | IOException e) {
449             fail("Unexpected exception: " + e.getMessage());
450         }
451 
452         Assert.assertArrayEquals(new int[]{0, 0, 0}, errors);
453         Assert.assertArrayEquals(new int[]{0, 0, 5, 5}, events);
454         Assert.assertArrayEquals(new String[]{"note", "to", "from", "heading", "body"},
455                 tagsEncountered.toArray());
456         Assert.assertArrayEquals(new String[]{
457                 "John", "Smith", "Lunch today", "Hi, shall we go to lunch at 12?"
458         }, textsEncountered.toArray());
459     }
460 
testStartElement()461     public void testStartElement() throws XmlPullParserException, IOException, SAXException {
462         boolean[] called = {false};
463         ContentHandler handler = new DefaultHandler() {
464             @Override
465             public void startElement(String uri, String localName, String qName,
466                     Attributes attributes) throws SAXException {
467                 super.startElement(uri, localName, qName, attributes);
468                 called[0] = true;
469             }
470         };
471         ExtendsDriver d = new ExtendsDriver(handler);
472         d.setContentHandler(handler);
473         d.parse(new InputSource(new StringReader(XML)));
474 
475         assertTrue(called[0]);
476     }
477 
478     private static class ExtendsDriver extends Driver {
479 
480         private final ContentHandler handler;
481 
ExtendsDriver(ContentHandler handler)482         public ExtendsDriver(ContentHandler handler) throws XmlPullParserException {
483             this.handler = handler;
484         }
485 
486         @Override
startElement(String namespace, String localName, String qName)487         protected void startElement(String namespace, String localName, String qName)
488                 throws SAXException {
489             super.startElement(namespace, localName, qName);
490             handler.startElement(namespace, localName, qName, this);
491         }
492     }
493 }
494