Home | History | Annotate | Download | only in xml
      1 /*
      2  * Copyright (C) 2009 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 
     17 package libcore.xml;
     18 
     19 import java.io.ByteArrayOutputStream;
     20 import java.io.IOException;
     21 import java.io.StringWriter;
     22 import junit.framework.TestCase;
     23 import org.kxml2.io.KXmlSerializer;
     24 import org.w3c.dom.Document;
     25 import org.w3c.dom.Node;
     26 import org.w3c.dom.NodeList;
     27 import org.w3c.dom.Text;
     28 import org.xmlpull.v1.XmlSerializer;
     29 import static tests.support.Support_Xml.domOf;
     30 
     31 public final class KxmlSerializerTest extends TestCase {
     32     private static final String NAMESPACE = null;
     33 
     34     public void testWhitespaceInAttributeValue() throws Exception {
     35         StringWriter stringWriter = new StringWriter();
     36         XmlSerializer serializer = new KXmlSerializer();
     37         serializer.setOutput(stringWriter);
     38         serializer.startDocument("UTF-8", null);
     39         serializer.startTag(NAMESPACE, "a");
     40         serializer.attribute(NAMESPACE, "cr", "\r");
     41         serializer.attribute(NAMESPACE, "lf", "\n");
     42         serializer.attribute(NAMESPACE, "tab", "\t");
     43         serializer.attribute(NAMESPACE, "space", " ");
     44         serializer.endTag(NAMESPACE, "a");
     45         serializer.endDocument();
     46         assertXmlEquals("<a cr=\"&#13;\" lf=\"&#10;\" tab=\"&#9;\" space=\" \" />",
     47                 stringWriter.toString());
     48     }
     49 
     50     public void testWriteDocument() throws Exception {
     51         StringWriter stringWriter = new StringWriter();
     52         XmlSerializer serializer = new KXmlSerializer();
     53         serializer.setOutput(stringWriter);
     54         serializer.startDocument("UTF-8", null);
     55         serializer.startTag(NAMESPACE, "foo");
     56         serializer.attribute(NAMESPACE, "quux", "abc");
     57         serializer.startTag(NAMESPACE, "bar");
     58         serializer.endTag(NAMESPACE, "bar");
     59         serializer.startTag(NAMESPACE, "baz");
     60         serializer.endTag(NAMESPACE, "baz");
     61         serializer.endTag(NAMESPACE, "foo");
     62         serializer.endDocument();
     63         assertXmlEquals("<foo quux=\"abc\"><bar /><baz /></foo>", stringWriter.toString());
     64     }
     65 
     66     // http://code.google.com/p/android/issues/detail?id=21250
     67     public void testWriteSpecialCharactersInText() throws Exception {
     68         StringWriter stringWriter = new StringWriter();
     69         XmlSerializer serializer = new KXmlSerializer();
     70         serializer.setOutput(stringWriter);
     71         serializer.startDocument("UTF-8", null);
     72         serializer.startTag(NAMESPACE, "foo");
     73         serializer.text("5'8\", 5 < 6 & 7 > 3!");
     74         serializer.endTag(NAMESPACE, "foo");
     75         serializer.endDocument();
     76         assertXmlEquals("<foo>5'8\", 5 &lt; 6 &amp; 7 &gt; 3!</foo>", stringWriter.toString());
     77     }
     78 
     79     private void assertXmlEquals(String expectedXml, String actualXml) throws Exception {
     80         String declaration = "<?xml version='1.0' encoding='UTF-8' ?>";
     81         assertEquals(declaration + expectedXml, actualXml);
     82     }
     83 
     84     private static XmlSerializer newSerializer() throws IOException {
     85         ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
     86         XmlSerializer serializer = new KXmlSerializer();
     87         serializer.setOutput(bytesOut, "UTF-8");
     88         serializer.startDocument("UTF-8", null);
     89         return serializer;
     90     }
     91 
     92     public String fromCodePoint(int codePoint) {
     93         if (codePoint > Character.MAX_VALUE) {
     94             return new String(Character.toChars(codePoint));
     95         }
     96         return Character.toString((char) codePoint);
     97     }
     98 
     99     // http://b/17960630
    100     public void testSpeakNoEvilMonkeys() throws Exception {
    101         StringWriter stringWriter = new StringWriter();
    102         XmlSerializer serializer = new KXmlSerializer();
    103         serializer.setOutput(stringWriter);
    104         serializer.startDocument("UTF-8", null);
    105         serializer.startTag(NAMESPACE, "tag");
    106         serializer.attribute(NAMESPACE, "attr", "a\ud83d\ude4ab");
    107         serializer.text("c\ud83d\ude4ad");
    108         serializer.cdsect("e\ud83d\ude4af");
    109         serializer.endTag(NAMESPACE, "tag");
    110         serializer.endDocument();
    111         assertXmlEquals("<tag attr=\"a&#128586;b\">" +
    112                         "c&#128586;d" +
    113                         "<![CDATA[e]]>&#128586;<![CDATA[f]]>" +
    114                         "</tag>", stringWriter.toString());
    115 
    116         // Check we can parse what we just output.
    117         Document doc = domOf(stringWriter.toString());
    118         Node root = doc.getDocumentElement();
    119         assertEquals("a\ud83d\ude4ab", root.getAttributes().getNamedItem("attr").getNodeValue());
    120         Text text = (Text) root.getFirstChild();
    121         assertEquals("c\ud83d\ude4ade\ud83d\ude4af", text.getNodeValue());
    122     }
    123 
    124     public void testBadSurrogates() throws Exception {
    125         StringWriter stringWriter = new StringWriter();
    126         XmlSerializer serializer = new KXmlSerializer();
    127         serializer.setOutput(stringWriter);
    128         serializer.startDocument("UTF-8", null);
    129         serializer.startTag(NAMESPACE, "tag");
    130         try {
    131             serializer.attribute(NAMESPACE, "attr", "a\ud83d\u0040b");
    132             fail();
    133         } catch (IllegalArgumentException expected) {
    134         }
    135         try {
    136             serializer.text("c\ud83d\u0040d");
    137             fail();
    138         } catch (IllegalArgumentException expected) {
    139         }
    140         try {
    141             serializer.cdsect("e\ud83d\u0040f");
    142             fail();
    143         } catch (IllegalArgumentException expected) {
    144         }
    145     }
    146 
    147     // Cover all the BMP code points plus a few that require us to use surrogates.
    148     private static int MAX_TEST_CODE_POINT = 0x10008;
    149 
    150     public void testInvalidCharactersInText() throws IOException {
    151         XmlSerializer serializer = newSerializer();
    152         serializer.startTag(NAMESPACE, "root");
    153         for (int c = 0; c <= MAX_TEST_CODE_POINT; ++c) {
    154             final String s = fromCodePoint(c);
    155             if (isValidXmlCodePoint(c)) {
    156                 serializer.text("a" + s + "b");
    157             } else {
    158                 try {
    159                     serializer.text("a" + s + "b");
    160                     fail(s);
    161                 } catch (IllegalArgumentException expected) {
    162                 }
    163             }
    164         }
    165         serializer.endTag(NAMESPACE, "root");
    166     }
    167 
    168     public void testInvalidCharactersInAttributeValues() throws IOException {
    169         XmlSerializer serializer = newSerializer();
    170         serializer.startTag(NAMESPACE, "root");
    171         for (int c = 0; c <= MAX_TEST_CODE_POINT; ++c) {
    172             final String s = fromCodePoint(c);
    173             if (isValidXmlCodePoint(c)) {
    174                 serializer.attribute(NAMESPACE, "a", "a" + s + "b");
    175             } else {
    176                 try {
    177                     serializer.attribute(NAMESPACE, "a", "a" + s + "b");
    178                     fail(s);
    179                 } catch (IllegalArgumentException expected) {
    180                 }
    181             }
    182         }
    183         serializer.endTag(NAMESPACE, "root");
    184     }
    185 
    186     public void testInvalidCharactersInCdataSections() throws IOException {
    187         XmlSerializer serializer = newSerializer();
    188         serializer.startTag(NAMESPACE, "root");
    189         for (int c = 0; c <= MAX_TEST_CODE_POINT; ++c) {
    190             final String s = fromCodePoint(c);
    191             if (isValidXmlCodePoint(c)) {
    192                 serializer.cdsect("a" + s + "b");
    193             } else {
    194                 try {
    195                     serializer.cdsect("a" + s + "b");
    196                     fail(s);
    197                 } catch (IllegalArgumentException expected) {
    198                 }
    199             }
    200         }
    201         serializer.endTag(NAMESPACE, "root");
    202     }
    203 
    204     public void testCdataWithTerminatorInside() throws Exception {
    205         StringWriter writer = new StringWriter();
    206         XmlSerializer serializer = new KXmlSerializer();
    207         serializer.setOutput(writer);
    208         serializer.startDocument("UTF-8", null);
    209         serializer.startTag(NAMESPACE, "p");
    210         serializer.cdsect("a]]>b");
    211         serializer.endTag(NAMESPACE, "p");
    212         serializer.endDocument();
    213         // Adjacent CDATA sections aren't merged, so let's stick them together ourselves...
    214         Document doc = domOf(writer.toString());
    215         NodeList children = doc.getFirstChild().getChildNodes();
    216         String text = "";
    217         for (int i = 0; i < children.getLength(); ++i) {
    218             text += children.item(i).getNodeValue();
    219         }
    220         assertEquals("a]]>b", text);
    221     }
    222 
    223     private static boolean isValidXmlCodePoint(int c) {
    224         // http://www.w3.org/TR/REC-xml/#charsets
    225         return (c >= 0x20 && c <= 0xd7ff) || (c == 0x9) || (c == 0xa) || (c == 0xd) ||
    226                 (c >= 0xe000 && c <= 0xfffd) || (c >= 0x10000 && c <= 0x10ffff);
    227     }
    228 }
    229