View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2024 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 com.google.common.truth.Truth.assertWithMessage;
23  
24  import java.io.IOException;
25  import java.io.PrintWriter;
26  
27  import org.junit.jupiter.api.Test;
28  
29  import com.puppycrawl.tools.checkstyle.AbstractAutomaticBean.OutputStreamOptions;
30  import com.puppycrawl.tools.checkstyle.api.AuditEvent;
31  import com.puppycrawl.tools.checkstyle.api.AutomaticBean;
32  import com.puppycrawl.tools.checkstyle.api.SeverityLevel;
33  import com.puppycrawl.tools.checkstyle.api.Violation;
34  import com.puppycrawl.tools.checkstyle.internal.utils.CloseAndFlushTestByteArrayOutputStream;
35  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
36  
37  /**
38   * Enter a description of class XMLLoggerTest.java.
39   */
40  // -@cs[AbbreviationAsWordInName] Test should be named as its main class.
41  public class XMLLoggerTest extends AbstractXmlTestSupport {
42  
43      /**
44       * Output stream to hold the test results. The IntelliJ IDEA issues the AutoCloseableResource
45       * warning here, so it needs to be suppressed. The {@code ByteArrayOutputStream} does not hold
46       * any resources that need to be released.
47       */
48      private final CloseAndFlushTestByteArrayOutputStream outStream =
49          new CloseAndFlushTestByteArrayOutputStream();
50  
51      @Override
52      protected String getPackageLocation() {
53          return "com/puppycrawl/tools/checkstyle/xmllogger";
54      }
55  
56      @Test
57      public void testEncode()
58              throws IOException {
59          final XMLLogger test = new XMLLogger(outStream, OutputStreamOptions.NONE);
60          assertWithMessage("should be able to create XMLLogger without issue")
61              .that(test)
62              .isNotNull();
63          final String[][] encodings = {
64              {"<", "&lt;"},
65              {">", "&gt;"},
66              {"'", "&apos;"},
67              {"\"", "&quot;"},
68              {"&", "&amp;"},
69              {"&lt;", "&amp;lt;"},
70              {"abc;", "abc;"},
71              {"&#0;", "&amp;#0;"},
72              {"&#0", "&amp;#0"},
73              {"&#X0;", "&amp;#X0;"},
74              {"\u0001", "#x1;"},
75              {"\u0080", "#x80;"},
76          };
77          for (String[] encoding : encodings) {
78              final String encoded = XMLLogger.encode(encoding[0]);
79              assertWithMessage("\"" + encoding[0] + "\"")
80                  .that(encoded)
81                  .isEqualTo(encoding[1]);
82          }
83          outStream.close();
84      }
85  
86      @Test
87      public void testIsReference()
88              throws IOException {
89          final XMLLogger test = new XMLLogger(outStream, OutputStreamOptions.NONE);
90          assertWithMessage("should be able to create XMLLogger without issue")
91              .that(test)
92              .isNotNull();
93          final String[] references = {
94              "&#0;",
95              "&#x0;",
96              "&lt;",
97              "&gt;",
98              "&apos;",
99              "&quot;",
100             "&amp;",
101         };
102         for (String reference : references) {
103             assertWithMessage("reference: " + reference)
104                     .that(XMLLogger.isReference(reference))
105                     .isTrue();
106         }
107         final String[] noReferences = {
108             "&",
109             "&;",
110             "&#;",
111             "&#a;",
112             "&#X0;",
113             "&#x;",
114             "&#xg;",
115             "ramp;",
116             "ref",
117         };
118         for (String noReference : noReferences) {
119             assertWithMessage("no reference: " + noReference)
120                     .that(XMLLogger.isReference(noReference))
121                     .isFalse();
122         }
123 
124         outStream.close();
125     }
126 
127     @Test
128     public void testCloseStream()
129             throws Exception {
130         final XMLLogger logger = new XMLLogger(outStream, OutputStreamOptions.CLOSE);
131         logger.auditStarted(null);
132         logger.auditFinished(null);
133 
134         assertWithMessage("Invalid close count")
135             .that(outStream.getCloseCount())
136             .isEqualTo(1);
137 
138         verifyXml(getPath("ExpectedXMLLoggerEmpty.xml"), outStream);
139     }
140 
141     @Test
142     public void testNoCloseStream()
143             throws Exception {
144         final XMLLogger logger = new XMLLogger(outStream, OutputStreamOptions.NONE);
145         logger.auditStarted(null);
146         logger.auditFinished(null);
147 
148         assertWithMessage("Invalid close count")
149             .that(outStream.getCloseCount())
150             .isEqualTo(0);
151 
152         outStream.close();
153         verifyXml(getPath("ExpectedXMLLoggerEmpty.xml"), outStream);
154     }
155 
156     @Test
157     public void testFileStarted()
158             throws Exception {
159         final XMLLogger logger = new XMLLogger(outStream, OutputStreamOptions.CLOSE);
160         logger.auditStarted(null);
161         final AuditEvent ev = new AuditEvent(this, "Test.java");
162         logger.fileStarted(ev);
163         logger.fileFinished(ev);
164         logger.auditFinished(null);
165         verifyXml(getPath("ExpectedXMLLogger.xml"), outStream);
166     }
167 
168     @Test
169     public void testFileFinished()
170             throws Exception {
171         final XMLLogger logger = new XMLLogger(outStream, OutputStreamOptions.CLOSE);
172         logger.auditStarted(null);
173         final AuditEvent ev = new AuditEvent(this, "Test.java");
174         logger.fileFinished(ev);
175         logger.auditFinished(null);
176         verifyXml(getPath("ExpectedXMLLogger.xml"), outStream);
177     }
178 
179     @Test
180     public void testAddError() throws Exception {
181         final XMLLogger logger = new XMLLogger(outStream, OutputStreamOptions.CLOSE);
182         logger.auditStarted(null);
183         final Violation violation =
184             new Violation(1, 1,
185                 "messages.properties", "key", null, SeverityLevel.ERROR, null,
186                     getClass(), null);
187         final AuditEvent ev = new AuditEvent(this, "Test.java", violation);
188         logger.fileStarted(ev);
189         logger.addError(ev);
190         logger.fileFinished(ev);
191         logger.auditFinished(null);
192         verifyXml(getPath("ExpectedXMLLoggerError.xml"), outStream, violation.getViolation());
193     }
194 
195     @Test
196     public void testAddErrorWithNullFileName() throws Exception {
197         final XMLLogger logger = new XMLLogger(outStream, OutputStreamOptions.CLOSE);
198         logger.auditStarted(null);
199         final Violation violation =
200                 new Violation(1, 1,
201                         "messages.properties", "key", null, SeverityLevel.ERROR, null,
202                         getClass(), null);
203         final AuditEvent ev = new AuditEvent(this, null, violation);
204         logger.addError(ev);
205         logger.auditFinished(null);
206         verifyXml(getPath("ExpectedXMLLoggerErrorNullFileName.xml"), outStream,
207                 violation.getViolation());
208     }
209 
210     @Test
211     public void testAddErrorModuleId() throws Exception {
212         final XMLLogger logger = new XMLLogger(outStream, OutputStreamOptions.CLOSE);
213         logger.auditStarted(null);
214         final Violation violation =
215             new Violation(1, 1,
216                 "messages.properties", "key", null, SeverityLevel.ERROR, "module",
217                     getClass(), null);
218         final AuditEvent ev = new AuditEvent(this, "Test.java", violation);
219         logger.addError(ev);
220         logger.auditFinished(null);
221         verifyXml(getPath("ExpectedXMLLoggerErrorModuleId.xml"), outStream,
222                 violation.getViolation());
223     }
224 
225     @Test
226     public void testAddErrorOnZeroColumns() throws Exception {
227         final XMLLogger logger = new XMLLogger(outStream, OutputStreamOptions.CLOSE);
228         logger.auditStarted(null);
229         final Violation violation =
230                 new Violation(1, 0,
231                         "messages.properties", "key", null, SeverityLevel.ERROR, null,
232                         getClass(), null);
233         final AuditEvent ev = new AuditEvent(this, "Test.java", violation);
234         logger.fileStarted(ev);
235         logger.addError(ev);
236         logger.fileFinished(ev);
237         logger.auditFinished(null);
238         verifyXml(getPath("ExpectedXMLLoggerErrorZeroColumn.xml"), outStream,
239                 violation.getViolation());
240     }
241 
242     @Test
243     public void testAddIgnored() throws Exception {
244         final XMLLogger logger = new XMLLogger(outStream, OutputStreamOptions.CLOSE);
245         logger.auditStarted(null);
246         final Violation violation =
247                 new Violation(1, 1,
248                         "messages.properties", "key", null, SeverityLevel.IGNORE, null,
249                         getClass(), null);
250         final AuditEvent ev = new AuditEvent(this, "Test.java", violation);
251         logger.addError(ev);
252         logger.auditFinished(null);
253         verifyXml(getPath("ExpectedXMLLoggerEmpty.xml"), outStream);
254     }
255 
256     @Test
257     public void testAddException()
258             throws Exception {
259         final XMLLogger logger = new XMLLogger(outStream, OutputStreamOptions.CLOSE);
260         logger.auditStarted(null);
261         final Violation violation =
262             new Violation(1, 1,
263                 "messages.properties", null, null, null, getClass(), null);
264         final AuditEvent ev = new AuditEvent(this, "Test.java", violation);
265         logger.addException(ev, new TestException("msg", new RuntimeException("msg")));
266         logger.auditFinished(null);
267         verifyXml(getPath("ExpectedXMLLoggerException.xml"), outStream);
268         assertWithMessage("Invalid close count")
269             .that(outStream.getCloseCount())
270             .isEqualTo(1);
271     }
272 
273     @Test
274     public void testAddExceptionWithNullFileName()
275             throws Exception {
276         final XMLLogger logger = new XMLLogger(outStream, OutputStreamOptions.CLOSE);
277         logger.auditStarted(null);
278         final Violation violation =
279                 new Violation(1, 1,
280                         "messages.properties", null, null, null, getClass(), null);
281         final AuditEvent ev = new AuditEvent(this, null, violation);
282         logger.addException(ev, new TestException("msg", new RuntimeException("msg")));
283         logger.auditFinished(null);
284         verifyXml(getPath("ExpectedXMLLoggerExceptionNullFileName.xml"), outStream);
285         assertWithMessage("Invalid close count")
286             .that(outStream.getCloseCount())
287             .isEqualTo(1);
288     }
289 
290     @Test
291     public void testAddExceptionAfterFileStarted()
292             throws Exception {
293         final XMLLogger logger = new XMLLogger(outStream, OutputStreamOptions.CLOSE);
294         logger.auditStarted(null);
295 
296         final AuditEvent fileStartedEvent = new AuditEvent(this, "Test.java");
297         logger.fileStarted(fileStartedEvent);
298 
299         final Violation violation =
300                 new Violation(1, 1,
301                         "messages.properties", null, null, null, getClass(), null);
302         final AuditEvent ev = new AuditEvent(this, "Test.java", violation);
303         logger.addException(ev, new TestException("msg", new RuntimeException("msg")));
304 
305         logger.fileFinished(ev);
306         logger.auditFinished(null);
307         verifyXml(getPath("ExpectedXMLLoggerException2.xml"), outStream);
308         assertWithMessage("Invalid close count")
309             .that(outStream.getCloseCount())
310             .isEqualTo(1);
311     }
312 
313     @Test
314     public void testAddExceptionBeforeFileFinished()
315             throws Exception {
316         final XMLLogger logger = new XMLLogger(outStream, OutputStreamOptions.CLOSE);
317         logger.auditStarted(null);
318         final Violation violation =
319                 new Violation(1, 1,
320                         "messages.properties", null, null, null, getClass(), null);
321         final AuditEvent ev = new AuditEvent(this, "Test.java", violation);
322         logger.addException(ev, new TestException("msg", new RuntimeException("msg")));
323         final AuditEvent fileFinishedEvent = new AuditEvent(this, "Test.java");
324         logger.fileFinished(fileFinishedEvent);
325         logger.auditFinished(null);
326         verifyXml(getPath("ExpectedXMLLoggerException3.xml"), outStream);
327         assertWithMessage("Invalid close count")
328             .that(outStream.getCloseCount())
329             .isEqualTo(1);
330     }
331 
332     @Test
333     public void testAddExceptionBetweenFileStartedAndFinished()
334             throws Exception {
335         final XMLLogger logger = new XMLLogger(outStream, OutputStreamOptions.CLOSE);
336         logger.auditStarted(null);
337         final Violation violation =
338                 new Violation(1, 1,
339                         "messages.properties", null, null, null, getClass(), null);
340         final AuditEvent fileStartedEvent = new AuditEvent(this, "Test.java");
341         logger.fileStarted(fileStartedEvent);
342         final AuditEvent ev = new AuditEvent(this, "Test.java", violation);
343         logger.addException(ev, new TestException("msg", new RuntimeException("msg")));
344         final AuditEvent fileFinishedEvent = new AuditEvent(this, "Test.java");
345         logger.fileFinished(fileFinishedEvent);
346         logger.auditFinished(null);
347         verifyXml(getPath("ExpectedXMLLoggerException2.xml"), outStream);
348         assertWithMessage("Invalid close count")
349             .that(outStream.getCloseCount())
350             .isEqualTo(1);
351     }
352 
353     @Test
354     public void testAuditFinishedWithoutFileFinished() throws Exception {
355         final XMLLogger logger = new XMLLogger(outStream, OutputStreamOptions.CLOSE);
356         logger.auditStarted(null);
357         final AuditEvent fileStartedEvent = new AuditEvent(this, "Test.java");
358         logger.fileStarted(fileStartedEvent);
359 
360         final Violation violation =
361                 new Violation(1, 1,
362                         "messages.properties", "key", null, SeverityLevel.ERROR, null,
363                         getClass(), null);
364         final AuditEvent errorEvent = new AuditEvent(this, "Test.java", violation);
365         logger.addError(errorEvent);
366 
367         logger.fileFinished(errorEvent);
368         logger.auditFinished(null);
369         verifyXml(getPath("ExpectedXMLLoggerError.xml"), outStream, violation.getViolation());
370     }
371 
372     @Test
373     public void testNullOutputStreamOptions() {
374         try {
375             final XMLLogger logger = new XMLLogger(outStream,
376                     (OutputStreamOptions) null);
377             // assert required to calm down eclipse's 'The allocated object is never used' violation
378             assertWithMessage("Null instance")
379                 .that(logger)
380                 .isNotNull();
381             assertWithMessage("Exception was expected").fail();
382         }
383         catch (IllegalArgumentException exception) {
384             assertWithMessage("Invalid error message")
385                 .that(exception.getMessage())
386                 .isEqualTo("Parameter outputStreamOptions can not be null");
387         }
388     }
389 
390     @Test
391     public void testFinishLocalSetup() {
392         final XMLLogger logger = new XMLLogger(outStream, OutputStreamOptions.CLOSE);
393         logger.finishLocalSetup();
394         logger.auditStarted(null);
395         logger.auditFinished(null);
396         assertWithMessage("instance should not be null")
397             .that(logger)
398             .isNotNull();
399     }
400 
401     /**
402      * We keep this test for 100% coverage. Until #12873.
403      */
404     @Test
405     public void testCtorWithTwoParametersCloseStreamOptions() {
406         final XMLLogger logger = new XMLLogger(outStream, AutomaticBean.OutputStreamOptions.CLOSE);
407         final boolean closeStream = TestUtil.getInternalState(logger, "closeStream");
408 
409         assertWithMessage("closeStream should be true")
410                 .that(closeStream)
411                 .isTrue();
412     }
413 
414     /**
415      * We keep this test for 100% coverage. Until #12873.
416      */
417     @Test
418     public void testCtorWithTwoParametersNoneStreamOptions() {
419         final XMLLogger logger = new XMLLogger(outStream, AutomaticBean.OutputStreamOptions.NONE);
420         final boolean closeStream = TestUtil.getInternalState(logger, "closeStream");
421 
422         assertWithMessage("closeStream should be false")
423                 .that(closeStream)
424                 .isFalse();
425     }
426 
427     private static final class TestException extends RuntimeException {
428 
429         private static final long serialVersionUID = 1L;
430 
431         private TestException(String msg, Throwable cause) {
432             super(msg, cause);
433         }
434 
435         @Override
436         public void printStackTrace(PrintWriter printWriter) {
437             printWriter.print("stackTrace\r\nexample");
438         }
439 
440     }
441 
442 }