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.coding;
21  
22  import static com.puppycrawl.tools.checkstyle.checks.coding.ModifiedControlVariableCheck.MSG_KEY;
23  import static org.junit.Assert.assertTrue;
24  
25  import java.io.File;
26  import java.util.Collection;
27  import java.util.Optional;
28  import java.util.Set;
29  
30  import org.junit.Assert;
31  import org.junit.Test;
32  
33  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
34  import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
35  import com.puppycrawl.tools.checkstyle.api.DetailAST;
36  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
37  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
38  import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
39  
40  public class ModifiedControlVariableCheckTest
41      extends AbstractModuleTestSupport {
42      @Override
43      protected String getPackageLocation() {
44          return "com/puppycrawl/tools/checkstyle/checks/coding/modifiedcontrolvariable";
45      }
46  
47      @Test
48      public void testModifiedControlVariable() throws Exception {
49          final DefaultConfiguration checkConfig =
50              createModuleConfig(ModifiedControlVariableCheck.class);
51          final String[] expected = {
52              "14:14: " + getCheckMessage(MSG_KEY, "i"),
53              "17:15: " + getCheckMessage(MSG_KEY, "i"),
54              "20:37: " + getCheckMessage(MSG_KEY, "i"),
55              "21:17: " + getCheckMessage(MSG_KEY, "i"),
56              "49:15: " + getCheckMessage(MSG_KEY, "s"),
57              "56:14: " + getCheckMessage(MSG_KEY, "m"),
58              "67:15: " + getCheckMessage(MSG_KEY, "i"),
59              "68:15: " + getCheckMessage(MSG_KEY, "k"),
60              "78:15: " + getCheckMessage(MSG_KEY, "v"),
61          };
62          verify(checkConfig, getPath("InputModifiedControlVariableBothForLoops.java"), expected);
63      }
64  
65      @Test
66      public void testEnhancedForLoopVariableTrue() throws Exception {
67          final DefaultConfiguration checkConfig =
68              createModuleConfig(ModifiedControlVariableCheck.class);
69          checkConfig.addAttribute("skipEnhancedForLoopVariable", "true");
70  
71          final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
72          verify(checkConfig, getPath("InputModifiedControlVariableEnhancedForLoopVariable.java"),
73              expected);
74      }
75  
76      @Test
77      public void testEnhancedForLoopVariableFalse() throws Exception {
78          final DefaultConfiguration checkConfig =
79              createModuleConfig(ModifiedControlVariableCheck.class);
80  
81          final String[] expected = {
82              "9:18: " + getCheckMessage(MSG_KEY, "line"),
83          };
84          verify(checkConfig, getPath("InputModifiedControlVariableEnhancedForLoopVariable.java"),
85              expected);
86      }
87  
88      @Test
89      public void testEnhancedForLoopVariable2() throws Exception {
90          final DefaultConfiguration checkConfig =
91                  createModuleConfig(ModifiedControlVariableCheck.class);
92          checkConfig.addAttribute("skipEnhancedForLoopVariable", "true");
93  
94          final String[] expected = {
95              "14:18: " + getCheckMessage(MSG_KEY, "i"),
96          };
97          verify(checkConfig, getPath("InputModifiedControlVariableEnhancedForLoopVariable2.java"),
98              expected);
99      }
100 
101     @Test
102     public void testTokensNotNull() {
103         final ModifiedControlVariableCheck check = new ModifiedControlVariableCheck();
104         Assert.assertNotNull("Acceptable tokens should not be null", check.getAcceptableTokens());
105         Assert.assertNotNull("Default tokens should not be null", check.getDefaultTokens());
106         Assert.assertNotNull("Required tokens should not be null", check.getRequiredTokens());
107     }
108 
109     @Test
110     public void testImproperToken() {
111         final ModifiedControlVariableCheck check = new ModifiedControlVariableCheck();
112 
113         final DetailAST classDefAst = new DetailAST();
114         classDefAst.setType(TokenTypes.CLASS_DEF);
115 
116         try {
117             check.visitToken(classDefAst);
118             Assert.fail("IllegalStateException is expected");
119         }
120         catch (IllegalStateException ex) {
121             // it is OK
122         }
123 
124         try {
125             check.leaveToken(classDefAst);
126             Assert.fail("IllegalStateException is expected");
127         }
128         catch (IllegalStateException ex) {
129             // it is OK
130         }
131     }
132 
133     /**
134      * We cannot reproduce situation when visitToken is called and leaveToken is not.
135      * So, we have to use reflection to be sure that even in such situation
136      * state of the field will be cleared.
137      *
138      * @throws Exception when code tested throws exception
139      */
140     @Test
141     @SuppressWarnings("unchecked")
142     public void testClearState() throws Exception {
143         final ModifiedControlVariableCheck check = new ModifiedControlVariableCheck();
144         final Optional<DetailAST> methodDef = TestUtil.findTokenInAstByPredicate(
145             TestUtil.parseFile(new File(
146                 getPath("InputModifiedControlVariableEnhancedForLoopVariable.java"))),
147             ast -> ast.getType() == TokenTypes.OBJBLOCK);
148 
149         assertTrue("Ast should contain METHOD_DEF", methodDef.isPresent());
150         assertTrue("State is not cleared on beginTree",
151             TestUtil.isStatefulFieldClearedDuringBeginTree(check, methodDef.get(),
152                 "variableStack",
153                 variableStack -> ((Collection<Set<String>>) variableStack).isEmpty()));
154     }
155 }