View Javadoc
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 org.apache.rat.report.xml.writer.InvalidXmlException;
22  import org.apache.rat.report.xml.writer.OperationNotAllowedException;
23  import org.junit.Before;
24  import org.junit.Test;
25  
26  import java.io.StringWriter;
27  
28  import static org.junit.Assert.assertEquals;
29  import static org.junit.Assert.assertFalse;
30  import static org.junit.Assert.assertTrue;
31  import static org.junit.Assert.fail;
32  
33  public class XmlWriterTest {
34  
35      private static final char[] ZERO_CHAR = {(char)0};
36      
37      private XmlWriter writer;
38      private StringWriter out;
39      
40      @Before
41      public void setUp() throws Exception {
42          out = new StringWriter();
43          writer = new XmlWriter(out);
44      }
45  
46      @Test
47      public void returnValues() throws Exception {
48          assertEquals("XmlWriters should always return themselves", 
49                  writer, writer.openElement("alpha"));
50          assertEquals("XmlWriters should always return themselves", 
51                  writer, writer.attribute("beta", "b"));
52          assertEquals("XmlWriters should always return themselves", 
53                  writer, writer.content("gamma"));
54          assertEquals("XmlWriters should always return themselves", 
55                  writer, writer.closeElement());
56      }
57  
58      @Test
59      public void openElement() throws Exception {
60          assertEquals("XmlWriters should always return themselves", 
61                  writer, writer.openElement("alpha"));
62          assertEquals("Alpha element started", "<alpha", out.toString());
63          assertEquals("XmlWriters should always return themselves", 
64                  writer, writer.openElement("beta"));
65          assertEquals("Alpha element tag closed and beta started", "<alpha><beta", out.toString());
66          assertEquals("XmlWriters should always return themselves", 
67                  writer, writer.closeElement());
68          assertEquals("Beta tag ended", "<alpha><beta/>", out.toString());
69          assertEquals("XmlWriters should always return themselves", 
70                  writer, writer.openElement("gamma"));
71          assertEquals("Gamma tag started", "<alpha><beta/><gamma", out.toString());
72      }
73      
74      @Test
75      public void invalidElementName() throws Exception {
76          assertTrue("All strings ok", isValidElementName("alpha"));
77          assertTrue("Strings and digits ok", isValidElementName("alpha77"));
78          assertFalse("Must no start with digit", isValidElementName("5alpha77"));
79          assertFalse("Greater than not ok", isValidElementName("alph<a77"));
80          assertFalse("Less than not ok", isValidElementName("alph<a77"));
81          assertFalse("Quote not ok", isValidElementName("alph'a77"));
82          assertTrue("Dash ok", isValidElementName("alph-a77"));
83          assertTrue("Underscore ok", isValidElementName("alph_a77"));
84          assertTrue("Dot ok", isValidElementName("alph.a77"));
85          assertTrue("Colon ok", isValidElementName("alpha:77"));
86          assertFalse("Start with dash not ok", isValidElementName("-a77"));
87          assertTrue("Start with underscore ok", isValidElementName("_a77"));
88          assertFalse("Start with dot not ok", isValidElementName(".a77"));
89          assertTrue("Start with colon ok", isValidElementName(":a77"));
90      }
91      
92      private boolean isValidElementName(String elementName) throws Exception {
93          boolean result = true;
94          try {
95              writer.openElement(elementName);
96          } catch (InvalidXmlException e) {
97              result = false;
98          }
99          return result;
100     }
101 
102     @Test
103     public void callOpenElementAfterLastElementClosed() throws Exception {
104         assertEquals("XmlWriters should always return themselves", 
105                 writer, writer.openElement("alpha"));
106         assertEquals("Alpha element started", "<alpha", out.toString());
107         assertEquals("XmlWriters should always return themselves", 
108                 writer, writer.closeElement());
109         assertEquals("Element alpha is closed", "<alpha/>", out.toString());
110         try {
111             writer.openElement("delta");
112             fail("Cannot open new elements once the first element has been closed");
113         } catch (OperationNotAllowedException e) {
114             // Cannot open new elements once the first element has been closed
115         }
116     }    
117 
118     @Test
119     public void callCloseElementAfterLastElementClosed() throws Exception {
120         assertEquals("XmlWriters should always return themselves", 
121                 writer, writer.openElement("alpha"));
122         assertEquals("Alpha element started", "<alpha", out.toString());
123         assertEquals("XmlWriters should always return themselves", 
124                 writer, writer.closeElement());
125         assertEquals("Element alpha is closed", "<alpha/>", out.toString());
126         try {
127             writer.closeElement();
128             fail("Cannot close elements once the first element has been closed");
129         } catch (OperationNotAllowedException e) {
130             // Cannot open new elements once the first element has been closed
131         }
132     }
133 
134     @Test
135     public void closeFirstElement() throws Exception {
136         assertEquals("XmlWriters should always return themselves", 
137                 writer, writer.openElement("alpha"));
138         assertEquals("Alpha element started", "<alpha", out.toString());
139         assertEquals("XmlWriters should always return themselves", 
140                 writer, writer.closeElement());
141         assertEquals("Element alpha is closed", "<alpha/>", out.toString());
142     }
143     
144     @Test
145     public void closeElementWithContent() throws Exception {
146         assertEquals("XmlWriters should always return themselves", 
147                 writer, writer.openElement("alpha"));
148         assertEquals("Alpha element started", "<alpha", out.toString());
149         assertEquals("XmlWriters should always return themselves", 
150                 writer, writer.openElement("beta"));
151         assertEquals("Beta element started", "<alpha><beta", out.toString());
152         assertEquals("XmlWriters should always return themselves", 
153                 writer, writer.closeElement());
154         assertEquals("Element beta is closed", "<alpha><beta/>", out.toString());
155         assertEquals("XmlWriters should always return themselves", 
156                 writer, writer.closeElement());
157         assertEquals("Element beta is closed", "<alpha><beta/></alpha>", out.toString());
158         try {
159             writer.closeElement();
160             fail("Cannot close elements once the first element has been closed");
161         } catch (OperationNotAllowedException e) {
162             // Cannot open new elements once the first element has been closed
163         }
164     }
165     
166     @Test
167     public void closeElementBeforeFirstElement() throws Exception {
168         try {
169             writer.closeElement();
170             fail("Cannot close elements before the first element has been closed");
171         } catch (OperationNotAllowedException e) {
172             // Cannot open new elements before the first element has been closed
173         }
174     }
175     
176     @Test
177     public void contentAfterElement() throws Exception {
178         assertEquals("XmlWriters should always return themselves", 
179                 writer, writer.openElement("alpha"));
180         assertEquals("Alpha element started", "<alpha", out.toString());
181         assertEquals("XmlWriters should always return themselves", 
182                 writer, writer.content("foo bar"));
183         assertEquals("Alpha tag closed. Content written", "<alpha>foo bar", out.toString());
184         assertEquals("XmlWriters should always return themselves", 
185                 writer, writer.content(" and more foo bar"));
186         assertEquals("Alpha tag closed. Content written", "<alpha>foo bar and more foo bar", out.toString());
187         assertEquals("XmlWriters should always return themselves", 
188                 writer, writer.openElement("beta"));
189         assertEquals("Beta element started", "<alpha>foo bar and more foo bar<beta", out.toString());
190         assertEquals("XmlWriters should always return themselves", 
191                 writer, writer.closeElement());
192         assertEquals("Element beta is closed", "<alpha>foo bar and more foo bar<beta/>", out.toString());
193         assertEquals("XmlWriters should always return themselves", 
194                 writer, writer.closeElement());
195         assertEquals("Element beta is closed", "<alpha>foo bar and more foo bar<beta/></alpha>", out.toString());
196         try {
197             writer.content("A Sentence Too far");
198             fail("Cannot write content once the first element has been closed");
199         } catch (OperationNotAllowedException e) {
200             // Cannot open new elements once the first element has been closed
201         }
202     }
203 
204     @Test
205     public void contentAfterLastElement() throws Exception {
206         assertEquals("XmlWriters should always return themselves", 
207                 writer, writer.openElement("alpha"));
208         assertEquals("Alpha element started", "<alpha", out.toString());
209         assertEquals("XmlWriters should always return themselves", 
210                 writer, writer.closeElement());
211         assertEquals("Element beta is closed", "<alpha/>", out.toString());
212         try {
213             writer.content("A Sentence Too far");
214             fail("Cannot write content once the first element has been closed");
215         } catch (OperationNotAllowedException e) {
216             // Cannot open new elements once the first element has been closed
217         }
218     }
219     
220     @Test
221     public void writeContentBeforeFirstElement() throws Exception {
222         try {
223             writer.content("Too early");
224             fail("Cannot close elements before the first element has been closed");
225         } catch (OperationNotAllowedException e) {
226             // Cannot open new elements before the first element has been closed
227         }
228     }
229     
230     @Test
231     public void contentEscaping() throws Exception {
232         assertEquals("XmlWriters should always return themselves", 
233                 writer, writer.openElement("alpha"));
234         assertEquals("Alpha element started", "<alpha", out.toString());
235         assertEquals("XmlWriters should always return themselves", 
236                 writer, writer.content("this&that"));
237         assertEquals("Amphersands must be escaped", "<alpha>this&amp;that", out.toString());
238         assertEquals("XmlWriters should always return themselves", 
239                 writer, writer.content("small<large"));
240         assertEquals("Left angle brackets must be escaped", "<alpha>this&amp;thatsmall&lt;large", out.toString());
241         assertEquals("XmlWriters should always return themselves", 
242                 writer, writer.content("12>1"));
243         assertEquals("Choose to escape right angle brackets", "<alpha>this&amp;thatsmall&lt;large12&gt;1", out.toString());
244 
245     }
246 
247     @Test
248     public void attributeAfterLastElement() throws Exception {
249         assertEquals("XmlWriters should always return themselves", 
250                 writer, writer.openElement("alpha"));
251         assertEquals("Alpha element started", "<alpha", out.toString());
252         assertEquals("XmlWriters should always return themselves", 
253                 writer, writer.closeElement());
254         assertEquals("Element beta is closed", "<alpha/>", out.toString());
255         try {
256             writer.attribute("foo", "bar");
257             fail("Cannot write content once the first element has been closed");
258         } catch (OperationNotAllowedException e) {
259             // Cannot open new elements once the first element has been closed
260         }
261     }
262     
263     @Test
264     public void attributeContentBeforeFirstElement() throws Exception {
265         try {
266             writer.attribute("foo", "bar");
267             fail("Cannot close elements before the first element has been closed");
268         } catch (OperationNotAllowedException e) {
269             // Cannot open new elements before the first element has been closed
270         }
271     }
272     
273     @Test
274     public void invalidAttributeName() throws Exception {
275         writer.openElement("alpha");
276         assertTrue("All strings ok", isValidAttributeName("alpha"));
277         assertTrue("Strings and digits ok", isValidAttributeName("alpha77"));
278         assertFalse("Must not start with digit", isValidAttributeName("5alpha77"));
279         assertTrue("Colon ok", isValidAttributeName("alpha:77"));
280         assertFalse("Greater than not ok", isValidAttributeName("alph<a77"));
281         assertFalse("Less than not ok", isValidAttributeName("alph<a77"));
282         assertFalse("Quote not ok", isValidAttributeName("alph'a77"));
283     }
284     
285     private boolean isValidAttributeName(String name) throws Exception {
286         boolean result = true;
287         try {
288             writer.attribute(name, "");
289         } catch (InvalidXmlException e) {
290             result = false;
291         }
292         return result;
293     }
294     
295     @Test
296     public void escapeAttributeContent() throws Exception {
297         assertEquals("XmlWriters should always return themselves", 
298                 writer, writer.openElement("alpha"));
299         assertEquals("Alpha element started", "<alpha", out.toString());
300         assertEquals("XmlWriters should always return themselves", 
301                 writer, writer.attribute("one", "this&that"));
302         assertEquals("Amphersands must be escaped", "<alpha one='this&amp;that'", out.toString());
303         assertEquals("XmlWriters should always return themselves", 
304                 writer, writer.attribute("two", "small<large"));
305         assertEquals("Left angle brackets must be escaped", "<alpha one='this&amp;that' two='small&lt;large'", out.toString());
306         assertEquals("XmlWriters should always return themselves", 
307                 writer, writer.attribute("three", "12>1"));
308         assertEquals("Choose to escape right angle brackets", "<alpha one='this&amp;that' two='small&lt;large' three='12&gt;1'", out.toString());
309         assertEquals("XmlWriters should always return themselves", 
310                 writer, writer.attribute("four", "'quote'"));
311         assertEquals("Apostrophes must be escape", "<alpha one='this&amp;that' two='small&lt;large' three='12&gt;1' four='&apos;quote&apos;'", out.toString());
312         assertEquals("XmlWriters should always return themselves", 
313                 writer, writer.attribute("five", "\"quote\""));
314         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());
315 
316     }
317     
318     @Test
319     public void attributeInContent() throws Exception {
320         assertEquals("XmlWriters should always return themselves", 
321                 writer, writer.openElement("alpha"));
322         assertEquals("Alpha element started", "<alpha", out.toString());
323         assertEquals("XmlWriters should always return themselves", 
324                 writer, writer.content("foo bar"));
325         try {
326             writer.attribute("name", "value");
327             fail("attributes after body content are not allowed");
328         } catch (InvalidXmlException e) {
329             // attributes after body content are not allowed
330         }
331     }
332   
333     @Test
334     public void outOfRangeCharacter() throws Exception {
335         assertEquals("XmlWriters should always return themselves", 
336                 writer, writer.openElement("alpha"));
337         assertEquals("Alpha element started", "<alpha", out.toString());
338         assertEquals("XmlWriters should always return themselves", 
339                 writer, writer.content(new String(ZERO_CHAR)));
340         String out = this.out.toString();
341         assertEquals("Replace illegal characters with question marks", "<alpha>?", out);
342     }
343     
344     @Test
345     public void attributeAfterElementClosed() throws Exception {
346         assertEquals("XmlWriters should always return themselves", 
347                 writer, writer.openElement("alpha"));
348         assertEquals("Alpha element started", "<alpha", out.toString());
349         assertEquals("XmlWriters should always return themselves", 
350                 writer, writer.openElement("beta"));
351         assertEquals("Beta element started", "<alpha><beta", out.toString());
352         assertEquals("XmlWriters should always return themselves", 
353                 writer, writer.closeElement());
354         assertEquals("Beta element closed", "<alpha><beta/>", out.toString());
355         try {
356             writer.attribute("name", "value");
357             fail("attributes after closed element are not allowed");
358         } catch (InvalidXmlException e) {
359             // attributes after body content are not allowed
360         }
361     }
362     
363     @Test
364     public void closeDocumentBeforeOpen() throws Exception {
365         try {
366             writer.closeDocument();
367             fail("Cannot close document before the first element has been opened");
368         } catch (OperationNotAllowedException e) {
369             // Cannot open new elements before the first element has been opened
370         }
371     }
372     
373     @Test
374     public void closeDocumentAfterRootElementClosed() throws Exception {
375         assertEquals("XmlWriters should always return themselves", 
376                 writer, writer.openElement("alpha"));
377         assertEquals("Alpha element started", "<alpha", out.toString());
378         assertEquals("XmlWriters should always return themselves", 
379                 writer, writer.closeElement());
380         assertEquals("Beta element started", "<alpha/>", out.toString());
381         try {
382             writer.closeDocument();
383         } catch (OperationNotAllowedException e) {
384             fail("No exception should be thrown when called after the root element is closed.");
385         }
386     }   
387     
388     @Test
389     public void closeSimpleDocument() throws Exception {
390         assertEquals("XmlWriters should always return themselves", 
391                 writer, writer.openElement("alpha"));
392         assertEquals("Alpha element started", "<alpha", out.toString());
393         assertEquals("XmlWriters should always return themselves", 
394                 writer, writer.openElement("beta"));
395         assertEquals("Beta element started", "<alpha><beta", out.toString());
396         assertEquals("XmlWriters should always return themselves", 
397                 writer, writer.closeDocument());
398         assertEquals("Beta element started", "<alpha><beta/></alpha>", out.toString());
399     }
400     
401     @Test
402     public void closeComplexDocument() throws Exception {
403         assertEquals("XmlWriters should always return themselves", 
404                 writer, writer.openElement("alpha"));
405         assertEquals("Alpha element started", "<alpha", out.toString());
406         assertEquals("XmlWriters should always return themselves", 
407                 writer, writer.openElement("beta"));
408         assertEquals("Beta element started", "<alpha><beta", out.toString());
409         assertEquals("XmlWriters should always return themselves", 
410                 writer, writer.attribute("name", "value"));
411         assertEquals("Beta element started", "<alpha><beta name='value'", out.toString());
412         assertEquals("XmlWriters should always return themselves", 
413                 writer, writer.closeElement());
414         assertEquals("Beta element started", "<alpha><beta name='value'/>", out.toString());
415         assertEquals("XmlWriters should always return themselves", 
416                 writer, writer.openElement("beta"));
417         assertEquals("Beta element started", "<alpha><beta name='value'/><beta", out.toString());
418         assertEquals("XmlWriters should always return themselves", 
419                 writer, writer.attribute("name", "value"));
420         assertEquals("Beta element started", "<alpha><beta name='value'/><beta name='value'", out.toString());
421         assertEquals("XmlWriters should always return themselves", 
422                 writer, writer.openElement("gamma"));
423         assertEquals("Beta element started", "<alpha><beta name='value'/><beta name='value'><gamma", out.toString());
424         assertEquals("XmlWriters should always return themselves", 
425                 writer, writer.closeDocument());
426         assertEquals("Beta element started", "<alpha><beta name='value'/><beta name='value'><gamma/></beta></alpha>", out.toString());
427     }
428     
429     @Test
430     public void writeProlog() throws Exception {
431         assertEquals("XmlWriters should always return themselves", 
432                 writer, writer.startDocument());
433         assertEquals("Prolog written", "<?xml version='1.0'?>", out.toString());
434     }
435     
436     @Test
437     public void writeAfterElement() throws Exception {
438         assertEquals("XmlWriters should always return themselves", 
439                 writer, writer.openElement("alpha"));
440         assertEquals("Alpha element started", "<alpha", out.toString());
441         try {
442             writer.startDocument();
443             fail("Operation not allowed once an element has been written");
444         } catch (OperationNotAllowedException e) {
445             // Operation not allowed once an element has been written
446         }
447     }
448     
449     @Test
450     public void writePrologTwo() throws Exception {
451         assertEquals("XmlWriters should always return themselves", 
452                 writer, writer.startDocument());
453         assertEquals("Prolog written", "<?xml version='1.0'?>", out.toString());
454         try {
455             writer.startDocument();
456             fail("Operation not allow once a prolog has been written");
457         } catch (OperationNotAllowedException e) {
458             // Operation not allowed once an prolog has been written
459         }
460     }
461     
462     @Test
463     public void duplicateAttributes() throws Exception {
464         assertEquals("XmlWriters should always return themselves", 
465                 writer, writer.openElement("alpha"));
466         assertEquals("Alpha element started", "<alpha", out.toString());
467         assertEquals("XmlWriters should always return themselves", 
468                 writer, writer.attribute("one", "1"));
469         assertEquals("Attribute written", "<alpha one='1'", out.toString());
470         assertEquals("XmlWriters should always return themselves", 
471                 writer, writer.openElement("beta"));
472         assertEquals("Beta element started", "<alpha one='1'><beta", out.toString());
473         assertEquals("XmlWriters should always return themselves", 
474                 writer, writer.attribute("one", "1"));
475         assertEquals("Beta element started", "<alpha one='1'><beta one='1'", out.toString());
476         try {
477             writer.attribute("one", "2");
478             fail("Each attribute may only be written once");
479         } catch (InvalidXmlException e) {
480             // Each attribute may only be written once
481         }
482     }
483 }