1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2019 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle;
21  
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertFalse;
24  import static org.junit.Assert.assertNotNull;
25  import static org.junit.Assert.assertTrue;
26  import static org.junit.Assert.fail;
27  
28  import java.io.IOException;
29  import java.io.PrintWriter;
30  
31  import org.junit.Test;
32  
33  import com.puppycrawl.tools.checkstyle.api.AuditEvent;
34  import com.puppycrawl.tools.checkstyle.api.AutomaticBean;
35  import com.puppycrawl.tools.checkstyle.api.AutomaticBean.OutputStreamOptions;
36  import com.puppycrawl.tools.checkstyle.api.LocalizedMessage;
37  import com.puppycrawl.tools.checkstyle.api.SeverityLevel;
38  import com.puppycrawl.tools.checkstyle.internal.utils.CloseAndFlushTestByteArrayOutputStream;
39  
40  /**
41   * Enter a description of class XMLLoggerTest.java.
42   */
43  // -@cs[AbbreviationAsWordInName] Test should be named as its main class.
44  public class XMLLoggerTest extends AbstractXmlTestSupport {
45  
46      /**
47       * Output stream to hold the test results. The IntelliJ IDEA issues the AutoCloseableResource
48       * warning here, so it need to be suppressed. The {@code ByteArrayOutputStream} does not hold
49       * any resources that need to be released.
50       */
51      private final CloseAndFlushTestByteArrayOutputStream outStream =
52          new CloseAndFlushTestByteArrayOutputStream();
53  
54      @Override
55      protected String getPackageLocation() {
56          return "com/puppycrawl/tools/checkstyle/xmllogger";
57      }
58  
59      @Test
60      public void testEncode()
61              throws IOException {
62          final XMLLogger test = new XMLLogger(outStream, false);
63          assertNotNull("should be able to create XMLLogger without issue", test);
64          final String[][] encodings = {
65              {"<", "&lt;"},
66              {">", "&gt;"},
67              {"'", "&apos;"},
68              {"\"", "&quot;"},
69              {"&", "&amp;"},
70              {"&lt;", "&amp;lt;"},
71              {"abc;", "abc;"},
72              {"&#0;", "&amp;#0;"},
73              {"&#0", "&amp;#0"},
74              {"&#X0;", "&amp;#X0;"},
75              {"\u0001", "#x1;"},
76              {"\u0080", "#x80;"},
77          };
78          for (String[] encoding : encodings) {
79              final String encoded = XMLLogger.encode(encoding[0]);
80              assertEquals("\"" + encoding[0] + "\"", encoding[1], encoded);
81          }
82          outStream.close();
83      }
84  
85      @Test
86      public void testIsReference()
87              throws IOException {
88          final XMLLogger test = new XMLLogger(outStream, false);
89          assertNotNull("should be able to create XMLLogger without issue", test);
90          final String[] references = {
91              "&#0;",
92              "&#x0;",
93              "&lt;",
94              "&gt;",
95              "&apos;",
96              "&quot;",
97              "&amp;",
98          };
99          for (String reference : references) {
100             assertTrue("reference: " + reference,
101                     XMLLogger.isReference(reference));
102         }
103         final String[] noReferences = {
104             "&",
105             "&;",
106             "&#;",
107             "&#a;",
108             "&#X0;",
109             "&#x;",
110             "&#xg;",
111             "ramp;",
112             "ref",
113         };
114         for (String noReference : noReferences) {
115             assertFalse("no reference: " + noReference,
116                     XMLLogger.isReference(noReference));
117         }
118 
119         outStream.close();
120     }
121 
122     @Test
123     public void testCloseStream()
124             throws Exception {
125         final XMLLogger logger = new XMLLogger(outStream,
126                 AutomaticBean.OutputStreamOptions.CLOSE);
127         logger.auditStarted(null);
128         logger.auditFinished(null);
129 
130         assertEquals("Invalid close count", 1, outStream.getCloseCount());
131 
132         verifyXml(getPath("ExpectedXMLLoggerEmpty.xml"), outStream);
133     }
134 
135     @Test
136     public void testNoCloseStream()
137             throws Exception {
138         final XMLLogger logger = new XMLLogger(outStream,
139                 AutomaticBean.OutputStreamOptions.NONE);
140         logger.auditStarted(null);
141         logger.auditFinished(null);
142 
143         assertEquals("Invalid close count", 0, outStream.getCloseCount());
144 
145         outStream.close();
146         verifyXml(getPath("ExpectedXMLLoggerEmpty.xml"), outStream);
147     }
148 
149     @Test
150     public void testFileStarted()
151             throws Exception {
152         final XMLLogger logger = new XMLLogger(outStream, true);
153         logger.auditStarted(null);
154         final AuditEvent ev = new AuditEvent(this, "Test.java");
155         logger.fileStarted(ev);
156         logger.fileFinished(ev);
157         logger.auditFinished(null);
158         verifyXml(getPath("ExpectedXMLLogger.xml"), outStream);
159     }
160 
161     @Test
162     public void testFileFinished()
163             throws Exception {
164         final XMLLogger logger = new XMLLogger(outStream, true);
165         logger.auditStarted(null);
166         final AuditEvent ev = new AuditEvent(this, "Test.java");
167         logger.fileFinished(ev);
168         logger.auditFinished(null);
169         verifyXml(getPath("ExpectedXMLLogger.xml"), outStream);
170     }
171 
172     @Test
173     public void testAddError() throws Exception {
174         final XMLLogger logger = new XMLLogger(outStream, true);
175         logger.auditStarted(null);
176         final LocalizedMessage message =
177             new LocalizedMessage(1, 1,
178                 "messages.properties", "key", null, SeverityLevel.ERROR, null,
179                     getClass(), null);
180         final AuditEvent ev = new AuditEvent(this, "Test.java", message);
181         logger.fileStarted(ev);
182         logger.addError(ev);
183         logger.fileFinished(ev);
184         logger.auditFinished(null);
185         verifyXml(getPath("ExpectedXMLLoggerError.xml"), outStream, message.getMessage());
186     }
187 
188     @Test
189     public void testAddErrorWithNullFileName() throws Exception {
190         final XMLLogger logger = new XMLLogger(outStream, true);
191         logger.auditStarted(null);
192         final LocalizedMessage message =
193                 new LocalizedMessage(1, 1,
194                         "messages.properties", "key", null, SeverityLevel.ERROR, null,
195                         getClass(), null);
196         final AuditEvent ev = new AuditEvent(this, null, message);
197         logger.addError(ev);
198         logger.auditFinished(null);
199         verifyXml(getPath("ExpectedXMLLoggerErrorNullFileName.xml"), outStream,
200                 message.getMessage());
201     }
202 
203     @Test
204     public void testAddErrorModuleId() throws Exception {
205         final XMLLogger logger = new XMLLogger(outStream, true);
206         logger.auditStarted(null);
207         final LocalizedMessage message =
208             new LocalizedMessage(1, 1,
209                 "messages.properties", "key", null, SeverityLevel.ERROR, "module",
210                     getClass(), null);
211         final AuditEvent ev = new AuditEvent(this, "Test.java", message);
212         logger.addError(ev);
213         logger.auditFinished(null);
214         verifyXml(getPath("ExpectedXMLLoggerErrorModuleId.xml"), outStream, message.getMessage());
215     }
216 
217     @Test
218     public void testAddErrorOnZeroColumns() throws Exception {
219         final XMLLogger logger = new XMLLogger(outStream, true);
220         logger.auditStarted(null);
221         final LocalizedMessage message =
222                 new LocalizedMessage(1, 0,
223                         "messages.properties", "key", null, SeverityLevel.ERROR, null,
224                         getClass(), null);
225         final AuditEvent ev = new AuditEvent(this, "Test.java", message);
226         logger.fileStarted(ev);
227         logger.addError(ev);
228         logger.fileFinished(ev);
229         logger.auditFinished(null);
230         verifyXml(getPath("ExpectedXMLLoggerErrorZeroColumn.xml"), outStream,
231                 message.getMessage());
232     }
233 
234     @Test
235     public void testAddIgnored() throws Exception {
236         final XMLLogger logger = new XMLLogger(outStream, true);
237         logger.auditStarted(null);
238         final LocalizedMessage message =
239                 new LocalizedMessage(1, 1,
240                         "messages.properties", "key", null, SeverityLevel.IGNORE, null,
241                         getClass(), null);
242         final AuditEvent ev = new AuditEvent(this, "Test.java", message);
243         logger.addError(ev);
244         logger.auditFinished(null);
245         verifyXml(getPath("ExpectedXMLLoggerEmpty.xml"), outStream);
246     }
247 
248     @Test
249     public void testAddException()
250             throws Exception {
251         final XMLLogger logger = new XMLLogger(outStream, OutputStreamOptions.CLOSE);
252         logger.auditStarted(null);
253         final LocalizedMessage message =
254             new LocalizedMessage(1, 1,
255                 "messages.properties", null, null, null, getClass(), null);
256         final AuditEvent ev = new AuditEvent(this, "Test.java", message);
257         logger.addException(ev, new TestException("msg", new RuntimeException("msg")));
258         logger.auditFinished(null);
259         verifyXml(getPath("ExpectedXMLLoggerException.xml"), outStream);
260         assertEquals("Invalid close count", 1, outStream.getCloseCount());
261     }
262 
263     @Test
264     public void testAddExceptionWithNullFileName()
265             throws Exception {
266         final XMLLogger logger = new XMLLogger(outStream, true);
267         logger.auditStarted(null);
268         final LocalizedMessage message =
269                 new LocalizedMessage(1, 1,
270                         "messages.properties", null, null, null, getClass(), null);
271         final AuditEvent ev = new AuditEvent(this, null, message);
272         logger.addException(ev, new TestException("msg", new RuntimeException("msg")));
273         logger.auditFinished(null);
274         verifyXml(getPath("ExpectedXMLLoggerExceptionNullFileName.xml"), outStream);
275         assertEquals("Invalid close count", 1, outStream.getCloseCount());
276     }
277 
278     @Test
279     public void testAddExceptionAfterFileStarted()
280             throws Exception {
281         final XMLLogger logger = new XMLLogger(outStream, true);
282         logger.auditStarted(null);
283 
284         final AuditEvent fileStartedEvent = new AuditEvent(this, "Test.java");
285         logger.fileStarted(fileStartedEvent);
286 
287         final LocalizedMessage message =
288                 new LocalizedMessage(1, 1,
289                         "messages.properties", null, null, null, getClass(), null);
290         final AuditEvent ev = new AuditEvent(this, "Test.java", message);
291         logger.addException(ev, new TestException("msg", new RuntimeException("msg")));
292 
293         logger.fileFinished(ev);
294         logger.auditFinished(null);
295         verifyXml(getPath("ExpectedXMLLoggerException2.xml"), outStream);
296         assertEquals("Invalid close count", 1, outStream.getCloseCount());
297     }
298 
299     @Test
300     public void testAddExceptionBeforeFileFinished()
301             throws Exception {
302         final XMLLogger logger = new XMLLogger(outStream, true);
303         logger.auditStarted(null);
304         final LocalizedMessage message =
305                 new LocalizedMessage(1, 1,
306                         "messages.properties", null, null, null, getClass(), null);
307         final AuditEvent ev = new AuditEvent(this, "Test.java", message);
308         logger.addException(ev, new TestException("msg", new RuntimeException("msg")));
309         final AuditEvent fileFinishedEvent = new AuditEvent(this, "Test.java");
310         logger.fileFinished(fileFinishedEvent);
311         logger.auditFinished(null);
312         verifyXml(getPath("ExpectedXMLLoggerException3.xml"), outStream);
313         assertEquals("Invalid close count", 1, outStream.getCloseCount());
314     }
315 
316     @Test
317     public void testAddExceptionBetweenFileStartedAndFinished()
318             throws Exception {
319         final XMLLogger logger = new XMLLogger(outStream, true);
320         logger.auditStarted(null);
321         final LocalizedMessage message =
322                 new LocalizedMessage(1, 1,
323                         "messages.properties", null, null, null, getClass(), null);
324         final AuditEvent fileStartedEvent = new AuditEvent(this, "Test.java");
325         logger.fileStarted(fileStartedEvent);
326         final AuditEvent ev = new AuditEvent(this, "Test.java", message);
327         logger.addException(ev, new TestException("msg", new RuntimeException("msg")));
328         final AuditEvent fileFinishedEvent = new AuditEvent(this, "Test.java");
329         logger.fileFinished(fileFinishedEvent);
330         logger.auditFinished(null);
331         verifyXml(getPath("ExpectedXMLLoggerException2.xml"), outStream);
332         assertEquals("Invalid close count", 1, outStream.getCloseCount());
333     }
334 
335     @Test
336     public void testAuditFinishedWithoutFileFinished() throws Exception {
337         final XMLLogger logger = new XMLLogger(outStream, true);
338         logger.auditStarted(null);
339         final AuditEvent fileStartedEvent = new AuditEvent(this, "Test.java");
340         logger.fileStarted(fileStartedEvent);
341 
342         final LocalizedMessage message =
343                 new LocalizedMessage(1, 1,
344                         "messages.properties", "key", null, SeverityLevel.ERROR, null,
345                         getClass(), null);
346         final AuditEvent errorEvent = new AuditEvent(this, "Test.java", message);
347         logger.addError(errorEvent);
348 
349         logger.fileFinished(errorEvent);
350         logger.auditFinished(null);
351         verifyXml(getPath("ExpectedXMLLoggerError.xml"), outStream, message.getMessage());
352     }
353 
354     @Test
355     public void testNullOutputStreamOptions() {
356         try {
357             final XMLLogger logger = new XMLLogger(outStream, null);
358             // assert required to calm down eclipse's 'The allocated object is never used' violation
359             assertNotNull("Null instance", logger);
360             fail("Exception was expected");
361         }
362         catch (IllegalArgumentException exception) {
363             assertEquals("Invalid error message", "Parameter outputStreamOptions can not be null",
364                     exception.getMessage());
365         }
366     }
367 
368     @Test
369     public void testFinishLocalSetup() {
370         final XMLLogger logger = new XMLLogger(outStream, true);
371         logger.finishLocalSetup();
372         logger.auditStarted(null);
373         logger.auditFinished(null);
374         assertNotNull("instance should not be null", logger);
375     }
376 
377     private static class TestException extends RuntimeException {
378 
379         private static final long serialVersionUID = 1L;
380 
381         /* package */ TestException(String msg, Throwable cause) {
382             super(msg, cause);
383         }
384 
385         @Override
386         public void printStackTrace(PrintWriter printWriter) {
387             printWriter.print("stackTrace\r\nexample");
388         }
389 
390     }
391 
392 }