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
17package libcore.xml;
18
19import java.io.ByteArrayOutputStream;
20import java.io.IOException;
21import java.io.StringWriter;
22import junit.framework.TestCase;
23import org.kxml2.io.KXmlSerializer;
24import org.w3c.dom.Document;
25import org.w3c.dom.NodeList;
26import org.xmlpull.v1.XmlSerializer;
27import static tests.support.Support_Xml.domOf;
28
29public final class KxmlSerializerTest extends TestCase {
30    private static final String NAMESPACE = null;
31
32    public void testWhitespaceInAttributeValue() throws Exception {
33        StringWriter stringWriter = new StringWriter();
34        XmlSerializer serializer = new KXmlSerializer();
35        serializer.setOutput(stringWriter);
36        serializer.startDocument("UTF-8", null);
37        serializer.startTag(NAMESPACE, "a");
38        serializer.attribute(NAMESPACE, "cr", "\r");
39        serializer.attribute(NAMESPACE, "lf", "\n");
40        serializer.attribute(NAMESPACE, "tab", "\t");
41        serializer.attribute(NAMESPACE, "space", " ");
42        serializer.endTag(NAMESPACE, "a");
43        serializer.endDocument();
44        assertXmlEquals("<a cr=\"&#13;\" lf=\"&#10;\" tab=\"&#9;\" space=\" \" />",
45                stringWriter.toString());
46    }
47
48    public void testWriteDocument() throws Exception {
49        StringWriter stringWriter = new StringWriter();
50        XmlSerializer serializer = new KXmlSerializer();
51        serializer.setOutput(stringWriter);
52        serializer.startDocument("UTF-8", null);
53        serializer.startTag(NAMESPACE, "foo");
54        serializer.attribute(NAMESPACE, "quux", "abc");
55        serializer.startTag(NAMESPACE, "bar");
56        serializer.endTag(NAMESPACE, "bar");
57        serializer.startTag(NAMESPACE, "baz");
58        serializer.endTag(NAMESPACE, "baz");
59        serializer.endTag(NAMESPACE, "foo");
60        serializer.endDocument();
61        assertXmlEquals("<foo quux=\"abc\"><bar /><baz /></foo>", stringWriter.toString());
62    }
63
64    // http://code.google.com/p/android/issues/detail?id=21250
65    public void testWriteSpecialCharactersInText() throws Exception {
66        StringWriter stringWriter = new StringWriter();
67        XmlSerializer serializer = new KXmlSerializer();
68        serializer.setOutput(stringWriter);
69        serializer.startDocument("UTF-8", null);
70        serializer.startTag(NAMESPACE, "foo");
71        serializer.text("5'8\", 5 < 6 & 7 > 3!");
72        serializer.endTag(NAMESPACE, "foo");
73        serializer.endDocument();
74        assertXmlEquals("<foo>5'8\", 5 &lt; 6 &amp; 7 &gt; 3!</foo>", stringWriter.toString());
75    }
76
77    private void assertXmlEquals(String expectedXml, String actualXml) throws Exception {
78        String declaration = "<?xml version='1.0' encoding='UTF-8' ?>";
79        assertEquals(declaration + expectedXml, actualXml);
80    }
81
82    private static XmlSerializer newSerializer() throws IOException {
83        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
84        XmlSerializer serializer = new KXmlSerializer();
85        serializer.setOutput(bytesOut, "UTF-8");
86        serializer.startDocument("UTF-8", null);
87        return serializer;
88    }
89
90    public void testInvalidCharactersInText() throws IOException {
91        XmlSerializer serializer = newSerializer();
92        serializer.startTag(NAMESPACE, "root");
93        for (int ch = 0; ch <= 0xffff; ++ch) {
94            final String s = Character.toString((char) ch);
95            if (isValidXmlCodePoint(ch)) {
96                serializer.text("a" + s + "b");
97            } else {
98                try {
99                    serializer.text("a" + s + "b");
100                    fail(s);
101                } catch (IllegalArgumentException expected) {
102                }
103            }
104        }
105        serializer.endTag(NAMESPACE, "root");
106    }
107
108    public void testInvalidCharactersInAttributeValues() throws IOException {
109        XmlSerializer serializer = newSerializer();
110        serializer.startTag(NAMESPACE, "root");
111        for (int ch = 0; ch <= 0xffff; ++ch) {
112            final String s = Character.toString((char) ch);
113            if (isValidXmlCodePoint(ch)) {
114                serializer.attribute(NAMESPACE, "a", "a" + s + "b");
115            } else {
116                try {
117                    serializer.attribute(NAMESPACE, "a", "a" + s + "b");
118                    fail(s);
119                } catch (IllegalArgumentException expected) {
120                }
121            }
122        }
123        serializer.endTag(NAMESPACE, "root");
124    }
125
126    public void testInvalidCharactersInCdataSections() throws IOException {
127        XmlSerializer serializer = newSerializer();
128        serializer.startTag(NAMESPACE, "root");
129        for (int ch = 0; ch <= 0xffff; ++ch) {
130            final String s = Character.toString((char) ch);
131            if (isValidXmlCodePoint(ch)) {
132                serializer.cdsect("a" + s + "b");
133            } else {
134                try {
135                    serializer.cdsect("a" + s + "b");
136                    fail(s);
137                } catch (IllegalArgumentException expected) {
138                }
139            }
140        }
141        serializer.endTag(NAMESPACE, "root");
142    }
143
144    public void testCdataWithTerminatorInside() throws Exception {
145        StringWriter writer = new StringWriter();
146        XmlSerializer serializer = new KXmlSerializer();
147        serializer.setOutput(writer);
148        serializer.startDocument("UTF-8", null);
149        serializer.startTag(NAMESPACE, "p");
150        serializer.cdsect("a]]>b");
151        serializer.endTag(NAMESPACE, "p");
152        serializer.endDocument();
153        // Adjacent CDATA sections aren't merged, so let's stick them together ourselves...
154        Document doc = domOf(writer.toString());
155        NodeList children = doc.getFirstChild().getChildNodes();
156        String text = "";
157        for (int i = 0; i < children.getLength(); ++i) {
158            text += children.item(i).getNodeValue();
159        }
160        assertEquals("a]]>b", text);
161    }
162
163    private static boolean isValidXmlCodePoint(int c) {
164        // http://www.w3.org/TR/REC-xml/#charsets
165        return (c >= 0x20 && c <= 0xd7ff) || (c == 0x9) || (c == 0xa) || (c == 0xd) ||
166                (c >= 0xe000 && c <= 0xfffd) || (c >= 0x10000 && c <= 0x10ffff);
167    }
168}
169