1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2019 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  
26  import java.io.File;
27  import java.io.IOException;
28  import java.io.InputStream;
29  import java.lang.reflect.Constructor;
30  import java.lang.reflect.Method;
31  import java.nio.file.Files;
32  import java.nio.file.NoSuchFileException;
33  import java.util.ArrayList;
34  import java.util.Collections;
35  import java.util.HashMap;
36  import java.util.List;
37  import java.util.Map;
38  import java.util.SortedSet;
39  
40  import org.junit.Assert;
41  import org.junit.Test;
42  
43  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
44  import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
45  import com.puppycrawl.tools.checkstyle.api.FileText;
46  import com.puppycrawl.tools.checkstyle.api.LocalizedMessage;
47  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
48  
49  public class UniquePropertiesCheckTest extends AbstractModuleTestSupport {
50  
51      @Override
52      protected String getPackageLocation() {
53          return "com/puppycrawl/tools/checkstyle/checks/uniqueproperties";
54      }
55  
56      /* Additional test for jacoco, since valueOf()
57       * is generated by javac and jacoco reports that
58       * valueOf() is uncovered.
59       */
60      @Test
61      public void testLineSeparatorOptionValueOf() {
62          final LineSeparatorOption option = LineSeparatorOption.valueOf("CR");
63          assertEquals("Invalid valueOf result", LineSeparatorOption.CR, option);
64      }
65  
66      /**
67       * Tests the ordinal work of a check.
68       */
69      @Test
70      public void testDefault() throws Exception {
71          final DefaultConfiguration checkConfig = createModuleConfig(UniquePropertiesCheck.class);
72          final String[] expected = {
73              "3: " + getCheckMessage(MSG_KEY, "general.exception", 2),
74              "5: " + getCheckMessage(MSG_KEY, "DefaultLogger.auditStarted", 2),
75              "11: " + getCheckMessage(MSG_KEY, "onlineManual", 3),
76              "22: " + getCheckMessage(MSG_KEY, "time stamp", 3),
77              "28: " + getCheckMessage(MSG_KEY, "Support Link ", 2),
78              "34: " + getCheckMessage(MSG_KEY, "failed", 2),
79          };
80          verify(checkConfig, getPath("InputUniqueProperties.properties"), expected);
81      }
82  
83      /**
84       * Tests the {@link UniquePropertiesCheck#getLineNumber(FileText, String)}
85       * method return value.
86       * @noinspection JavadocReference Test javadocs should explain all.
87       */
88      @Test
89      public void testNotFoundKey() throws Exception {
90          final List<String> testStrings = new ArrayList<>(3);
91          final Method getLineNumber = UniquePropertiesCheck.class.getDeclaredMethod(
92              "getLineNumber", FileText.class, String.class);
93          Assert.assertNotNull("Get line number method should be present", getLineNumber);
94          getLineNumber.setAccessible(true);
95          testStrings.add("");
96          testStrings.add("0 = 0");
97          testStrings.add("445");
98          final FileText fileText = new FileText(new File("some.properties"), testStrings);
99          final Object lineNumber = getLineNumber.invoke(UniquePropertiesCheck.class,
100                 fileText, "some key");
101         Assert.assertNotNull("Line number should not be null", lineNumber);
102         assertEquals("Invalid line number", 1, lineNumber);
103     }
104 
105     @Test
106     public void testDuplicatedProperty() throws Exception {
107         final DefaultConfiguration checkConfig = createModuleConfig(UniquePropertiesCheck.class);
108         final String[] expected = {
109             "2: " + getCheckMessage(MSG_KEY, "key", 2),
110         };
111         verify(checkConfig, getPath("InputUniquePropertiesWithDuplicates.properties"), expected);
112     }
113 
114     @Test
115     public void testShouldNotProcessFilesWithWrongFileExtension() throws Exception {
116         final DefaultConfiguration checkConfig = createModuleConfig(UniquePropertiesCheck.class);
117         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
118         verify(checkConfig, getPath("InputUniqueProperties.txt"), expected);
119     }
120 
121     /**
122      * Tests IO exception, that can occur during reading of properties file.
123      */
124     @Test
125     public void testIoException() throws Exception {
126         final DefaultConfiguration checkConfig = createModuleConfig(UniquePropertiesCheck.class);
127         final UniquePropertiesCheck check = new UniquePropertiesCheck();
128         check.configure(checkConfig);
129         final String fileName =
130                 getPath("InputUniquePropertiesCheckNotExisting.properties");
131         final File file = new File(fileName);
132         final FileText fileText = new FileText(file, Collections.emptyList());
133         final SortedSet<LocalizedMessage> messages =
134                 check.process(file, fileText);
135         assertEquals("Wrong messages count: " + messages.size(),
136                 1, messages.size());
137         final LocalizedMessage message = messages.iterator().next();
138         final String retrievedMessage = messages.iterator().next().getKey();
139         assertEquals("Message key '" + retrievedMessage
140                         + "' is not valid", "unable.open.cause",
141                 retrievedMessage);
142         assertEquals("Message '" + message.getMessage()
143                         + "' is not valid", message.getMessage(),
144                 getCheckMessage(MSG_IO_EXCEPTION_KEY, fileName, getFileNotFoundDetail(file)));
145     }
146 
147     @Test
148     public void testWrongKeyTypeInProperties() throws Exception {
149         final Class<?> uniquePropertiesClass = Class
150                 .forName("com.puppycrawl.tools.checkstyle.checks."
151                     + "UniquePropertiesCheck$UniqueProperties");
152         final Constructor<?> constructor = uniquePropertiesClass.getDeclaredConstructor();
153         constructor.setAccessible(true);
154         final Object uniqueProperties = constructor.newInstance();
155         final Method method = uniqueProperties.getClass().getDeclaredMethod("put", Object.class,
156                 Object.class);
157         final Object result = method.invoke(uniqueProperties, 1, "value");
158         final Map<Object, Object> table = new HashMap<>();
159         final Object expected = table.put(1, "value");
160         assertEquals("Invalid result of put method", expected, result);
161 
162         final Object result2 = method.invoke(uniqueProperties, 1, "value");
163         final Object expected2 = table.put(1, "value");
164         assertEquals("Value should be substituted", expected2, result2);
165     }
166 
167     /**
168      * Method generates NoSuchFileException details. It tries to a open file that does not exist.
169      * @param file to be opened
170      * @return localized detail message of {@link NoSuchFileException}
171      */
172     private static String getFileNotFoundDetail(File file) {
173         // Create exception to know detail message we should wait in
174         // LocalisedMessage
175         try (InputStream stream = Files.newInputStream(file.toPath())) {
176             throw new IllegalStateException("File " + file.getPath() + " should not exist");
177         }
178         catch (IOException ex) {
179             return ex.getLocalizedMessage();
180         }
181     }
182 
183 }