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 org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertTrue;
24 import static org.junit.Assert.fail;
25
26 import java.io.ByteArrayOutputStream;
27 import java.io.File;
28 import java.io.OutputStream;
29 import java.nio.charset.StandardCharsets;
30
31 import org.junit.BeforeClass;
32 import org.junit.Test;
33
34 import com.puppycrawl.tools.checkstyle.api.AuditEvent;
35 import com.puppycrawl.tools.checkstyle.api.AutomaticBean;
36 import com.puppycrawl.tools.checkstyle.api.DetailAST;
37 import com.puppycrawl.tools.checkstyle.api.FileContents;
38 import com.puppycrawl.tools.checkstyle.api.FileText;
39 import com.puppycrawl.tools.checkstyle.api.LocalizedMessage;
40 import com.puppycrawl.tools.checkstyle.api.SeverityLevel;
41 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
42 import com.puppycrawl.tools.checkstyle.checks.blocks.LeftCurlyCheck;
43 import com.puppycrawl.tools.checkstyle.checks.coding.NestedForDepthCheck;
44 import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocVariableCheck;
45 import com.puppycrawl.tools.checkstyle.checks.whitespace.MethodParamPadCheck;
46 import com.puppycrawl.tools.checkstyle.internal.utils.CloseAndFlushTestByteArrayOutputStream;
47
48 public class XpathFileGeneratorAuditListenerTest {
49
50
51 private static final String EOL = System.getProperty("line.separator");
52
53 private static final LocalizedMessage FIRST_MESSAGE = createLocalizedMessage(3, 51,
54 TokenTypes.LCURLY, null, LeftCurlyCheck.class);
55
56 private static final LocalizedMessage SECOND_MESSAGE = createLocalizedMessage(15, 5,
57 TokenTypes.METHOD_DEF, "MyModule", MethodParamPadCheck.class);
58
59 private static final LocalizedMessage THIRD_MESSAGE = createLocalizedMessage(17, 13,
60 TokenTypes.LITERAL_FOR, null, NestedForDepthCheck.class);
61
62 private static final LocalizedMessage FOURTH_MESSAGE = createLocalizedMessage(5, 5,
63 TokenTypes.VARIABLE_DEF, "JavadocModuleId", JavadocVariableCheck.class);
64
65 private final CloseAndFlushTestByteArrayOutputStream outStream =
66 new CloseAndFlushTestByteArrayOutputStream();
67
68 @BeforeClass
69 public static void constructEvents() throws Exception {
70 final TreeWalkerAuditEvent event1 = createTreeWalkerAuditEvent(
71 "InputXpathFileGeneratorAuditListener.java", FIRST_MESSAGE);
72
73 final TreeWalkerAuditEvent event2 = createTreeWalkerAuditEvent(
74 "InputXpathFileGeneratorAuditListener.java", SECOND_MESSAGE);
75
76 final TreeWalkerAuditEvent event3 = createTreeWalkerAuditEvent(
77 "InputXpathFileGeneratorAuditListener.java", THIRD_MESSAGE);
78
79 final TreeWalkerAuditEvent event4 = createTreeWalkerAuditEvent(
80 "InputXpathFileGeneratorAuditListener.java", FOURTH_MESSAGE);
81
82 final XpathFileGeneratorAstFilter astFilter = new XpathFileGeneratorAstFilter();
83 astFilter.accept(event1);
84 astFilter.accept(event2);
85 astFilter.accept(event3);
86 astFilter.accept(event4);
87 }
88
89 @Test
90 public void testFinishLocalSetup() {
91 final OutputStream out = new ByteArrayOutputStream();
92 final XpathFileGeneratorAuditListener listener =
93 new XpathFileGeneratorAuditListener(out, AutomaticBean.OutputStreamOptions.CLOSE);
94
95 listener.finishLocalSetup();
96 listener.auditStarted(null);
97 listener.auditFinished(null);
98 final String actual = out.toString();
99 assertTrue("Output should be empty", actual.isEmpty());
100 }
101
102 @Test
103 public void testFileStarted() {
104 final OutputStream out = new ByteArrayOutputStream();
105 final XpathFileGeneratorAuditListener listener =
106 new XpathFileGeneratorAuditListener(out, AutomaticBean.OutputStreamOptions.CLOSE);
107 final AuditEvent ev = new AuditEvent(this, "Test.java", null);
108 listener.fileStarted(ev);
109 listener.auditFinished(null);
110 final String actual = out.toString();
111 assertTrue("Output should be empty", actual.isEmpty());
112 }
113
114 @Test
115 public void testFileFinished() {
116 final OutputStream out = new ByteArrayOutputStream();
117 final XpathFileGeneratorAuditListener listener =
118 new XpathFileGeneratorAuditListener(out, AutomaticBean.OutputStreamOptions.CLOSE);
119 final AuditEvent ev = new AuditEvent(this, "Test.java", null);
120 listener.fileFinished(ev);
121 listener.auditFinished(null);
122 final String actual = out.toString();
123 assertTrue("Output should be empty", actual.isEmpty());
124 }
125
126 @Test
127 public void testAddException() {
128 final OutputStream out = new ByteArrayOutputStream();
129 final XpathFileGeneratorAuditListener logger =
130 new XpathFileGeneratorAuditListener(out, AutomaticBean.OutputStreamOptions.CLOSE);
131 logger.auditStarted(null);
132 final LocalizedMessage message =
133 new LocalizedMessage(1, 1,
134 "messages.properties", null, null, null, getClass(), null);
135 final AuditEvent ev = new AuditEvent(this, "Test.java", message);
136
137 try {
138 logger.addException(ev, null);
139 fail("Exception is excepted");
140 }
141 catch (UnsupportedOperationException ex) {
142 assertEquals("Invalid exception message",
143 "Operation is not supported",
144 ex.getMessage());
145 }
146 }
147
148 @Test
149 public void testCorrectOne() {
150 final AuditEvent event = createAuditEvent("InputXpathFileGeneratorAuditListener.java",
151 FIRST_MESSAGE);
152
153 final String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + EOL
154 + "<!DOCTYPE suppressions PUBLIC" + EOL
155 + " \"-//Checkstyle//DTD SuppressionXpathFilter Experimental Configuration 1.2"
156 + "//EN\"" + EOL
157 + " \"https://checkstyle.org/dtds/suppressions_1_2_xpath_experimental.dtd\">"
158 + EOL
159 + "<suppressions>" + EOL
160 + "<suppress-xpath" + EOL
161 + " files=\"InputXpathFileGeneratorAuditListener.java\"" + EOL
162 + " checks=\"LeftCurlyCheck\""
163 + EOL
164 + " query=\"/CLASS_DEF[./IDENT[@text='InputXpathFileGeneratorAuditListener']]"
165 + "/OBJBLOCK/LCURLY\"/>" + EOL
166 + "</suppressions>" + EOL;
167
168 verifyOutput(expected, event);
169 }
170
171 @Test
172 public void testCorrectTwo() {
173 final AuditEvent event1 = createAuditEvent("InputXpathFileGeneratorAuditListener.java",
174 SECOND_MESSAGE);
175
176 final AuditEvent event2 = createAuditEvent("InputXpathFileGeneratorAuditListener.java",
177 THIRD_MESSAGE);
178
179 final String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + EOL
180 + "<!DOCTYPE suppressions PUBLIC" + EOL
181 + " \"-//Checkstyle//DTD SuppressionXpathFilter Experimental Configuration 1.2"
182 + "//EN\"" + EOL
183 + " \"https://checkstyle.org/dtds/suppressions_1_2_xpath_experimental.dtd\">"
184 + EOL
185 + "<suppressions>" + EOL
186 + "<suppress-xpath" + EOL
187 + " files=\"InputXpathFileGeneratorAuditListener.java\"" + EOL
188 + " id=\"MyModule\"" + EOL
189 + " query=\"/CLASS_DEF[./IDENT[@text='InputXpathFileGeneratorAuditListener']]"
190 + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='sort']]\"/>" + EOL
191 + "<suppress-xpath" + EOL
192 + " files=\"InputXpathFileGeneratorAuditListener.java\"" + EOL
193 + " checks=\"NestedForDepthCheck\"" + EOL
194 + " query=\"/CLASS_DEF[./IDENT[@text='InputXpathFileGeneratorAuditListener']]"
195 + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='sort']]/SLIST/LITERAL_FOR/SLIST"
196 + "/LITERAL_FOR\"/>" + EOL
197 + "</suppressions>" + EOL;
198
199 verifyOutput(expected, event1, event2);
200 }
201
202 @Test
203 public void testOnlyOneMatching() {
204 final AuditEvent event1 = createAuditEvent("InputXpathFileGeneratorAuditListener.java",
205 10, 5, MethodParamPadCheck.class);
206
207 final AuditEvent event2 = createAuditEvent("InputXpathFileGeneratorAuditListener.java",
208 5, 5, JavadocVariableCheck.class);
209
210 final AuditEvent event3 = createAuditEvent("InputXpathFileGeneratorAuditListener.java",
211 FOURTH_MESSAGE);
212
213 final String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + EOL
214 + "<!DOCTYPE suppressions PUBLIC" + EOL
215 + " \"-//Checkstyle//DTD SuppressionXpathFilter Experimental Configuration 1.2"
216 + "//EN\"" + EOL
217 + " \"https://checkstyle.org/dtds/suppressions_1_2_xpath_experimental.dtd\">"
218 + EOL
219 + "<suppressions>" + EOL
220 + "<suppress-xpath" + EOL
221 + " files=\"InputXpathFileGeneratorAuditListener.java\"" + EOL
222 + " id=\"JavadocModuleId\"" + EOL
223 + " query=\"/CLASS_DEF[./IDENT[@text='InputXpathFileGeneratorAuditListener']]"
224 + "/OBJBLOCK/VARIABLE_DEF[./IDENT[@text='isValid']]\"/>" + EOL
225 + "</suppressions>" + EOL;
226
227 verifyOutput(expected, event1, event2, event3);
228 }
229
230 @Test
231 public void testCloseStream() {
232 final XpathFileGeneratorAuditListener listener =
233 new XpathFileGeneratorAuditListener(outStream,
234 AutomaticBean.OutputStreamOptions.CLOSE);
235 listener.finishLocalSetup();
236 listener.auditStarted(null);
237 listener.auditFinished(null);
238
239 assertEquals("Invalid close count", 1, outStream.getCloseCount());
240 }
241
242 @Test
243 public void testNoCloseStream() {
244 final XpathFileGeneratorAuditListener listener =
245 new XpathFileGeneratorAuditListener(outStream,
246 AutomaticBean.OutputStreamOptions.NONE);
247 listener.finishLocalSetup();
248 listener.auditStarted(null);
249 listener.auditFinished(null);
250
251 assertEquals("Invalid close count", 0, outStream.getCloseCount());
252 }
253
254 private AuditEvent createAuditEvent(String fileName, int lineNumber, int columnNumber,
255 Class<?> sourceClass) {
256 final LocalizedMessage message =
257 new LocalizedMessage(lineNumber, columnNumber, "messages.properties", null,
258 null, null, sourceClass, null);
259
260 return new AuditEvent(this,
261 getPath(fileName), message);
262 }
263
264 private AuditEvent createAuditEvent(String fileName, LocalizedMessage message) {
265 return new AuditEvent(this,
266 getPath(fileName), message);
267 }
268
269 private static LocalizedMessage createLocalizedMessage(int lineNumber,
270 int columnNumber, int tokenType,
271 String moduleId,
272 Class<?> sourceClass) {
273 return new LocalizedMessage(lineNumber, columnNumber, tokenType,
274 "messages.properties", null, null,
275 SeverityLevel.ERROR, moduleId, sourceClass, null);
276 }
277
278 private static TreeWalkerAuditEvent createTreeWalkerAuditEvent(String fileName,
279 LocalizedMessage message)
280 throws Exception {
281 final File file = new File(getPath(fileName));
282 final FileText fileText = new FileText(
283 file.getAbsoluteFile(),
284 System.getProperty("file.encoding", StandardCharsets.UTF_8.name()));
285 final FileContents fileContents = new FileContents(fileText);
286 final DetailAST rootAst = JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS);
287
288 return new TreeWalkerAuditEvent(fileContents, fileName,
289 message, rootAst);
290 }
291
292 private static String getPath(String filename) {
293 return "src/test/resources/com/puppycrawl/tools/checkstyle/xpathfilegeneratorauditlistener/"
294 + filename;
295 }
296
297 private static void verifyOutput(String expected, AuditEvent... events) {
298 final TestByteArrayOutputStream out = new TestByteArrayOutputStream();
299
300 final XpathFileGeneratorAuditListener listener =
301 new XpathFileGeneratorAuditListener(out, AutomaticBean.OutputStreamOptions.CLOSE);
302
303 for (AuditEvent event : events) {
304 listener.addError(event);
305 }
306
307 listener.auditFinished(null);
308
309 assertEquals("expected number of flushes", 1, out.flushCount);
310 assertEquals("expected number of closes", 1, out.closeCount);
311
312 final String actual = out.toString();
313 assertEquals("Invalid suppressions file content", expected, actual);
314 }
315
316 private static class TestByteArrayOutputStream extends ByteArrayOutputStream {
317
318 private int closeCount;
319 private int flushCount;
320
321 @Override
322 public void close() {
323 closeCount++;
324 }
325
326 @Override
327 public void flush() {
328 flushCount++;
329 }
330
331 }
332 }