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 com.puppycrawl.tools.checkstyle.checks.UniquePropertiesCheck.MSG_IO_EXCEPTION_KEY;
23  import static com.puppycrawl.tools.checkstyle.checks.UniquePropertiesCheck.MSG_KEY;
24  import static org.junit.Assert.assertEquals;
25  import static org.mockito.Matchers.any;
26  import static org.mockito.Mockito.times;
27  import static org.powermock.api.mockito.PowerMockito.doNothing;
28  import static org.powermock.api.mockito.PowerMockito.mockStatic;
29  import static org.powermock.api.mockito.PowerMockito.verifyStatic;
30  
31  import java.io.File;
32  import java.io.FileInputStream;
33  import java.io.FileNotFoundException;
34  import java.io.InputStream;
35  import java.lang.reflect.Constructor;
36  import java.lang.reflect.Method;
37  import java.util.ArrayList;
38  import java.util.Collections;
39  import java.util.HashMap;
40  import java.util.List;
41  import java.util.Map;
42  import java.util.SortedSet;
43  
44  import org.junit.Assert;
45  import org.junit.Test;
46  import org.junit.runner.RunWith;
47  import org.powermock.core.classloader.annotations.PrepareForTest;
48  import org.powermock.modules.junit4.PowerMockRunner;
49  
50  import com.google.common.io.Closeables;
51  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
52  import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
53  import com.puppycrawl.tools.checkstyle.api.FileText;
54  import com.puppycrawl.tools.checkstyle.api.LocalizedMessage;
55  import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
56  
57  @RunWith(PowerMockRunner.class)
58  @PrepareForTest(Closeables.class)
59  public class UniquePropertiesCheckTest extends AbstractModuleTestSupport {
60  
61      @Override
62      protected String getPackageLocation() {
63          return "com/puppycrawl/tools/checkstyle/checks/uniqueproperties";
64      }
65  
66      /* Additional test for jacoco, since valueOf()
67       * is generated by javac and jacoco reports that
68       * valueOf() is uncovered.
69       */
70      @Test
71      public void testLineSeparatorOptionValueOf() {
72          final LineSeparatorOption option = LineSeparatorOption.valueOf("CR");
73          assertEquals("Invalid valueOf result", LineSeparatorOption.CR, option);
74      }
75  
76      /**
77       * Tests the ordinal work of a check.
78       */
79      @Test
80      public void testDefault() throws Exception {
81          final DefaultConfiguration checkConfig = createModuleConfig(UniquePropertiesCheck.class);
82          final String[] expected = {
83              "3: " + getCheckMessage(MSG_KEY, "general.exception", 2),
84              "5: " + getCheckMessage(MSG_KEY, "DefaultLogger.auditStarted", 2),
85              "11: " + getCheckMessage(MSG_KEY, "onlineManual", 3),
86              "22: " + getCheckMessage(MSG_KEY, "time stamp", 3),
87              "28: " + getCheckMessage(MSG_KEY, "Support Link ", 2),
88              "34: " + getCheckMessage(MSG_KEY, "failed", 2),
89          };
90          verify(checkConfig, getPath("InputUniqueProperties.properties"), expected);
91      }
92  
93      /**
94       * Pitest requires all closes of streams and readers to be verified. Using PowerMock
95       * is almost only possibility to check it without rewriting production code.
96       *
97       * @throws Exception when code tested throws some exception
98       */
99      @Test
100     public void testCloseInputStream() throws Exception {
101         mockStatic(Closeables.class);
102         doNothing().when(Closeables.class);
103         Closeables.closeQuietly(any(FileInputStream.class));
104 
105         final DefaultConfiguration checkConfig = createModuleConfig(UniquePropertiesCheck.class);
106         final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
107         verify(checkConfig, getPath("InputUniquePropertiesWithoutErrors.properties"), expected);
108 
109         verifyStatic(times(1));
110         Closeables.closeQuietly(any(FileInputStream.class));
111     }
112 
113     /**
114      * Tests the {@link UniquePropertiesCheck#getLineNumber(FileText, String)}
115      * method return value.
116      */
117     @Test
118     public void testNotFoundKey() throws Exception {
119         final List<String> testStrings = new ArrayList<>(3);
120         final Method getLineNumber = UniquePropertiesCheck.class.getDeclaredMethod(
121             "getLineNumber", FileText.class, String.class);
122         Assert.assertNotNull("Get line number method should be present", getLineNumber);
123         getLineNumber.setAccessible(true);
124         testStrings.add("");
125         testStrings.add("0 = 0");
126         testStrings.add("445");
127         final FileText fileText = new FileText(new File("some.properties"), testStrings);
128         final Object lineNumber = getLineNumber.invoke(UniquePropertiesCheck.class,
129                 fileText, "some key");
130         Assert.assertNotNull("Line number should not be null", lineNumber);
131         assertEquals("Invalid line number", 0, lineNumber);
132     }
133 
134     @Test
135     public void testDuplicatedProperty() throws Exception {
136         final DefaultConfiguration checkConfig = createModuleConfig(UniquePropertiesCheck.class);
137         final String[] expected = {
138             "2: " + getCheckMessage(MSG_KEY, "key", 2),
139         };
140         verify(checkConfig, getPath("InputUniquePropertiesWithDuplicates.properties"), expected);
141     }
142 
143     @Test
144     public void testShouldNotProcessFilesWithWrongFileExtension() throws Exception {
145         final DefaultConfiguration checkConfig = createModuleConfig(UniquePropertiesCheck.class);
146         final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
147         verify(checkConfig, getPath("InputUniqueProperties.txt"), expected);
148     }
149 
150     /**
151      * Tests IO exception, that can occur during reading of properties file.
152      */
153     @Test
154     public void testIoException() throws Exception {
155         final DefaultConfiguration checkConfig = createModuleConfig(UniquePropertiesCheck.class);
156         final UniquePropertiesCheck check = new UniquePropertiesCheck();
157         check.configure(checkConfig);
158         final String fileName =
159                 getPath("InputUniquePropertiesCheckNotExisting.properties");
160         final File file = new File(fileName);
161         final FileText fileText = new FileText(file, Collections.emptyList());
162         final SortedSet<LocalizedMessage> messages =
163                 check.process(file, fileText);
164         assertEquals("Wrong messages count: " + messages.size(),
165                 1, messages.size());
166         final LocalizedMessage message = messages.iterator().next();
167         final String retrievedMessage = messages.iterator().next().getKey();
168         assertEquals("Message key '" + retrievedMessage
169                         + "' is not valid", "unable.open.cause",
170                 retrievedMessage);
171         assertEquals("Message '" + message.getMessage()
172                         + "' is not valid", message.getMessage(),
173                 getCheckMessage(MSG_IO_EXCEPTION_KEY, fileName, getFileNotFoundDetail(file)));
174     }
175 
176     @Test
177     public void testWrongKeyTypeInProperties() throws Exception {
178         final Class<?> uniquePropertiesClass = Class
179                 .forName("com.puppycrawl.tools.checkstyle.checks."
180                     + "UniquePropertiesCheck$UniqueProperties");
181         final Constructor<?> constructor = uniquePropertiesClass.getDeclaredConstructor();
182         constructor.setAccessible(true);
183         final Object uniqueProperties = constructor.newInstance();
184         final Method method = uniqueProperties.getClass().getDeclaredMethod("put", Object.class,
185                 Object.class);
186         final Object result = method.invoke(uniqueProperties, 1, "value");
187         final Map<Object, Object> table = new HashMap<>();
188         final Object expected = table.put(1, "value");
189         assertEquals("Invalid result of put method", expected, result);
190 
191         final Object result2 = method.invoke(uniqueProperties, 1, "value");
192         final Object expected2 = table.put(1, "value");
193         assertEquals("Value should be substituted", expected2, result2);
194     }
195 
196     /**
197      * Method generates FileNotFound exception details. It tries to open file,
198      * that does not exist.
199      * @param file to be opened
200      * @return detail message of {@link FileNotFoundException}
201      */
202     private static String getFileNotFoundDetail(File file) throws Exception {
203         // Create exception to know detail message we should wait in
204         // LocalisedMessage
205         try {
206             final InputStream stream = new FileInputStream(file);
207             stream.close();
208             throw new IllegalStateException("File " + file.getPath() + " should not exist");
209         }
210         catch (FileNotFoundException ex) {
211             return ex.getLocalizedMessage();
212         }
213     }
214 }