View Javadoc
1   package net.sourceforge.pmd.properties;
2   
3   import static org.junit.Assert.assertNotNull;
4   import static org.junit.Assert.assertNull;
5   import static org.junit.Assert.assertTrue;
6   
7   import java.util.Arrays;
8   import java.util.HashMap;
9   import java.util.Map;
10  
11  import net.sourceforge.pmd.PropertyDescriptor;
12  import net.sourceforge.pmd.PropertyDescriptorFactory;
13  import net.sourceforge.pmd.PropertyDescriptorFields;
14  import net.sourceforge.pmd.lang.rule.properties.factories.PropertyDescriptorUtil;
15  import net.sourceforge.pmd.util.CollectionUtil;
16  
17  import org.junit.Assert;
18  import org.junit.Assume;
19  import org.junit.Test;
20  
21  /**
22   * Base functionality for all concrete subclasses that evaluate type-specific
23   * property descriptors. Checks for error conditions during construction, error
24   * value detection, serialization, etc.
25   * 
26   * @author Brian Remedios
27   */
28  public abstract class AbstractPropertyDescriptorTester {
29  
30      public AbstractPropertyDescriptorTester(String typeName) {
31          this.typeName = typeName;
32      }
33  
34      protected final String typeName;
35  
36      private static final int multiValueCount = 10;
37  
38      public static final String punctuationChars = "!@#$%^&*()_-+=[]{}\\|;:'\",.<>/?`~";
39      public static final String whitespaceChars = " \t\n";
40      public static final String digitChars = "0123456789";
41      public static final String alphaChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmniopqrstuvwxyz";
42      public static final String alphaNumericChars = digitChars + alphaChars;
43      public static final String allChars = punctuationChars + whitespaceChars + alphaNumericChars;
44  
45      /**
46       * Return a legal value(s) per the general scope of the descriptor.
47       * 
48       * @param count int
49       * @return Object
50       */
51      protected abstract Object createValue(int count);
52  
53      /**
54       * Return a value(s) that is known to be faulty per the general scope of the
55       * descriptor.
56       * 
57       * @param count int
58       * @return Object
59       */
60      protected abstract Object createBadValue(int count);
61  
62      /**
63       * Creates and returns a properly configured property descriptor.
64       * 
65       * @param multiValue boolean
66       * @return PropertyDescriptor
67       */
68      protected abstract PropertyDescriptor createProperty(boolean multiValue);
69  
70      /**
71       * Attempt to create a property with faulty configuration values. This
72       * method should throw an IllegalArgumentException if done correctly.
73       * 
74       * @param multiValue boolean
75       * @return PropertyDescriptor
76       */
77      protected abstract PropertyDescriptor createBadProperty(boolean multiValue);
78  
79      protected final PropertyDescriptorFactory getSingleFactory() {
80          return PropertyDescriptorUtil.factoryFor(typeName);
81      }
82  
83      protected final PropertyDescriptorFactory getMultiFactory() {
84          return PropertyDescriptorUtil.factoryFor(typeName + "[]");
85      }
86  
87      private Map<String, String> getPropertyDescriptorValues() {
88          Map<String, String> valuesById = new HashMap<String, String>();
89          valuesById.put(PropertyDescriptorFields.NAME, "test");
90          valuesById.put(PropertyDescriptorFields.DESCRIPTION, "desc");
91          valuesById.put(PropertyDescriptorFields.MIN, "0");
92          valuesById.put(PropertyDescriptorFields.MAX, "10");
93          return valuesById;
94      }
95  
96      @Test
97      public void testFactorySingleValue() {
98          PropertyDescriptor prop = getSingleFactory().createWith(getPropertyDescriptorValues());
99          Object originalValue = createValue(1);
100         Object value = prop.valueFrom(originalValue instanceof Class ? ((Class) originalValue).getName() : String
101                 .valueOf(originalValue));
102         String asDelimitedString = prop.asDelimitedString(value);
103         Object value2 = prop.valueFrom(asDelimitedString);
104         Assert.assertEquals(value, value2);
105     }
106 
107     @Test
108     public void testFactoryMultiValueDefaultDelimiter() {
109         PropertyDescriptorFactory multiFactory = getMultiFactory();
110         PropertyDescriptor prop = multiFactory.createWith(getPropertyDescriptorValues());
111         Object originalValue = createValue(multiValueCount);
112         String asDelimitedString = prop.asDelimitedString(originalValue);
113         Object value2 = prop.valueFrom(asDelimitedString);
114         Assert.assertArrayEquals((Object[]) originalValue, (Object[]) value2);
115     }
116 
117     @Test
118     public void testFactoryMultiValueCustomDelimiter() {
119         PropertyDescriptorFactory multiFactory = getMultiFactory();
120         Map<String, String> valuesById = getPropertyDescriptorValues();
121         String customDelimiter = "รค";
122         Assert.assertFalse(allChars.contains(customDelimiter));
123         valuesById.put(PropertyDescriptorFields.DELIMITER, customDelimiter);
124         PropertyDescriptor prop = multiFactory.createWith(valuesById);
125         Object originalValue = createValue(multiValueCount);
126         String asDelimitedString = prop.asDelimitedString(originalValue);
127         Object value2 = prop.valueFrom(asDelimitedString);
128         Assert.assertEquals(Arrays.toString((Object[]) originalValue), Arrays.toString((Object[]) value2));
129         Assert.assertArrayEquals((Object[]) originalValue, (Object[]) value2);
130     }
131 
132     @Test
133     public void testConstructors() {
134 
135         PropertyDescriptor<?> desc = createProperty(false);
136         assertNotNull(desc);
137 
138         try {
139             createBadProperty(false);
140 
141         } catch (Exception ex) {
142             return; // caught ok
143         }
144 
145         Assert.fail("uncaught constructor exception");
146     }
147 
148     @Test
149     public void testAsDelimitedString() {
150 
151         Object testValue = createValue(multiValueCount);
152         PropertyDescriptor pmdProp = createProperty(true);
153 
154         String storeValue = pmdProp.asDelimitedString(testValue);
155 
156         Object returnedValue = pmdProp.valueFrom(storeValue);
157 
158         assertTrue(CollectionUtil.areEqual(returnedValue, testValue));
159     }
160 
161     @Test
162     public void testValueFrom() {
163 
164         Object testValue = createValue(1);
165         PropertyDescriptor pmdProp = createProperty(false);
166 
167         String storeValue = pmdProp.asDelimitedString(testValue);
168 
169         Object returnedValue = pmdProp.valueFrom(storeValue);
170 
171         assertTrue(CollectionUtil.areEqual(returnedValue, testValue));
172     }
173 
174     @Test
175     public void testErrorFor() {
176 
177         Object testValue = createValue(1);
178         PropertyDescriptor<?> pmdProp = createProperty(false); // plain vanilla
179                                                                // property &
180                                                                // valid test
181                                                                // value
182         String errorMsg = pmdProp.errorFor(testValue);
183         assertNull(errorMsg, errorMsg);
184 
185         testValue = createValue(multiValueCount); // multi-value property, all
186                                                   // valid test values
187         pmdProp = createProperty(true);
188         errorMsg = pmdProp.errorFor(testValue);
189         assertNull(errorMsg, errorMsg);
190 
191     }
192 
193     @Test
194     public void testErrorForBad() {
195 
196         PropertyDescriptor<?> pmdProp = createProperty(false);
197         Object testValue = createBadValue(1);
198         String errorMsg = pmdProp.errorFor(testValue); // bad value should
199                                                        // result in an error
200         if (errorMsg == null) {
201             Assert.fail("uncaught bad value: " + testValue);
202         }
203 
204         testValue = createBadValue(multiValueCount); // multi-value prop,
205                                                      // several bad values
206         pmdProp = createProperty(true);
207         errorMsg = pmdProp.errorFor(testValue);
208         if (errorMsg == null) {
209             Assert.fail("uncaught bad value in: " + testValue);
210         }
211     }
212 
213     @Test
214     public void testType() {
215 
216         PropertyDescriptor<?> pmdProp = createProperty(false);
217 
218         assertNotNull(pmdProp.type());
219     }
220 
221     public static boolean randomBool() {
222         return ((Math.random() * 100) % 2) == 0;
223     }
224 
225     /**
226      * Method randomInt.
227      * 
228      * @return int
229      */
230     public static int randomInt() {
231 
232         int randomVal = (int) (Math.random() * 100 + 1D);
233         return randomVal + (int) (Math.random() * 100000D);
234     }
235 
236     /**
237      * Method randomInt.
238      * 
239      * @param min int
240      * @param max int
241      * @return int
242      */
243     public static int randomInt(int min, int max) {
244         if (max < min)
245             max = min;
246         int range = Math.abs(max - min);
247         int x = (int) (range * Math.random());
248         return x + min;
249     }
250 
251     public static String randomString(int length) {
252 
253         final char[] chars = alphaChars.toCharArray();
254 
255         StringBuilder sb = new StringBuilder(length);
256         for (int i = 0; i < length; i++)
257             sb.append(randomChar(chars));
258         return sb.toString();
259     }
260 
261     /**
262      * Method randomFloat.
263      * 
264      * @param min float
265      * @param max float
266      * @return float
267      */
268     public static float randomFloat(float min, float max) {
269 
270         return (float) randomDouble(min, max);
271     }
272 
273     /**
274      * Method randomDouble.
275      * 
276      * @param min double
277      * @param max double
278      * @return double
279      */
280     public static double randomDouble(double min, double max) {
281         if (max < min)
282             max = min;
283         double range = Math.abs(max - min);
284         double x = range * Math.random();
285         return x + min;
286     }
287 
288     /**
289      * Method randomChar.
290      * 
291      * @param characters char[]
292      * @return char
293      */
294     public static char randomChar(char[] characters) {
295         return characters[randomInt(0, characters.length - 1)];
296     }
297 
298     /**
299      * Method randomChoice.
300      * 
301      * @param items Object[]
302      * @return Object
303      */
304     public static Object randomChoice(Object[] items) {
305         return items[randomInt(0, items.length - 1)];
306     }
307 
308     /**
309      * Method filter.
310      * 
311      * @param chars char[]
312      * @param removeChar char
313      * @return char[]
314      */
315     protected static final char[] filter(char[] chars, char removeChar) {
316         int count = 0;
317         for (int i = 0; i < chars.length; i++)
318             if (chars[i] == removeChar)
319                 count++;
320         char[] results = new char[chars.length - count];
321 
322         int index = 0;
323         for (int i = 0; i < chars.length; i++) {
324             if (chars[i] != removeChar)
325                 results[index++] = chars[i];
326         }
327         return results;
328     }
329 }