View Javadoc
1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2017 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.checks;
21  
22  import static org.junit.Assert.assertArrayEquals;
23  import static org.junit.Assert.assertEquals;
24  import static org.junit.Assert.assertFalse;
25  import static org.junit.Assert.assertTrue;
26  import static org.junit.Assert.fail;
27  import static org.powermock.api.mockito.PowerMockito.mock;
28  
29  import java.lang.reflect.Constructor;
30  import java.lang.reflect.Field;
31  import java.lang.reflect.InvocationTargetException;
32  import java.lang.reflect.Method;
33  import java.util.ArrayList;
34  import java.util.List;
35  
36  import org.junit.Test;
37  import org.junit.runner.RunWith;
38  import org.powermock.api.mockito.PowerMockito;
39  import org.powermock.core.classloader.annotations.PrepareForTest;
40  import org.powermock.modules.junit4.PowerMockRunner;
41  
42  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
43  import com.puppycrawl.tools.checkstyle.Checker;
44  import com.puppycrawl.tools.checkstyle.api.AuditEvent;
45  import com.puppycrawl.tools.checkstyle.api.Configuration;
46  import com.puppycrawl.tools.checkstyle.api.DetailAST;
47  import com.puppycrawl.tools.checkstyle.api.LocalizedMessage;
48  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
49  import com.puppycrawl.tools.checkstyle.checks.naming.MemberNameCheck;
50  import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
51  
52  @RunWith(PowerMockRunner.class)
53  @PrepareForTest({ SuppressWarningsHolder.class, SuppressWarningsHolderTest.class })
54  public class SuppressWarningsHolderTest extends AbstractModuleTestSupport {
55      @Override
56      protected String getPackageLocation() {
57          return "com/puppycrawl/tools/checkstyle/checks/suppresswarningsholder";
58      }
59  
60      @Test
61      public void testGetRequiredTokens() {
62          final SuppressWarningsHolder checkObj = new SuppressWarningsHolder();
63          final int[] expected = {TokenTypes.ANNOTATION};
64          assertArrayEquals("Required token array differs from expected",
65                  expected, checkObj.getRequiredTokens());
66      }
67  
68      @Test
69      public void testOnComplexAnnotations() throws Exception {
70          final Configuration checkConfig = createModuleConfig(SuppressWarningsHolder.class);
71  
72          final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
73  
74          verify(checkConfig, getPath("InputSuppressWarningsHolder.java"), expected);
75      }
76  
77      @Test
78      public void testCustomAnnotation() throws Exception {
79          final Configuration checkConfig = createModuleConfig(SuppressWarningsHolder.class);
80  
81          final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
82  
83          verify(checkConfig, getPath("InputSuppressWarningsHolder5.java"), expected);
84      }
85  
86      @Test
87      public void testGetDefaultAlias() {
88          assertEquals("Default alias differs from expected",
89                  "somename", SuppressWarningsHolder.getDefaultAlias("SomeName"));
90          assertEquals("Default alias differs from expected",
91                  "somename", SuppressWarningsHolder.getDefaultAlias("SomeNameCheck"));
92      }
93  
94      @Test
95      public void testSetAliasListEmpty() {
96          final SuppressWarningsHolder holder = new SuppressWarningsHolder();
97          holder.setAliasList("");
98          assertEquals("Empty alias list should not be set", "",
99              SuppressWarningsHolder.getAlias(""));
100     }
101 
102     @Test
103     public void testSetAliasListCorrect() {
104         final SuppressWarningsHolder holder = new SuppressWarningsHolder();
105         holder.setAliasList("alias=value");
106         assertEquals("Alias differs from expected",
107                 "value", SuppressWarningsHolder.getAlias("alias"));
108     }
109 
110     @Test
111     public void testSetAliasListWrong() {
112         final SuppressWarningsHolder holder = new SuppressWarningsHolder();
113 
114         try {
115             holder.setAliasList("=SomeAlias");
116             fail("Exception expected");
117         }
118         catch (IllegalArgumentException ex) {
119             assertEquals("Error message is unexpected",
120                     "'=' expected in alias list item: =SomeAlias", ex.getMessage());
121         }
122 
123     }
124 
125     @Test
126     public void testIsSuppressed() throws Exception {
127         createHolder("MockEntry", 100, 100, 350, 350);
128         final AuditEvent event = createAuditEvent("check", 100, 10);
129 
130         assertFalse("Event is not suppressed", SuppressWarningsHolder.isSuppressed(event));
131     }
132 
133     @Test
134     public void testIsSuppressedByName() throws Exception {
135         final SuppressWarningsHolder holder = createHolder("check", 100, 100, 350, 350);
136         final AuditEvent event = createAuditEvent("id", 110, 10);
137         holder.setAliasList(MemberNameCheck.class.getName() + "=check");
138 
139         assertTrue("Event is not suppressed", SuppressWarningsHolder.isSuppressed(event));
140     }
141 
142     @Test
143     public void testIsSuppressedByModuleId() throws Exception {
144         createHolder("check", 100, 100, 350, 350);
145         final AuditEvent event = createAuditEvent("check", 350, 350);
146 
147         assertTrue("Event is not suppressed", SuppressWarningsHolder.isSuppressed(event));
148     }
149 
150     @Test
151     public void testIsSuppressedAfterEventEnd() throws Exception {
152         createHolder("check", 100, 100, 350, 350);
153         final AuditEvent event = createAuditEvent("check", 350, 352);
154 
155         assertFalse("Event is not suppressed", SuppressWarningsHolder.isSuppressed(event));
156     }
157 
158     @Test
159     public void testIsSuppressedAfterEventStart() throws Exception {
160         createHolder("check", 100, 100, 350, 350);
161         final AuditEvent event = createAuditEvent("check", 100, 100);
162 
163         assertTrue("Event is not suppressed", SuppressWarningsHolder.isSuppressed(event));
164     }
165 
166     @Test
167     public void testIsSuppressedWithAllArgument() throws Exception {
168         createHolder("all", 100, 100, 350, 350);
169 
170         final Checker source = new Checker();
171         final LocalizedMessage firstMessageForTest =
172             new LocalizedMessage(100, 10, null, null, null, "id", MemberNameCheck.class, "msg");
173         final AuditEvent firstEventForTest =
174             new AuditEvent(source, "fileName", firstMessageForTest);
175         assertFalse("Event is suppressed",
176                 SuppressWarningsHolder.isSuppressed(firstEventForTest));
177 
178         final LocalizedMessage secondMessageForTest =
179             new LocalizedMessage(100, 150, null, null, null, "id", MemberNameCheck.class, "msg");
180         final AuditEvent secondEventForTest =
181             new AuditEvent(source, "fileName", secondMessageForTest);
182         assertTrue("Event is not suppressed",
183                 SuppressWarningsHolder.isSuppressed(secondEventForTest));
184 
185         final LocalizedMessage thirdMessageForTest =
186             new LocalizedMessage(200, 1, null, null, null, "id", MemberNameCheck.class, "msg");
187         final AuditEvent thirdEventForTest =
188             new AuditEvent(source, "fileName", thirdMessageForTest);
189         assertTrue("Event is not suppressed",
190                 SuppressWarningsHolder.isSuppressed(thirdEventForTest));
191     }
192 
193     @Test
194     public void testAnnotationInTry() throws Exception {
195         final Configuration checkConfig = createModuleConfig(SuppressWarningsHolder.class);
196 
197         final String[] expected = {
198             "11: " + getCheckMessage(SuppressWarningsHolder.MSG_KEY),
199         };
200 
201         verify(checkConfig, getPath("InputSuppressWarningsHolder2.java"), expected);
202     }
203 
204     @Test
205     public void testEmptyAnnotation() throws Exception {
206         final Configuration checkConfig = createModuleConfig(SuppressWarningsHolder.class);
207 
208         final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
209 
210         verify(checkConfig, getPath("InputSuppressWarningsHolder3.java"), expected);
211     }
212 
213     @Test
214     public void testGetAllAnnotationValuesWrongArg() throws ReflectiveOperationException {
215         final SuppressWarningsHolder holder = new SuppressWarningsHolder();
216         final Method getAllAnnotationValues = holder.getClass()
217                 .getDeclaredMethod("getAllAnnotationValues", DetailAST.class);
218         getAllAnnotationValues.setAccessible(true);
219 
220         final DetailAST methodDef = new DetailAST();
221         methodDef.setType(TokenTypes.METHOD_DEF);
222         methodDef.setText("Method Def");
223         methodDef.setLineNo(0);
224         methodDef.setColumnNo(0);
225 
226         final DetailAST lparen = new DetailAST();
227         lparen.setType(TokenTypes.LPAREN);
228 
229         final DetailAST parent = new DetailAST();
230         parent.addChild(lparen);
231         parent.addChild(methodDef);
232 
233         try {
234             getAllAnnotationValues.invoke(holder, parent);
235             fail("Exception expected");
236         }
237         catch (InvocationTargetException ex) {
238             assertTrue("Error type is unexpected",
239                     ex.getCause() instanceof IllegalArgumentException);
240             assertEquals("Error message is unexpected",
241                     "Unexpected AST: Method Def[0x0]", ex.getCause().getMessage());
242         }
243     }
244 
245     @Test
246     public void testGetAnnotationValuesWrongArg() throws ReflectiveOperationException {
247         final SuppressWarningsHolder holder = new SuppressWarningsHolder();
248         final Method getAllAnnotationValues = holder.getClass()
249                 .getDeclaredMethod("getAnnotationValues", DetailAST.class);
250         getAllAnnotationValues.setAccessible(true);
251 
252         final DetailAST methodDef = new DetailAST();
253         methodDef.setType(TokenTypes.METHOD_DEF);
254         methodDef.setText("Method Def");
255         methodDef.setLineNo(0);
256         methodDef.setColumnNo(0);
257 
258         try {
259             getAllAnnotationValues.invoke(holder, methodDef);
260             fail("Exception expected");
261         }
262         catch (InvocationTargetException ex) {
263             assertTrue("Error type is unexpected",
264                     ex.getCause() instanceof IllegalArgumentException);
265             assertEquals("Error message is unexpected",
266                     "Expression or annotation array"
267                     + " initializer AST expected: Method Def[0x0]", ex.getCause().getMessage());
268         }
269     }
270 
271     @Test
272     public void testGetAnnotationTargetWrongArg() throws ReflectiveOperationException {
273         final SuppressWarningsHolder holder = new SuppressWarningsHolder();
274         final Method getAnnotationTarget = holder.getClass()
275                 .getDeclaredMethod("getAnnotationTarget", DetailAST.class);
276         getAnnotationTarget.setAccessible(true);
277 
278         final DetailAST methodDef = new DetailAST();
279         methodDef.setType(TokenTypes.METHOD_DEF);
280         methodDef.setText("Method Def");
281 
282         final DetailAST parent = new DetailAST();
283         parent.setType(TokenTypes.ASSIGN);
284         parent.setText("Parent ast");
285         parent.addChild(methodDef);
286         parent.setLineNo(0);
287         parent.setColumnNo(0);
288 
289         try {
290             getAnnotationTarget.invoke(holder, methodDef);
291             fail("Exception expected");
292         }
293         catch (InvocationTargetException ex) {
294             assertTrue("Error type is unexpected",
295                     ex.getCause() instanceof IllegalArgumentException);
296             assertEquals("Error message is unexpected",
297                     "Unexpected container AST: Parent ast[0x0]", ex.getCause().getMessage());
298         }
299     }
300 
301     @Test
302     public void testAstWithoutChildren() {
303         final SuppressWarningsHolder holder = new SuppressWarningsHolder();
304         final DetailAST methodDef = new DetailAST();
305         methodDef.setType(TokenTypes.METHOD_DEF);
306 
307         try {
308             holder.visitToken(methodDef);
309             fail("Exception expected");
310         }
311         catch (IllegalArgumentException ex) {
312             assertEquals("Error message is unexpected",
313                     "Identifier AST expected, but get null.", ex.getMessage());
314         }
315 
316     }
317 
318     @Test
319     public void testAnnotationWithFullName() throws Exception {
320         final Configuration checkConfig = createModuleConfig(SuppressWarningsHolder.class);
321 
322         final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
323 
324         verify(checkConfig, getPath("InputSuppressWarningsHolder4.java"), expected);
325     }
326 
327     private static SuppressWarningsHolder createHolder(String checkName, int firstLine,
328                                                        int firstColumn, int lastLine,
329                                                        int lastColumn) throws Exception {
330         final Class<?> entry = Class
331                 .forName("com.puppycrawl.tools.checkstyle.checks.SuppressWarningsHolder$Entry");
332         final Constructor<?> entryConstr = entry.getDeclaredConstructor(String.class, int.class,
333                 int.class, int.class, int.class);
334         entryConstr.setAccessible(true);
335 
336         final Object entryInstance = entryConstr.newInstance(checkName, firstLine,
337                 firstColumn, lastLine, lastColumn);
338 
339         final List<Object> entriesList = new ArrayList<>();
340         entriesList.add(entryInstance);
341 
342         final ThreadLocal<?> threadLocal = mock(ThreadLocal.class);
343         PowerMockito.doReturn(entriesList).when(threadLocal, "get");
344 
345         final SuppressWarningsHolder holder = new SuppressWarningsHolder();
346         final Field entries = holder.getClass().getDeclaredField("ENTRIES");
347         entries.setAccessible(true);
348         entries.set(holder, threadLocal);
349         return holder;
350     }
351 
352     private static AuditEvent createAuditEvent(String moduleId, int line, int column) {
353         final Checker source = new Checker();
354         final LocalizedMessage message = new LocalizedMessage(line, column, null, null, null,
355                 moduleId, MemberNameCheck.class, "message");
356         return new AuditEvent(source, "filename", message);
357     }
358 }