001: /*
002: * Copyright (C) 2004, 2005 Joe Walnes.
003: * Copyright (C) 2006, 2007, 2008 XStream Committers.
004: * All rights reserved.
005: *
006: * The software in this package is published under the terms of the BSD
007: * style license a copy of which has been included with this distribution in
008: * the LICENSE.txt file.
009: *
010: * Created on 07. March 2004 by Joe Walnes
011: */
012: package com.thoughtworks.xstream.io.xml;
013:
014: import com.thoughtworks.xstream.core.util.QuickWriter;
015: import com.thoughtworks.xstream.io.StreamException;
016:
017: import java.io.StringWriter;
018:
019: public class PrettyPrintWriterTest extends AbstractXMLWriterTest {
020: private StringWriter buffer;
021:
022: protected void setUp() throws Exception {
023: super .setUp();
024: buffer = new StringWriter();
025: writer = new PrettyPrintWriter(buffer, " ");
026: }
027:
028: protected void assertXmlProducedIs(String expected) {
029: assertEquals(expected, buffer.toString());
030: }
031:
032: public void testSupportsNestedElements() { // Note: This overrides a test in superclass to
033: // include indentation
034:
035: writer.startNode("hello");
036: writer.startNode("world");
037: writer.addAttribute("id", "one");
038:
039: writer.startNode("one");
040: writer.setValue("potato");
041: writer.endNode();
042:
043: writer.startNode("two");
044: writer.addAttribute("id", "two");
045: writer.setValue("potatae");
046: writer.endNode();
047:
048: writer.endNode();
049:
050: writer.startNode("empty");
051: writer.endNode();
052:
053: writer.endNode();
054:
055: String expected = "" + "<hello>\n" + " <world id=\"one\">\n"
056: + " <one>potato</one>\n"
057: + " <two id=\"two\">potatae</two>\n"
058: + " </world>\n" + " <empty/>\n" + "</hello>";
059:
060: assertXmlProducedIs(expected);
061: }
062:
063: public void testAttributesAreResettedForNewNode() { // Note: This overrides a test in
064: // superclass to include indentation
065: writer.startNode("work");
066: writer.startNode("person");
067: writer.addAttribute("firstname", "Joe");
068: writer.addAttribute("lastname", "Walnes");
069: writer.endNode();
070: writer.startNode("project");
071: writer.addAttribute("XStream", "Codehaus");
072: writer.endNode();
073: writer.endNode();
074:
075: String expected = "" + "<work>\n"
076: + " <person firstname=\"Joe\" lastname=\"Walnes\"/>\n"
077: + " <project XStream=\"Codehaus\"/>\n" + "</work>";
078:
079: assertXmlProducedIs(expected);
080: }
081:
082: public void testAllowsUserToOverrideTextAndAttributeEscapingRules() {
083: writer = new PrettyPrintWriter(buffer, " ") {
084: protected void writeAttributeValue(QuickWriter writer,
085: String text) {
086: writer.write(replace(text, '&', "_&_"));
087: }
088:
089: protected void writeText(QuickWriter writer, String text) {
090: writer.write(replace(text, '&', "AND"));
091: }
092: };
093:
094: writer.startNode("evil");
095: writer.addAttribute("attr", "hello & stuff");
096: writer.setValue("bye & stuff");
097: writer.endNode();
098:
099: assertXmlProducedIs("<evil attr=\"hello _&_ stuff\">bye AND stuff</evil>");
100: }
101:
102: public void testSupportsUserDefinedEOL() {
103: writer = new PrettyPrintWriter(buffer, "\t", "\r");
104:
105: writer.startNode("element");
106: writer.startNode("empty");
107: writer.endNode();
108: writer.endNode();
109:
110: assertXmlProducedIs("<element>\r\t<empty/>\r</element>");
111: }
112:
113: public void testSupportsEmptyNestedTags() {
114: writer.startNode("parent");
115: writer.startNode("child");
116: writer.endNode();
117: writer.endNode();
118:
119: assertXmlProducedIs("<parent>\n <child/>\n</parent>");
120: }
121:
122: public void testSupportsNullInQuirksMode() {
123: writer = new PrettyPrintWriter(buffer,
124: PrettyPrintWriter.XML_QUIRKS);
125: writer.startNode("tag");
126: writer.setValue("\u0000");
127: writer.endNode();
128:
129: assertXmlProducedIs("<tag>�</tag>");
130: }
131:
132: public void testThrowsForNullInXml1_0Mode() {
133: writer = new PrettyPrintWriter(buffer,
134: PrettyPrintWriter.XML_1_0);
135: writer.startNode("tag");
136: try {
137: writer.setValue("\u0000");
138: fail("Thrown " + StreamException.class.getName()
139: + " expected");
140: } catch (final StreamException e) {
141: assertTrue(e.getMessage().indexOf('0') > 0);
142: }
143: }
144:
145: public void testThrowsForNullInXml1_1Mode() {
146: writer = new PrettyPrintWriter(buffer,
147: PrettyPrintWriter.XML_1_1);
148: writer.startNode("tag");
149: try {
150: writer.setValue("\u0000");
151: fail("Thrown " + StreamException.class.getName()
152: + " expected");
153: } catch (final StreamException e) {
154: assertTrue(e.getMessage().indexOf('0') > 0);
155: }
156: }
157:
158: public void testSupportsOnlyValidControlCharactersInXml1_0Mode() {
159: writer = new PrettyPrintWriter(buffer,
160: PrettyPrintWriter.XML_1_0);
161: writer.startNode("tag");
162: String ctrl = ""
163: + "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007"
164: + "\u0008\u0009\n\u000b\u000c\r\u000e\u000f" + "\u007f"
165: + "\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087"
166: + "\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f"
167: + "\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097"
168: + "\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f"
169: + "";
170: for (int i = 0; i < ctrl.length(); i++) {
171: char c = ctrl.charAt(i);
172: try {
173: writer.setValue(new Character(c).toString());
174: if (c != '\t' && c != '\n' && c != '\r' && c < '\u007f') {
175: fail("Thrown " + StreamException.class.getName()
176: + " expected");
177: }
178: } catch (final StreamException e) {
179: assertTrue(e.getMessage().indexOf(
180: Integer.toHexString(c)) > 0);
181: }
182: }
183: writer.endNode();
184: assertXmlProducedIs("<tag>\t\n
"
185: + "€‚ƒ„…†‡"
186: + "ˆ‰Š‹ŒŽ"
187: + "‘’“”•–—"
188: + "˜™š›œžŸ</tag>");
189: }
190:
191: public void testSupportsOnlyValidControlCharactersInXml1_1Mode() {
192: writer = new PrettyPrintWriter(buffer,
193: PrettyPrintWriter.XML_1_1);
194: writer.startNode("tag");
195: String ctrl = ""
196: + "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007"
197: + "\u0008\u0009\n\u000b\u000c\r\u000e\u000f" + "\u007f"
198: + "\u0080\u0081\u0082\u0083\u0084\u0085\u0086\u0087"
199: + "\u0088\u0089\u008a\u008b\u008c\u008d\u008e\u008f"
200: + "\u0090\u0091\u0092\u0093\u0094\u0095\u0096\u0097"
201: + "\u0098\u0099\u009a\u009b\u009c\u009d\u009e\u009f"
202: + "";
203: for (int i = 0; i < ctrl.length(); i++) {
204: char c = ctrl.charAt(i);
205: try {
206: writer.setValue(new Character(c).toString());
207: if (c == 0) {
208: fail("Thrown " + StreamException.class.getName()
209: + " expected");
210: }
211: } catch (final StreamException e) {
212: assertTrue(e.getMessage().indexOf(
213: Integer.toHexString(c)) > 0);
214: }
215: }
216: writer.endNode();
217: assertXmlProducedIs("<tag>"
218: + "\t\n
"
219: + "€‚ƒ„…†‡"
220: + "ˆ‰Š‹ŒŽ"
221: + "‘’“”•–—"
222: + "˜™š›œžŸ</tag>");
223: }
224:
225: public void testSupportsInvalidUnicodeCharacterslInQuirksMode() {
226: writer = new PrettyPrintWriter(buffer,
227: PrettyPrintWriter.XML_QUIRKS);
228: writer.startNode("tag");
229: String ctrl = "\ud7ff\ud800\udfff\ue000\ufffd\ufffe\uffff";
230: for (int i = 0; i < ctrl.length(); i++) {
231: char c = ctrl.charAt(i);
232: writer.setValue(new Character(c).toString());
233: }
234: writer.endNode();
235: assertXmlProducedIs("<tag>퟿\ud800\udfff\ue000\ufffd</tag>");
236: }
237:
238: public void testThrowsForInvalidUnicodeCharacterslInXml1_0Mode() {
239: writer = new PrettyPrintWriter(buffer,
240: PrettyPrintWriter.XML_1_0);
241: writer.startNode("tag");
242: String ctrl = "\ud7ff\ud800\udfff\ue000\ufffd\ufffe\uffff";
243: for (int i = 0; i < ctrl.length(); i++) {
244: char c = ctrl.charAt(i);
245: try {
246: writer.setValue(new Character(c).toString());
247: if ((c >= '\ud800' && c < '\udfff') || c == '\ufffe'
248: || c == '\uffff') {
249: fail("Thrown " + StreamException.class.getName()
250: + " for character value "
251: + Integer.toHexString(c) + " expected");
252: }
253: } catch (final StreamException e) {
254: assertTrue(e.getMessage().indexOf(
255: Integer.toHexString(c)) > 0);
256: }
257: }
258: writer.endNode();
259: assertXmlProducedIs("<tag>퟿\ue000\ufffd</tag>");
260: }
261:
262: public void testThrowsForInvalidUnicodeCharacterslInXml1_1Mode() {
263: writer = new PrettyPrintWriter(buffer,
264: PrettyPrintWriter.XML_1_1);
265: writer.startNode("tag");
266: String ctrl = "\ud7ff\ud800\udfff\ue000\ufffd\ufffe\uffff";
267: for (int i = 0; i < ctrl.length(); i++) {
268: char c = ctrl.charAt(i);
269: try {
270: writer.setValue(new Character(c).toString());
271: if ((c >= '\ud800' && c < '\udfff') || c == '\ufffe'
272: || c == '\uffff') {
273: fail("Thrown " + StreamException.class.getName()
274: + " for character value "
275: + Integer.toHexString(c) + " expected");
276: }
277: } catch (final StreamException e) {
278: assertTrue(e.getMessage().indexOf(
279: Integer.toHexString(c)) > 0);
280: }
281: }
282: writer.endNode();
283: assertXmlProducedIs("<tag>퟿\ue000\ufffd</tag>");
284: }
285:
286: private String replace(String in, char what, String with) {
287: int pos = in.indexOf(what);
288: if (pos == -1) {
289: return in;
290: } else {
291: return in.substring(0, pos) + with + in.substring(pos + 1);
292: }
293: }
294: }
|