1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle;
21
22 import static com.google.common.truth.Truth.assertWithMessage;
23
24 import java.io.ByteArrayOutputStream;
25 import java.io.IOException;
26 import java.io.OutputStream;
27 import java.io.PrintWriter;
28 import java.nio.charset.StandardCharsets;
29
30 import org.junit.jupiter.api.Test;
31
32 import com.puppycrawl.tools.checkstyle.AbstractAutomaticBean.OutputStreamOptions;
33 import com.puppycrawl.tools.checkstyle.api.AuditEvent;
34 import com.puppycrawl.tools.checkstyle.api.AutomaticBean;
35 import com.puppycrawl.tools.checkstyle.api.SeverityLevel;
36 import com.puppycrawl.tools.checkstyle.api.Violation;
37 import com.puppycrawl.tools.checkstyle.internal.utils.CloseAndFlushTestByteArrayOutputStream;
38 import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
39
40 public class SarifLoggerTest extends AbstractModuleTestSupport {
41
42
43
44
45
46
47 private final CloseAndFlushTestByteArrayOutputStream outStream =
48 new CloseAndFlushTestByteArrayOutputStream();
49
50 @Override
51 protected String getPackageLocation() {
52 return "com/puppycrawl/tools/checkstyle/sariflogger";
53 }
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68 public final void executeLogger(
69 SarifLoggerTest instance, SarifLogger logger, String fileName, Violation violation) {
70 final AuditEvent event = new AuditEvent(this, "Test.java", violation);
71 logger.fileStarted(event);
72 logger.addError(event);
73 logger.fileFinished(event);
74 logger.auditFinished(null);
75 }
76
77 @Test
78 public void testEscape() {
79 final String[][] encodings = {
80 {"\"", "\\\""},
81 {"\\", "\\\\"},
82 {"\b", "\\b"},
83 {"\f", "\\f"},
84 {"\n", "\\n"},
85 {"\r", "\\r"},
86 {"\t", "\\t"},
87 {"/", "\\/"},
88 {"\u0010", "\\u0010"},
89 {"\u001E", "\\u001E"},
90 {"\u001F", "\\u001F"},
91 {" ", " "},
92 {"bar1234", "bar1234"},
93 };
94 for (String[] encoding : encodings) {
95 final String encoded = SarifLogger.escape(encoding[0]);
96 assertWithMessage("\"" + encoding[0] + "\"")
97 .that(encoded)
98 .isEqualTo(encoding[1]);
99 }
100 }
101
102 @Test
103 public void testSingleError() throws Exception {
104 final String inputFile = "InputSarifLoggerSingleError.java";
105 final String expectedReportFile = "ExpectedSarifLoggerSingleError.sarif";
106 final SarifLogger logger = new SarifLogger(outStream,
107 OutputStreamOptions.CLOSE);
108
109 verifyWithInlineConfigParserAndLogger(
110 getPath(inputFile), getPath(expectedReportFile), logger, outStream);
111 }
112
113 @Test
114 public void testAddErrorAtColumn1() throws IOException {
115 final SarifLogger logger = new SarifLogger(outStream,
116 OutputStreamOptions.CLOSE);
117 logger.auditStarted(null);
118 final Violation violation =
119 new Violation(1, 1,
120 "messages.properties", "ruleId", null, SeverityLevel.ERROR, null,
121 getClass(), "found an error\ntry again");
122 executeLogger(this, logger, "Test.java", violation);
123 verifyContent(getPath("ExpectedSarifLoggerSingleErrorColumn1.sarif"), outStream);
124 }
125
126 @Test
127 public void testAddErrorAtColumn0() throws Exception {
128 final String inputFile = "InputSarifLoggerErrorColumn0.java";
129 final String expectedReportFile = "ExpectedSarifLoggerSingleErrorColumn0.sarif";
130 final SarifLogger logger = new SarifLogger(outStream,
131 OutputStreamOptions.CLOSE);
132
133 verifyWithInlineConfigParserAndLogger(
134 getPath(inputFile), getPath(expectedReportFile), logger, outStream);
135 }
136
137 @Test
138 public void testAddErrorWithWarningLevel() throws IOException {
139 final SarifLogger logger = new SarifLogger(outStream,
140 OutputStreamOptions.CLOSE);
141 logger.auditStarted(null);
142 final Violation violation =
143 new Violation(1, 1,
144 "messages.properties", "ruleId", null, SeverityLevel.WARNING, null,
145 getClass(), "found an error");
146 final AuditEvent ev = new AuditEvent(this, "Test.java", violation);
147 logger.fileStarted(ev);
148 logger.addError(ev);
149 logger.fileFinished(ev);
150 logger.auditFinished(null);
151 verifyContent(getPath("ExpectedSarifLoggerSingleWarning.sarif"), outStream);
152 }
153
154 @Test
155 public void testAddErrors() throws IOException {
156 final SarifLogger logger = new SarifLogger(outStream,
157 OutputStreamOptions.CLOSE);
158 logger.auditStarted(null);
159 final Violation violation =
160 new Violation(1, 1,
161 "messages.properties", "ruleId", null, SeverityLevel.INFO, null,
162 getClass(), "found an error");
163 final AuditEvent ev = new AuditEvent(this, "Test.java", violation);
164 final Violation violation2 =
165 new Violation(1, 1,
166 "messages.properties", "ruleId2", null, SeverityLevel.IGNORE, null,
167 getClass(), "found another error");
168 final AuditEvent ev2 = new AuditEvent(this, "Test.java", violation2);
169 logger.fileStarted(ev);
170 logger.addError(ev);
171 logger.fileFinished(ev);
172 logger.fileStarted(ev2);
173 logger.addError(ev2);
174 logger.fileFinished(ev2);
175 logger.auditFinished(null);
176 verifyContent(getPath("ExpectedSarifLoggerDoubleError.sarif"), outStream);
177 }
178
179 @Test
180 public void testAddException() throws IOException {
181 final SarifLogger logger = new SarifLogger(outStream,
182 OutputStreamOptions.CLOSE);
183 logger.auditStarted(null);
184 final Violation message =
185 new Violation(1, 1,
186 "messages.properties", "null", null, null,
187 getClass(), "found an error");
188 final AuditEvent ev = new AuditEvent(this, null, message);
189 logger.fileStarted(ev);
190 logger.addException(ev, new TestException("msg", new RuntimeException("msg")));
191 logger.fileFinished(ev);
192 logger.auditFinished(null);
193 verifyContent(getPath("ExpectedSarifLoggerSingleException.sarif"), outStream);
194 }
195
196 @Test
197 public void testAddExceptions() throws IOException {
198 final SarifLogger logger = new SarifLogger(outStream,
199 OutputStreamOptions.CLOSE);
200 logger.auditStarted(null);
201 final Violation violation =
202 new Violation(1, 1,
203 "messages.properties", "null", null, null,
204 getClass(), "found an error");
205 final AuditEvent ev = new AuditEvent(this, null, violation);
206 final Violation violation2 =
207 new Violation(1, 1,
208 "messages.properties", "null", null, null,
209 getClass(), "found an error");
210 final AuditEvent ev2 = new AuditEvent(this, "Test.java", violation2);
211 logger.fileStarted(ev);
212 logger.addException(ev, new TestException("msg", new RuntimeException("msg")));
213 logger.fileFinished(ev);
214 logger.fileStarted(ev2);
215 logger.addException(ev2, new TestException("msg2", new RuntimeException("msg2")));
216 logger.fileFinished(ev);
217 logger.auditFinished(null);
218 verifyContent(getPath("ExpectedSarifLoggerDoubleException.sarif"), outStream);
219 }
220
221 @Test
222 public void testLineOnly() throws IOException {
223 final SarifLogger logger = new SarifLogger(outStream,
224 OutputStreamOptions.CLOSE);
225 logger.auditStarted(null);
226 final Violation violation =
227 new Violation(1, 0,
228 "messages.properties", "ruleId", null, null,
229 getClass(), "found an error");
230 final AuditEvent ev = new AuditEvent(this, "Test.java", violation);
231 logger.fileStarted(ev);
232 logger.addError(ev);
233 logger.fileFinished(ev);
234 logger.auditFinished(null);
235 verifyContent(getPath("ExpectedSarifLoggerLineOnly.sarif"), outStream);
236 }
237
238 @Test
239 public void testEmpty() throws IOException {
240 final SarifLogger logger = new SarifLogger(outStream,
241 OutputStreamOptions.CLOSE);
242 logger.auditStarted(null);
243 final Violation violation =
244 new Violation(1, 1,
245 "messages.properties", "null", null, null,
246 getClass(), "found an error");
247 final AuditEvent ev = new AuditEvent(this, null, violation);
248 logger.fileStarted(ev);
249 logger.fileFinished(ev);
250 logger.auditFinished(null);
251 verifyContent(getPath("ExpectedSarifLoggerEmpty.sarif"), outStream);
252 }
253
254 @Test
255 public void testAddErrorWithSpaceInPath() throws IOException {
256 final SarifLogger logger = new SarifLogger(outStream,
257 OutputStreamOptions.CLOSE);
258 logger.auditStarted(null);
259 final Violation violation =
260 new Violation(1, 1,
261 "messages.properties", "ruleId", null, SeverityLevel.ERROR, null,
262 getClass(), "found an error");
263 final AuditEvent ev = new AuditEvent(this, "/home/someuser/Code/Test 2.java", violation);
264 logger.fileStarted(ev);
265 logger.addError(ev);
266 logger.fileFinished(ev);
267 logger.auditFinished(null);
268 verifyContent(getPath("ExpectedSarifLoggerSpaceInPath.sarif"), outStream);
269 }
270
271 @Test
272 public void testAddErrorWithAbsoluteLinuxPath() throws IOException {
273 final SarifLogger logger = new SarifLogger(outStream,
274 OutputStreamOptions.CLOSE);
275 logger.auditStarted(null);
276 final Violation violation =
277 new Violation(1, 1,
278 "messages.properties", "ruleId", null, SeverityLevel.ERROR, null,
279 getClass(), "found an error");
280 final AuditEvent ev = new AuditEvent(this, "/home/someuser/Code/Test.java", violation);
281 logger.fileStarted(ev);
282 logger.addError(ev);
283 logger.fileFinished(ev);
284 logger.auditFinished(null);
285 verifyContent(getPath("ExpectedSarifLoggerAbsoluteLinuxPath.sarif"), outStream);
286 }
287
288 @Test
289 public void testAddErrorWithRelativeLinuxPath() throws IOException {
290 final SarifLogger logger = new SarifLogger(outStream,
291 OutputStreamOptions.CLOSE);
292 logger.auditStarted(null);
293 final Violation violation =
294 new Violation(1, 1,
295 "messages.properties", "ruleId", null, SeverityLevel.ERROR, null,
296 getClass(), "found an error");
297 final AuditEvent ev = new AuditEvent(this, "./Test.java", violation);
298 logger.fileStarted(ev);
299 logger.addError(ev);
300 logger.fileFinished(ev);
301 logger.auditFinished(null);
302 verifyContent(getPath("ExpectedSarifLoggerRelativeLinuxPath.sarif"), outStream);
303 }
304
305 @Test
306 public void testAddErrorWithAbsoluteWindowsPath() throws IOException {
307 final SarifLogger logger = new SarifLogger(outStream,
308 OutputStreamOptions.CLOSE);
309 logger.auditStarted(null);
310 final Violation violation =
311 new Violation(1, 1,
312 "messages.properties", "ruleId", null, SeverityLevel.ERROR, null,
313 getClass(), "found an error");
314 final AuditEvent ev =
315 new AuditEvent(this, "C:\\Users\\SomeUser\\Code\\Test.java", violation);
316 logger.fileStarted(ev);
317 logger.addError(ev);
318 logger.fileFinished(ev);
319 logger.auditFinished(null);
320 verifyContent(getPath("ExpectedSarifLoggerAbsoluteWindowsPath.sarif"), outStream);
321 }
322
323 @Test
324 public void testAddErrorWithRelativeWindowsPath() throws IOException {
325 final SarifLogger logger = new SarifLogger(outStream,
326 OutputStreamOptions.CLOSE);
327 logger.auditStarted(null);
328 final Violation violation =
329 new Violation(1, 1,
330 "messages.properties", "ruleId", null, SeverityLevel.ERROR, null,
331 getClass(), "found an error");
332 final AuditEvent ev = new AuditEvent(this, ".\\Test.java", violation);
333 logger.fileStarted(ev);
334 logger.addError(ev);
335 logger.fileFinished(ev);
336 logger.auditFinished(null);
337 verifyContent(getPath("ExpectedSarifLoggerRelativeWindowsPath.sarif"), outStream);
338 }
339
340
341
342
343 @Test
344 public void testCtorWithTwoParametersCloseStreamOptions() throws IOException {
345 final OutputStream infoStream = new ByteArrayOutputStream();
346 final SarifLogger logger = new SarifLogger(infoStream,
347 AutomaticBean.OutputStreamOptions.CLOSE);
348 final boolean closeStream = TestUtil.getInternalState(logger, "closeStream");
349
350 assertWithMessage("closeStream should be true")
351 .that(closeStream)
352 .isTrue();
353 }
354
355
356
357
358 @Test
359 public void testCtorWithTwoParametersNoneStreamOptions() throws IOException {
360 final OutputStream infoStream = new ByteArrayOutputStream();
361 final SarifLogger logger = new SarifLogger(infoStream,
362 AutomaticBean.OutputStreamOptions.NONE);
363 final boolean closeStream = TestUtil.getInternalState(logger, "closeStream");
364
365 assertWithMessage("closeStream should be false")
366 .that(closeStream)
367 .isFalse();
368 }
369
370 @Test
371 public void testNullOutputStreamOptions() {
372 try {
373 final SarifLogger logger = new SarifLogger(outStream, (OutputStreamOptions) null);
374
375 assertWithMessage("Null instance")
376 .that(logger)
377 .isNotNull();
378 assertWithMessage("Exception was expected").fail();
379 }
380 catch (IllegalArgumentException | IOException exception) {
381 assertWithMessage("Invalid error message")
382 .that(exception.getMessage())
383 .isEqualTo("Parameter outputStreamOptions can not be null");
384 }
385 }
386
387 @Test
388 public void testCloseStream() throws IOException {
389 final SarifLogger logger = new SarifLogger(outStream,
390 OutputStreamOptions.CLOSE);
391 logger.auditStarted(null);
392 logger.auditFinished(null);
393
394 assertWithMessage("Invalid close count")
395 .that(outStream.getCloseCount())
396 .isEqualTo(1);
397
398 verifyContent(getPath("ExpectedSarifLoggerEmpty.sarif"), outStream);
399 }
400
401 @Test
402 public void testNoCloseStream() throws IOException {
403 final SarifLogger logger = new SarifLogger(outStream,
404 OutputStreamOptions.NONE);
405 logger.auditStarted(null);
406 logger.auditFinished(null);
407
408 assertWithMessage("Invalid close count")
409 .that(outStream.getCloseCount())
410 .isEqualTo(0);
411 assertWithMessage("Invalid flush count")
412 .that(outStream.getFlushCount())
413 .isEqualTo(1);
414
415 outStream.close();
416 verifyContent(getPath("ExpectedSarifLoggerEmpty.sarif"), outStream);
417 }
418
419 @Test
420 public void testFinishLocalSetup() throws IOException {
421 final SarifLogger logger = new SarifLogger(outStream,
422 OutputStreamOptions.CLOSE);
423 logger.finishLocalSetup();
424 logger.auditStarted(null);
425 logger.auditFinished(null);
426 assertWithMessage("instance should not be null")
427 .that(logger)
428 .isNotNull();
429 }
430
431 @Test
432 public void testReadResourceWithInvalidName() {
433 try {
434 SarifLogger.readResource("random");
435 assertWithMessage("Exception expected").fail();
436 }
437 catch (IOException exception) {
438 assertWithMessage("Exception message must match")
439 .that(exception.getMessage())
440 .isEqualTo("Cannot find the resource random");
441 }
442 }
443
444 private static void verifyContent(
445 String expectedOutputFile,
446 ByteArrayOutputStream actualOutputStream) throws IOException {
447 final String expectedContent = readFile(expectedOutputFile);
448 final String actualContent =
449 toLfLineEnding(actualOutputStream.toString(StandardCharsets.UTF_8));
450 assertWithMessage("sarif content should match")
451 .that(actualContent)
452 .isEqualTo(expectedContent);
453 }
454
455 private static final class TestException extends RuntimeException {
456
457 private static final long serialVersionUID = 1L;
458
459 private TestException(String msg, Throwable cause) {
460 super(msg, cause);
461 }
462
463 @Override
464 public void printStackTrace(PrintWriter printWriter) {
465 printWriter.print("stackTrace\nexample");
466 }
467 }
468 }