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