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