1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   */ 
19  package org.apache.rat.report.xml.writer.impl.base;
20  
21  import java.io.StringWriter;
22  
23  import junit.framework.TestCase;
24  import org.apache.rat.report.xml.writer.InvalidXmlException;
25  import org.apache.rat.report.xml.writer.OperationNotAllowedException;
26  
27  public class XmlWriterTest extends TestCase {
28  
29      private static final char[] ZERO_CHAR = {(char)0};
30      
31      XmlWriter writer;
32      StringWriter out;
33      
34      protected void setUp() throws Exception {
35          super.setUp();
36          out = new StringWriter();
37          writer = new XmlWriter(out);
38      }
39  
40      protected void tearDown() throws Exception {
41          super.tearDown();
42      }
43  
44      public void testReturnValues() throws Exception {
45          assertEquals("XmlWriters should always return themselves", 
46                  writer, writer.openElement("alpha"));
47          assertEquals("XmlWriters should always return themselves", 
48                  writer, writer.attribute("beta", "b"));
49          assertEquals("XmlWriters should always return themselves", 
50                  writer, writer.content("gamma"));
51          assertEquals("XmlWriters should always return themselves", 
52                  writer, writer.closeElement());
53      }
54  
55      public void testOpenElement() throws Exception {
56          assertEquals("XmlWriters should always return themselves", 
57                  writer, writer.openElement("alpha"));
58          assertEquals("Alpha element started", "<alpha", out.toString());
59          assertEquals("XmlWriters should always return themselves", 
60                  writer, writer.openElement("beta"));
61          assertEquals("Alpha element tag closed and beta started", "<alpha><beta", out.toString());
62          assertEquals("XmlWriters should always return themselves", 
63                  writer, writer.closeElement());
64          assertEquals("Beta tag ended", "<alpha><beta/>", out.toString());
65          assertEquals("XmlWriters should always return themselves", 
66                  writer, writer.openElement("gamma"));
67          assertEquals("Gamma tag started", "<alpha><beta/><gamma", out.toString());
68      }
69      
70      public void testInvalidElementName() throws Exception {
71          assertTrue("All strings ok", isValidElementName("alpha"));
72          assertTrue("Strings and digits ok", isValidElementName("alpha77"));
73          assertFalse("Must no start with digit", isValidElementName("5alpha77"));
74          assertFalse("Greater than not ok", isValidElementName("alph<a77"));
75          assertFalse("Less than not ok", isValidElementName("alph<a77"));
76          assertFalse("Quote not ok", isValidElementName("alph'a77"));
77          assertTrue("Dash ok", isValidElementName("alph-a77"));
78          assertTrue("Underscore ok", isValidElementName("alph_a77"));
79          assertTrue("Dot ok", isValidElementName("alph.a77"));
80          assertTrue("Colon ok", isValidElementName("alpha:77"));
81          assertFalse("Start with dash not ok", isValidElementName("-a77"));
82          assertTrue("Start with underscore ok", isValidElementName("_a77"));
83          assertFalse("Start with dot not ok", isValidElementName(".a77"));
84          assertTrue("Start with colon ok", isValidElementName(":a77"));
85      }
86      
87      private boolean isValidElementName(String elementName) throws Exception {
88          boolean result = true;
89          try {
90              writer.openElement(elementName);
91          } catch (InvalidXmlException e) {
92              result = false;
93          }
94          return result;
95      }
96      
97      public void testCallOpenElementAfterLastElementClosed() throws Exception {
98          assertEquals("XmlWriters should always return themselves", 
99                  writer, writer.openElement("alpha"));
100         assertEquals("Alpha element started", "<alpha", out.toString());
101         assertEquals("XmlWriters should always return themselves", 
102                 writer, writer.closeElement());
103         assertEquals("Element alpha is closed", "<alpha/>", out.toString());
104         try {
105             writer.openElement("delta");
106             fail("Cannot open new elements once the first element has been closed");
107         } catch (OperationNotAllowedException e) {
108             // Cannot open new elements once the first element has been closed
109         }
110     }    
111     
112     public void testCallCloseElementAfterLastElementClosed() throws Exception {
113         assertEquals("XmlWriters should always return themselves", 
114                 writer, writer.openElement("alpha"));
115         assertEquals("Alpha element started", "<alpha", out.toString());
116         assertEquals("XmlWriters should always return themselves", 
117                 writer, writer.closeElement());
118         assertEquals("Element alpha is closed", "<alpha/>", out.toString());
119         try {
120             writer.closeElement();
121             fail("Cannot close elements once the first element has been closed");
122         } catch (OperationNotAllowedException e) {
123             // Cannot open new elements once the first element has been closed
124         }
125     }
126     
127     
128     public void testCloseFirstElement() throws Exception {
129         assertEquals("XmlWriters should always return themselves", 
130                 writer, writer.openElement("alpha"));
131         assertEquals("Alpha element started", "<alpha", out.toString());
132         assertEquals("XmlWriters should always return themselves", 
133                 writer, writer.closeElement());
134         assertEquals("Element alpha is closed", "<alpha/>", out.toString());
135     }
136     
137     public void testCloseElementWithContent() throws Exception {
138         assertEquals("XmlWriters should always return themselves", 
139                 writer, writer.openElement("alpha"));
140         assertEquals("Alpha element started", "<alpha", out.toString());
141         assertEquals("XmlWriters should always return themselves", 
142                 writer, writer.openElement("beta"));
143         assertEquals("Beta element started", "<alpha><beta", out.toString());
144         assertEquals("XmlWriters should always return themselves", 
145                 writer, writer.closeElement());
146         assertEquals("Element beta is closed", "<alpha><beta/>", out.toString());
147         assertEquals("XmlWriters should always return themselves", 
148                 writer, writer.closeElement());
149         assertEquals("Element beta is closed", "<alpha><beta/></alpha>", out.toString());
150         try {
151             writer.closeElement();
152             fail("Cannot close elements once the first element has been closed");
153         } catch (OperationNotAllowedException e) {
154             // Cannot open new elements once the first element has been closed
155         }
156     }
157     
158     public void testCloseElementBeforeFirstElement() throws Exception {
159         try {
160             writer.closeElement();
161             fail("Cannot close elements before the first element has been closed");
162         } catch (OperationNotAllowedException e) {
163             // Cannot open new elements before the first element has been closed
164         }
165     }
166     
167     public void testContentAfterElement() throws Exception {
168         assertEquals("XmlWriters should always return themselves", 
169                 writer, writer.openElement("alpha"));
170         assertEquals("Alpha element started", "<alpha", out.toString());
171         assertEquals("XmlWriters should always return themselves", 
172                 writer, writer.content("foo bar"));
173         assertEquals("Alpha tag closed. Content written", "<alpha>foo bar", out.toString());
174         assertEquals("XmlWriters should always return themselves", 
175                 writer, writer.content(" and more foo bar"));
176         assertEquals("Alpha tag closed. Content written", "<alpha>foo bar and more foo bar", out.toString());
177         assertEquals("XmlWriters should always return themselves", 
178                 writer, writer.openElement("beta"));
179         assertEquals("Beta element started", "<alpha>foo bar and more foo bar<beta", out.toString());
180         assertEquals("XmlWriters should always return themselves", 
181                 writer, writer.closeElement());
182         assertEquals("Element beta is closed", "<alpha>foo bar and more foo bar<beta/>", out.toString());
183         assertEquals("XmlWriters should always return themselves", 
184                 writer, writer.closeElement());
185         assertEquals("Element beta is closed", "<alpha>foo bar and more foo bar<beta/></alpha>", out.toString());
186         try {
187             writer.content("A Sentence Too far");
188             fail("Cannot write content once the first element has been closed");
189         } catch (OperationNotAllowedException e) {
190             // Cannot open new elements once the first element has been closed
191         }
192     }
193     
194 
195     public void testContentAfterLastElement() throws Exception {
196         assertEquals("XmlWriters should always return themselves", 
197                 writer, writer.openElement("alpha"));
198         assertEquals("Alpha element started", "<alpha", out.toString());
199         assertEquals("XmlWriters should always return themselves", 
200                 writer, writer.closeElement());
201         assertEquals("Element beta is closed", "<alpha/>", out.toString());
202         try {
203             writer.content("A Sentence Too far");
204             fail("Cannot write content once the first element has been closed");
205         } catch (OperationNotAllowedException e) {
206             // Cannot open new elements once the first element has been closed
207         }
208     }
209     
210     public void testWriteContentBeforeFirstElement() throws Exception {
211         try {
212             writer.content("Too early");
213             fail("Cannot close elements before the first element has been closed");
214         } catch (OperationNotAllowedException e) {
215             // Cannot open new elements before the first element has been closed
216         }
217     }
218     
219     public void testContentEscaping() throws Exception {
220         assertEquals("XmlWriters should always return themselves", 
221                 writer, writer.openElement("alpha"));
222         assertEquals("Alpha element started", "<alpha", out.toString());
223         assertEquals("XmlWriters should always return themselves", 
224                 writer, writer.content("this&that"));
225         assertEquals("Amphersands must be escaped", "<alpha>this&amp;that", out.toString());
226         assertEquals("XmlWriters should always return themselves", 
227                 writer, writer.content("small<large"));
228         assertEquals("Left angle brackets must be escaped", "<alpha>this&amp;thatsmall&lt;large", out.toString());
229         assertEquals("XmlWriters should always return themselves", 
230                 writer, writer.content("12>1"));
231         assertEquals("Choose to escape right angle brackets", "<alpha>this&amp;thatsmall&lt;large12&gt;1", out.toString());
232 
233     }
234 
235     public void testAttributeAfterLastElement() throws Exception {
236         assertEquals("XmlWriters should always return themselves", 
237                 writer, writer.openElement("alpha"));
238         assertEquals("Alpha element started", "<alpha", out.toString());
239         assertEquals("XmlWriters should always return themselves", 
240                 writer, writer.closeElement());
241         assertEquals("Element beta is closed", "<alpha/>", out.toString());
242         try {
243             writer.attribute("foo", "bar");
244             fail("Cannot write content once the first element has been closed");
245         } catch (OperationNotAllowedException e) {
246             // Cannot open new elements once the first element has been closed
247         }
248     }
249     
250     public void testAttributeContentBeforeFirstElement() throws Exception {
251         try {
252             writer.attribute("foo", "bar");
253             fail("Cannot close elements before the first element has been closed");
254         } catch (OperationNotAllowedException e) {
255             // Cannot open new elements before the first element has been closed
256         }
257     }
258     
259     public void testInvalidAttributeName() throws Exception {
260         writer.openElement("alpha");
261         assertTrue("All strings ok", isValidAttributeName("alpha"));
262         assertTrue("Strings and digits ok", isValidAttributeName("alpha77"));
263         assertFalse("Must not start with digit", isValidAttributeName("5alpha77"));
264         assertTrue("Colon ok", isValidAttributeName("alpha:77"));
265         assertFalse("Greater than not ok", isValidAttributeName("alph<a77"));
266         assertFalse("Less than not ok", isValidAttributeName("alph<a77"));
267         assertFalse("Quote not ok", isValidAttributeName("alph'a77"));
268     }
269     
270     private boolean isValidAttributeName(String name) throws Exception {
271         boolean result = true;
272         try {
273             writer.attribute(name, "");
274         } catch (InvalidXmlException e) {
275             result = false;
276         }
277         return result;
278     }
279     
280     public void testEscapeAttributeContent() throws Exception {
281         assertEquals("XmlWriters should always return themselves", 
282                 writer, writer.openElement("alpha"));
283         assertEquals("Alpha element started", "<alpha", out.toString());
284         assertEquals("XmlWriters should always return themselves", 
285                 writer, writer.attribute("one", "this&that"));
286         assertEquals("Amphersands must be escaped", "<alpha one='this&amp;that'", out.toString());
287         assertEquals("XmlWriters should always return themselves", 
288                 writer, writer.attribute("two", "small<large"));
289         assertEquals("Left angle brackets must be escaped", "<alpha one='this&amp;that' two='small&lt;large'", out.toString());
290         assertEquals("XmlWriters should always return themselves", 
291                 writer, writer.attribute("three", "12>1"));
292         assertEquals("Choose to escape right angle brackets", "<alpha one='this&amp;that' two='small&lt;large' three='12&gt;1'", out.toString());
293         assertEquals("XmlWriters should always return themselves", 
294                 writer, writer.attribute("four", "'quote'"));
295         assertEquals("Apostrophes must be escape", "<alpha one='this&amp;that' two='small&lt;large' three='12&gt;1' four='&apos;quote&apos;'", out.toString());
296         assertEquals("XmlWriters should always return themselves", 
297                 writer, writer.attribute("five", "\"quote\""));
298         assertEquals("Double quotes must be escape", "<alpha one='this&amp;that' two='small&lt;large' three='12&gt;1' four='&apos;quote&apos;' five='&quot;quote&quot;'", out.toString());
299 
300     }
301     
302     public void testAttributeInContent() throws Exception {
303         assertEquals("XmlWriters should always return themselves", 
304                 writer, writer.openElement("alpha"));
305         assertEquals("Alpha element started", "<alpha", out.toString());
306         assertEquals("XmlWriters should always return themselves", 
307                 writer, writer.content("foo bar"));
308         try {
309             writer.attribute("name", "value");
310             fail("attributes after body content are not allowed");
311         } catch (InvalidXmlException e) {
312             // attributes after body content are not allowed
313         }
314     }
315   
316     public void testOutOfRangeCharacter() throws Exception {
317         assertEquals("XmlWriters should always return themselves", 
318                 writer, writer.openElement("alpha"));
319         assertEquals("Alpha element started", "<alpha", out.toString());
320         assertEquals("XmlWriters should always return themselves", 
321                 writer, writer.content(new String(ZERO_CHAR)));
322         String out = this.out.toString();
323         assertEquals("Replace illegal characters with question marks", "<alpha>?", out);
324     }
325     
326     public void testAttributeAfterElementClosed() throws Exception {
327         assertEquals("XmlWriters should always return themselves", 
328                 writer, writer.openElement("alpha"));
329         assertEquals("Alpha element started", "<alpha", out.toString());
330         assertEquals("XmlWriters should always return themselves", 
331                 writer, writer.openElement("beta"));
332         assertEquals("Beta element started", "<alpha><beta", out.toString());
333         assertEquals("XmlWriters should always return themselves", 
334                 writer, writer.closeElement());
335         assertEquals("Beta element closed", "<alpha><beta/>", out.toString());
336         try {
337             writer.attribute("name", "value");
338             fail("attributes after closed element are not allowed");
339         } catch (InvalidXmlException e) {
340             // attributes after body content are not allowed
341         }
342     }
343     
344     public void testCloseDocumentBeforeOpen() throws Exception {
345         try {
346             writer.closeDocument();
347             fail("Cannot close document before the first element has been opened");
348         } catch (OperationNotAllowedException e) {
349             // Cannot open new elements before the first element has been opened
350         }
351     }
352     
353     public void testCloseDocumentAfterRootElementClosed() throws Exception {
354         assertEquals("XmlWriters should always return themselves", 
355                 writer, writer.openElement("alpha"));
356         assertEquals("Alpha element started", "<alpha", out.toString());
357         assertEquals("XmlWriters should always return themselves", 
358                 writer, writer.closeElement());
359         assertEquals("Beta element started", "<alpha/>", out.toString());
360         try {
361             writer.closeDocument();
362         } catch (OperationNotAllowedException e) {
363             fail("No exception should be thrown when called after the root element is closed.");
364         }
365     }   
366     
367     public void testCloseSimpleDocument() throws Exception {
368         assertEquals("XmlWriters should always return themselves", 
369                 writer, writer.openElement("alpha"));
370         assertEquals("Alpha element started", "<alpha", out.toString());
371         assertEquals("XmlWriters should always return themselves", 
372                 writer, writer.openElement("beta"));
373         assertEquals("Beta element started", "<alpha><beta", out.toString());
374         assertEquals("XmlWriters should always return themselves", 
375                 writer, writer.closeDocument());
376         assertEquals("Beta element started", "<alpha><beta/></alpha>", out.toString());
377     }
378     
379     public void testCloseComplexDocument() throws Exception {
380         assertEquals("XmlWriters should always return themselves", 
381                 writer, writer.openElement("alpha"));
382         assertEquals("Alpha element started", "<alpha", out.toString());
383         assertEquals("XmlWriters should always return themselves", 
384                 writer, writer.openElement("beta"));
385         assertEquals("Beta element started", "<alpha><beta", out.toString());
386         assertEquals("XmlWriters should always return themselves", 
387                 writer, writer.attribute("name", "value"));
388         assertEquals("Beta element started", "<alpha><beta name='value'", out.toString());
389         assertEquals("XmlWriters should always return themselves", 
390                 writer, writer.closeElement());
391         assertEquals("Beta element started", "<alpha><beta name='value'/>", out.toString());
392         assertEquals("XmlWriters should always return themselves", 
393                 writer, writer.openElement("beta"));
394         assertEquals("Beta element started", "<alpha><beta name='value'/><beta", out.toString());
395         assertEquals("XmlWriters should always return themselves", 
396                 writer, writer.attribute("name", "value"));
397         assertEquals("Beta element started", "<alpha><beta name='value'/><beta name='value'", out.toString());
398         assertEquals("XmlWriters should always return themselves", 
399                 writer, writer.openElement("gamma"));
400         assertEquals("Beta element started", "<alpha><beta name='value'/><beta name='value'><gamma", out.toString());
401         assertEquals("XmlWriters should always return themselves", 
402                 writer, writer.closeDocument());
403         assertEquals("Beta element started", "<alpha><beta name='value'/><beta name='value'><gamma/></beta></alpha>", out.toString());
404     }
405     
406     public void testWriteProlog() throws Exception {
407         assertEquals("XmlWriters should always return themselves", 
408                 writer, writer.startDocument());
409         assertEquals("Prolog written", "<?xml version='1.0'?>", out.toString());
410     }
411     
412     public void testWriteAfterElement() throws Exception {
413         assertEquals("XmlWriters should always return themselves", 
414                 writer, writer.openElement("alpha"));
415         assertEquals("Alpha element started", "<alpha", out.toString());
416         try {
417             writer.startDocument();
418             fail("Operation not allowed once an element has been written");
419         } catch (OperationNotAllowedException e) {
420             // Operation not allowed once an element has been written
421         }
422     }
423     
424     public void testWritePrologTwo() throws Exception {
425         assertEquals("XmlWriters should always return themselves", 
426                 writer, writer.startDocument());
427         assertEquals("Prolog written", "<?xml version='1.0'?>", out.toString());
428         try {
429             writer.startDocument();
430             fail("Operation not allow once a prolog has been written");
431         } catch (OperationNotAllowedException e) {
432             // Operation not allowed once an prolog has been written
433         }
434     }
435     
436     public void testDuplicateAttributes() throws Exception {
437         assertEquals("XmlWriters should always return themselves", 
438                 writer, writer.openElement("alpha"));
439         assertEquals("Alpha element started", "<alpha", out.toString());
440         assertEquals("XmlWriters should always return themselves", 
441                 writer, writer.attribute("one", "1"));
442         assertEquals("Attribute written", "<alpha one='1'", out.toString());
443         assertEquals("XmlWriters should always return themselves", 
444                 writer, writer.openElement("beta"));
445         assertEquals("Beta element started", "<alpha one='1'><beta", out.toString());
446         assertEquals("XmlWriters should always return themselves", 
447                 writer, writer.attribute("one", "1"));
448         assertEquals("Beta element started", "<alpha one='1'><beta one='1'", out.toString());
449         try {
450             writer.attribute("one", "2");
451             fail("Each attribute may only be written once");
452         } catch (InvalidXmlException e) {
453             // Each attribute may only be written once
454         }
455     }
456 }