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